public ManeuverNodeStorage FromManeuverNode(ManeuverNode ManNodeToStore) { this.DeltaV = ManNodeToStore.DeltaV; this.NodeRotation = ManNodeToStore.nodeRotation; this.UT = ManNodeToStore.UT; return this; }
public static ManeuverCommand WithNode(ManeuverNode node, FlightComputer f) { double thrust = FlightCore.GetTotalThrust(f.Vessel); double advance = f.Delay; if (thrust > 0) { advance += (node.DeltaV.magnitude / (thrust / f.Vessel.GetTotalMass())) / 2; } var newNode = new ManeuverCommand() { Node = new ManeuverNode() { DeltaV = node.DeltaV, patch = node.patch, solver = node.solver, scaledSpaceTarget = node.scaledSpaceTarget, nextPatch = node.nextPatch, UT = node.UT, nodeRotation = node.nodeRotation, }, TimeStamp = node.UT - advance, }; return newNode; }
internal bool compare(ManeuverNode m) { if (deltaV.x != m.DeltaV.x || deltaV.y != m.DeltaV.y || deltaV.z != m.DeltaV.z || UT != m.UT) { return false; } return true; }
protected override void AdjustNode( ManeuverNode originalNode, Maneuver original, double originalPeriod, double originalMagnitude, ManeuverNode node, double value, double splitDv) { double fraction; double minFraction = 0; double maxFraction = 1; double targetPeriod = value * 60; for(int iteration = 0; iteration < MNSSettings.Instance.splitByPeriodIterations; iteration += 1) { fraction = (minFraction + maxFraction) / 2; Vector3d dv = original.DeltaV * fraction; if(node != originalNode) { RotateDeltaV(originalNode, node, ref dv); } node.DeltaV = dv; node.solver.UpdateFlightPlan(); if(node.nextPatch.ApA > 0 && node.nextPatch.period < targetPeriod) minFraction = fraction; else maxFraction = fraction; } }
public ManeuverNode ToManeuverNode() { ManeuverNode retManNode = new ManeuverNode(); retManNode.DeltaV = DeltaV; retManNode.nodeRotation = NodeRotation; retManNode.UT = UT; return retManNode; }
public Node(Vessel v, ManeuverNode existingNode) { nodeRef = existingNode; vesselRef = v; NodeLookup.Add(existingNode, this); UpdateValues(); }
private Node(Vessel v, ManeuverNode existingNode, SharedObjects shareObj) : this(shareObj) { nodeRef = existingNode; vesselRef = v; nodeLookup.Add(existingNode, this); FromNodeRef(); }
internal NodeManager(ManeuverNode n) { curState = new NodeState(n); curNodeState = new NodeState(); node = n; updateCurrentNodeState(); if (n.findNextEncounter() != null) { encounter = true; } }
public NodeManager(ManeuverNode n) { curState = new NodeState(n); curNodeState = new NodeState(); node = n; updateCurrentNodeState(); if(NodeTools.findNextEncounter(n) != null) { encounter = true; } }
protected override void AdjustNode( ManeuverNode originalNode, Maneuver original, double originalPeriod, double originalMagnitude, ManeuverNode node, double value, double splitDv) { Vector3d dv = original.DeltaV * (value / originalMagnitude); if(node != originalNode) { RotateDeltaV(originalNode, node, ref dv); } node.DeltaV = dv; node.solver.UpdateFlightPlan(); }
protected override bool ValidateInput(ManeuverNode originalNode, List<double> inputValues) { foreach(double input in inputValues) { if(input <= 0) { ScreenMessages.PostScreenMessage("Delta-V values must be greater than zero", 6f, ScreenMessageStyle.UPPER_CENTER); return false; } } return true; }
public void AddToVessel(Vessel v) { if (nodeRef != null) throw new kOSException("Node has already been added"); vesselRef = v; nodeRef = v.patchedConicSolver.AddManeuverNode(Time); UpdateNodeDeltaV(); v.patchedConicSolver.UpdateFlightPlan(); NodeLookup.Add(nodeRef, this); }
public static ManeuverCommand WithNode(ManeuverNode node) { var newNode = new ManeuverCommand() { Node = new ManeuverNode() { DeltaV = node.DeltaV, patch = node.patch, solver = node.solver, scaledSpaceTarget = node.scaledSpaceTarget, nextPatch = node.nextPatch, UT = node.UT, nodeRotation = node.nodeRotation, }, TimeStamp = node.UT, }; return newNode; }
public static ManeuverCommand WithNode(int nodeIndex, FlightComputer f) { double thrust = FlightCore.GetTotalThrust(f.Vessel); ManeuverNode node = f.Vessel.patchedConicSolver.maneuverNodes[nodeIndex]; double advance = f.Delay; if (thrust > 0) { advance += (node.DeltaV.magnitude / (thrust / f.Vessel.GetTotalMass())) / 2; // add 1 second for the throttle down time @ the end of the burn advance += 1; } var newNode = new ManeuverCommand() { Node = node, TimeStamp = node.UT - advance, }; return(newNode); }
public override bool Pop(FlightComputer f) { if (f.Vessel.patchedConicSolver == null) { f.Vessel.AttachPatchedConicsSolver(); f.Vessel.patchedConicSolver.Update(); } if (this.Node.solver == null) // need to repair (due to the scenario of 2 vessels within phyical range) { this.Node = f.Vessel.patchedConicSolver.maneuverNodes.Find(x => x.UT == this.Node.UT); } var burn = f.ActiveCommands.FirstOrDefault(c => c is BurnCommand); if (burn != null) { f.Remove(burn); } OriginalDelta = Node.DeltaV.magnitude; RemainingDelta = this.getRemainingDeltaV(f); this.EngineActivated = true; double thrustToMass = FlightCore.GetTotalThrust(f.Vessel) / f.Vessel.GetTotalMass(); if (thrustToMass == 0.0) { this.EngineActivated = false; RTUtil.ScreenMessage("[Flight Computer]: No engine to carry out the maneuver."); } else { RemainingTime = RemainingDelta / thrustToMass; } f.PIDController.setPIDParameters(FlightComputer.PIDKp, FlightComputer.PIDKi, FlightComputer.PIDKd); return(true); }
private void UpdateIntuitiveManeuverHandlersList() { PatchedConicSolver solver = NodeTools.getSolver(); if (solver != curSolver) { this.maneuverGizmoHandlers.Clear(); curSolver = solver; if (solver != null) { List <ManeuverNode> nodes = solver.maneuverNodes; for (int i = 0; i < nodes.Count; i++) { ManeuverNode node = nodes[i]; if ((node.attachedGizmo != null) && !isHandled(node)) { this.maneuverGizmoHandlers.Add(new IntuitiveNodeGizmoHandler(this, node, options)); } } } } }
protected override bool ValidateInput(ManeuverNode originalNode, List <double> inputValues) { double period = originalNode.patch.period; double prior = period; foreach (double input in inputValues) { if (input * 60 < period) { ScreenMessages.PostScreenMessage("Periods must be greater than the current orbital period", 6f, ScreenMessageStyle.UPPER_CENTER); return(false); } if (!(input * 60 > prior)) { ScreenMessages.PostScreenMessage("Periods must be listed in increasing order", 6f, ScreenMessageStyle.UPPER_CENTER); return(false); } prior = input * 60; } return(true); }
protected override void reset() { base.reset(); if (Working) { THR.Throttle = 0; } if (CFG.AT[Attitude.ManeuverNode]) { CFG.AT.On(Attitude.KillRotation); } CFG.AP1.OffIfOn(Autopilot1.Maneuver); Executor.Reset(); NodeDeltaV = Vector3d.zero; MinDeltaV = GLB.THR.MinDeltaV; min_deltaV = double.MaxValue; within_threshold = false; VSL.Info.Countdown = 0; VSL.Info.TTB = 0; Working = false; Node = null; }
protected override bool ValidateInput(ManeuverNode originalNode, List<double> inputValues) { double apoapsis = originalNode.patch.ApA; double prior = apoapsis; foreach(double input in inputValues) { if(input * 1000 < apoapsis) { ScreenMessages.PostScreenMessage("Apoapsis values must be greater than the current apoapsis", 6f, ScreenMessageStyle.UPPER_CENTER); return false; } if(!(input * 1000 > prior)) { ScreenMessages.PostScreenMessage("Apoapsis values must be listed in increasing order", 6f, ScreenMessageStyle.UPPER_CENTER); return false; } prior = input * 1000; } return true; }
internal static void copyToClipboard(Orbit o, ManeuverNode node) { string message = "Precise Maneuver Information\r\n"; message += String.Format("Depart at: {0}\r\n", convertUTtoHumanTime(node.UT)); message += String.Format(" UT: {0:0}\r\n", node.UT); double eang = o.getEjectionAngle(node); if (!double.IsNaN(eang)) { string e = String.Format("{0:0.00° to prograde;0.00° to retrograde}", o.getEjectionAngle(node)); message += String.Format("Ejection Angle: {0}\r\n", e); e = String.Format("{0:0.00}°", o.getEjectionInclination(node)); message += String.Format("Ejection Inc.: {0}\r\n", e); } message += String.Format("Prograde Δv: {0:0.0} m/s\r\n", node.DeltaV.z); message += String.Format("Normal Δv: {0:0.0} m/s\r\n", node.DeltaV.y); message += String.Format("Radial Δv: {0:0.0} m/s\r\n", node.DeltaV.x); message += String.Format("Total Δv: {0:0} m/s", node.DeltaV.magnitude); GUIUtility.systemCopyBuffer = message; }
protected override bool ValidateInput(ManeuverNode originalNode, List<double> inputValues) { double period = originalNode.patch.period; double prior = period; foreach(double input in inputValues) { if(input * 60 < period) { ScreenMessages.PostScreenMessage("Periods must be greater than the current orbital period", 6f, ScreenMessageStyle.UPPER_CENTER); return false; } if(!(input * 60 > prior)) { ScreenMessages.PostScreenMessage("Periods must be listed in increasing order", 6f, ScreenMessageStyle.UPPER_CENTER); return false; } prior = input * 60; } return true; }
protected override bool ValidateInput(ManeuverNode originalNode, List <double> inputValues) { double apoapsis = originalNode.patch.ApA; double prior = apoapsis; foreach (double input in inputValues) { if (input * 1000 < apoapsis) { ScreenMessages.PostScreenMessage("Apoapsis values must be greater than the current apoapsis", 6f, ScreenMessageStyle.UPPER_CENTER); return(false); } if (!(input * 1000 > prior)) { ScreenMessages.PostScreenMessage("Apoapsis values must be listed in increasing order", 6f, ScreenMessageStyle.UPPER_CENTER); return(false); } prior = input * 1000; } return(true); }
//If there is a maneuver node on this patch, returns the patch that follows that maneuver node //Otherwise, if this patch ends in an SOI transition, returns the patch that follows that transition //Otherwise, returns null public static Orbit GetNextPatch(this Vessel vessel, Orbit patch, ManeuverNode ignoreNode = null) { if (patch == null) { return(null); } //Determine whether this patch ends in an SOI transition or if it's the final one: bool finalPatch = (patch.patchEndTransition == Orbit.PatchTransitionType.FINAL); if (vessel.patchedConicSolver == null) { vessel.patchedConicSolver = vessel.gameObject.AddComponent <PatchedConicSolver>(); vessel.patchedConicSolver.Load(vessel.flightPlanNode); } //See if any maneuver nodes occur during this patch. If there is one //return the patch that follows it var nodes = vessel.patchedConicSolver.maneuverNodes.Slinq().Where((n, p) => n.patch == p && n != ignoreNode, patch); // Slinq is nice but you can only enumerate it once var first = nodes.FirstOrDefault(); if (first != null) { return(first.nextPatch); } //return the next patch, or null if there isn't one: if (!finalPatch) { return(patch.nextPatch); } else { return(null); } }
public void UpdateManeuverNodes(PatchedConicSolver solver) { if (solver == null) { return; } // Avoid flickering by not overwriting nodes where possible var maneuversLength = this.Maneuvers == null ? 0 : this.Maneuvers.Length; int commonLength = Math.Min(solver.maneuverNodes.Count, maneuversLength); // update the common ones for (int i = 0; i < commonLength; i++) { var node = solver.maneuverNodes[i]; var nodeUpdate = this.Maneuvers[i]; node.UT = nodeUpdate.UniversalTime; node.DeltaV = nodeUpdate.DeltaV; node.OnGizmoUpdated(node.DeltaV, node.UT); } // remove any extra ones for (int i = solver.maneuverNodes.Count; i > maneuversLength; i--) { var node = solver.maneuverNodes[i - 1]; solver.RemoveManeuverNode(node); } // add any new ones for (int i = solver.maneuverNodes.Count; i < maneuversLength; i++) { var maneuver = this.Maneuvers[i]; ManeuverNode node = solver.AddManeuverNode(maneuver.UniversalTime); node.DeltaV = maneuver.DeltaV; node.OnGizmoUpdated(node.DeltaV, node.UT); } }
public void AddToVessel(Vessel v) { if (nodeRef != null) { throw new Exception("Node has already been added"); } string careerReason; if (!Career.CanMakeNodes(out careerReason)) { throw new KOSLowTechException("use maneuver nodes", careerReason); } vesselRef = v; nodeRef = v.patchedConicSolver.AddManeuverNode(time); UpdateNodeDeltaV(); v.patchedConicSolver.UpdateFlightPlan(); nodeLookup.Add(nodeRef, this); }
public void AddToVessel(Vessel v) { if (nodeRef != null) throw new Exception("Node has already been added"); string careerReason; if (! Career.CanMakeNodes(out careerReason)) throw new KOSLowTechException("use maneuver nodes", careerReason); vesselRef = v; if (v.patchedConicSolver == null) throw new KOSSituationallyInvalidException( "A KSP limitation makes it impossible to access the manuever nodes of this vessel at this time. " + "(perhaps it's not the active vessel?)"); nodeRef = v.patchedConicSolver.AddManeuverNode(time); UpdateNodeDeltaV(); v.patchedConicSolver.UpdateFlightPlan(); nodeLookup.Add(nodeRef, this); }
protected void UpdateWidgetColorForCurrentTime(TrackingStationWidget widget) { ManeuverNode node = this.NextManeuverNodeForVessel(widget.vessel); if (node == null) { return; } double maneuverTime = node.UT; // if the maneuver node is less than 15mins away - yellow if (maneuverTime < Planetarium.GetUniversalTime() + ManeuverQueue.minimumManeuverDeltaT) { this.ApplyColorToVesselWidget(widget, this.nodeWarningColor); } // if the maneuver nodes is in the past - red if (maneuverTime < Planetarium.GetUniversalTime()) { this.ApplyColorToVesselWidget(widget, this.nodePassedColor); } }
internal void SearchNewGizmo() { var solver = FlightGlobals.ActiveVessel.patchedConicSolver; var curList = solver.maneuverNodes.Where(a => a.attachedGizmo != null); var tmp = curList.ToList(); /* let's see if user is hovering a mouse * * over any gizmo. That would be a hint. */ if (curList.Count(a => a.attachedGizmo.MouseOverGizmo) == 1) { var node = curList.First(a => a.attachedGizmo.MouseOverGizmo); if (node != currentNode) { currentNode = node; NotifyNodeChanged(); } } else { /* then, let's see if we can find any * * new gizmos that were created recently. */ if (prevGizmos != null) { curList = curList.Except(prevGizmos); } if (curList.Count() == 1) { var node = curList.First(); if (node != currentNode) { currentNode = node; NotifyNodeChanged(); } } } prevGizmos = tmp; }
public static ManeuverNode PlaceManeuverNode(Vessel vessel, Orbit patch, Vector3d dV, double UT) { if (vessel.patchedConicsUnlocked()) { //placing a maneuver node with bad dV values can really mess up the game, so try to protect against that //and log an exception if we get a bad dV vector: for (int i = 0; i < 3; i++) { if (double.IsNaN(dV[i]) || double.IsInfinity(dV[i])) { throw new Exception("VesselExtensions.PlaceManeuverNode: bad dV: " + dV); } } if (double.IsNaN(UT) || double.IsInfinity(UT)) { throw new Exception("VesselExtensions.PlaceManeuverNode: bad UT: " + UT); } //It seems that sometimes the game can freak out if you place a maneuver node in the past, so this //protects against that. UT = Math.Max(UT, Planetarium.GetUniversalTime()); //convert a dV in world coordinates into the coordinate system of the maneuver node, //which uses (x, y, z) = (radial+, normal-, prograde) Vector3d nodeDV = patch.DeltaVToManeuverNodeCoordinates(UT, dV); ManeuverNode mn = vessel.patchedConicSolver.AddManeuverNode(UT); mn.DeltaV = nodeDV; vessel.patchedConicSolver.UpdateFlightPlan(); return(mn); } else { return(null); } }
private bool update_maneuver_node() { Node = null; NodeCB = null; TargetOrbit = null; if (Solver != null) { if (Solver.maneuverNodes.Count <= 0) { return(false); } Node = Solver.maneuverNodes[0]; } else { if (VSL.vessel.flightPlanNode.nodes.Count <= 0) { return(false); } var node = VSL.vessel.flightPlanNode.nodes[0]; Node = new ManeuverNode(); Node.Load(node); Node.patch = new Orbit(VSL.orbit); Node.nextPatch = TrajectoryCalculator.NewOrbit(VSL.orbit, Utils.Node2OrbitalDeltaV(Node), Node.UT); VSL.vessel.flightPlanNode.RemoveNode(node); } NodeCB = Node.patch.referenceBody; TargetOrbit = Node.nextPatch; update_node_deltaV(); if (VSL.Engines.MaxDeltaV < Node.DeltaV.magnitude) { Status(Colors.Warning, "WARNING: there may be not enough propellant for the maneuver"); } return(true); }
ReferenceFrame( ReferenceFrameType type, global::CelestialBody body = null, global::Vessel vessel = null, ManeuverNode node = null, Part part = null, ModuleDockingNode dockingPort = null, Thruster thruster = null, ReferenceFrame parent = null, ReferenceFrame hybridPosition = null, ReferenceFrame hybridRotation = null, ReferenceFrame hybridVelocity = null, ReferenceFrame hybridAngularVelocity = null) { this.type = type; this.body = body; vesselId = vessel != null ? vessel.id : Guid.Empty; this.node = node; //TODO: is it safe to use a part id of 0 to mean no part? if (part != null) { partId = part.flightID; } this.dockingPort = dockingPort; this.thruster = thruster; this.parent = parent; this.hybridPosition = hybridPosition; this.hybridRotation = hybridRotation; this.hybridVelocity = hybridVelocity; this.hybridAngularVelocity = hybridAngularVelocity; }
//Draws the gauge textures to the screen private void PaintGauge(ManeuverNode node) { //Draw the face (background) GUI.DrawTextureWithTexCoords(new Rect(0f, 0f, 400f * Scale, 407f * Scale), texture, new Rect(0f, 0f, 0.5f, 0.499f)); //PatchedConicSolver PCS = FlightGlobals.ActiveVessel.patchedConicSolver; //Draw the dV needle drawNeedle(); //Draw the digital readouts drawNumbers(node); //Draw the bezel, if selected if (SteamGauges.drawBezels) { GUI.DrawTextureWithTexCoords(new Rect(0f, 0f, 400f * Scale, 407f * Scale), texture, new Rect(0f, 0.5f, 0.5f, 0.5f)); } //Draw the casing (foreground) GUI.DrawTextureWithTexCoords(new Rect(0f, 0f, 400f * Scale, 407f * Scale), texture, new Rect(0.5f, 0.5f, 0.5f, 0.5f)); //Draw the buttons if (autoBurn) { GUI.DrawTextureWithTexCoords(burn_toggle, texture, new Rect(0.5800f, 0.3649f, 0.08625f, 0.0553f)); //Green Burn } else { GUI.DrawTextureWithTexCoords(burn_toggle, texture, new Rect(0.6713f, 0.3649f, 0.08625f, 0.0553f)); //Grey Burn } if (autoShutdown) { GUI.DrawTextureWithTexCoords(shutdown_toggle, texture, new Rect(0.7625f, 0.3649f, 0.08625f, 0.0553f)); //Green Stop } else { GUI.DrawTextureWithTexCoords(shutdown_toggle, texture, new Rect(0.8563f, 0.3649f, 0.08625f, 0.0553f)); //Grey Stop } }
void UpdateManeuverNode() { if (vessel.patchedConicSolver != null) { node = vessel.patchedConicSolver.maneuverNodes.Count > 0 ? vessel.patchedConicSolver.maneuverNodes[0] : null; if (node != null) { nodeOrbit = node.nextPatch; } else { nodeOrbit = null; } } else { node = null; nodeOrbit = null; } nodeDV = -1.0; maneuverVector = Vector3d.zero; maneuverNodeComponentVector = Vector3d.zero; }
//If there is a maneuver node on this patch, returns the patch that follows that maneuver node //Otherwise, if this patch ends in an SOI transition, returns the patch that follows that transition //Otherwise, returns null public static Orbit GetNextPatch(this Vessel vessel, Orbit patch, ManeuverNode ignoreNode = null) { //Determine whether this patch ends in an SOI transition or if it's the final one: bool finalPatch = (patch.patchEndTransition == Orbit.PatchTransitionType.FINAL); //See if any maneuver nodes occur during this patch. If there is one //return the patch that follows it var nodes = vessel.patchedConicSolver.maneuverNodes.Where(n => (n.patch == patch && n != ignoreNode)); if (nodes.Count() > 0) { return(nodes.First().nextPatch); } //return the next patch, or null if there isn't one: if (!finalPatch) { return(patch.nextPatch); } else { return(null); } }
/// <summary> /// Gets the ejection angle of the current maneuver node. /// </summary> /// <returns>The ejection angle in degrees. Positive results are the angle from prograde, negative results are the angle from retrograde.</returns> /// <param name="nodeUT">Kerbal Space Program Universal Time.</param> internal static double getEjectionAngle(this Orbit o, ManeuverNode node) { if (node.nextPatch.patchEndTransition == Orbit.PatchTransitionType.ESCAPE) { CelestialBody body = o.referenceBody; // Calculate the angle between the node's position and the reference body's velocity at nodeUT Vector3d prograde = body.orbit.getOrbitalVelocityAtUT(node.UT); Vector3d position = o.getRelativePositionAtUT(node.UT); double eangle = ((Math.Atan2(prograde.y, prograde.x) - Math.Atan2(position.y, position.x)) * 180.0 / Math.PI).Angle360(); // Correct to angle from retrograde if needed. if (eangle > 180) { eangle = 180 - eangle; } return(eangle); } else { return(double.NaN); } }
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("-o", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT - node.patch.period); } 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); } if (GUILayout.Button("+o", GUILayout.ExpandWidth(false))) { node.OnGizmoUpdated(node.DeltaV, node.UT + node.patch.period); } 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); }
/// <summary> /// Remove a maneuver node from the flight plane. /// </summary> /// <param name="node">The maneuver node to be removed.</param> public extern void RemoveManeuverNode(ManeuverNode node);
protected void LogNode(string message, ManeuverNode node) { #if DEBUG //Quaternion rot = node.nodeRotation; //Vector3 angles = rot.eulerAngles; Orbit orbit = node.nextPatch; Debug.Log(string.Format("{0} Node dv:{1} ut:{2} next per:{3} per:{4}", message, node.DeltaV.magnitude, node.UT, node.nextPatch.period, node.patch.period)); //Debug.Log(string.Format("{0} Quat w:{1} x:{2} y:{3} z:{4}", message, rot.w, rot.x, rot.y, rot.z)); //Debug.Log(string.Format("{0} Euler x:{1} y:{2} z:{3}", message, angles.x, angles.y, angles.z)); Debug.Log(string.Format("{0} Orbit inc:{1} ecc:{2} sma:{3} end:{4}", message, orbit.inclination, orbit.eccentricity, orbit.semiMajorAxis, orbit.patchEndTransition)); #endif }
public static Node FromExisting(Vessel v, ManeuverNode existingNode) { return NodeLookup.ContainsKey(existingNode) ? NodeLookup[existingNode] : new Node(v, existingNode); }
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); }
internal NodeState(ManeuverNode m) { deltaV = new Vector3d(m.DeltaV.x, m.DeltaV.y, m.DeltaV.z); UT = m.UT; }
protected void MaintainAerobrakeNode() { if (makeAerobrakeNodes) { //Remove node after finishing aerobraking: if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode)) { if (aerobrakeNode.UT < vesselState.time && vesselState.altitudeASL > mainBody.RealMaxAtmosphereAltitude()) { vessel.patchedConicSolver.RemoveManeuverNode(aerobrakeNode); aerobrakeNode = null; } } //Update or create node if necessary: ReentrySimulation.Result r = GetResult(); if (r != null && r.outcome == ReentrySimulation.Outcome.AEROBRAKED) { //Compute the node dV: Orbit preAerobrakeOrbit = GetReenteringPatch(); //Put the node at periapsis, unless we're past periapsis. In that case put the node at the current time. double UT; if (preAerobrakeOrbit == orbit && vesselState.altitudeASL < mainBody.RealMaxAtmosphereAltitude() && vesselState.speedVertical > 0) { UT = vesselState.time; } else { UT = preAerobrakeOrbit.NextPeriapsisTime(preAerobrakeOrbit.StartUT); } Orbit postAerobrakeOrbit = MuUtils.OrbitFromStateVectors(r.WorldEndPosition(), r.WorldEndVelocity(), r.body, r.endUT); Vector3d dV = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(preAerobrakeOrbit, UT, postAerobrakeOrbit.ApR); if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode)) { //update the existing node Vector3d nodeDV = preAerobrakeOrbit.DeltaVToManeuverNodeCoordinates(UT, dV); aerobrakeNode.OnGizmoUpdated(nodeDV, UT); } else { //place a new node aerobrakeNode = vessel.PlaceManeuverNode(preAerobrakeOrbit, dV, UT); } } else { //no aerobraking, remove the node: if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode)) { vessel.patchedConicSolver.RemoveManeuverNode(aerobrakeNode); } } } else { //Remove aerobrake node when it is turned off: if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode)) { vessel.patchedConicSolver.RemoveManeuverNode(aerobrakeNode); } } }
internal static double getEjectionInclination(this Orbit o, ManeuverNode node) { if (node.nextPatch.patchEndTransition == Orbit.PatchTransitionType.ESCAPE) { CelestialBody body = o.referenceBody; Orbit bodyOrbit = body.orbit; Orbit orbitAfterEscape = node.nextPatch.nextPatch; return bodyOrbit.getRelativeInclination(orbitAfterEscape); } else { return double.NaN; } }
// Analysis disable once UnusedParameter public bool RenderOrbit(RenderTexture screen, float cameraAspect) { if (!startupComplete || HighLogic.LoadedSceneIsEditor) { return(false); } // Make sure the parameters fit on the screen. Vector4 displayPosition = orbitDisplayPosition; displayPosition.z = Mathf.Min(screen.width - displayPosition.x, displayPosition.z); displayPosition.w = Mathf.Min(screen.height - displayPosition.y, displayPosition.w); // Here is our pixel budget in each direction: double horizPixelSize = displayPosition.z - iconPixelSize; double vertPixelSize = displayPosition.w - iconPixelSize; // Find a basis for transforming values into the framework of // vessel.orbit. The rendering framework assumes the periapsis // is drawn directly to the right of the mainBody center of mass. // It assumes the orbit's prograde direction is "up" (screen // relative) at the periapsis, providing a counter-clockwise // motion for vessel. // Once we have the basic transform, we will add in scalars // that will ultimately transform an arbitrary point (relative to // the planet's center) into screen space. Matrix4x4 screenTransform = Matrix4x4.identity; double now = Planetarium.GetUniversalTime(); double timeAtPe = vessel.orbit.NextPeriapsisTime(now); // Get the 3 direction vectors, based on Pe being on the right of the screen // OrbitExtensions provides handy utilities to get these. Vector3d right = vessel.orbit.Up(timeAtPe); Vector3d forward = vessel.orbit.SwappedOrbitNormal(); // MOARdV: OrbitExtensions.Horizontal is unstable. I've seen it // become (0, 0, 0) intermittently in flight. Instead, use the // cross product of the other two. // We flip the sign of this vector because we are using an inverted // y coordinate system to keep the icons right-side up. Vector3d up = -Vector3d.Cross(forward, right); //Vector3d up = -vessel.orbit.Horizontal(timeAtPe); screenTransform.SetRow(0, new Vector4d(right.x, right.y, right.z, 0.0)); screenTransform.SetRow(1, new Vector4d(up.x, up.y, up.z, 0.0)); screenTransform.SetRow(2, new Vector4d(forward.x, forward.y, forward.z, 0.0)); // Figure out our bounds. First, make sure the entire planet // fits on the screen. We define the center of the vessel.mainBody // as the origin of our coodinate system. double maxX = vessel.mainBody.Radius; double minX = -maxX; double maxY = maxX; double minY = -maxX; if (vessel.mainBody.atmosphere) { maxX += vessel.mainBody.maxAtmosphereAltitude; minX = -maxX; maxY = maxX; minY = -maxX; } // Now make sure the entire orbit fits on the screen. Vector3 vesselPos; // The PeR, ApR, and semiMinorAxis are all one dimensional, so we // can just apply them directly to these values. maxX = Math.Max(maxX, vessel.orbit.PeR); if (vessel.orbit.eccentricity < 1.0) { minX = Math.Min(minX, -vessel.orbit.ApR); maxY = Math.Max(maxY, vessel.orbit.semiMinorAxis); minY = Math.Min(minY, -vessel.orbit.semiMinorAxis); } else if (vessel.orbit.EndUT > 0.0) { // If we're hyperbolic, let's get the SoI transition vesselPos = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(vessel.orbit.EndUT)); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); } // Make sure the vessel shows up on-screen. Since a hyperbolic // orbit doesn't have a meaningful ApR, we use this as a proxy for // how far we need to extend the bounds to show the vessel. vesselPos = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(now)); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); // Account for a target vessel var targetBody = FlightGlobals.fetch.VesselTarget as CelestialBody; var targetVessel = FlightGlobals.fetch.VesselTarget as Vessel; if (targetVessel != null && targetVessel.mainBody != vessel.mainBody) { // We only care about tgtVessel if it is in the same SoI. targetVessel = null; } if (targetVessel != null && !targetVessel.LandedOrSplashed) { if (targetVessel.mainBody == vessel.mainBody) { double tgtPe = targetVessel.orbit.NextPeriapsisTime(now); vesselPos = screenTransform.MultiplyPoint3x4(targetVessel.orbit.SwappedRelativePositionAtUT(tgtPe)); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); if (targetVessel.orbit.eccentricity < 1.0) { vesselPos = screenTransform.MultiplyPoint3x4(targetVessel.orbit.SwappedRelativePositionAtUT(targetVessel.orbit.NextApoapsisTime(now))); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); } vesselPos = screenTransform.MultiplyPoint3x4(targetVessel.orbit.SwappedRelativePositionAtUT(now)); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); } } if (targetBody != null) { // Validate some values up front, so we don't need to test them later. if (targetBody.GetOrbit() == null) { targetBody = null; } else if (targetBody.orbit.referenceBody == vessel.orbit.referenceBody) { // If the target body orbits our current world, let's at // least make sure the body's location is visible. vesselPos = screenTransform.MultiplyPoint3x4(targetBody.GetOrbit().SwappedRelativePositionAtUT(now)); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); } } ManeuverNode node = (vessel.patchedConicSolver.maneuverNodes.Count > 0) ? vessel.patchedConicSolver.maneuverNodes[0] : null; if (node != null) { double nodePe = node.nextPatch.NextPeriapsisTime(now); vesselPos = screenTransform.MultiplyPoint3x4(node.nextPatch.SwappedRelativePositionAtUT(nodePe)); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); if (node.nextPatch.eccentricity < 1.0) { double nodeAp = node.nextPatch.NextApoapsisTime(now); vesselPos = screenTransform.MultiplyPoint3x4(node.nextPatch.SwappedRelativePositionAtUT(nodeAp)); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); } else if (node.nextPatch.EndUT > 0.0) { // If the next patch is hyperbolic, include the endpoint. vesselPos = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(node.nextPatch.EndUT)); maxX = Math.Max(maxX, vesselPos.x); minX = Math.Min(minX, vesselPos.x); maxY = Math.Max(maxY, vesselPos.y); minY = Math.Min(minY, vesselPos.y); } } // Add translation. This will ensure that all of the features // under consideration above will be displayed. screenTransform[0, 3] = -0.5f * (float)(maxX + minX); screenTransform[1, 3] = -0.5f * (float)(maxY + minY); double neededWidth = maxX - minX; double neededHeight = maxY - minY; // Pick a scalar that will fit the bounding box we just created. float pixelScalar = (float)Math.Min(horizPixelSize / neededWidth, vertPixelSize / neededHeight); screenTransform = Matrix4x4.Scale(new Vector3(pixelScalar, pixelScalar, pixelScalar)) * screenTransform; GL.Clear(true, true, backgroundColorValue); GL.PushMatrix(); GL.LoadPixelMatrix(-displayPosition.z * 0.5f, displayPosition.z * 0.5f, displayPosition.w * 0.5f, -displayPosition.w * 0.5f); GL.Viewport(new Rect(displayPosition.x, screen.height - displayPosition.y - displayPosition.w, displayPosition.z, displayPosition.w)); lineMaterial.SetPass(0); GL.Begin(GL.LINES); // Draw the planet: Vector3 focusCenter = screenTransform.MultiplyPoint3x4(new Vector3(0.0f, 0.0f, 0.0f)); // orbitDriver is null on the sun, so we'll just use white instead. GL.Color((vessel.mainBody.orbitDriver == null) ? new Color(1.0f, 1.0f, 1.0f) : vessel.mainBody.orbitDriver.orbitColor); DrawCircle(focusCenter.x, focusCenter.y, (float)(vessel.mainBody.Radius * pixelScalar), orbitPoints); if (vessel.mainBody.atmosphere) { // Use the atmospheric ambient to color the atmosphere circle. GL.Color(vessel.mainBody.atmosphericAmbientColor); DrawCircle(focusCenter.x, focusCenter.y, (float)((vessel.mainBody.Radius + vessel.mainBody.maxAtmosphereAltitude) * pixelScalar), orbitPoints); } if (targetVessel != null && !targetVessel.LandedOrSplashed) { GL.Color(iconColorTargetValue); if (!targetVessel.orbit.activePatch && targetVessel.orbit.eccentricity < 1.0 && targetVessel.orbit.referenceBody == vessel.orbit.referenceBody) { // For some reason, activePatch is false for targetVessel. // If we have a stable orbit for the target, use a fallback // rendering method: ReallyDrawOrbit(targetVessel.orbit, vessel.orbit.referenceBody, screenTransform, orbitPoints); } else { DrawOrbit(targetVessel.orbit, vessel.orbit.referenceBody, screenTransform, orbitPoints); } } foreach (CelestialBody moon in vessel.orbit.referenceBody.orbitingBodies) { if (moon != targetBody) { GL.Color(moon.orbitDriver.orbitColor); ReallyDrawOrbit(moon.GetOrbit(), vessel.orbit.referenceBody, screenTransform, orbitPoints); } } if (targetBody != null) { GL.Color(iconColorTargetValue); ReallyDrawOrbit(targetBody.GetOrbit(), vessel.orbit.referenceBody, screenTransform, orbitPoints); } if (node != null) { GL.Color(orbitColorNextNodeValue); DrawOrbit(node.nextPatch, vessel.orbit.referenceBody, screenTransform, orbitPoints); } if (vessel.orbit.nextPatch != null && vessel.orbit.nextPatch.activePatch) { GL.Color(orbitColorNextNodeValue); DrawOrbit(vessel.orbit.nextPatch, vessel.orbit.referenceBody, screenTransform, orbitPoints); } // Draw the vessel orbit GL.Color(orbitColorSelfValue); DrawOrbit(vessel.orbit, vessel.orbit.referenceBody, screenTransform, orbitPoints); // Done drawing lines. Reset color to white, so we don't mess up anyone else. GL.Color(Color.white); GL.End(); // Draw target vessel icons. Vector3 transformedPosition; foreach (CelestialBody moon in vessel.orbit.referenceBody.orbitingBodies) { if (moon != targetBody) { transformedPosition = screenTransform.MultiplyPoint3x4(moon.getTruePositionAtUT(now) - vessel.orbit.referenceBody.getTruePositionAtUT(now)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, moon.orbitDriver.orbitColor, MapIcons.OtherIcon.PLANET); } } if (targetVessel != null || targetBody != null) { var orbit = (targetVessel != null) ? targetVessel.GetOrbit() : targetBody.GetOrbit(); double tClosestApproach, dClosestApproach; if (targetVessel != null && targetVessel.LandedOrSplashed) { orbit = JUtil.ClosestApproachSrfOrbit(vessel.orbit, targetVessel, out tClosestApproach, out dClosestApproach); } else { dClosestApproach = JUtil.GetClosestApproach(vessel.orbit, orbit, out tClosestApproach); DrawNextPe(orbit, vessel.orbit.referenceBody, now, iconColorTargetValue, screenTransform); DrawNextAp(orbit, vessel.orbit.referenceBody, now, iconColorTargetValue, screenTransform); } if (targetBody != null) { transformedPosition = screenTransform.MultiplyPoint3x4(targetBody.getTruePositionAtUT(now) - vessel.orbit.referenceBody.getTruePositionAtUT(now)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, iconColorTargetValue, MapIcons.OtherIcon.PLANET); } else { transformedPosition = screenTransform.MultiplyPoint3x4(orbit.SwappedRelativePositionAtUT(now)); DrawIcon(transformedPosition.x, transformedPosition.y, targetVessel.vesselType, iconColorTargetValue); } if (vessel.orbit.AscendingNodeExists(orbit)) { double anTime = vessel.orbit.TimeOfAscendingNode(orbit, now); if (anTime < vessel.orbit.EndUT || (vessel.orbit.patchEndTransition != Orbit.PatchTransitionType.ESCAPE && vessel.orbit.patchEndTransition != Orbit.PatchTransitionType.ENCOUNTER)) { transformedPosition = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(anTime)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, orbitColorSelfValue, MapIcons.OtherIcon.AN); } } if (vessel.orbit.DescendingNodeExists(orbit)) { double dnTime = vessel.orbit.TimeOfDescendingNode(orbit, now); if (dnTime < vessel.orbit.EndUT || (vessel.orbit.patchEndTransition != Orbit.PatchTransitionType.ESCAPE && vessel.orbit.patchEndTransition != Orbit.PatchTransitionType.ENCOUNTER)) { transformedPosition = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(dnTime)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, orbitColorSelfValue, MapIcons.OtherIcon.DN); } } Orbit o = GetPatchAtUT(vessel.orbit, tClosestApproach); if (o != null) { Vector3d encounterPosition = o.SwappedRelativePositionAtUT(tClosestApproach) + o.referenceBody.getTruePositionAtUT(tClosestApproach) - vessel.orbit.referenceBody.getTruePositionAtUT(tClosestApproach); transformedPosition = screenTransform.MultiplyPoint3x4(encounterPosition); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, iconColorClosestApproachValue, MapIcons.OtherIcon.SHIPATINTERCEPT); } // Unconditionally try to draw the closest approach point on // the target orbit. transformedPosition = screenTransform.MultiplyPoint3x4(orbit.SwappedRelativePositionAtUT(tClosestApproach)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, iconColorClosestApproachValue, MapIcons.OtherIcon.TGTATINTERCEPT); } else { if (vessel.orbit.AscendingNodeEquatorialExists()) { double anTime = vessel.orbit.TimeOfAscendingNodeEquatorial(now); if (anTime < vessel.orbit.EndUT || (vessel.orbit.patchEndTransition != Orbit.PatchTransitionType.ESCAPE && vessel.orbit.patchEndTransition != Orbit.PatchTransitionType.ENCOUNTER)) { transformedPosition = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(anTime)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, orbitColorSelfValue, MapIcons.OtherIcon.AN); } } if (vessel.orbit.DescendingNodeEquatorialExists()) { double dnTime = vessel.orbit.TimeOfDescendingNodeEquatorial(now); if (dnTime < vessel.orbit.EndUT || (vessel.orbit.patchEndTransition != Orbit.PatchTransitionType.ESCAPE && vessel.orbit.patchEndTransition != Orbit.PatchTransitionType.ENCOUNTER)) { transformedPosition = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(dnTime)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, orbitColorSelfValue, MapIcons.OtherIcon.DN); } } } // Draw orbital features DrawNextPe(vessel.orbit, vessel.orbit.referenceBody, now, iconColorPEValue, screenTransform); DrawNextAp(vessel.orbit, vessel.orbit.referenceBody, now, iconColorAPValue, screenTransform); if (vessel.orbit.nextPatch != null && vessel.orbit.nextPatch.activePatch) { transformedPosition = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(vessel.orbit.EndUT)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, orbitColorSelfValue, MapIcons.OtherIcon.EXITSOI); Orbit nextPatch = vessel.orbit.nextPatch.nextPatch; if (nextPatch != null && nextPatch.activePatch) { transformedPosition = screenTransform.MultiplyPoint3x4(nextPatch.SwappedRelativePositionAtUT(nextPatch.EndUT) + nextPatch.referenceBody.getTruePositionAtUT(nextPatch.EndUT) - vessel.orbit.referenceBody.getTruePositionAtUT(nextPatch.EndUT)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, orbitColorNextNodeValue, MapIcons.OtherIcon.EXITSOI); } } if (node != null && node.nextPatch.activePatch) { DrawNextPe(node.nextPatch, vessel.orbit.referenceBody, now, orbitColorNextNodeValue, screenTransform); DrawNextAp(node.nextPatch, vessel.orbit.referenceBody, now, orbitColorNextNodeValue, screenTransform); transformedPosition = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(node.UT)); DrawIcon(transformedPosition.x, transformedPosition.y, VesselType.Unknown, orbitColorNextNodeValue, MapIcons.OtherIcon.NODE); } // Draw ownship icon transformedPosition = screenTransform.MultiplyPoint3x4(vessel.orbit.SwappedRelativePositionAtUT(now)); DrawIcon(transformedPosition.x, transformedPosition.y, vessel.vesselType, iconColorSelfValue); GL.PopMatrix(); GL.Viewport(new Rect(0, 0, screen.width, screen.height)); return(true); }
public static Node FromExisting(Vessel v, ManeuverNode existingNode, SharedObjects shared) { return(nodeLookup.ContainsKey(existingNode) ? nodeLookup[existingNode] : new Node(v, existingNode, shared)); }
protected override void AdjustNode( ManeuverNode originalNode, Maneuver original, double originalPeriod, double originalMagnitude, ManeuverNode node, double value, double splitDv) { double fraction; double minFraction = 0; double maxFraction = 1; double targetApo = value * 1000; for (int iteration = 0; iteration < HighLogic.CurrentGame.Parameters.CustomParams <MNS>().splitByApoIterations; iteration += 1) { fraction = (minFraction + maxFraction) / 2; Vector3d dv = original.DeltaV * fraction; if (node != originalNode) { RotateDeltaV(originalNode, node, ref dv); } node.DeltaV = dv; node.solver.UpdateFlightPlan(); if (node.nextPatch.ApA > 0 && node.nextPatch.ApA < targetApo) { minFraction = fraction; } else { maxFraction = fraction; } } }
internal void createManeuverNode(PatchedConicSolver p) { ManeuverNode newnode = p.AddManeuverNode(UT); newnode.OnGizmoUpdated(deltaV, UT); }
public override void OnFixedUpdate() { if (!vessel.patchedConicsUnlocked() || !vessel.patchedConicSolver.maneuverNodes.Any()) { Abort(); return; } //check if we've finished a node: ManeuverNode node = vessel.patchedConicSolver.maneuverNodes.First(); double dVLeft = node.GetBurnVector(orbit).magnitude; if (dVLeft < tolerance && core.attitude.attitudeAngleFromTarget() > 5) { burnTriggered = false; node.RemoveSelf(); if (mode == Mode.ONE_NODE) { Abort(); return; } else if (mode == Mode.ALL_NODES) { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { Abort(); return; } else { node = vessel.patchedConicSolver.maneuverNodes.First(); } } } //aim along the node core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.MANEUVER_NODE, this); double halfBurnTime; double burnTime = BurnTime(dVLeft, out halfBurnTime); double timeToNode = node.UT - vesselState.time; if (timeToNode < halfBurnTime) { burnTriggered = true; if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } } //autowarp, but only if we're already aligned with the node if (autowarp && !burnTriggered) { if (core.attitude.attitudeAngleFromTarget() < 1 || (core.attitude.attitudeAngleFromTarget() < 10 && !MuUtils.PhysicsRunning())) { core.warp.WarpToUT(node.UT - halfBurnTime - leadTime); } else if (!MuUtils.PhysicsRunning() && core.attitude.attitudeAngleFromTarget() > 10 && timeToNode < 600) { //realign core.warp.MinimumWarp(); } } core.thrust.targetThrottle = 0; if (burnTriggered) { if (alignedForBurn) { if (core.attitude.attitudeAngleFromTarget() < 90) { double timeConstant = (dVLeft > 10 || vesselState.minThrustAccel > 0.25 * vesselState.maxThrustAccel ? 0.5 : 2); core.thrust.ThrustForDV(dVLeft + tolerance, timeConstant); } else { alignedForBurn = false; } } else { if (core.attitude.attitudeAngleFromTarget() < 2) { alignedForBurn = true; } } } }
public void RestoreManeuverNode(ManeuverNode newManNode) { ManeuverNode tmpNode = FlightGlobals.ActiveVessel.patchedConicSolver.AddManeuverNode(newManNode.UT); tmpNode.DeltaV = newManNode.DeltaV; tmpNode.nodeRotation = newManNode.nodeRotation; FlightGlobals.ActiveVessel.patchedConicSolver.UpdateFlightPlan(); }
protected override void WindowGUI(int windowID) { if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { GUILayout.Label("No maneuver nodes to edit."); GUI.DragWindow(); 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("Add", GUILayout.ExpandWidth(false))) { prograde += progradeDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Radial+:", radialPlus, "m/s", 60); if (GUILayout.Button("Add", GUILayout.ExpandWidth(false))) { radialPlus += radialPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GuiUtils.SimpleTextBox("Normal+:", normalPlus, "m/s", 60); if (GUILayout.Button("Add", GUILayout.ExpandWidth(false))) { normalPlus += normalPlusDelta; node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); } normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50)); GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Update")) node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT); GUILayout.BeginHorizontal(); if (GUILayout.Button("Shift time by", GUILayout.ExpandWidth(true))) { node.OnGizmoUpdated(node.DeltaV, node.UT + timeOffset); } timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100)); 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.Orbit.referenceBody == o.referenceBody) { if (o.AscendingNodeExists(core.target.Orbit)) UT = o.TimeOfAscendingNode(core.target.Orbit, UT - o.period / 2); } break; case Snap.REL_DESCENDING: if (core.target.NormalTargetExists && core.target.Orbit.referenceBody == o.referenceBody) { if (o.DescendingNodeExists(core.target.Orbit)) UT = o.TimeOfDescendingNode(core.target.Orbit, UT - o.period / 2); } break; } node.OnGizmoUpdated(node.DeltaV, UT); } snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]); GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUI.DragWindow(); }
public void Remove() { if (nodeRef == null) return; NodeLookup.Remove(nodeRef); vesselRef.patchedConicSolver.RemoveManeuverNode(nodeRef); nodeRef = null; vesselRef = null; }
/// <summary> /// Draw the main window. /// </summary> /// <param name="windowId">Window identifier.</param> void OnWindow(int windowId) { if (FlightGlobals.ActiveVessel == null) { return; } PatchedConicSolver solver = FlightGlobals.ActiveVessel.patchedConicSolver; GUILayout.BeginVertical(GUILayout.Width(320.0f)); GUILayout.BeginHorizontal(); if (GUILayout.Button("New") && IsAllowed()) { _maneuver = solver.AddManeuverNode(Planetarium.GetUniversalTime() + (10.0 * 60.0)); _mindex = solver.maneuverNodes.IndexOf(_maneuver); } if (GUILayout.Button("Delete") && _maneuver != null) { _maneuver.RemoveSelf(); } if (GUILayout.Button("Delete All") && _maneuver != null) { DeleteAll(); } if (GUILayout.Button("Store") && solver.maneuverNodes.Count > 0) { StoredManeuver start = null; StoredManeuver prev = null; foreach (ManeuverNode node in solver.maneuverNodes) { StoredManeuver temp = new StoredManeuver(node.DeltaV, node.UT); if (start == null) { start = temp; } if (prev != null) { prev.Next = temp; } prev = temp; } _stored.Add(start); } if (GUILayout.Button("Close")) { ToggleWindow(); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Warp"); if (GUILayout.Button("+10m")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(Planetarium.GetUniversalTime() + 10.0 * Format.ONE_KMIN); } if (GUILayout.Button("+1h")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(Planetarium.GetUniversalTime() + Format.ONE_KHOUR); } if (GUILayout.Button("+1d")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(Planetarium.GetUniversalTime() + Format.ONE_KDAY); } if (GUILayout.Button("+10d")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(Planetarium.GetUniversalTime() + 10.0 * Format.ONE_KDAY); } if (FlightGlobals.ActiveVessel.orbit.patchEndTransition != Orbit.PatchTransitionType.FINAL) { if (GUILayout.Button("Transition")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(FlightGlobals.ActiveVessel.orbit.EndUT - Format.ONE_KMIN); } } GUILayout.EndHorizontal(); if (solver.maneuverNodes.Count > 0) { if (_maneuver == null || _mvessel != FlightGlobals.ActiveVessel || !solver.maneuverNodes.Contains(_maneuver)) { _maneuver = solver.maneuverNodes [0]; _mvessel = FlightGlobals.ActiveVessel; _mindex = 0; } GUILayout.BeginHorizontal(); GUILayout.Label("Maneuver:" + (_mindex + 1) + " of " + solver.maneuverNodes.Count); if (GUILayout.Button("Prev")) { _mindex--; if (_mindex < 0) { _mindex = solver.maneuverNodes.Count - 1; } _maneuver = solver.maneuverNodes [_mindex]; _mvessel = FlightGlobals.ActiveVessel; } if (GUILayout.Button("Next")) { _mindex++; if (_mindex >= solver.maneuverNodes.Count) { _mindex = 0; } _maneuver = solver.maneuverNodes [_mindex]; _mvessel = FlightGlobals.ActiveVessel; } GUILayout.EndHorizontal(); if (_maneuver != null) { double timeToNode = Planetarium.GetUniversalTime() - _maneuver.UT; if (_mindex == 0) { GUILayout.BeginHorizontal(); GUILayout.Label("Warp To Maneuver"); if (GUILayout.Button("-1m") && -timeToNode > Format.ONE_KMIN) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(_maneuver.UT - Format.ONE_KMIN); } if (GUILayout.Button("-10m") && -timeToNode > 10.0 * Format.ONE_KMIN) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(_maneuver.UT - 10.0 * Format.ONE_KMIN); } if (GUILayout.Button("-1h") && -timeToNode > Format.ONE_KHOUR) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(_maneuver.UT - Format.ONE_KHOUR); } GUILayout.EndHorizontal(); } else { GUILayout.Label("Warp To Maneuver - Switch to first maneuver"); } GUILayout.Label("Time:" + KSPUtil.dateTimeFormatter.PrintDateDeltaCompact(timeToNode, true, true, true)); GUILayout.Label("Δv:" + Format.GetNumberString(_maneuver.DeltaV.magnitude) + "m/s"); GUILayout.BeginHorizontal(); _menuSelection = GUILayout.SelectionGrid(_menuSelection, new string [] { ".01 m/s", ".1 m/s", "1 m/s", "10 m/s", "100 m/s", "1000 m/s" }, 3, GUILayout.MinWidth(300.0f)); if (_menuSelection == 0) { _increment = 0.01d; } else if (_menuSelection == 1) { _increment = 0.1d; } else if (_menuSelection == 2) { _increment = 1.0d; } else if (_menuSelection == 3) { _increment = 10.0d; } else if (_menuSelection == 4) { _increment = 100.0d; } else if (_menuSelection == 5) { _increment = 1000.0d; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Prograde:" + Format.GetNumberString(_maneuver.DeltaV.z) + "m/s", GUILayout.MinWidth(200.0f)); if (GUILayout.Button("-")) { Vector3d dv = _maneuver.DeltaV; dv.z -= _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("0")) { Vector3d dv = _maneuver.DeltaV; dv.z = 0.0d; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("+")) { Vector3d dv = _maneuver.DeltaV; dv.z += _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Normal :" + Format.GetNumberString(_maneuver.DeltaV.y) + "m/s", GUILayout.MinWidth(200.0f)); if (GUILayout.Button("-")) { Vector3d dv = _maneuver.DeltaV; dv.y -= _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("0")) { Vector3d dv = _maneuver.DeltaV; dv.y = 0.0d; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("+")) { Vector3d dv = _maneuver.DeltaV; dv.y += _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Radial :" + Format.GetNumberString(_maneuver.DeltaV.x) + "m/s", GUILayout.MinWidth(200.0f)); if (GUILayout.Button("-")) { Vector3d dv = _maneuver.DeltaV; dv.x -= _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("0")) { Vector3d dv = _maneuver.DeltaV; dv.x = 0.0d; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("+")) { Vector3d dv = _maneuver.DeltaV; dv.x += _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } GUILayout.EndHorizontal(); double ut = _maneuver.UT; double utUpdate = _timeControl.TimeGUI(ut, FlightGlobals.ActiveVessel); if (utUpdate != ut) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, utUpdate); } GUILayout.BeginHorizontal(); if (GUILayout.Button("=10min")) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, Planetarium.GetUniversalTime() + (10.0 * 60.0)); } double period = _maneuver.patch.period; if (GUILayout.Button("-10 Orbit") && period > 0 && -timeToNode > 10.0 * period) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, _maneuver.UT - (10.0 * period)); } if (GUILayout.Button("-1 Orbit") && period > 0 && -timeToNode > period) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, _maneuver.UT - period); } if (GUILayout.Button("+1 Orbit") && period > 0) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, _maneuver.UT + period); } if (GUILayout.Button("+10 Orbit") && period > 0) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, _maneuver.UT + (10.0 * period)); } GUILayout.EndHorizontal(); } else { _windowPos.height = 0; } } else if (_maneuver != null) { _maneuver = null; _windowPos.height = 0; } GUILayout.EndVertical(); GUI.DragWindow(); }
private static ManeuverNode ManNodeDeserialize(String strInput) { ManeuverNode mReturn = new ManeuverNode(); String[] manparts = strInput.Split(",".ToCharArray()); mReturn.UT = Convert.ToDouble(manparts[0]); mReturn.DeltaV = new Vector3d(Convert.ToDouble(manparts[1]), Convert.ToDouble(manparts[2]), Convert.ToDouble(manparts[3]) ); mReturn.nodeRotation = new Quaternion(Convert.ToSingle(manparts[4]), Convert.ToSingle(manparts[5]), Convert.ToSingle(manparts[6]), Convert.ToSingle(manparts[7]) ); return mReturn; }
public static Node FromExisting(Vessel v, ManeuverNode existingNode, SharedObjects shared) { return nodeLookup.ContainsKey(existingNode) ? nodeLookup[existingNode] : new Node(v, existingNode, shared); }
protected override void AdjustNode( ManeuverNode originalNode, Maneuver original, double originalPeriod, double originalMagnitude, ManeuverNode node, double value, double splitDv) { double fraction; double minFraction = 0; double maxFraction = 1; IBurnCalculator calculator = GetAvailableCalculator(); for (int iteration = 0; iteration < HighLogic.CurrentGame.Parameters.CustomParams <MNS>().splitByBurnTimeIterations; iteration += 1) { fraction = (minFraction + maxFraction) / 2; Vector3d dv = original.DeltaV * fraction; if (node != originalNode) { RotateDeltaV(originalNode, node, ref dv); } node.DeltaV = dv; node.solver.UpdateFlightPlan(); double burnTime = calculator.CalculateBurnTime(dv.magnitude, splitDv); if (node.nextPatch.ApA > 0 && burnTime < value) { minFraction = fraction; } else { maxFraction = fraction; } } }
// calculation function for mergeNodeDown private static Vector3d mergeBurnVectors(double UT, ManeuverNode first, Orbit projOrbit) { Orbit curOrbit = first.findPreviousOrbit(); return difference(curOrbit.getOrbitalVelocityAtUT(UT), projOrbit.getOrbitalVelocityAtUT(UT)); }
/* Nodes after the first will be in a different orbital plane if the maneuver is * not purely a prograde burn, so they must be rotated since the dV is specified * relative to the orbit at the point of the maneuver node */ protected void RotateDeltaV(ManeuverNode original, ManeuverNode node, ref Vector3d dv) { DebugLog("dV before {0},{1},{2}", dv.x, dv.y, dv.z); dv = Quaternion.Inverse(node.nodeRotation) * original.nodeRotation * dv; DebugLog("dV after {0},{1},{2}", dv.x, dv.y, dv.z); }
public void Remove() { if (nodeRef == null) return; string careerReason; if (! Career.CanMakeNodes(out careerReason)) throw new KOSLowTechException("use maneuver nodes", careerReason); nodeLookup.Remove(nodeRef); if (vesselRef.patchedConicSolver == null) throw new KOSSituationallyInvalidException( "A KSP limitation makes it impossible to access the manuever nodes of this vessel at this time. " + "(perhaps it's not the active vessel?)"); nodeRef.RemoveSelf(); nodeRef = null; vesselRef = null; }
// calculation function for mergeNodeDown private static Vector3d mergeBurnVectors(double UT, ManeuverNode first, Orbit projOrbit) { Orbit curOrbit = first.findPreviousOrbit(); return(difference(curOrbit.getOrbitalVelocityAtUT(UT), projOrbit.getOrbitalVelocityAtUT(UT))); }