void driveTransferInjection(FlightCtrlState s) { if (part.vessel.orbit.eccentricity > 1) { endOperation(); return; } if (getPredictedPostTransferPeR() != -1 && part.vessel.orbit.relativeInclination(transferTarget.orbit) < 1) { transState = TRANSState.LOWERING_PERIAPSIS; return; } if(part.vessel.orbit.ApR > transferTarget.orbit.PeR) { transState = TRANSState.WAITING_FOR_CORRECTION; return; } if ((TimeWarp.WarpMode == TimeWarp.Modes.HIGH) && (TimeWarp.CurrentRate > TimeWarp.MaxPhysicsRate)) core.warpMinimum(this); core.attitudeTo(Vector3d.forward, MechJebCore.AttitudeReference.ORBIT, this); if (core.attitudeAngleFromTarget() < 5) s.mainThrottle = 1.0F; else s.mainThrottle = 0.0F; }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); GUIStyle normal = new GUIStyle(GUI.skin.label); GUIStyle yellow = new GUIStyle(GUI.skin.label); yellow.normal.textColor = Color.yellow; if (part.vessel.orbit.eccentricity < 1.0) { GUILayout.Label(String.Format("Current orbit: {0:0}km x {1:0}km, inclined {2:0.0}°", part.vessel.orbit.PeA / 1000.0, part.vessel.orbit.ApA / 1000.0, part.vessel.orbit.inclination)); } else { GUILayout.Label(String.Format("Current orbit: hyperbolic, Pe = {0:0}km, inclined {1:0.0}°", part.vessel.orbit.PeA / 1000.0, part.vessel.orbit.inclination)); } guiTab = (Operation)GUILayout.Toolbar((int)guiTab, guiTabStrings); switch (guiTab) { case Operation.PERIAPSIS: newPeA = ARUtils.doGUITextInput("New periapsis: ", 250.0F, newPeAString, 50.0F, "km", 30.0F, out newPeAString, newPeA, 1000.0); if (newPeA > vesselState.altitudeASL) { GUILayout.Label("Periapsis cannot be above current altitude.", yellow); } else if (GUILayout.Button(String.Format("Burn (Δv = {0:0} m/s)", deltaVToChangePeriapsis(newPeA)))) { core.controlClaim(this); currentOperation = Operation.PERIAPSIS; raisingApsis = (part.vessel.orbit.PeA < newPeA); } break; case Operation.APOAPSIS: newApA = ARUtils.doGUITextInput("New apoapsis: ", 250.0F, newApAString, 50.0F, "km", 30.0F, out newApAString, newApA, 1000.0); if (newApA < vesselState.altitudeASL) { GUILayout.Label("Apoapsis cannot be below current altitude.", yellow); } else if (GUILayout.Button(String.Format("Burn (Δv = {0:0} m/s)", deltaVToChangeApoapsis(newApA)))) { core.controlClaim(this); currentOperation = Operation.APOAPSIS; raisingApsis = (part.vessel.orbit.ApR > 0 && part.vessel.orbit.ApA < newApA); } break; case Operation.ELLIPTICIZE: newPeA = ARUtils.doGUITextInput("New periapsis: ", 250.0F, newPeAString, 50.0F, "km", 30.0F, out newPeAString, newPeA, 1000.0); newApA = ARUtils.doGUITextInput("New apoapsis: ", 250.0F, newApAString, 50.0F, "km", 30.0F, out newApAString, newApA, 1000.0); if (newPeA > vesselState.altitudeASL) { GUILayout.Label("Periapsis cannot be above current altitude.", yellow); } else if (newApA < vesselState.altitudeASL) { GUILayout.Label("Apoapsis cannot be below current altitude.", yellow); } else if (GUILayout.Button(String.Format("Burn (Δv = {0:0} m/s)", ellipticizationVelocityCorrection(newPeA, newApA).magnitude))) { core.controlClaim(this); currentOperation = Operation.ELLIPTICIZE; } break; case Operation.CIRCULARIZE: if (GUILayout.Button(String.Format("Circularize at {0:0} km (Δv = {1:0} m/s)", vesselState.altitudeASL / 1000.0, circularizationVelocityCorrection().magnitude))) { core.controlClaim(this); currentOperation = Operation.CIRCULARIZE; } break; case Operation.TRANSFER_INJECTION: if (part.vessel.mainBody.orbitingBodies.Count > 0) { desiredPostTransferPeA = ARUtils.doGUITextInput("Desired final periapsis:", 250.0F, desiredPostTransferPeAString, 50.0F, "km", 30.0F, out desiredPostTransferPeAString, desiredPostTransferPeA, 1000.0); double postTransferPeR = getPredictedPostTransferPeR(); if (transferTarget != null && postTransferPeR != -1) { GUILayout.Label(String.Format("Predicted periapsis after transfer to " + transferTarget.name + ": {0:0} km", (postTransferPeR - transferTarget.Radius) / 1000.0)); } foreach (CelestialBody body in part.vessel.mainBody.orbitingBodies) { double deltaV = deltaVToChangeApoapsis(body.orbit.PeA); Orbit transferOrbit = ARUtils.computeOrbit(part.vessel, deltaV * vesselState.velocityVesselOrbitUnit, vesselState.time); double arrivalTime = vesselState.time + transferOrbit.timeToAp; Vector3d vesselArrivalPosition = transferOrbit.getAbsolutePositionAtUT(arrivalTime); Orbit targetOrbit = ARUtils.computeOrbit(body.position, (FlightGlobals.RefFrameIsRotating ? -1 : 1) * body.orbit.GetVel(), part.vessel.mainBody, vesselState.time); Vector3d targetArrivalPosition = targetOrbit.getAbsolutePositionAtUT(arrivalTime); Vector3d targetPlaneNormal = Vector3d.Cross(body.position - part.vessel.mainBody.position, body.orbit.GetVel()); Vector3d vesselArrivalPositionTargetPlane = part.vessel.mainBody.position + Vector3d.Exclude(targetPlaneNormal, vesselArrivalPosition - part.vessel.mainBody.position); double angleOffset = Math.Abs(Vector3d.Angle(targetArrivalPosition - part.vessel.mainBody.position, vesselArrivalPositionTargetPlane - part.vessel.mainBody.position)); if ( Math.Abs(Vector3d.Angle(vesselState.velocityVesselOrbitUnit, targetArrivalPosition - part.vessel.mainBody.position)) < Math.Abs(Vector3d.Angle(vesselState.velocityVesselOrbitUnit * -1, targetArrivalPosition - part.vessel.mainBody.position)) ) { angleOffset = 360.0 - angleOffset; //if we have passed the transfer point then give the user the time to loop back around the long way } angleOffset = Math.Max(angleOffset - 1.0, 0.0); //give us a 1 degree window double timeOffset = Math.Abs(angleOffset) / 360 * part.vessel.orbit.period; if (GUILayout.Button(String.Format("Transfer point to " + body.name + " in {1:0} s (Δv ≈ {0:0} m/s)", deltaV, MuUtils.ToSI(timeOffset, 1)))) { core.controlClaim(this); currentOperation = Operation.TRANSFER_INJECTION; transState = TRANSState.WAITING_FOR_INJECTION; transferTarget = body; } } if (part.vessel.orbit.eccentricity > 1.0) { GUILayout.Label("Transfer injection failed. Did you start from a circular equatorial orbit?", ARUtils.labelStyle(Color.yellow)); } } else { GUILayout.Label("No bodies orbit " + part.vessel.mainBody.name); } break; case Operation.WARP: GUILayout.BeginHorizontal(); GUILayout.Label("Warp to:"); warpPoint = (WarpPoint)GUILayout.Toolbar((int)warpPoint, warpPointStrings); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (warpPoint == WarpPoint.APOAPSIS || warpPoint == WarpPoint.PERIAPSIS) { warpTimeOffset = ARUtils.doGUITextInput("Lead time:", 150.0F, warpTimeOffsetString, 50.0F, "s", 30.0F, out warpTimeOffsetString, warpTimeOffset); } if (GUILayout.Button("Warp")) { core.controlClaim(this); FlightInputHandler.SetNeutralControls(); currentOperation = Operation.WARP; } GUILayout.EndHorizontal(); break; } GUILayout.BeginHorizontal(); String statusString = "Idle"; switch (currentOperation) { case Operation.PERIAPSIS: statusString = String.Format((raisingApsis ? "Raising" : "Lowering") + " periapsis to {0:0} km", newPeA / 1000.0); break; case Operation.APOAPSIS: statusString = String.Format((raisingApsis ? "Raising" : "Lowering") + " apoapsis to {0:0} km", newApA / 1000.0); break; case Operation.ELLIPTICIZE: statusString = String.Format("Changing orbit to {0:0}km x {1:0}km", newPeA / 1000.0, newApA / 1000.0); break; case Operation.CIRCULARIZE: statusString = String.Format("Circularizing at {0:0} km", vesselState.altitudeASL / 1000.0); break; case Operation.TRANSFER_INJECTION: statusString = "Transferring to " + transferTarget.name + "\n" + transStateStrings[(int)transState]; break; case Operation.WARP: String offsetString = ""; if (warpPoint != WarpPoint.SOI_CHANGE) { if (warpTimeOffset > 0) offsetString = "" + warpTimeOffset + "s before "; else if (warpTimeOffset < 0) offsetString = "" + Math.Abs(warpTimeOffset) + "s after "; } statusString = "Warping to " + offsetString + warpPointStrings2[(int)warpPoint]; break; } GUILayout.Label("Status: " + statusString, GUILayout.Width(200.0F)); GUIStyle abortStyle = (currentOperation == Operation.NONE ? ARUtils.buttonStyle(Color.gray) : ARUtils.buttonStyle(Color.red)); if (GUILayout.Button("Abort", abortStyle)) { endOperation(); } showHelpWindow = GUILayout.Toggle(showHelpWindow, "?", new GUIStyle(GUI.skin.button)); GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUI.DragWindow(); }
void driveTransferWaitingForInjection(FlightCtrlState s) { if (transferTarget == null || part.vessel.orbit.eccentricity > 1.0) { endOperation(); return; } Orbit transferOrbit = ARUtils.computeOrbit(part.vessel, deltaVToChangeApoapsis(transferTarget.orbit.PeA) * vesselState.velocityVesselOrbitUnit, vesselState.time); double arrivalTime = vesselState.time + transferOrbit.timeToAp; Vector3d vesselArrivalPosition = transferOrbit.getAbsolutePositionAtUT(arrivalTime); //minus sign is there because transferTarget.orbit.GetVel() seems to be mysteriously negated //when the ship is in the rotating reference frame of the original body. Orbit targetOrbit = ARUtils.computeOrbit(transferTarget.position, (FlightGlobals.RefFrameIsRotating ? -1 : 1) * transferTarget.orbit.GetVel(), part.vessel.mainBody, vesselState.time); Vector3d targetArrivalPosition = targetOrbit.getAbsolutePositionAtUT(arrivalTime); Vector3d targetPlaneNormal = Vector3d.Cross(transferTarget.position - part.vessel.mainBody.position, transferTarget.orbit.GetVel()); Vector3d vesselArrivalPositionTargetPlane = part.vessel.mainBody.position + Vector3d.Exclude(targetPlaneNormal, vesselArrivalPosition - part.vessel.mainBody.position); double angleOffset = Math.Abs(Vector3d.Angle(targetArrivalPosition - part.vessel.mainBody.position, vesselArrivalPositionTargetPlane - part.vessel.mainBody.position)); //If within 1 degree of our angle then cut warp and set state to injecting if (Math.Abs(angleOffset) < 1) { transState = TRANSState.INJECTING; if ((TimeWarp.WarpMode == TimeWarp.Modes.HIGH) && (TimeWarp.CurrentRate > TimeWarp.MaxPhysicsRate)) core.warpMinimum(this); } else { double timeOffset = angleOffset / 360 * part.vessel.orbit.period; core.warpTo(this, timeOffset - 30, warpLookaheadTimes); } core.attitudeTo(Vector3d.forward, MechJebCore.AttitudeReference.ORBIT, this); //don't burn: s.mainThrottle = 0.0F; }
public LuaValue proxyTransfer(LuaValue[] args) { if (args.Count() != 2) throw new Exception("transfer usage: transfer(target body, final periapsis [in meters])"); try { foreach (CelestialBody body in part.vessel.mainBody.orbitingBodies) { if (body.name.ToLower().Contains(args[0].ToString().ToLower())) { transferTarget = body; break; } } } catch (Exception) { throw new Exception("transfer: invalid target body"); } try { desiredPostTransferPeA = ((LuaNumber)args[1]).Number; } catch (Exception) { throw new Exception("transfer: invalid final periapsis"); } desiredPostTransferPeAString = (desiredPostTransferPeA / 1000.0).ToString(); this.enabled = true; core.controlClaim(this); currentOperation = Operation.TRANSFER_INJECTION; transState = TRANSState.WAITING_FOR_INJECTION; guiTab = Operation.TRANSFER_INJECTION; return LuaNil.Nil; }
void driveTransferWaitingForCorrection(FlightCtrlState s) { if(vesselState.radius < 0.5 * (part.vessel.orbit.PeR + part.vessel.orbit.ApR)) { core.warpIncrease(this, false); } else { core.warpMinimum(this, false); transState = TRANSState.LOWERING_PERIAPSIS; } s.mainThrottle = 0.0F; }