//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); }
protected override void WindowGUI(int windowID) { if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label1"));//"No maneuver nodes to edit." RelativityModeSelectUI(); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); ManeuverNode oldNode = node; if (vessel.patchedConicSolver.maneuverNodes.Count == 1) { node = vessel.patchedConicSolver.maneuverNodes[0]; } else { if (!vessel.patchedConicSolver.maneuverNodes.Contains(node)) { node = vessel.patchedConicSolver.maneuverNodes[0]; } int nodeIndex = vessel.patchedConicSolver.maneuverNodes.IndexOf(node); int numNodes = vessel.patchedConicSolver.maneuverNodes.Count; nodeIndex = GuiUtils.ArrowSelector(nodeIndex, numNodes, "Maneuver node #" + (nodeIndex + 1)); node = vessel.patchedConicSolver.maneuverNodes[nodeIndex]; if (nodeIndex < (numNodes - 1) && GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button1"))) { MergeNext(nodeIndex); //"Merge next node" } } if (node != oldNode) { prograde = node.DeltaV.z; radialPlus = node.DeltaV.x; normalPlus = node.DeltaV.y; } if (gizmo != node.attachedGizmo) { if (gizmo != null) { gizmo.OnGizmoUpdated -= GizmoUpdateHandler; } gizmo = node.attachedGizmo; if (gizmo != null) { gizmo.OnGizmoUpdated += GizmoUpdateHandler; } } GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label2"), prograde, "m/s", 60);//"Prograde:" if (LimitedRepeatButtoon("-")) { prograde -= progradeDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50)); if (LimitedRepeatButtoon("+")) { prograde += progradeDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label3"), radialPlus, "m/s", 60);//"Radial+:" if (LimitedRepeatButtoon("-")) { radialPlus -= radialPlusDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50)); if (LimitedRepeatButtoon("+")) { radialPlus += radialPlusDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label4"), normalPlus, "m/s", 60);//"Normal+:" if (LimitedRepeatButtoon("-")) { normalPlus -= normalPlusDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50)); if (LimitedRepeatButtoon("+")) { normalPlus += normalPlusDelta; node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label5"), GUILayout.ExpandWidth(true));//"Set delta to:" if (GUILayout.Button("0.01", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 0.01; } if (GUILayout.Button("0.1", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 0.1; } if (GUILayout.Button("1", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 1; } if (GUILayout.Button("10", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 10; } if (GUILayout.Button("100", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 100; } GUILayout.EndHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button2"))) { node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT); //"Update" } GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label6"), GUILayout.ExpandWidth(true));//"Shift time" if (GUILayout.Button("-o", GUILayout.ExpandWidth(false))) { node.UpdateNode(node.DeltaV, node.UT - node.patch.period); } if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { node.UpdateNode(node.DeltaV, node.UT - timeOffset); } timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { node.UpdateNode(node.DeltaV, node.UT + timeOffset); } if (GUILayout.Button("+o", GUILayout.ExpandWidth(false))) { node.UpdateNode(node.DeltaV, node.UT + node.patch.period); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button3"), GUILayout.ExpandWidth(true)))//"Snap node to" { Orbit o = node.patch; double UT = node.UT; switch (snap) { case Snap.PERIAPSIS: UT = o.NextPeriapsisTime(o.eccentricity < 1 ? UT - o.period / 2 : UT); break; case Snap.APOAPSIS: if (o.eccentricity < 1) { UT = o.NextApoapsisTime(UT - o.period / 2); } break; case Snap.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) { UT = o.TimeOfAscendingNodeEquatorial(UT - o.period / 2); } break; case Snap.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT - o.period / 2); } break; case Snap.REL_ASCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.AscendingNodeExists(core.target.TargetOrbit)) { UT = o.TimeOfAscendingNode(core.target.TargetOrbit, UT - o.period / 2); } } break; case Snap.REL_DESCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.DescendingNodeExists(core.target.TargetOrbit)) { UT = o.TimeOfDescendingNode(core.target.TargetOrbit, UT - o.period / 2); } } break; } node.UpdateNode(node.DeltaV, UT); } snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]); GUILayout.EndHorizontal(); RelativityModeSelectUI(); if (core.node != null) { if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && !core.node.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button4")))//"Execute next node" { core.node.ExecuteOneNode(this); } if (MechJebModuleGuidanceController.isLoadedPrincipia && GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button7")))//Execute next Principia node { core.node.ExecuteOnePNode(this); } if (vessel.patchedConicSolver.maneuverNodes.Count > 1) { if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button5")))//"Execute all nodes" { core.node.ExecuteAllNodes(this); } } } else if (core.node.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button6")))//"Abort node execution" { core.node.Abort(); } } GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, Localizer.Format("#MechJeb_NodeEd_checkbox1"), GUILayout.ExpandWidth(true)); //"Auto-warp" GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label7"), GUILayout.ExpandWidth(false)); //"Tolerance:" core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
public double ComputeManeuverTime(Orbit o, double UT, MechJebModuleTargetController target) { switch (allowedTimeRef[currentTimeRef]) { case TimeReference.X_FROM_NOW: UT += leadTime.val; break; case TimeReference.APOAPSIS: if (o.eccentricity < 1) { UT = o.NextApoapsisTime(UT); } else { throw new OperationException("Warning: orbit is hyperbolic, so apoapsis doesn't exist."); } break; case TimeReference.PERIAPSIS: UT = o.NextPeriapsisTime(UT); break; case TimeReference.CLOSEST_APPROACH: if (target.NormalTargetExists) { UT = o.NextClosestApproachTime(target.TargetOrbit, UT); } else { throw new OperationException("Warning: no target selected."); } break; case TimeReference.ALTITUDE: if (circularizeAltitude > o.PeA && (circularizeAltitude < o.ApA || o.eccentricity >= 1)) { UT = o.NextTimeOfRadius(UT, o.referenceBody.Radius + circularizeAltitude); } else { throw new OperationException("Warning: can't circularize at this altitude, since current orbit does not reach it."); } break; case TimeReference.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) { UT = o.TimeOfAscendingNodeEquatorial(UT); } else { throw new OperationException("Warning: equatorial ascending node doesn't exist."); } break; case TimeReference.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT); } else { throw new OperationException("Warning: equatorial descending node doesn't exist."); } break; case TimeReference.EQ_NEAREST_AD: if (o.AscendingNodeEquatorialExists()) { UT = o.DescendingNodeEquatorialExists() ? System.Math.Min(o.TimeOfAscendingNodeEquatorial(UT), o.TimeOfDescendingNodeEquatorial(UT)) : o.TimeOfAscendingNodeEquatorial(UT); } else if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT); } else { throw new OperationException("Warning: neither ascending nor descending node exists."); } break; case TimeReference.EQ_HIGHEST_AD: if (o.AscendingNodeEquatorialExists()) { if (o.DescendingNodeEquatorialExists()) { var anTime = o.TimeOfAscendingNodeEquatorial(UT); var dnTime = o.TimeOfDescendingNodeEquatorial(UT); UT = o.getOrbitalVelocityAtUT(anTime).magnitude <= o.getOrbitalVelocityAtUT(dnTime).magnitude ? anTime : dnTime; } else { UT = o.TimeOfAscendingNodeEquatorial(UT); } } else if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT); } else { throw new OperationException("Warning: neither ascending nor descending node exists."); } break; } universalTime = UT; return(universalTime); }
protected override void WindowGUI(int windowID) { if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { GUILayout.Label("No maneuver nodes to edit."); RelativityModeSelectUI(); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); ManeuverNode oldNode = node; if (vessel.patchedConicSolver.maneuverNodes.Count == 1) { node = vessel.patchedConicSolver.maneuverNodes[0]; } else { if (!vessel.patchedConicSolver.maneuverNodes.Contains(node)) { node = vessel.patchedConicSolver.maneuverNodes[0]; } int nodeIndex = vessel.patchedConicSolver.maneuverNodes.IndexOf(node); int numNodes = vessel.patchedConicSolver.maneuverNodes.Count; nodeIndex = GuiUtils.ArrowSelector(nodeIndex, numNodes, "Maneuver node #" + (nodeIndex + 1)); node = vessel.patchedConicSolver.maneuverNodes[nodeIndex]; } if (node != oldNode) { prograde = node.DeltaV.z; radialPlus = node.DeltaV.x; normalPlus = node.DeltaV.y; } if (gizmo != node.attachedGizmo) { if (gizmo != null) { gizmo.OnGizmoUpdated -= GizmoUpdateHandler; } gizmo = node.attachedGizmo; if (gizmo != null) { gizmo.OnGizmoUpdated += GizmoUpdateHandler; } } GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Prograde:", prograde, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { prograde -= progradeDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { prograde += progradeDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Radial+:", radialPlus, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { radialPlus -= radialPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { radialPlus += radialPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Normal+:", normalPlus, "m/s", 60); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { normalPlus -= normalPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { normalPlus += normalPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Set delta to:", GUILayout.ExpandWidth(true)); if (GUILayout.Button("0.01", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 0.01; } if (GUILayout.Button("0.1", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 0.1; } if (GUILayout.Button("1", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 1; } if (GUILayout.Button("10", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 10; } if (GUILayout.Button("100", GUILayout.ExpandWidth(true))) { progradeDelta = radialPlusDelta = normalPlusDelta = 100; } GUILayout.EndHorizontal(); if (GUILayout.Button("Update")) { node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } GUILayout.BeginHorizontal(); GUILayout.Label("Shift time", GUILayout.ExpandWidth(true)); if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT - timeOffset); } timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT + timeOffset); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Snap node to", GUILayout.ExpandWidth(true))) { Orbit o = node.patch; double UT = node.UT; switch (snap) { case Snap.PERIAPSIS: UT = o.NextPeriapsisTime(UT - o.period / 2); //period is who-knows-what for e > 1, but this should still work break; case Snap.APOAPSIS: if (o.eccentricity < 1) { UT = o.NextApoapsisTime(UT - o.period / 2); } break; case Snap.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) { UT = o.TimeOfAscendingNodeEquatorial(UT - o.period / 2); } break; case Snap.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT - o.period / 2); } break; case Snap.REL_ASCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.AscendingNodeExists(core.target.TargetOrbit)) { UT = o.TimeOfAscendingNode(core.target.TargetOrbit, UT - o.period / 2); } } break; case Snap.REL_DESCENDING: if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody) { if (o.DescendingNodeExists(core.target.TargetOrbit)) { UT = o.TimeOfDescendingNode(core.target.TargetOrbit, UT - o.period / 2); } } break; } node.OnGizmoUpdated(node.DeltaV, UT); } snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]); GUILayout.EndHorizontal(); RelativityModeSelectUI(); if (core.node != null) { if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && !core.node.enabled) { if (GUILayout.Button("Execute next node")) { core.node.ExecuteOneNode(this); } if (vessel.patchedConicSolver.maneuverNodes.Count > 1) { if (GUILayout.Button("Execute all nodes")) { core.node.ExecuteAllNodes(this); } } } else if (core.node.enabled) { if (GUILayout.Button("Abort node execution")) { core.node.Abort(); } } GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp", GUILayout.ExpandWidth(true)); GUILayout.Label("Tolerance:", GUILayout.ExpandWidth(false)); core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
//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; }
public double ComputeManeuverTime(Orbit o, double UT, MechJebModuleTargetController target) { switch (allowedTimeRef[currentTimeRef]) { case TimeReference.X_FROM_NOW: UT += leadTime.val; break; case TimeReference.APOAPSIS: if (o.eccentricity < 1) { UT = o.NextApoapsisTime(UT); } else { throw new OperationException("Warning: orbit is hyperbolic, so apoapsis doesn't exist."); } break; case TimeReference.PERIAPSIS: UT = o.NextPeriapsisTime(UT); break; case TimeReference.CLOSEST_APPROACH: if (target.NormalTargetExists) { UT = o.NextClosestApproachTime(target.TargetOrbit, UT); } else { throw new OperationException("Warning: no target selected."); } break; case TimeReference.ALTITUDE: if (circularizeAltitude > o.PeA && (circularizeAltitude < o.ApA || o.eccentricity >= 1)) { UT = o.NextTimeOfRadius(UT, o.referenceBody.Radius + circularizeAltitude); } else { throw new OperationException("Warning: can't circularize at this altitude, since current orbit does not reach it."); } break; case TimeReference.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) { UT = o.TimeOfAscendingNodeEquatorial(UT); } else { throw new OperationException("Warning: equatorial ascending node doesn't exist."); } break; case TimeReference.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT); } else { throw new OperationException("Warning: equatorial descending node doesn't exist."); } break; case TimeReference.EQ_NEAREST_AD: if(o.AscendingNodeEquatorialExists()) { UT = o.DescendingNodeEquatorialExists() ? System.Math.Min(o.TimeOfAscendingNodeEquatorial(UT), o.TimeOfDescendingNodeEquatorial(UT)) : o.TimeOfAscendingNodeEquatorial(UT); } else if(o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT); } else { throw new OperationException("Warning: neither ascending nor descending node exists."); } break; case TimeReference.EQ_HIGHEST_AD: if(o.AscendingNodeEquatorialExists()) { if(o.DescendingNodeEquatorialExists()) { var anTime = o.TimeOfAscendingNodeEquatorial(UT); var dnTime = o.TimeOfDescendingNodeEquatorial(UT); UT = o.getOrbitalVelocityAtUT(anTime).magnitude <= o.getOrbitalVelocityAtUT(dnTime).magnitude ? anTime : dnTime; } else { UT = o.TimeOfAscendingNodeEquatorial(UT); } } else if(o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT); } else { throw new OperationException("Warning: neither ascending nor descending node exists."); } break; } universalTime = UT; return universalTime; }
double DoChooseTimeGUI() { Dictionary <Operation, TimeReference[]> references = new Dictionary <Operation, TimeReference[]>(); references[Operation.CIRCULARIZE] = new TimeReference[] { TimeReference.APOAPSIS, TimeReference.PERIAPSIS, TimeReference.ALTITUDE, TimeReference.X_FROM_NOW }; references[Operation.PERIAPSIS] = new TimeReference[] { TimeReference.X_FROM_NOW, TimeReference.APOAPSIS, TimeReference.PERIAPSIS }; references[Operation.APOAPSIS] = new TimeReference[] { TimeReference.X_FROM_NOW, TimeReference.APOAPSIS, TimeReference.PERIAPSIS }; references[Operation.ELLIPTICIZE] = new TimeReference[] { TimeReference.X_FROM_NOW }; references[Operation.INCLINATION] = new TimeReference[] { TimeReference.EQ_ASCENDING, TimeReference.EQ_DESCENDING, TimeReference.X_FROM_NOW }; references[Operation.PLANE] = new TimeReference[] { TimeReference.REL_ASCENDING, TimeReference.REL_DESCENDING }; references[Operation.TRANSFER] = new TimeReference[] { TimeReference.COMPUTED }; references[Operation.MOON_RETURN] = new TimeReference[] { TimeReference.COMPUTED }; references[Operation.INTERPLANETARY_TRANSFER] = new TimeReference[] { TimeReference.COMPUTED }; references[Operation.COURSE_CORRECTION] = new TimeReference[] { TimeReference.COMPUTED }; references[Operation.LAMBERT] = new TimeReference[] { TimeReference.X_FROM_NOW }; references[Operation.KILL_RELVEL] = new TimeReference[] { TimeReference.CLOSEST_APPROACH, TimeReference.X_FROM_NOW }; TimeReference[] allowedReferences = references[operation]; int referenceIndex = 0; if (allowedReferences.Contains(timeReference)) { referenceIndex = Array.IndexOf(allowedReferences, timeReference); } referenceIndex = GuiUtils.ArrowSelector(referenceIndex, allowedReferences.Length, () => { switch (timeReference) { case TimeReference.APOAPSIS: GUILayout.Label("at the next apoapsis"); break; case TimeReference.CLOSEST_APPROACH: GUILayout.Label("at closest approach to target"); break; case TimeReference.EQ_ASCENDING: GUILayout.Label("at the equatorial AN"); break; case TimeReference.EQ_DESCENDING: GUILayout.Label("at the equatorial DN"); break; case TimeReference.PERIAPSIS: GUILayout.Label("at the next periapsis"); break; case TimeReference.REL_ASCENDING: GUILayout.Label("at the next AN with the target."); break; case TimeReference.REL_DESCENDING: GUILayout.Label("at the next DN with the target."); break; case TimeReference.X_FROM_NOW: leadTime.text = GUILayout.TextField(leadTime.text, GUILayout.Width(50)); GUILayout.Label(" from now"); break; case TimeReference.ALTITUDE: GuiUtils.SimpleTextBox("at an altitude of", circularizeAltitude, "km"); break; } }); timeReference = allowedReferences[referenceIndex]; bool error = false; string timeErrorMessage = ""; double UT = vesselState.time; Orbit o = orbit; List <ManeuverNode> maneuverNodes = GetManeuverNodes(); if (maneuverNodes.Count() > 0) { GUILayout.Label("after the last maneuver node."); ManeuverNode last = maneuverNodes.Last(); UT = last.UT; o = last.nextPatch; } switch (timeReference) { case TimeReference.X_FROM_NOW: UT += leadTime; break; case TimeReference.APOAPSIS: if (o.eccentricity < 1) { UT = o.NextApoapsisTime(UT); } else { error = true; timeErrorMessage = "Warning: orbit is hyperbolic, so apoapsis doesn't exist."; } break; case TimeReference.PERIAPSIS: UT = o.NextPeriapsisTime(UT); break; case TimeReference.CLOSEST_APPROACH: if (core.target.NormalTargetExists) { UT = o.NextClosestApproachTime(core.target.Orbit, UT); } else { error = true; timeErrorMessage = "Warning: no target selected."; } break; case TimeReference.ALTITUDE: if (circularizeAltitude > o.PeA && circularizeAltitude < o.ApA) { UT = o.NextTimeOfRadius(UT, o.referenceBody.Radius + circularizeAltitude); } else { error = true; timeErrorMessage = "Warning: can't circularize at this altitude, since current orbit does not reach it."; } break; case TimeReference.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) { UT = o.TimeOfAscendingNodeEquatorial(UT); } else { error = true; timeErrorMessage = "Warning: equatorial ascending node doesn't exist."; } break; case TimeReference.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT); } else { error = true; timeErrorMessage = "Warning: equatorial descending node doesn't exist."; } break; } if (operation == Operation.COURSE_CORRECTION && core.target.NormalTargetExists) { Orbit correctionPatch = o; while (correctionPatch != null) { if (correctionPatch.referenceBody == core.target.Orbit.referenceBody) { o = correctionPatch; UT = correctionPatch.StartUT; break; } correctionPatch = vessel.GetNextPatch(correctionPatch); } } if (error) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.Label(timeErrorMessage, s); } return(UT); }
double DoChooseTimeGUI(Operation op, TimeReference timeRef, out string timeErrorMessage, bool InvolveGUI = true, double leadingTime = 0) { if (InvolveGUI) { TimeReference[] allowedReferences = references[op]; int referenceIndex = 0; if (allowedReferences.Contains(timeReference)) { referenceIndex = Array.IndexOf(allowedReferences, timeReference); } referenceIndex = GuiUtils.ArrowSelector(referenceIndex, allowedReferences.Length, () => { switch (timeReference) { case TimeReference.APOAPSIS: GUILayout.Label("at the next apoapsis"); break; case TimeReference.CLOSEST_APPROACH: GUILayout.Label("at closest approach to target"); break; case TimeReference.EQ_ASCENDING: GUILayout.Label("at the equatorial AN"); break; case TimeReference.EQ_DESCENDING: GUILayout.Label("at the equatorial DN"); break; case TimeReference.PERIAPSIS: GUILayout.Label("at the next periapsis"); break; case TimeReference.REL_ASCENDING: GUILayout.Label("at the next AN with the target."); break; case TimeReference.REL_DESCENDING: GUILayout.Label("at the next DN with the target."); break; case TimeReference.X_FROM_NOW: leadTime.text = GUILayout.TextField(leadTime.text, GUILayout.Width(50)); GUILayout.Label(" from now"); break; case TimeReference.ALTITUDE: GuiUtils.SimpleTextBox("at an altitude of", circularizeAltitude, "km"); break; } }); timeReference = allowedReferences[referenceIndex]; } timeErrorMessage = ""; bool error = false; double UT = vesselState.time; Orbit o = orbit; List <ManeuverNode> maneuverNodes = GetManeuverNodes(); if (maneuverNodes.Any()) { if (InvolveGUI) { GUILayout.Label("after the last maneuver node."); } ManeuverNode last = maneuverNodes.Last(); UT = last.UT; o = last.nextPatch; } switch (InvolveGUI ? timeReference : timeRef) { case TimeReference.X_FROM_NOW: UT += (InvolveGUI ? leadTime.val : leadingTime); break; case TimeReference.APOAPSIS: if (o.eccentricity < 1) { UT = o.NextApoapsisTime(UT); } else { error = true; timeErrorMessage = "Warning: orbit is hyperbolic, so apoapsis doesn't exist."; } break; case TimeReference.PERIAPSIS: UT = o.NextPeriapsisTime(UT); break; case TimeReference.CLOSEST_APPROACH: if (core.target.NormalTargetExists) { UT = o.NextClosestApproachTime(core.target.TargetOrbit, UT); } else { error = true; timeErrorMessage = "Warning: no target selected."; } break; case TimeReference.ALTITUDE: if (circularizeAltitude > o.PeA && (circularizeAltitude < o.ApA || o.eccentricity >= 1)) { UT = o.NextTimeOfRadius(UT, o.referenceBody.Radius + circularizeAltitude); } else { error = true; timeErrorMessage = "Warning: can't circularize at this altitude, since current orbit does not reach it."; } break; case TimeReference.EQ_ASCENDING: if (o.AscendingNodeEquatorialExists()) { UT = o.TimeOfAscendingNodeEquatorial(UT); } else { error = true; timeErrorMessage = "Warning: equatorial ascending node doesn't exist."; } break; case TimeReference.EQ_DESCENDING: if (o.DescendingNodeEquatorialExists()) { UT = o.TimeOfDescendingNodeEquatorial(UT); } else { error = true; timeErrorMessage = "Warning: equatorial descending node doesn't exist."; } break; } if (op == Operation.COURSE_CORRECTION && core.target.NormalTargetExists) { Orbit correctionPatch = o; while (correctionPatch != null) { if (correctionPatch.referenceBody == core.target.TargetOrbit.referenceBody) { o = correctionPatch; UT = correctionPatch.StartUT; break; } correctionPatch = vessel.GetNextPatch(correctionPatch); } } if (error && InvolveGUI) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.Label(timeErrorMessage, s); } return(UT); }