/// <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); }