/// <summary>
        /// Calculates the fuel units required for the transfer.
        /// </summary>
        public float CalculateFuelUnits()
        {
            // Fuel required is cached at launch, so just return the cached value
            if (Status != DeliveryStatus.PreLaunch)
            {
                return(_fuelUnits);
            }

            CelestialBody mainBody = Origin.mainBody;

            var sourceProtoVessel = Origin.protoVessel;
            var targetProtoVessel = Destination.protoVessel;

            var sourceSituation = sourceProtoVessel.situation;
            var targetSituation = targetProtoVessel.situation;

            double fuelUnits = double.PositiveInfinity;

            // Calculate fuel requirements based on source/target situation (i.e. landed or orbiting)
            // Both vessels on the ground
            if (sourceSituation == (sourceSituation & SURFACE) && targetSituation == (targetSituation & SURFACE))
            {
                // Determine central angle between the vessels' coordinates
                double centralAngle = GetCentralAngle(
                    sourceProtoVessel.latitude, sourceProtoVessel.longitude,
                    targetProtoVessel.latitude, targetProtoVessel.longitude
                    );

                // Determine the percentage of 360 degrees the central angle represents
                double anglePercent = centralAngle / 360;

                // Determine the velocity of a low, circular orbit around the body
                double orbitV = OrbitalLogisticsExtensions.OrbitalVelocity(mainBody, mainBody.minOrbitalDistance + mainBody.Radius);

                // Determine dV required to reach the target (i.e. a percentage of the dV required to achieve full orbit)
                double dV = orbitV * anglePercent * GRAV_LOSS_MODIFIER;

                fuelUnits = CalculateFuelNeededFromDeltaV(dV, mainBody.atmosphere);
            }
            // One or both vessels in orbit
            else
            {
                // One vessel on the ground, one in orbit
                if ((sourceSituation == (sourceSituation & SURFACE) && targetSituation == Vessel.Situations.ORBITING) ||
                    (sourceSituation == Vessel.Situations.ORBITING && targetSituation == (targetSituation & SURFACE))
                    )
                {
                    // Determine average orbital velocity
                    double velocity = sourceSituation == Vessel.Situations.ORBITING
                        ? Origin.AverageOrbitalVelocity()
                        : Destination.AverageOrbitalVelocity();

                    // Determine dV required to land/launch
                    double dV = velocity * INC_CHANGE_MODIFIER * GRAV_LOSS_MODIFIER;

                    fuelUnits = CalculateFuelNeededFromDeltaV(dV, mainBody.atmosphere);
                }
                // Both vessels in orbit
                else if (sourceSituation == Vessel.Situations.ORBITING && targetSituation == Vessel.Situations.ORBITING)
                {
                    // Determine which vessel has the higher semi major axis and which is lower
                    double highOrbitSMA;
                    double lowOrbitSMA;
                    if (sourceProtoVessel.orbitSnapShot.semiMajorAxis >= targetProtoVessel.orbitSnapShot.semiMajorAxis)
                    {
                        highOrbitSMA = sourceProtoVessel.orbitSnapShot.semiMajorAxis;
                        lowOrbitSMA  = targetProtoVessel.orbitSnapShot.semiMajorAxis;
                    }
                    else
                    {
                        highOrbitSMA = targetProtoVessel.orbitSnapShot.semiMajorAxis;
                        lowOrbitSMA  = sourceProtoVessel.orbitSnapShot.semiMajorAxis;
                    }

                    // Determine orbit velocity of origin and destination vessels
                    double highOrbitV = OrbitalLogisticsExtensions.OrbitalVelocity(mainBody, highOrbitSMA);
                    double lowOrbitV  = OrbitalLogisticsExtensions.OrbitalVelocity(mainBody, lowOrbitSMA);

                    // Determine difference in sma
                    double dSMA = highOrbitSMA - lowOrbitSMA;

                    // If the orbits are similar, we need to spend some extra fuel to get into a transfer orbit
                    double transferV = 0;
                    if (dSMA < 10000)
                    {
                        // Determine the dV needed to get into a higher orbit
                        transferV = highOrbitV - OrbitalLogisticsExtensions.OrbitalVelocity(mainBody, highOrbitSMA + 30000);
                    }

                    // Total dV is the difference between the orbital velocities plus any transfer dV needed
                    // Note: Remember, the lower orbit has the higher velocity!
                    double dV = lowOrbitV - highOrbitV + transferV;

                    // Factor in potential inclination changes to calculate the total cost
                    fuelUnits = CalculateFuelNeededFromDeltaV(dV * INC_CHANGE_MODIFIER);
                }
            }

            return((float)fuelUnits * FUEL_MULTIPLIER);
        }