/// <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); }
/// <summary> /// Calculates delivery time and updates <see cref="Duration"/>. /// </summary> public void CalculateDuration() { CelestialBody mainBody = Origin.mainBody; var sourceProtoVessel = Origin.protoVessel; var targetProtoVessel = Destination.protoVessel; var sourceSituation = sourceProtoVessel.situation; var targetSituation = targetProtoVessel.situation; // Set base duration (i.e. docking maneuver, refueling and loading/unloading) double baseDuration = DOCKING_TIME * 2 + REFUELING_TIME * 2 + PER_TONNE_LOAD_RATE * TotalMass() * 2; // 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 orbital period of a low, circular orbit around the body double velocity = OrbitalLogisticsExtensions.OrbitalVelocity(mainBody, mainBody.minOrbitalDistance + mainBody.Radius); double period = OrbitalLogisticsExtensions.OrbitalPeriod(mainBody, mainBody.minOrbitalDistance + mainBody.Radius); // Determine the time spent in the air (i.e. a percentage of the orbital period) double inFlight = period * anglePercent; Duration = baseDuration + inFlight * 2; } // One vessel on the ground, one in orbit else if ((sourceSituation == (sourceSituation & SURFACE) && targetSituation == Vessel.Situations.ORBITING) || (sourceSituation == Vessel.Situations.ORBITING && targetSituation == (targetSituation & SURFACE)) ) { // Determine the orbital period of the vessel in orbit double period = sourceSituation == Vessel.Situations.ORBITING ? OrbitalLogisticsExtensions.OrbitalPeriod(mainBody, sourceProtoVessel.orbitSnapShot.semiMajorAxis) : OrbitalLogisticsExtensions.OrbitalPeriod(mainBody, targetProtoVessel.orbitSnapShot.semiMajorAxis); // We'll guess on average it will take 1.5 orbits for the vessel in orbit to be in the right position // for de-orbiting and rendezvous. Duration = baseDuration + period * 1.5; } // 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 difference in sma double dSMA = highOrbitSMA - lowOrbitSMA; // Determine orbital periods of both vessels double highOrbitPeriod = OrbitalLogisticsExtensions.OrbitalPeriod(mainBody, highOrbitSMA); double lowOrbitPeriod = OrbitalLogisticsExtensions.OrbitalPeriod(mainBody, lowOrbitSMA); // If the orbits are similar, we need spend some extra time to get into a transfer orbit double transferPeriod = 0; if (dSMA < 10000) { // Say we'll spend an extra orbit from each vessel to get into a transfer orbit transferPeriod = highOrbitPeriod + lowOrbitPeriod; } // We'll guess on average it will take 4 total orbits to rendezvous, plus any time spent in transfer orbits Duration = baseDuration + highOrbitPeriod * 2 + lowOrbitPeriod * 2 + transferPeriod; } else { Duration = double.PositiveInfinity; } }