本文整理汇总了C#中Orbit.SwappedOrbitalVelocityAtUT方法的典型用法代码示例。如果您正苦于以下问题:C# Orbit.SwappedOrbitalVelocityAtUT方法的具体用法?C# Orbit.SwappedOrbitalVelocityAtUT怎么用?C# Orbit.SwappedOrbitalVelocityAtUT使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Orbit
的用法示例。
在下文中一共展示了Orbit.SwappedOrbitalVelocityAtUT方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: DeltaVAndTimeForCheapestCourseCorrection
public static Vector3d DeltaVAndTimeForCheapestCourseCorrection(Orbit o, double UT, Orbit target, CelestialBody targetBody, double finalPeR, out double burnUT)
{
Vector3d collisionDV = DeltaVAndTimeForCheapestCourseCorrection(o, UT, target, out burnUT);
Orbit collisionOrbit = o.PerturbedOrbit(burnUT, collisionDV);
double collisionUT = collisionOrbit.NextClosestApproachTime(target, burnUT);
Vector3d collisionPosition = target.SwappedAbsolutePositionAtUT(collisionUT);
Vector3d collisionRelVel = collisionOrbit.SwappedOrbitalVelocityAtUT(collisionUT) - target.SwappedOrbitalVelocityAtUT(collisionUT);
double soiEnterUT = collisionUT - targetBody.sphereOfInfluence / collisionRelVel.magnitude;
Vector3d soiEnterRelVel = collisionOrbit.SwappedOrbitalVelocityAtUT(soiEnterUT) - target.SwappedOrbitalVelocityAtUT(soiEnterUT);
double E = 0.5 * soiEnterRelVel.sqrMagnitude - targetBody.gravParameter / targetBody.sphereOfInfluence; //total orbital energy on SoI enter
double finalPeSpeed = Math.Sqrt(2 * (E + targetBody.gravParameter / finalPeR)); //conservation of energy gives the orbital speed at finalPeR.
double desiredImpactParameter = finalPeR * finalPeSpeed / soiEnterRelVel.magnitude; //conservation of angular momentum gives the required impact parameter
Vector3d displacementDir = Vector3d.Cross(collisionRelVel, o.SwappedOrbitNormal()).normalized;
Vector3d interceptTarget = collisionPosition + desiredImpactParameter * displacementDir;
Vector3d velAfterBurn;
Vector3d arrivalVel;
LambertSolver.Solve(o.SwappedRelativePositionAtUT(burnUT), interceptTarget - o.referenceBody.position, collisionUT - burnUT, o.referenceBody, true, out velAfterBurn, out arrivalVel);
Vector3d deltaV = velAfterBurn - o.SwappedOrbitalVelocityAtUT(burnUT);
return deltaV;
}
示例2: DeltaVToChangePeriapsis
//Computes the delta-V of the burn required to attain a given periapsis, starting from
//a given orbit and burning at a given UT. Throws an ArgumentException if given an impossible periapsis.
//The computed burn is always horizontal, though this may not be strictly optimal.
public static Vector3d DeltaVToChangePeriapsis(Orbit o, double UT, double newPeR)
{
double radius = o.Radius(UT);
//sanitize input
newPeR = MuUtils.Clamp(newPeR, 0 + 1, radius - 1);
//are we raising or lowering the periapsis?
bool raising = (newPeR > o.PeR);
Vector3d burnDirection = (raising ? 1 : -1) * o.Horizontal(UT);
double minDeltaV = 0;
double maxDeltaV;
if (raising)
{
//put an upper bound on the required deltaV:
maxDeltaV = 0.25;
while (o.PerturbedOrbit(UT, maxDeltaV * burnDirection).PeR < newPeR)
{
maxDeltaV *= 2;
if (maxDeltaV > 100000) break; //a safety precaution
}
}
else
{
//when lowering periapsis, we burn horizontally, and max possible deltaV is the deltaV required to kill all horizontal velocity
maxDeltaV = Math.Abs(Vector3d.Dot(o.SwappedOrbitalVelocityAtUT(UT), burnDirection));
}
//now do a binary search to find the needed delta-v
while (maxDeltaV - minDeltaV > 0.01)
{
double testDeltaV = (maxDeltaV + minDeltaV) / 2.0;
double testPeriapsis = o.PerturbedOrbit(UT, testDeltaV * burnDirection).PeR;
if ((testPeriapsis > newPeR && raising) || (testPeriapsis < newPeR && !raising))
{
maxDeltaV = testDeltaV;
}
else
{
minDeltaV = testDeltaV;
}
}
return ((maxDeltaV + minDeltaV) / 2) * burnDirection;
}
示例3: DeltaVToEllipticize
//Computes the deltaV of the burn needed to set a given PeR and ApR at at a given UT.
public static Vector3d DeltaVToEllipticize(Orbit o, double UT, double newPeR, double newApR)
{
double radius = o.Radius(UT);
//sanitize inputs
newPeR = MuUtils.Clamp(newPeR, 0 + 1, radius - 1);
newApR = Math.Max(newApR, radius + 1);
double GM = o.referenceBody.gravParameter;
double E = -GM / (newPeR + newApR); //total energy per unit mass of new orbit
double L = Math.Sqrt(Math.Abs((Math.Pow(E * (newApR - newPeR), 2) - GM * GM) / (2 * E))); //angular momentum per unit mass of new orbit
double kineticE = E + GM / radius; //kinetic energy (per unit mass) of new orbit at UT
double horizontalV = L / radius; //horizontal velocity of new orbit at UT
double verticalV = Math.Sqrt(Math.Abs(2 * kineticE - horizontalV * horizontalV)); //vertical velocity of new orbit at UT
Vector3d actualVelocity = o.SwappedOrbitalVelocityAtUT(UT);
//untested:
verticalV *= Math.Sign(Vector3d.Dot(o.Up(UT), actualVelocity));
Vector3d desiredVelocity = horizontalV * o.Horizontal(UT) + verticalV * o.Up(UT);
return desiredVelocity - actualVelocity;
}
示例4: DeltaVToMatchVelocities
//Computes the delta-V of the burn at a given time required to zero out the difference in orbital velocities
//between a given orbit and a target.
public static Vector3d DeltaVToMatchVelocities(Orbit o, double UT, Orbit target)
{
return target.SwappedOrbitalVelocityAtUT(UT) - o.SwappedOrbitalVelocityAtUT(UT);
}
示例5: DeltaVToInterceptAtTime
//Computes the delta-V of a burn at a given time that will put an object with a given orbit on a
//course to intercept a target at a specific interceptUT.
public static Vector3d DeltaVToInterceptAtTime(Orbit o, double UT, Orbit target, double interceptUT, double offsetDistance = 0)
{
double initialT = UT;
Vector3d initialRelPos = o.SwappedRelativePositionAtUT(initialT);
double finalT = interceptUT;
Vector3d finalRelPos = target.SwappedRelativePositionAtUT(finalT);
double targetOrbitalSpeed = o.SwappedOrbitalVelocityAtUT(finalT).magnitude;
double deltaTPrecision = 20.0 / targetOrbitalSpeed;
Vector3d initialVelocity, finalVelocity;
LambertSolver.Solve(initialRelPos, finalRelPos, finalT - initialT, o.referenceBody, true, out initialVelocity, out finalVelocity);
if (offsetDistance != 0)
{
finalRelPos += offsetDistance * Vector3d.Cross(finalVelocity, finalRelPos).normalized;
LambertSolver.Solve(initialRelPos, finalRelPos, finalT - initialT, o.referenceBody, true, out initialVelocity, out finalVelocity);
}
Vector3d currentInitialVelocity = o.SwappedOrbitalVelocityAtUT(initialT);
return initialVelocity - currentInitialVelocity;
}
示例6: DeltaVToCircularize
//Computes the deltaV of the burn needed to circularize an orbit at a given UT.
public static Vector3d DeltaVToCircularize(Orbit o, double UT)
{
Vector3d desiredVelocity = CircularOrbitSpeed(o.referenceBody, o.Radius(UT)) * o.Horizontal(UT);
Vector3d actualVelocity = o.SwappedOrbitalVelocityAtUT(UT);
return desiredVelocity - actualVelocity;
}
示例7: DeltaVToChangeInclination
//Computes the delta-V of the burn required to change an orbit's inclination to a given value
//at a given UT. If the latitude at that time is too high, so that the desired inclination
//cannot be attained, the burn returned will achieve as low an inclination as possible (namely, inclination = latitude).
//The input inclination is in degrees.
//Note that there are two orbits through each point with a given inclination. The convention used is:
// - first, clamp newInclination to the range -180, 180
// - if newInclination > 0, do the cheaper burn to set that inclination
// - if newInclination < 0, do the more expensive burn to set that inclination
public static Vector3d DeltaVToChangeInclination(Orbit o, double UT, double newInclination)
{
double latitude = o.referenceBody.GetLatitude(o.SwappedAbsolutePositionAtUT(UT));
double desiredHeading = HeadingForInclination(newInclination, latitude);
Vector3d actualHorizontalVelocity = Vector3d.Exclude(o.Up(UT), o.SwappedOrbitalVelocityAtUT(UT));
Vector3d eastComponent = actualHorizontalVelocity.magnitude * Math.Sin(Math.PI / 180 * desiredHeading) * o.East(UT);
Vector3d northComponent = actualHorizontalVelocity.magnitude * Math.Cos(Math.PI / 180 * desiredHeading) * o.North(UT);
if (Vector3d.Dot(actualHorizontalVelocity, northComponent) < 0) northComponent *= -1;
if (MuUtils.ClampDegrees180(newInclination) < 0) northComponent *= -1;
Vector3d desiredHorizontalVelocity = eastComponent + northComponent;
return desiredHorizontalVelocity - actualHorizontalVelocity;
}
示例8: DeltaVToChangeApoapsis
//Computes the delta-V of the burn at a given UT required to change an orbits apoapsis to a given value.
//The computed burn is always prograde or retrograde, though this may not be strictly optimal.
//Note that you can pass in a negative apoapsis if the desired final orbit is hyperbolic
public static Vector3d DeltaVToChangeApoapsis(Orbit o, double UT, double newApR)
{
double radius = o.Radius(UT);
//sanitize input
if (newApR > 0) newApR = Math.Max(newApR, radius + 1);
//are we raising or lowering the periapsis?
bool raising = ApoapsisIsHigher(newApR, o.ApR);
Vector3d burnDirection = (raising ? 1 : -1) * o.Prograde(UT);
double minDeltaV = 0;
double maxDeltaV;
if (raising)
{
//put an upper bound on the required deltaV:
maxDeltaV = 0.25;
double ap = o.ApR;
while (ApoapsisIsHigher(newApR, ap))
{
maxDeltaV *= 2;
ap = o.PerturbedOrbit(UT, maxDeltaV * burnDirection).ApR;
if (maxDeltaV > 100000) break; //a safety precaution
}
}
else
{
//when lowering apoapsis, we burn retrograde, and max possible deltaV is total velocity
maxDeltaV = o.SwappedOrbitalVelocityAtUT(UT).magnitude;
}
//now do a binary search to find the needed delta-v
while (maxDeltaV - minDeltaV > 0.01)
{
double testDeltaV = (maxDeltaV + minDeltaV) / 2.0;
double testApoapsis = o.PerturbedOrbit(UT, testDeltaV * burnDirection).ApR;
bool above = ApoapsisIsHigher(testApoapsis, newApR);
if ((raising && above) || (!raising && !above))
{
maxDeltaV = testDeltaV;
}
else
{
minDeltaV = testDeltaV;
}
}
return ((maxDeltaV + minDeltaV) / 2) * burnDirection;
}
示例9: DeltaVAndTimeToMatchPlanesDescending
//Computes the delta-V and time of a burn to match planes with the target orbit. The output burnUT
//will be equal to the time of the first descending node with respect to the target after the given UT.
//Throws an ArgumentException if o is hyperbolic and doesn't have a descending node relative to the target.
public static Vector3d DeltaVAndTimeToMatchPlanesDescending(Orbit o, Orbit target, double UT, out double burnUT)
{
burnUT = o.TimeOfDescendingNode(target, UT);
Vector3d desiredHorizontal = Vector3d.Cross(target.SwappedOrbitNormal(), o.Up(burnUT));
Vector3d actualHorizontalVelocity = Vector3d.Exclude(o.Up(burnUT), o.SwappedOrbitalVelocityAtUT(burnUT));
Vector3d desiredHorizontalVelocity = actualHorizontalVelocity.magnitude * desiredHorizontal;
return desiredHorizontalVelocity - actualHorizontalVelocity;
}
示例10: DeltaVAndTimeForInterplanetaryTransferEjection
//Computes the time and delta-V of an ejection burn to a Hohmann transfer from one planet to another.
//It's assumed that the initial orbit around the first planet is circular, and that this orbit
//is in the same plane as the orbit of the first planet around the sun. It's also assumed that
//the target planet has a fairly low relative inclination with respect to the first planet. If the
//inclination change is nonzero you should also do a mid-course correction burn, as computed by
//DeltaVForCourseCorrection.
public static Vector3d DeltaVAndTimeForInterplanetaryTransferEjection(Orbit o, double UT, Orbit target, bool syncPhaseAngle, out double burnUT)
{
Orbit planetOrbit = o.referenceBody.orbit;
//Compute the time and dV for a Hohmann transfer where we pretend that we are the planet we are orbiting.
//This gives us the "ideal" deltaV and UT of the ejection burn, if we didn't have to worry about waiting for the right
//ejection angle and if we didn't have to worry about the planet's gravity dragging us back and increasing the required dV.
double idealBurnUT;
Vector3d idealDeltaV;
if (syncPhaseAngle)
{
//time the ejection burn to intercept the target
idealDeltaV = DeltaVAndTimeForHohmannTransfer(planetOrbit, target, UT, out idealBurnUT);
}
else
{
//don't time the ejection burn to intercept the target; we just care about the final peri/apoapsis
idealBurnUT = UT;
if (target.semiMajorAxis < planetOrbit.semiMajorAxis) idealDeltaV = DeltaVToChangePeriapsis(planetOrbit, idealBurnUT, target.semiMajorAxis);
else idealDeltaV = DeltaVToChangeApoapsis(planetOrbit, idealBurnUT, target.semiMajorAxis);
}
//Compute the actual transfer orbit this ideal burn would lead to.
Orbit transferOrbit = planetOrbit.PerturbedOrbit(idealBurnUT, idealDeltaV);
//Now figure out how to approximately eject from our current orbit into the Hohmann orbit we just computed.
//Assume we want to exit the SOI with the same velocity as the ideal transfer orbit at idealUT -- i.e., immediately
//after the "ideal" burn we used to compute the transfer orbit. This isn't quite right.
//We intend to eject from our planet at idealUT and only several hours later will we exit the SOI. Meanwhile
//the transfer orbit will have acquired a slightly different velocity, which we should correct for. Maybe
//just add in (1/2)(sun gravity)*(time to exit soi)^2 ? But how to compute time to exit soi? Or maybe once we
//have the ejection orbit we should just move the ejection burn back by the time to exit the soi?
Vector3d soiExitVelocity = idealDeltaV;
//project the desired exit direction into the current orbit plane to get the feasible exit direction
Vector3d inPlaneSoiExitDirection = Vector3d.Exclude(o.SwappedOrbitNormal(), soiExitVelocity).normalized;
//compute the angle by which the trajectory turns between periapsis (where we do the ejection burn)
//and SOI exit (approximated as radius = infinity)
double soiExitEnergy = 0.5 * soiExitVelocity.sqrMagnitude - o.referenceBody.gravParameter / o.referenceBody.sphereOfInfluence;
double ejectionRadius = o.semiMajorAxis; //a guess, good for nearly circular orbits
double ejectionKineticEnergy = soiExitEnergy + o.referenceBody.gravParameter / ejectionRadius;
double ejectionSpeed = Math.Sqrt(2 * ejectionKineticEnergy);
//construct a sample ejection orbit
Vector3d ejectionOrbitInitialVelocity = ejectionSpeed * (Vector3d)o.referenceBody.transform.right;
Vector3d ejectionOrbitInitialPosition = o.referenceBody.position + ejectionRadius * (Vector3d)o.referenceBody.transform.up;
Orbit sampleEjectionOrbit = MuUtils.OrbitFromStateVectors(ejectionOrbitInitialPosition, ejectionOrbitInitialVelocity, o.referenceBody, 0);
double ejectionOrbitDuration = sampleEjectionOrbit.NextTimeOfRadius(0, o.referenceBody.sphereOfInfluence);
Vector3d ejectionOrbitFinalVelocity = sampleEjectionOrbit.SwappedOrbitalVelocityAtUT(ejectionOrbitDuration);
double turningAngle = Math.Abs(Vector3d.Angle(ejectionOrbitInitialVelocity, ejectionOrbitFinalVelocity));
//rotate the exit direction by 90 + the turning angle to get a vector pointing to the spot in our orbit
//where we should do the ejection burn. Then convert this to a true anomaly and compute the time closest
//to planetUT at which we will pass through that true anomaly.
Vector3d ejectionPointDirection = Quaternion.AngleAxis(-(float)(90 + turningAngle), o.SwappedOrbitNormal()) * inPlaneSoiExitDirection;
double ejectionTrueAnomaly = o.TrueAnomalyFromVector(ejectionPointDirection);
burnUT = o.TimeOfTrueAnomaly(ejectionTrueAnomaly, idealBurnUT - o.period);
if ((idealBurnUT - burnUT > o.period / 2) || (burnUT < UT))
{
burnUT += o.period;
}
//rotate the exit direction by the turning angle to get a vector pointing to the spot in our orbit
//where we should do the ejection burn
Vector3d ejectionBurnDirection = Quaternion.AngleAxis(-(float)(turningAngle), o.SwappedOrbitNormal()) * inPlaneSoiExitDirection;
Vector3d ejectionVelocity = ejectionSpeed * ejectionBurnDirection;
Vector3d preEjectionVelocity = o.SwappedOrbitalVelocityAtUT(burnUT);
return ejectionVelocity - preEjectionVelocity;
}
示例11: FreefallEnded
//Freefall orbit ends when either
// - we enter the atmosphere, or
// - our vertical velocity is negative and either
// - we've landed or
// - the descent speed policy says to start braking
bool FreefallEnded(Orbit initialOrbit, double UT)
{
Vector3d pos = initialOrbit.SwappedRelativePositionAtUT(UT);
Vector3d surfaceVelocity = SurfaceVelocity(pos, initialOrbit.SwappedOrbitalVelocityAtUT(UT));
if (pos.magnitude < aerobrakedRadius) return true;
if (Vector3d.Dot(surfaceVelocity, initialOrbit.Up(UT)) > 0) return false;
if (pos.magnitude < landedRadius) return true;
if (descentSpeedPolicy != null && surfaceVelocity.magnitude > descentSpeedPolicy.MaxAllowedSpeed(pos, surfaceVelocity)) return true;
return false;
}
示例12: AdvanceToFreefallEnd
void AdvanceToFreefallEnd(Orbit initialOrbit)
{
t = FindFreefallEndTime(initialOrbit);
x = initialOrbit.SwappedRelativePositionAtUT(t);
v = initialOrbit.SwappedOrbitalVelocityAtUT(t);
if (double.IsNaN(v.magnitude))
{
//For eccentricities close to 1, the Orbit class functions are unreliable and
//v may come out as NaN. If that happens we estimate v from conservation
//of energy and the assumption that v is vertical (since ecc. is approximately 1).
//0.5 * v^2 - GM / r = E => v = sqrt(2 * (E + GM / r))
double GM = initialOrbit.referenceBody.gravParameter;
double E = -GM / (2 * initialOrbit.semiMajorAxis);
v = Math.Sqrt(Math.Abs(2 * (E + GM / x.magnitude))) * x.normalized;
if (initialOrbit.MeanAnomalyAtUT(t) > Math.PI) v *= -1;
}
}
示例13: DeltaVForSemiMajorAxis
public static Vector3d DeltaVForSemiMajorAxis(Orbit o, double UT, double newSMA)
{
bool raising = o.semiMajorAxis < newSMA;
Vector3d burnDirection = (raising ? 1 : -1) * o.Prograde(UT);
double minDeltaV = 0;
double maxDeltaV;
if (raising)
{
//put an upper bound on the required deltaV:
maxDeltaV = 0.25;
while (o.PerturbedOrbit(UT, maxDeltaV * burnDirection).semiMajorAxis < newSMA)
{
maxDeltaV *= 2;
if (maxDeltaV > 100000)
break; //a safety precaution
}
}
else
{
//when lowering the SMA, we burn horizontally, and max possible deltaV is the deltaV required to kill all horizontal velocity
maxDeltaV = Math.Abs(Vector3d.Dot(o.SwappedOrbitalVelocityAtUT(UT), burnDirection));
}
// Debug.Log (String.Format ("We are {0} SMA to {1}", raising ? "raising" : "lowering", newSMA));
// Debug.Log (String.Format ("Starting SMA iteration with maxDeltaV of {0}", maxDeltaV));
//now do a binary search to find the needed delta-v
while (maxDeltaV - minDeltaV > 0.01)
{
double testDeltaV = (maxDeltaV + minDeltaV) / 2.0;
double testSMA = o.PerturbedOrbit(UT, testDeltaV * burnDirection).semiMajorAxis;
// Debug.Log (String.Format ("Testing dV of {0} gave an SMA of {1}", testDeltaV, testSMA));
if ((testSMA < 0) || (testSMA > newSMA && raising) || (testSMA < newSMA && !raising))
{
maxDeltaV = testDeltaV;
}
else
{
minDeltaV = testDeltaV;
}
}
return ((maxDeltaV + minDeltaV) / 2) * burnDirection;
}
示例14: DeltaVToShiftLAN
//Computes the deltaV of the burn needed to set a given LAN at a given UT.
public static Vector3d DeltaVToShiftLAN(Orbit o, double UT, double newLAN)
{
Vector3d pos = o.SwappedAbsolutePositionAtUT(UT);
// Burn position in the same reference frame as LAN
double burn_latitude = o.referenceBody.GetLatitude(pos);
double burn_longitude = o.referenceBody.GetLongitude(pos) + o.referenceBody.rotationAngle;
const double target_latitude = 0; // Equator
double target_longitude = 0; // Prime Meridian
// Select the location of either the descending or ascending node.
// If the descending node is closer than the ascending node, or there is no ascending node, target the reverse of the newLAN
// Otherwise target the newLAN
if (o.AscendingNodeEquatorialExists() && o.DescendingNodeEquatorialExists())
{
if (o.TimeOfDescendingNodeEquatorial(UT) < o.TimeOfAscendingNodeEquatorial(UT))
{
// DN is closer than AN
// Burning for the AN would entail flipping the orbit around, and would be very expensive
// therefore, burn for the corresponding Longitude of the Descending Node
target_longitude = MuUtils.ClampDegrees360(newLAN + 180.0);
}
else
{
// DN is closer than AN
target_longitude = MuUtils.ClampDegrees360(newLAN);
}
}
else if (o.AscendingNodeEquatorialExists() && !o.DescendingNodeEquatorialExists())
{
// No DN
target_longitude = MuUtils.ClampDegrees360(newLAN);
}
else if (!o.AscendingNodeEquatorialExists() && o.DescendingNodeEquatorialExists())
{
// No AN
target_longitude = MuUtils.ClampDegrees360(newLAN + 180.0);
}
else
{
throw new ArgumentException("OrbitalManeuverCalculator.DeltaVToShiftLAN: No Equatorial Nodes");
}
double desiredHeading = MuUtils.ClampDegrees360(Heading(burn_latitude, burn_longitude, target_latitude, target_longitude));
Vector3d actualHorizontalVelocity = Vector3d.Exclude(o.Up(UT), o.SwappedOrbitalVelocityAtUT(UT));
Vector3d eastComponent = actualHorizontalVelocity.magnitude * Math.Sin(Math.PI / 180 * desiredHeading) * o.East(UT);
Vector3d northComponent = actualHorizontalVelocity.magnitude * Math.Cos(Math.PI / 180 * desiredHeading) * o.North(UT);
Vector3d desiredHorizontalVelocity = eastComponent + northComponent;
return desiredHorizontalVelocity - actualHorizontalVelocity;
}
示例15: DeltaVAndTimeForInterplanetaryLambertTransferEjection
//Computes the time and delta-V of an ejection burn to a Hohmann transfer from one planet to another.
//It's assumed that the initial orbit around the first planet is circular, and that this orbit
//is in the same plane as the orbit of the first planet around the sun. It's also assumed that
//the target planet has a fairly low relative inclination with respect to the first planet. If the
//inclination change is nonzero you should also do a mid-course correction burn, as computed by
//DeltaVForCourseCorrection.
public static Vector3d DeltaVAndTimeForInterplanetaryLambertTransferEjection(Orbit o, double UT, Orbit target, out double burnUT)
{
Orbit planetOrbit = o.referenceBody.orbit;
//Compute the time and dV for a Hohmann transfer where we pretend that we are the planet we are orbiting.
//This gives us the "ideal" deltaV and UT of the ejection burn, if we didn't have to worry about waiting for the right
//ejection angle and if we didn't have to worry about the planet's gravity dragging us back and increasing the required dV.
double idealBurnUT;
Vector3d idealDeltaV;
//time the ejection burn to intercept the target
//idealDeltaV = DeltaVAndTimeForHohmannTransfer(planetOrbit, target, UT, out idealBurnUT);
double vesselOrbitVelocity = OrbitalManeuverCalculator.CircularOrbitSpeed(o.referenceBody, o.semiMajorAxis);
idealDeltaV = DeltaVAndTimeForHohmannLambertTransfer(planetOrbit, target, UT, out idealBurnUT, vesselOrbitVelocity);
Debug.Log("idealBurnUT = " + idealBurnUT + ", idealDeltaV = " + idealDeltaV);
//Compute the actual transfer orbit this ideal burn would lead to.
Orbit transferOrbit = planetOrbit.PerturbedOrbit(idealBurnUT, idealDeltaV);
//Now figure out how to approximately eject from our current orbit into the Hohmann orbit we just computed.
//Assume we want to exit the SOI with the same velocity as the ideal transfer orbit at idealUT -- i.e., immediately
//after the "ideal" burn we used to compute the transfer orbit. This isn't quite right.
//We intend to eject from our planet at idealUT and only several hours later will we exit the SOI. Meanwhile
//the transfer orbit will have acquired a slightly different velocity, which we should correct for. Maybe
//just add in (1/2)(sun gravity)*(time to exit soi)^2 ? But how to compute time to exit soi? Or maybe once we
//have the ejection orbit we should just move the ejection burn back by the time to exit the soi?
Vector3d soiExitVelocity = idealDeltaV;
Debug.Log("soiExitVelocity = " + (Vector3)soiExitVelocity);
//compute the angle by which the trajectory turns between periapsis (where we do the ejection burn)
//and SOI exit (approximated as radius = infinity)
double soiExitEnergy = 0.5 * soiExitVelocity.sqrMagnitude - o.referenceBody.gravParameter / o.referenceBody.sphereOfInfluence;
double ejectionRadius = o.semiMajorAxis; //a guess, good for nearly circular orbits
Debug.Log("soiExitEnergy = " + soiExitEnergy);
Debug.Log("ejectionRadius = " + ejectionRadius);
double ejectionKineticEnergy = soiExitEnergy + o.referenceBody.gravParameter / ejectionRadius;
double ejectionSpeed = Math.Sqrt(2 * ejectionKineticEnergy);
Debug.Log("ejectionSpeed = " + ejectionSpeed);
//construct a sample ejection orbit
Vector3d ejectionOrbitInitialVelocity = ejectionSpeed * (Vector3d)o.referenceBody.transform.right;
Vector3d ejectionOrbitInitialPosition = o.referenceBody.position + ejectionRadius * (Vector3d)o.referenceBody.transform.up;
Orbit sampleEjectionOrbit = MuUtils.OrbitFromStateVectors(ejectionOrbitInitialPosition, ejectionOrbitInitialVelocity, o.referenceBody, 0);
double ejectionOrbitDuration = sampleEjectionOrbit.NextTimeOfRadius(0, o.referenceBody.sphereOfInfluence);
Vector3d ejectionOrbitFinalVelocity = sampleEjectionOrbit.SwappedOrbitalVelocityAtUT(ejectionOrbitDuration);
double turningAngle = Vector3d.Angle(ejectionOrbitInitialVelocity, ejectionOrbitFinalVelocity);
Debug.Log("turningAngle = " + turningAngle);
//sine of the angle between the vessel orbit and the desired SOI exit velocity
double outOfPlaneAngle = (Math.PI / 180) * (90 - Vector3d.Angle(soiExitVelocity, o.SwappedOrbitNormal()));
Debug.Log("outOfPlaneAngle (rad) = " + outOfPlaneAngle);
double coneAngle = Math.PI / 2 - (Math.PI / 180) * turningAngle;
Debug.Log("coneAngle (rad) = " + coneAngle);
Vector3d exitNormal = Vector3d.Cross(-soiExitVelocity, o.SwappedOrbitNormal()).normalized;
Vector3d normal2 = Vector3d.Cross(exitNormal, -soiExitVelocity).normalized;
//unit vector pointing to the spot on our orbit where we will burn.
//fails if outOfPlaneAngle > coneAngle.
Vector3d ejectionPointDirection = Math.Cos(coneAngle) * (-soiExitVelocity.normalized)
+ Math.Cos(coneAngle) * Math.Tan(outOfPlaneAngle) * normal2
- Math.Sqrt(Math.Pow(Math.Sin(coneAngle), 2) - Math.Pow(Math.Cos(coneAngle) * Math.Tan(outOfPlaneAngle), 2)) * exitNormal;
Debug.Log("soiExitVelocity = " + (Vector3)soiExitVelocity);
Debug.Log("vessel orbit normal = " + (Vector3)(1000 * o.SwappedOrbitNormal()));
Debug.Log("exitNormal = " + (Vector3)(1000 * exitNormal));
Debug.Log("normal2 = " + (Vector3)(1000 * normal2));
Debug.Log("ejectionPointDirection = " + ejectionPointDirection);
double ejectionTrueAnomaly = o.TrueAnomalyFromVector(ejectionPointDirection);
burnUT = o.TimeOfTrueAnomaly(ejectionTrueAnomaly, idealBurnUT - o.period);
if ((idealBurnUT - burnUT > o.period / 2) || (burnUT < UT))
{
burnUT += o.period;
}
Vector3d ejectionOrbitNormal = Vector3d.Cross(ejectionPointDirection, soiExitVelocity).normalized;
Debug.Log("ejectionOrbitNormal = " + ejectionOrbitNormal);
Vector3d ejectionBurnDirection = Quaternion.AngleAxis(-(float)(turningAngle), ejectionOrbitNormal) * soiExitVelocity.normalized;
Debug.Log("ejectionBurnDirection = " + ejectionBurnDirection);
Vector3d ejectionVelocity = ejectionSpeed * ejectionBurnDirection;
Vector3d preEjectionVelocity = o.SwappedOrbitalVelocityAtUT(burnUT);
return ejectionVelocity - preEjectionVelocity;
}