Example #1
0
        void DriveCircularizationBurn(FlightCtrlState s)
        {
            if (!vessel.patchedConicsUnlocked() || skipCircularization)
            {
                this.users.Clear();
                return;
            }

            DriveDeployableComponents(s);

            if (placedCircularizeNode)
            {
                if (vessel.patchedConicSolver.maneuverNodes.Count == 0)
                {
                    MechJebModuleFlightRecorder recorder = core.GetComputerModule <MechJebModuleFlightRecorder>();
                    if (recorder != null)
                    {
                        launchPhaseAngle = recorder.phaseAngleFromMark;
                    }
                    if (recorder != null)
                    {
                        launchLANDifference = vesselState.orbitLAN - recorder.markLAN;
                    }

                    //finished circularize
                    this.users.Clear();
                    return;
                }
            }
            else
            {
                //place circularization node
                vessel.RemoveAllManeuverNodes();
                double UT = orbit.NextApoapsisTime(vesselState.time);
                //During the circularization burn, try to correct any inclination errors because it's better to combine the two burns.
                //  For example, if you're about to do a 1500 m/s circularization burn, if you combine a 200 m/s inclination correction
                //  into it, you actually only spend 1513 m/s to execute combined manuver.  Mechjeb should also do correction burns before
                //  this if possible, and this can't correct all errors... but it's better then nothing.
                //   (A better version of this should try to match inclination & LAN if target is specified)
                // FIXME? this inclination correction is unlikely to be at tha AN/DN and will throw the LAN off with anything other than high
                // TWR launches from equatorial launch sites -- should probably be made optional (or clip it if the correction is too large).
                Vector3d inclinationCorrection = OrbitalManeuverCalculator.DeltaVToChangeInclination(orbit, UT, Math.Abs(desiredInclination));
                Vector3d smaCorrection         = OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(orbit.PerturbedOrbit(UT, inclinationCorrection), UT,
                                                                                                  desiredOrbitAltitude + mainBody.Radius);
                Vector3d dV = inclinationCorrection + smaCorrection;
                vessel.PlaceManeuverNode(orbit, dV, UT);
                placedCircularizeNode = true;

                core.node.ExecuteOneNode(this);
            }

            if (core.node.burnTriggered)
            {
                status = Localizer.Format("#MechJeb_Ascent_status7");                         //"Circularizing"
            }
            else
            {
                status = Localizer.Format("#MechJeb_Ascent_status8"); //"Coasting to circularization burn"
            }
        }
 public override void OnStart(PartModule.StartState state)
 {
     autopilot = core.GetComputerModule <MechJebModuleAscentAutopilot>();
     if (autopilot != null)
     {
         desiredInclination = autopilot.desiredInclination;
     }
 }
 public override void OnStart(PartModule.StartState state)
 {
     if (autopilot != null)
     {
         desiredInclination = autopilot.desiredInclination;  // FIXME: remove this indirection
     }
     navBall = core.GetComputerModule <MechJebModuleAscentNavBall>();
 }
 public override void OnStart(PartModule.StartState state)
 {
     autopilot = core.GetComputerModule<MechJebModuleAscentAutopilot>();
     if (autopilot != null)
     {
         autopilot.users.Add(this);
         desiredInclination = autopilot.desiredInclination;
     }
 }
 public override void OnStart(PartModule.StartState state)
 {
     autopilot = core.GetComputerModule<MechJebModuleAscentAutopilot>();
     if (autopilot != null)
     {
         desiredInclination = autopilot.desiredInclination;
     }
     navBall = core.GetComputerModule<MechJebModuleAscentNavBall>();
 }
Example #6
0
        void DriveCircularizationBurn(FlightCtrlState s)
        {
            if (!vessel.patchedConicsUnlocked() || skipCircularization)
            {
                this.users.Clear();
                return;
            }

            if (placedCircularizeNode)
            {
                if (!vessel.patchedConicSolver.maneuverNodes.Any())
                {
                    MechJebModuleFlightRecorder recorder = core.GetComputerModule <MechJebModuleFlightRecorder>();
                    if (recorder != null)
                    {
                        launchPhaseAngle = recorder.phaseAngleFromMark;
                    }
                    if (recorder != null)
                    {
                        launchLANDifference = vesselState.orbitLAN - recorder.markLAN;
                    }

                    //finished circularize
                    this.users.Clear();
                    return;
                }
            }
            else
            {
                //place circularization node
                vessel.RemoveAllManeuverNodes();
                double UT = orbit.NextApoapsisTime(vesselState.time);
                //During the circularization burn, try to correct any inclination errors because it's better to combine the two burns.
                //  For example, if you're about to do a 1500 m/s circularization burn, if you combine a 200 m/s inclination correction
                //  into it, you actually only spend 1513 m/s to execute combined manuver.  Mechjeb should also do correction burns before
                //  this if possible, and this can't correct all errors... but it's better then nothing.
                //   (A better version of this should try to match inclination & LAN if target is specified)
                Vector3d inclinationCorrection = OrbitalManeuverCalculator.DeltaVToChangeInclination(orbit, UT, desiredInclination);
                Vector3d smaCorrection         = OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(orbit.PerturbedOrbit(UT, inclinationCorrection), UT,
                                                                                                  desiredOrbitAltitude + mainBody.Radius);
                Vector3d dV = inclinationCorrection + smaCorrection;
                vessel.PlaceManeuverNode(orbit, dV, UT);
                placedCircularizeNode = true;

                core.node.ExecuteOneNode(this);
            }

            if (core.node.burnTriggered)
            {
                status = "Circularizing";
            }
            else
            {
                status = "Coasting to circularization burn";
            }
        }
 public override void OnStart(PartModule.StartState state)
 {
     Tf       = new EditableDouble(core.attitude.Tf);
     TfMin    = new EditableDouble(core.attitude.TfMin);
     TfMax    = new EditableDouble(core.attitude.TfMax);
     kpFactor = new EditableDouble(core.attitude.kpFactor);
     kiFactor = new EditableDouble(core.attitude.kiFactor);
     kdFactor = new EditableDouble(core.attitude.kdFactor);
     base.OnStart(state);
 }
 public override void OnStart(PartModule.StartState state)
 {
     Tf = new EditableDouble(core.attitude.Tf);
     TfMin = new EditableDouble(core.attitude.TfMin);
     TfMax = new EditableDouble(core.attitude.TfMax);
     kpFactor = new EditableDouble(core.attitude.kpFactor);
     kiFactor = new EditableDouble(core.attitude.kiFactor);
     kdFactor = new EditableDouble(core.attitude.kdFactor);
     base.OnStart(state);
 }
        public override void OnStart(PartModule.StartState state)
        {
            Kp = new EditableDouble(core.attitude.Kp);
            Ki = new EditableDouble(core.attitude.Ki);
            Kd = new EditableDouble(core.attitude.Kd);
            Tf = new EditableDouble(core.attitude.Tf);
            Ki_limit = new EditableDouble(core.attitude.Ki_limit);
            factor = new EditableDouble(core.attitude.drive_factor);

            base.OnStart(state);
        }
        public void setPIDParameters()
        {
            if (Tf < 2 * TimeWarp.fixedDeltaTime)
            {
                Tf = 2 * TimeWarp.fixedDeltaTime;
            }

            pid.Kd = 0.53 / Tf;
            pid.Kp = pid.Kd / (3 * Math.Sqrt(2) * Tf);
            pid.Ki = pid.Kp / (12 * Math.Sqrt(2) * Tf);
        }
Example #11
0
        public override void OnStart(PartModule.StartState state)
        {
            Kp       = new EditableDouble(core.attitude.Kp);
            Ki       = new EditableDouble(core.attitude.Ki);
            Kd       = new EditableDouble(core.attitude.Kd);
            Tf       = new EditableDouble(core.attitude.Tf);
            Ki_limit = new EditableDouble(core.attitude.Ki_limit);
            factor   = new EditableDouble(core.attitude.drive_factor);

            base.OnStart(state);
        }
Example #12
0
        public EditableAngle(double angle)
        {
            angle = MuUtils.ClampDegrees180(angle);

            negative = (angle < 0);
            angle    = Math.Abs(angle);
            degrees  = (int)angle;
            angle   -= degrees;
            minutes  = (int)(60 * angle);
            angle   -= minutes / 60;
            seconds  = Math.Round(3600 * angle);
        }
 public override void OnStart(PartModule.StartState state)
 {
     TfX      = new EditableDouble(core.attitude.TfV.x);
     TfY      = new EditableDouble(core.attitude.TfV.y);
     TfZ      = new EditableDouble(core.attitude.TfV.z);
     TfMin    = new EditableDouble(core.attitude.TfMin);
     TfMax    = new EditableDouble(core.attitude.TfMax);
     kpFactor = new EditableDouble(core.attitude.kpFactor);
     kiFactor = new EditableDouble(core.attitude.kiFactor);
     kdFactor = new EditableDouble(core.attitude.kdFactor);
     deadband = new EditableDouble(core.attitude.deadband);
     base.OnStart(state);
 }
 override public void readModuleConfiguration()
 {
     deployGear       = module_autopilot.deployGears;
     deployChutes     = module_autopilot.deployChutes;
     limitChutesStage = module_autopilot.limitChutesStage;
     touchdownSpeed   = module_autopilot.touchdownSpeed;
     if (core.target.PositionTargetExists)
     {
         landTarget      = true;
         targetLattitude = core.target.targetLatitude;
         targetLongitude = core.target.targetLongitude;
     }
 }
 public override void OnStart(PartModule.StartState state)
 {
     TfX = new EditableDouble(core.attitude.TfV.x);
     TfY = new EditableDouble(core.attitude.TfV.y);
     TfZ = new EditableDouble(core.attitude.TfV.z);
     TfMin = new EditableDouble(core.attitude.TfMin);
     TfMax = new EditableDouble(core.attitude.TfMax);
     kpFactor = new EditableDouble(core.attitude.kpFactor);
     kiFactor = new EditableDouble(core.attitude.kiFactor);
     kdFactor = new EditableDouble(core.attitude.kdFactor);
     deadband = new EditableDouble(core.attitude.deadband);
     base.OnStart(state);
 }
        void DriveCircularizationBurn(FlightCtrlState s)
        {
            if (!vessel.patchedConicsUnlocked() || skipCircularization)
            {
                this.users.Clear();
                return;
            }

            if (placedCircularizeNode)
            {
                if (!vessel.patchedConicSolver.maneuverNodes.Any())
                {
                    MechJebModuleFlightRecorder recorder = core.GetComputerModule <MechJebModuleFlightRecorder>();
                    if (recorder != null)
                    {
                        launchPhaseAngle = recorder.phaseAngleFromMark;
                    }
                    if (recorder != null)
                    {
                        launchLANDifference = vesselState.orbitLAN - recorder.markLAN;
                    }

                    //finished circularize
                    this.users.Clear();
                    return;
                }
            }
            else
            {
                //place circularization node
                vessel.RemoveAllManeuverNodes();
                double UT = orbit.NextApoapsisTime(vesselState.time);
                //Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT);
                Vector3d dV = OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(orbit, UT, desiredOrbitAltitude + mainBody.Radius);
                vessel.PlaceManeuverNode(orbit, dV, UT);
                placedCircularizeNode = true;

                core.node.ExecuteOneNode(this);
            }

            if (core.node.burnTriggered)
            {
                status = "Circularizing";
            }
            else
            {
                status = "Coasting to circularization burn";
            }
        }
 override public void activateAction()
 {
     base.activateAction();
     this.smartAss.mode         = Target2Mode[(int)target];
     this.smartAss.target       = target;
     this.smartAss.srfHdg       = this.srfHdg;
     this.smartAss.srfPit       = this.srfPit;
     this.smartAss.srfRol       = this.srfRol;
     this.smartAss.srfVelYaw    = this.srfVelYaw;
     this.smartAss.srfVelPit    = this.srfVelPit;
     this.smartAss.srfVelRol    = this.srfVelRol;
     this.smartAss.rol          = this.rol;
     this.smartAss.advReference = this.advReference;
     this.smartAss.advDirection = this.advDirection;
     this.smartAss.forceRol     = this.forceRol;
     this.smartAss.forcePitch   = this.forcePitch;
     this.smartAss.forceYaw     = this.forceYaw;
     this.smartAss.Engage();
 }
        public void setPIDParameters()
        {
            if (rcsManualPID)
            {
                pid.Kd = Kd;
                pid.Kp = Kp;
                pid.Ki = Ki;
            }
            else
            {
                Tf = Math.Max(Tf, 0.02);

                pid.Kd = 0.53 / Tf;
                pid.Kp = pid.Kd / (3 * Math.Sqrt(2) * Tf);
                pid.Ki = pid.Kp / (12 * Math.Sqrt(2) * Tf);

                Kd.val = pid.Kd;
                Kp.val = pid.Kp;
                Ki.val = pid.Ki;
            }
        }
        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);
        }
        protected override void WindowGUI(int windowID)
        {
            if (btNormal == null)
            {
                btNormal = new GUIStyle(GUI.skin.button);
                btNormal.normal.textColor   = btNormal.focused.textColor = Color.white;
                btNormal.hover.textColor    = btNormal.active.textColor = Color.yellow;
                btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green;
                //btNormal.padding = new RectOffset(8, 8, 8, 8);

                btActive           = new GUIStyle(btNormal);
                btActive.active    = btActive.onActive;
                btActive.normal    = btActive.onNormal;
                btActive.onFocused = btActive.focused;
                btActive.hover     = btActive.onHover;

                btGreen = new GUIStyle(btNormal);
                btGreen.normal.textColor = Color.green;
                btGreen.fixedWidth       = 35;

                btWhite = new GUIStyle(btNormal);
                btWhite.normal.textColor = Color.white;
                btWhite.fixedWidth       = 35;

                btAuto                  = new GUIStyle(btNormal);
                btAuto.padding          = new RectOffset(8, 8, 8, 8);
                btAuto.normal.textColor = Color.red;
                btAuto.onActive         = btAuto.onFocused = btAuto.onHover = btAuto.onNormal = btAuto.active = btAuto.focused = btAuto.hover = btAuto.normal;
            }

            if (autopilot.enabled)
            {
                if (GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_button1"), btActive))   //Disengage autopilot
                {
                    autopilot.users.Remove(this);
                }
            }
            else if (core.attitude.enabled && core.attitude.users.Count(u => !this.Equals(u)) > 0)
            {
                if (core.attitude.users.Contains(this))
                {
                    core.attitude.users.Remove(this);  // so we don't suddenly turn on when the other autopilot finishes
                }
                GUILayout.Button("Auto", btAuto, GUILayout.ExpandWidth(true));
            }
            else
            {
                if (GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_button2")))   //Engage autopilot
                {
                    autopilot.users.Add(this);
                }
            }

            GUILayout.BeginHorizontal();
            bool AltitudeHold = autopilot.AltitudeHoldEnabled;

            autopilot.AltitudeHoldEnabled = GUILayout.Toggle(autopilot.AltitudeHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label1"), GUILayout.Width(140));  //Altitude Hold
            if (AltitudeHold != autopilot.AltitudeHoldEnabled)
            {
                if (autopilot.AltitudeHoldEnabled)
                {
                    autopilot.EnableAltitudeHold();
                }
                else
                {
                    autopilot.DisableAltitudeHold();
                }
            }
            bool change = false;

            if (GUILayout.Button("-", GUILayout.Width(18)))
            {
                AltitudeTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            AltitudeTargettmp.text = GUILayout.TextField(AltitudeTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
            if (GUILayout.Button("+", GUILayout.Width(18)))
            {
                AltitudeTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            if (AltitudeTargettmp < 0)
            {
                AltitudeTargettmp = 0;
            }
            GUILayout.Label("m", GUILayout.ExpandWidth(true));
            if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset1"), autopilot.AltitudeTarget == AltitudeTargettmp ? btWhite : btGreen))   //Set
            {
                autopilot.AltitudeTarget = AltitudeTargettmp;
            }
            GUILayout.EndHorizontal();


            if (!autopilot.AltitudeHoldEnabled)
            {
                bool _VertSpeedHoldEnabled = autopilot.VertSpeedHoldEnabled;
                GUILayout.BeginHorizontal();
                autopilot.VertSpeedHoldEnabled = GUILayout.Toggle(autopilot.VertSpeedHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label2"), GUILayout.Width(140));  //Vertical Speed Hold
                if (_VertSpeedHoldEnabled != autopilot.VertSpeedHoldEnabled)
                {
                    if (autopilot.VertSpeedHoldEnabled)
                    {
                        autopilot.EnableVertSpeedHold();
                    }
                    else
                    {
                        autopilot.DisableVertSpeedHold();
                    }
                }
                change = false;
                if (GUILayout.Button("-", GUILayout.Width(18)))
                {
                    VertSpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                VertSpeedTargettmp.text = GUILayout.TextField(VertSpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
                if (GUILayout.Button("+", GUILayout.Width(18)))
                {
                    VertSpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                VertSpeedTargettmp = Math.Max(0, VertSpeedTargettmp);
                GUILayout.Label("m/s", GUILayout.ExpandWidth(true));
                if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset2"), autopilot.VertSpeedTarget == VertSpeedTargettmp ? btWhite : btGreen))
                {
                    autopilot.VertSpeedTarget = VertSpeedTargettmp;
                }
                GUILayout.EndHorizontal();
            }
            else
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_VS"), GUILayout.Width(140));//"    V/S ±"
                change = false;
                if (GUILayout.Button("-", GUILayout.Width(18)))
                {
                    VertSpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                VertSpeedTargettmp.text = GUILayout.TextField(VertSpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
                if (GUILayout.Button("+", GUILayout.Width(18)))
                {
                    VertSpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                VertSpeedTargettmp = Math.Max(0, VertSpeedTargettmp);
                GUILayout.Label("m/s", GUILayout.ExpandWidth(true));
                if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset6"), autopilot.VertSpeedTarget == VertSpeedTargettmp ? btWhite : btGreen))
                {
                    autopilot.VertSpeedTarget = VertSpeedTargettmp;
                }
                GUILayout.EndHorizontal();
            }


            GUILayout.BeginHorizontal();
            bool _HeadingHoldEnabled = autopilot.HeadingHoldEnabled;

            autopilot.HeadingHoldEnabled = GUILayout.Toggle(autopilot.HeadingHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label4"), GUILayout.Width(140));  //"Heading Hold"
            if (_HeadingHoldEnabled != autopilot.HeadingHoldEnabled)
            {
                if (autopilot.HeadingHoldEnabled)
                {
                    autopilot.EnableHeadingHold();
                }
                else
                {
                    autopilot.DisableHeadingHold();
                }
            }
            change = false;
            if (GUILayout.Button("-", GUILayout.Width(18)))
            {
                HeadingTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            HeadingTargettmp.text = GUILayout.TextField(HeadingTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
            if (GUILayout.Button("+", GUILayout.Width(18)))
            {
                HeadingTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            HeadingTargettmp = MuUtils.ClampDegrees360(HeadingTargettmp);
            GUILayout.Label("°", GUILayout.ExpandWidth(true));
            if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset4"), autopilot.HeadingTarget == HeadingTargettmp ? btWhite : btGreen))
            {
                autopilot.HeadingTarget = HeadingTargettmp;
            }
            GUILayout.EndHorizontal();


            if (!autopilot.HeadingHoldEnabled)
            {
                GUILayout.BeginHorizontal();
                autopilot.RollHoldEnabled = GUILayout.Toggle(autopilot.RollHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label5"), GUILayout.Width(140));  //"Roll Hold"
                change = false;
                if (GUILayout.Button("-", GUILayout.Width(18)))
                {
                    RollTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                RollTargettmp.text = GUILayout.TextField(RollTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
                if (GUILayout.Button("+", GUILayout.Width(18)))
                {
                    RollTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                RollTargettmp = MuUtils.Clamp(RollTargettmp, -90, 90);
                GUILayout.Label("°", GUILayout.ExpandWidth(true));
                if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset5"), autopilot.RollTarget == RollTargettmp ? btWhite : btGreen))
                {
                    autopilot.RollTarget = RollTargettmp;
                }
                GUILayout.EndHorizontal();
            }
            else
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Label6"), GUILayout.Width(140));  //"    Roll Limit ±"
                change = false;
                if (GUILayout.Button("-", GUILayout.Width(18)))
                {
                    RollMaxtmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                RollMaxtmp.text = GUILayout.TextField(RollMaxtmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
                if (GUILayout.Button("+", GUILayout.Width(18)))
                {
                    RollMaxtmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                RollMaxtmp = MuUtils.Clamp(RollMaxtmp, -60, 60);
                GUILayout.Label("°", GUILayout.ExpandWidth(true));
                if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset6"), autopilot.BankAngle == RollMaxtmp ? btWhite : btGreen))
                {
                    autopilot.BankAngle = RollMaxtmp;
                }
                GUILayout.EndHorizontal();
            }


            GUILayout.BeginHorizontal();
            bool _AutoThrustCtrl = autopilot.SpeedHoldEnabled;

            autopilot.SpeedHoldEnabled = GUILayout.Toggle(autopilot.SpeedHoldEnabled, Localizer.Format("#MechJeb_Aircraftauto_Label7"), GUILayout.Width(140));  //Speed Hold
            if (autopilot.SpeedHoldEnabled != _AutoThrustCtrl)
            {
                if (autopilot.SpeedHoldEnabled)
                {
                    autopilot.EnableSpeedHold();
                }
                else
                {
                    autopilot.DisableSpeedHold();
                }
            }
            change = false;
            if (GUILayout.Button("-", GUILayout.Width(18)))
            {
                SpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            SpeedTargettmp.text = GUILayout.TextField(SpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
            if (GUILayout.Button("+", GUILayout.Width(18)))
            {
                SpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            if (SpeedTargettmp < 0)
            {
                SpeedTargettmp = 0;
            }
            GUILayout.Label("m/s", GUILayout.ExpandWidth(true));
            if (change || GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_btnset7"), autopilot.SpeedTarget == SpeedTargettmp ? btWhite : btGreen))   //Set
            {
                autopilot.SpeedTarget = SpeedTargettmp;
            }
            GUILayout.EndHorizontal();


            if (!showpid)
            {
                if (GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_button3"), GUILayout.Width(40)))    //"PID"
                {
                    showpid = true;
                }
            }
            else
            {
                if (GUILayout.Button(Localizer.Format("#MechJeb_Aircraftauto_button4"), GUILayout.Width(140)))    //Hide PID
                {
                    showpid = false;
                }
                GUILayout.BeginHorizontal();
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Label8"), GUILayout.ExpandWidth(true));  //Accceleration
                GUILayout.Label("Kp", GUILayout.ExpandWidth(false));
                autopilot.AccKp.text = GUILayout.TextField(autopilot.AccKp.text, GUILayout.Width(40));
                GUILayout.Label("i", GUILayout.ExpandWidth(false));
                autopilot.AccKi.text = GUILayout.TextField(autopilot.AccKi.text, GUILayout.Width(40));
                GUILayout.Label("d", GUILayout.ExpandWidth(false));
                autopilot.AccKd.text = GUILayout.TextField(autopilot.AccKd.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
                if (autopilot.SpeedHoldEnabled)
                {
                    GUILayout.Label(Localizer.Format("#MecgJeb_Aircraftauto_error1", autopilot.a_err.ToString("F2"), autopilot.RealAccelerationTarget.ToString("F2"), autopilot.cur_acc.ToString("F2")), GUILayout.ExpandWidth(false));  //"error:"<<1>>" Target:"<<2>> " Cur:"<<3>>
                }
                GUILayout.BeginHorizontal();
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Pitch"), GUILayout.ExpandWidth(true));//"VertSpeed"
                GUILayout.Label("Kp", GUILayout.ExpandWidth(false));
                autopilot.PitKp.text = GUILayout.TextField(autopilot.PitKp.text, GUILayout.Width(40));
                GUILayout.Label("i", GUILayout.ExpandWidth(false));
                autopilot.PitKi.text = GUILayout.TextField(autopilot.PitKi.text, GUILayout.Width(40));
                GUILayout.Label("d", GUILayout.ExpandWidth(false));
                autopilot.PitKd.text = GUILayout.TextField(autopilot.PitKd.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
                if (autopilot.VertSpeedHoldEnabled)
                {
                    GUILayout.Label(Localizer.Format("#MecgJeb_Aircraftauto_error2", autopilot.pitch_err.ToString("F2"), autopilot.RealPitchTarget.ToString("F2"), vesselState.currentPitch.ToString("F2"), autopilot.pitch_act.ToString("F5"), GUILayout.ExpandWidth(false)));//error:" Target:"" Cur:"
                }
                GUILayout.BeginHorizontal();
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Label10"), GUILayout.ExpandWidth(true));  //Roll
                GUILayout.Label("Kp", GUILayout.ExpandWidth(false));
                autopilot.RolKp.text = GUILayout.TextField(autopilot.RolKp.text, GUILayout.Width(40));
                GUILayout.Label("i", GUILayout.ExpandWidth(false));
                autopilot.RolKi.text = GUILayout.TextField(autopilot.RolKi.text, GUILayout.Width(40));
                GUILayout.Label("d", GUILayout.ExpandWidth(false));
                autopilot.RolKd.text = GUILayout.TextField(autopilot.RolKd.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
                if (autopilot.RollHoldEnabled)
                {
                    GUILayout.Label(Localizer.Format("#MecgJeb_Aircraftauto_error2", autopilot.roll_err.ToString("F2"), autopilot.RealRollTarget.ToString("F2"), (-vesselState.currentRoll).ToString("F2"), autopilot.roll_act.ToString("F5"), GUILayout.ExpandWidth(false)));//error:" Target:"" Cur:"
                }
                GUILayout.BeginHorizontal();
                GUILayout.Label("Yaw", GUILayout.ExpandWidth(true));
                GUILayout.Label("Kp", GUILayout.ExpandWidth(false));
                autopilot.YawKp.text = GUILayout.TextField(autopilot.YawKp.text, GUILayout.Width(40));
                GUILayout.Label("i", GUILayout.ExpandWidth(false));
                autopilot.YawKi.text = GUILayout.TextField(autopilot.YawKi.text, GUILayout.Width(40));
                GUILayout.Label("d", GUILayout.ExpandWidth(false));
                autopilot.YawKd.text = GUILayout.TextField(autopilot.YawKd.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
                if (autopilot.HeadingHoldEnabled)
                {
                    GUILayout.Label(Localizer.Format("#MecgJeb_Aircraftauto_error2", autopilot.yaw_err.ToString("F2"), autopilot.RealYawTarget.ToString("F2"), autopilot.curr_yaw.ToString("F2"), autopilot.yaw_act.ToString("F5"), GUILayout.ExpandWidth(false)));//error:" Target:"" Cur:"
                }
                GUILayout.BeginHorizontal();
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_Limits"), GUILayout.ExpandWidth(false));  //Yaw Control Limit
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_PitchDownLimit"), GUILayout.ExpandWidth(false));
                autopilot.PitchDownLimit.text = GUILayout.TextField(autopilot.PitchDownLimit.text, GUILayout.Width(40));
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_PitchUpLimit"), GUILayout.ExpandWidth(false));
                autopilot.PitchUpLimit.text = GUILayout.TextField(autopilot.PitchUpLimit.text, GUILayout.Width(40));
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_YawLimit"), GUILayout.ExpandWidth(false));
                autopilot.YawLimit.text = GUILayout.TextField(autopilot.YawLimit.text, GUILayout.Width(40));
                GUILayout.Label(Localizer.Format("#MechJeb_Aircraftauto_RollLimit"), GUILayout.ExpandWidth(false));
                autopilot.RollLimit.text = GUILayout.TextField(autopilot.RollLimit.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
            }
            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            if (btNormal == null)
            {
                btNormal = new GUIStyle(GUI.skin.button);
                btNormal.normal.textColor   = btNormal.focused.textColor = Color.white;
                btNormal.hover.textColor    = btNormal.active.textColor = Color.yellow;
                btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green;
                btNormal.padding            = new RectOffset(8, 8, 8, 8);

                btActive           = new GUIStyle(btNormal);
                btActive.active    = btActive.onActive;
                btActive.normal    = btActive.onNormal;
                btActive.onFocused = btActive.focused;
                btActive.hover     = btActive.onHover;
            }

            GUILayout.BeginVertical();

            if (autopilot != null)
            {
                if (autopilot.enabled)
                {
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button1")))//Disengage autopilot
                    {
                        autopilot.users.Remove(this);
                    }
                }
                else
                {
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button2")))//Engage autopilot
                    {
                        autopilot.users.Add(this);
                    }
                }
                if (ascentPathIdx == ascentType.PVG)
                {
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button3")))//Reset Guidance (DO NOT PRESS)
                    {
                        core.guidance.Reset();
                    }


                    GUILayout.BeginHorizontal();                                                                                                                   // EditorStyles.toolbar);

                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button4"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //"TARG"
                    {
                        autopilot.showTargeting = !autopilot.showTargeting;
                    }
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button5"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))  //GUID
                    {
                        autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings;
                    }
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button6"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))  //OPTS
                    {
                        autopilot.showSettings = !autopilot.showSettings;
                    }
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button7"), autopilot.showStatus ? btActive : btNormal, GUILayout.ExpandWidth(true)))  //STATUS
                    {
                        autopilot.showStatus = !autopilot.showStatus;
                    }
                    GUILayout.EndHorizontal();
                }
                else if (ascentPathIdx == ascentType.GRAVITYTURN)
                {
                    GUILayout.BeginHorizontal();                                                                                                                   // EditorStyles.toolbar);
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button8"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG
                    {
                        autopilot.showTargeting = !autopilot.showTargeting;
                    }
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button9"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))  //GUID
                    {
                        autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings;
                    }
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button10"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))  //OPTS
                    {
                        autopilot.showSettings = !autopilot.showSettings;
                    }
                    GUILayout.EndHorizontal();
                }
                else if (ascentPathIdx == ascentType.BREATHING_GT)
                {
                    GUILayout.BeginHorizontal();                                                                                                                   // EditorStyles.toolbar);
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button8"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG
                    {
                        autopilot.showTargeting = !autopilot.showTargeting;
                    }
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button9"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))//GUID
                    {
                        autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings;
                    }
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button10"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))//OPTS
                    {
                        autopilot.showSettings = !autopilot.showSettings;
                    }
                    GUILayout.EndHorizontal();
                }
                else if (ascentPathIdx == ascentType.CLASSIC)
                {
                    GUILayout.BeginHorizontal();                                                                                                                    // EditorStyles.toolbar);
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button11"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG
                    {
                        autopilot.showTargeting = !autopilot.showTargeting;
                    }
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button12"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))  //OPTS
                    {
                        autopilot.showSettings = !autopilot.showSettings;
                    }
                    GUILayout.EndHorizontal();
                }

                if (autopilot.showTargeting)
                {
                    if (ascentPathIdx == ascentType.PVG)
                    {
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label1"), autopilot.desiredOrbitAltitude, "km"); //Target Periapsis
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label2"), pvgascent.desiredApoapsis, "km");      //Target Apoapsis:
                        if (pvgascent.desiredApoapsis >= 0 && pvgascent.desiredApoapsis < autopilot.desiredOrbitAltitude)
                        {
                            GUIStyle s = new GUIStyle(GUI.skin.label);
                            s.normal.textColor = Color.yellow;
                            GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label3"), s);//Ap < Pe: circularizing orbit
                        }
                        if (pvgascent.desiredApoapsis < 0)
                        {
                            GUIStyle s = new GUIStyle(GUI.skin.label);
                            s.normal.textColor = XKCDColors.Orange;
                            GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label4"), s);//Hyperbolic target orbit (neg Ap)
                        }
                    }
                    else
                    {
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label5"), autopilot.desiredOrbitAltitude, "km");//Orbit altitude
                    }

                    GUIStyle si = new GUIStyle(GUI.skin.label);
                    if (Math.Abs(desiredInclination) < Math.Abs(vesselState.latitude) - 2.001)
                    {
                        si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Orange;
                    }
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label6"), si, GUILayout.ExpandWidth(true));//Orbit inc.
                    desiredInclination.text = GUILayout.TextField(desiredInclination.text, GUILayout.ExpandWidth(true), GUILayout.Width(100));
                    GUILayout.Label("º", GUILayout.ExpandWidth(false));
                    if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button13")))//Current
                    {
                        desiredInclination.val = vesselState.latitude;
                    }
                    GUILayout.EndHorizontal();
                    GUILayout.BeginHorizontal();
                    if (Math.Abs(desiredInclination) < Math.Abs(vesselState.latitude) - 2.001)
                    {
                        GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label7", Math.Abs(vesselState.latitude) - Math.Abs(desiredInclination)), si);//inc {0:F1}º below current latitude
                    }
                    GUILayout.EndHorizontal();
                    autopilot.desiredInclination = desiredInclination;
                }

                if (autopilot.showGuidanceSettings)
                {
                    if (ascentPathIdx == ascentType.GRAVITYTURN)
                    {
                        GUILayout.BeginVertical();

                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label8"), gtascent.turnStartAltitude, "km");     //Turn start altitude:
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label9"), gtascent.turnStartVelocity, "m/s");    //Turn start velocity:
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label10"), gtascent.turnStartPitch, "deg");      //Turn start pitch:
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label11"), gtascent.intermediateAltitude, "km"); //Intermediate altitude:
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label12"), gtascent.holdAPTime, "s");            //Hold AP Time:

                        GUILayout.EndVertical();
                    }
                    else if (ascentPathIdx == ascentType.BREATHING_GT)
                    {
                        GUILayout.BeginVertical();

                        //GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label8"), bgtascent.turnStartAltitude, "km");//Turn start altitude:
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label9"), bgtascent.turnStartVelocity, "m/s");      //Turn start velocity:
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label10"), bgtascent.turnStartPitch, "deg");        //Turn start pitch:
                        GuiUtils.SimpleTextBox(Localizer.Format("speed for breathing mode:"), bgtascent.startBreathingSpeed, "m/s"); //speed for breathing mode:
                        GuiUtils.SimpleTextBox(Localizer.Format("TWR to throttle other:"), bgtascent.minTWRthrottle, "s");           //TWR to throttle other:

                        GUILayout.EndVertical();
                    }
                    else if (ascentPathIdx == ascentType.PVG)
                    {
                        GUILayout.BeginVertical();
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label13"), pvgascent.pitchStartVelocity, "m/s"); //Booster Pitch start:
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label14"), pvgascent.pitchRate, "°/s");          //Booster Pitch rate:
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label15"), core.guidance.pvgInterval, "s");      //Guidance Interval:
                        if (core.guidance.pvgInterval < 1 || core.guidance.pvgInterval > 30)
                        {
                            GUIStyle s = new GUIStyle(GUI.skin.label);
                            s.normal.textColor = Color.yellow;
                            GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label16"), s);                              //Guidance intervals are limited to between 1s and 30s
                        }
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label17"), autopilot.limitQa, "Pa-rad"); //Qα limit
                        if (autopilot.limitQa < 100 || autopilot.limitQa > 4000)
                        {
                            GUIStyle s = new GUIStyle(GUI.skin.label);
                            s.normal.textColor = Color.yellow;

                            if (autopilot.limitQa < 100)
                            {
                                GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label18"), s);//Qα limit cannot be set to lower than 100 Pa-rad
                            }
                            else if (autopilot.limitQa > 10000)
                            {
                                GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label19"), s);//Qα limit cannot be set to higher than 10000 Pa-rad
                            }
                            else
                            {
                                GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label20"), s);//Qα limit is recommended to be 1000 to 4000 Pa-rad
                            }
                        }
                        pvgascent.omitCoast = GUILayout.Toggle(pvgascent.omitCoast, Localizer.Format("#MechJeb_Ascent_checkbox1"));//Omit Coast
                        GUILayout.EndVertical();
                    }
                }

                autopilot.limitQaEnabled = (ascentPathIdx == ascentType.PVG);    // this is mandatory for PVG

                if (autopilot.showSettings)
                {
                    ToggleAscentNavballGuidanceInfoItem();
                    if (ascentPathIdx != ascentType.PVG)
                    {
                        core.thrust.LimitToPreventOverheatsInfoItem();
                        //core.thrust.LimitToTerminalVelocityInfoItem();
                        core.thrust.LimitToMaxDynamicPressureInfoItem();
                        core.thrust.LimitAccelerationInfoItem();
                        core.thrust.LimitThrottleInfoItem();
                        core.thrust.LimiterMinThrottleInfoItem();
                        core.thrust.LimitElectricInfoItem();
                    }
                    else
                    {
                        core.thrust.LimitToPreventOverheatsInfoItem();
                        //core.thrust.LimitToTerminalVelocityInfoItem();
                        core.thrust.LimitToMaxDynamicPressureInfoItem();
                        //core.thrust.LimitAccelerationInfoItem();
                        //core.thrust.LimitThrottleInfoItem();
                        core.thrust.LimiterMinThrottleInfoItem();
                        //core.thrust.LimitElectricInfoItem();

                        GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label21")); //FIXME: g-limiter is down for maintenance
                        core.thrust.limitAcceleration       = false;
                        core.thrust.limitThrottle           = false;
                        core.thrust.limitToTerminalVelocity = false;
                        core.thrust.electricThrottle        = false;
                    }

                    GUILayout.BeginHorizontal();
                    autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, Localizer.Format("#MechJeb_Ascent_checkbox2"));//Force Roll
                    if (autopilot.forceRoll)
                    {
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label22"), autopilot.verticalRoll, "º", 30f); //climb
                        GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label23"), autopilot.turnRoll, "º", 30f);     //turn
                    }
                    GUILayout.EndHorizontal();

                    if (ascentPathIdx != ascentType.PVG)
                    {
                        GUILayout.BeginHorizontal();
                        GUIStyle s = new GUIStyle(GUI.skin.toggle);
                        if (autopilot.limitingAoA)
                        {
                            s.onHover.textColor = s.onNormal.textColor = Color.green;
                        }
                        autopilot.limitAoA    = GUILayout.Toggle(autopilot.limitAoA, Localizer.Format("#MechJeb_Ascent_checkbox3"), s, GUILayout.ExpandWidth(true));//Limit AoA to
                        autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30));
                        GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true));
                        GUILayout.EndHorizontal();

                        GUILayout.BeginHorizontal();
                        GUILayout.Space(25);
                        if (autopilot.limitAoA)
                        {
                            GUIStyle sl = new GUIStyle(GUI.skin.label);
                            if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure)
                            {
                                sl.normal.textColor = sl.hover.textColor = Color.green;
                            }
                            GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label24"), autopilot.aoALimitFadeoutPressure, "Pa", 50, sl);//Dynamic Pressure Fadeout
                        }
                        GUILayout.EndHorizontal();
                        autopilot.limitQaEnabled = false; // this is only for PVG
                    }

                    if (ascentPathIdx == ascentType.CLASSIC)
                    {
                        // corrective steering only applies to Classic
                        GUILayout.BeginHorizontal();
                        autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, Localizer.Format("#MechJeb_Ascent_checkbox4"), GUILayout.ExpandWidth(false));//Corrective steering
                        if (autopilot.correctiveSteering)
                        {
                            GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label25"), GUILayout.ExpandWidth(false));//Gain
                            autopilot.correctiveSteeringGain.text = GUILayout.TextField(autopilot.correctiveSteeringGain.text, GUILayout.Width(40));
                        }
                        GUILayout.EndHorizontal();
                    }

                    autopilot.autostage = GUILayout.Toggle(autopilot.autostage, Localizer.Format("#MechJeb_Ascent_checkbox5"));//Autostage
                    if (autopilot.autostage)
                    {
                        core.staging.AutostageSettingsInfoItem();
                    }

                    autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels,
                                                                       Localizer.Format("#MechJeb_Ascent_checkbox6"));//Auto-deploy solar panels

                    autopilot.autoDeployAntennas = GUILayout.Toggle(autopilot.autoDeployAntennas,
                                                                    Localizer.Format("#MechJeb_Ascent_checkbox7"));//Auto-deploy antennas

                    GUILayout.BeginHorizontal();
                    core.node.autowarp = GUILayout.Toggle(core.node.autowarp, Localizer.Format("#MechJeb_Ascent_checkbox8"));//Auto-warp
                    if (ascentPathIdx != ascentType.PVG)
                    {
                        autopilot.skipCircularization = GUILayout.Toggle(autopilot.skipCircularization, Localizer.Format("#MechJeb_Ascent_checkbox9"));//Skip Circularization
                    }
                    else
                    {
                        // skipCircularization is always true for Optimizer
                        autopilot.skipCircularization = true;
                    }
                    GUILayout.EndHorizontal();
                }

                if (autopilot.showStatus)
                {
                    if (ascentPathIdx == ascentType.PVG)
                    {
                        if (core.guidance.solution != null)
                        {
                            for (int i = core.guidance.solution.num_segments; i > 0; i--)
                            {
                                GUILayout.Label(String.Format("{0}: {1}", i, core.guidance.solution.ArcString(vesselState.time, i - 1)));
                            }
                        }

                        GUILayout.BeginHorizontal();
                        GUILayout.Label(String.Format("vgo: {0:F1}", core.guidance.vgo), GUILayout.Width(100));
                        GUILayout.Label(String.Format("heading: {0:F1}", core.guidance.heading), GUILayout.Width(100));
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        GUILayout.Label(String.Format("tgo: {0:F3}", core.guidance.tgo), GUILayout.Width(100));
                        GUILayout.Label(String.Format("pitch: {0:F1}", core.guidance.pitch), GUILayout.Width(100));
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        GUIStyle si = new GUIStyle(GUI.skin.label);
                        if (core.guidance.isStable())
                        {
                            si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Green;
                        }
                        else if (core.guidance.isInitializing() || core.guidance.status == PVGStatus.FINISHED)
                        {
                            si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Orange;
                        }
                        else
                        {
                            si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Red;
                        }
                        GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label26") + core.guidance.status, si);//Guidance Status:
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label27") + core.guidance.successful_converges, GUILayout.Width(100)); //converges:
                        GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label28") + core.guidance.last_lm_status, GUILayout.Width(100));       //status:
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        GUILayout.Label("n: " + core.guidance.last_lm_iteration_count + "(" + core.guidance.max_lm_iteration_count + ")", GUILayout.Width(100));
                        GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label29") + GuiUtils.TimeToDHMS(core.guidance.staleness));//staleness:
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        GUILayout.Label(String.Format("znorm: {0:G5}", core.guidance.last_znorm));
                        GUILayout.EndHorizontal();
                        if (core.guidance.last_failure_cause != null)
                        {
                            GUIStyle s = new GUIStyle(GUI.skin.label);
                            s.normal.textColor = Color.red;
                            GUILayout.BeginHorizontal();
                            GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label30") + core.guidance.last_failure_cause, s);//LAST FAILURE:
                            GUILayout.EndHorizontal();
                        }

                        if (vessel.situation != Vessel.Situations.LANDED && vessel.situation != Vessel.Situations.PRELAUNCH && vessel.situation != Vessel.Situations.SPLASHED)
                        {
                            double m0     = atmoStats[vessel.currentStage].startMass;
                            double thrust = atmoStats[vessel.currentStage].startThrust;

                            if (Math.Abs(vesselState.mass - m0) / m0 > 0.01)
                            {
                                GUIStyle s = new GUIStyle(GUI.skin.label);
                                s.normal.textColor = Color.yellow;
                                GUILayout.BeginHorizontal();
                                GUILayout.Label(String.Format(Localizer.Format("#MechJeb_Ascent_label31") + "{0:F1}%", (vesselState.mass - m0) / m0 * 100.0), s);//MASS IS OFF BY
                                GUILayout.EndHorizontal();
                            }

                            if (Math.Abs(vesselState.thrustCurrent - thrust) / thrust > 0.01)
                            {
                                GUIStyle s = new GUIStyle(GUI.skin.label);
                                s.normal.textColor = Color.yellow;
                                GUILayout.BeginHorizontal();
                                GUILayout.Label(String.Format(Localizer.Format("#MechJeb_Ascent_label32") + "{0:F1}%", (vesselState.thrustCurrent - thrust) / thrust * 100.0), s);//THRUST IS OFF BY
                                GUILayout.EndHorizontal();
                            }
                        }
                    }
                }

                if (vessel.LandedOrSplashed)
                {
                    if (core.target.NormalTargetExists)
                    {
                        if (core.node.autowarp)
                        {
                            GUILayout.BeginHorizontal();
                            GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label33"), GUILayout.ExpandWidth(true));    //Launch countdown:
                            autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text,
                                                                               GUILayout.Width(60));
                            GUILayout.Label("s", GUILayout.ExpandWidth(false));
                            GUILayout.EndHorizontal();
                        }
                        if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary)
                        {
                            // disable plane/rendezvous/interplanetary for now
                            if (ascentPathIdx != ascentType.PVG)
                            {
                                GUILayout.BeginHorizontal();
                                if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button14"), GUILayout.ExpandWidth(false)))    //Launch to rendezvous:
                                {
                                    launchingToRendezvous = true;
                                    autopilot.StartCountdown(vesselState.time +
                                                             LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle,
                                                                                           mainBody, vesselState.longitude, core.target.TargetOrbit));
                                }
                                autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text,
                                                                                      GUILayout.Width(60));
                                GUILayout.Label("º", GUILayout.ExpandWidth(false));
                                GUILayout.EndHorizontal();
                            }

                            GUILayout.BeginHorizontal();
                            if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button15"), GUILayout.ExpandWidth(false)))    //Launch into plane of target
                            {
                                launchingToPlane = true;

                                autopilot.StartCountdown(vesselState.time +
                                                         LaunchTiming.TimeToPlane(autopilot.launchLANDifference,
                                                                                  mainBody, vesselState.latitude, vesselState.longitude,
                                                                                  core.target.TargetOrbit));
                            }
                            autopilot.launchLANDifference.text = GUILayout.TextField(
                                autopilot.launchLANDifference.text, GUILayout.Width(60));
                            GUILayout.Label("º", GUILayout.ExpandWidth(false));
                            GUILayout.EndHorizontal();

                            if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody)
                            {
                                if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button16")))    //Launch at interplanetary window
                                {
                                    launchingToInterplanetary = true;
                                    //compute the desired launch date
                                    OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit,
                                                                                              core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT);
                                    double desiredOrbitPeriod = 2 * Math.PI *
                                                                Math.Sqrt(
                                        Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3)
                                        / mainBody.gravParameter);
                                    //launch just before the window, but don't try to launch in the past
                                    interplanetaryWindowUT -= 3 * desiredOrbitPeriod;
                                    interplanetaryWindowUT  = Math.Max(vesselState.time + autopilot.warpCountDown,
                                                                       interplanetaryWindowUT);
                                    autopilot.StartCountdown(interplanetaryWindowUT);
                                }
                            }
                        }
                    }
                    else
                    {
                        launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                        GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label34"));    //Select a target for a timed launch.
                    }

                    if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous)
                    {
                        string message = "";
                        if (launchingToInterplanetary)
                        {
                            message = Localizer.Format("#MechJeb_Ascent_msg1");    //Launching at interplanetary window
                        }
                        else if (launchingToPlane)
                        {
                            desiredInclination  = MuUtils.Clamp(core.target.TargetOrbit.inclination, Math.Abs(vesselState.latitude), 180 - Math.Abs(vesselState.latitude));
                            desiredInclination *=
                                Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(),
                                                       Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up)));
                            message = Localizer.Format("#MechJeb_Ascent_msg2");    //Launching to target plane
                        }
                        else if (launchingToRendezvous)
                        {
                            message = "#MechJeb_Ascent_msg3";    //Launching to rendezvous
                        }

                        if (autopilot.tMinus > 3 * vesselState.deltaT)
                        {
                            message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1);
                        }

                        GUILayout.Label(message);

                        if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button17")))//Abort
                        {
                            launchingToInterplanetary =
                                launchingToPlane      = launchingToRendezvous = autopilot.timedLaunch = false;
                        }
                    }
                }

                if (autopilot.enabled)
                {
                    GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label35") + autopilot.status);//Autopilot status:
                }
                if (core.DeactivateControl)
                {
                    GUIStyle s = new GUIStyle(GUI.skin.label);
                    s.normal.textColor = Color.red;
                    GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label36"), s);//CONTROL DISABLED (AVIONICS)
                }
            }

            if (!vessel.patchedConicsUnlocked() && ascentPathIdx != ascentType.PVG)
            {
                GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label37"));//"Warning: MechJeb is unable to circularize without an upgraded Tracking Station."
            }

            GUILayout.BeginHorizontal();
            autopilot.ascentPathIdxPublic = (ascentType)GuiUtils.ComboBox.Box((int)autopilot.ascentPathIdxPublic, autopilot.ascentPathList, this);
            GUILayout.EndHorizontal();

            if (autopilot.ascentMenu != null)
            {
                autopilot.ascentMenu.enabled = GUILayout.Toggle(autopilot.ascentMenu.enabled, Localizer.Format("#MechJeb_Ascent_checkbox10"));                              //Edit ascent path
            }
            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            GUIStyle sty = new GUIStyle(GUI.skin.button);

            sty.normal.textColor   = sty.focused.textColor = Color.white;
            sty.hover.textColor    = sty.active.textColor = Color.yellow;
            sty.onNormal.textColor = sty.onFocused.textColor = sty.onHover.textColor = sty.onActive.textColor = Color.green;
            sty.padding            = new RectOffset(8, 8, 8, 8);

            GUILayout.BeginVertical();

            if ((core.thrust.users.Count > 1) && !core.thrust.users.Contains(this))
            {
                if (!autoMode)
                {
                    windowPos = new Rect(windowPos.x, windowPos.y, 10, 10);
                    autoMode  = true;
                }

                sty.normal.textColor = Color.red;
                sty.onActive         = sty.onFocused = sty.onHover = sty.onNormal = sty.active = sty.focused = sty.hover = sty.normal;
                GUILayout.Button(Localizer.Format("#MechJeb_Trans_auto"), sty, GUILayout.ExpandWidth(true));
            }
            else
            {
                if (autoMode)
                {
                    windowPos = new Rect(windowPos.x, windowPos.y, 10, 10);
                    autoMode  = false;
                }

                MechJebModuleThrustController.TMode newMode = (MechJebModuleThrustController.TMode)GUILayout.SelectionGrid((int)core.thrust.tmode, trans_texts, 2, sty);
                SetMode(newMode);

                float val = (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); // change by 5 if the mod_key is held down, else by 1 -- would be better if it actually worked...

                core.thrust.trans_kill_h = GUILayout.Toggle(core.thrust.trans_kill_h, Localizer.Format("#MechJeb_Trans_kill_h"), GUILayout.ExpandWidth(true));
                GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
                GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Trans_spd"), trans_spd, "", 37);
                bool change = false;
                if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                {
                    trans_spd -= val;
                    change     = true;
                }
                if (GUILayout.Button("0", GUILayout.ExpandWidth(false)))
                {
                    trans_spd = 0;
                    change    = true;
                }
                if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                {
                    trans_spd += val;
                    change     = true;
                }
                GUILayout.EndHorizontal();

                if (GUILayout.Button(Localizer.Format("#MechJeb_Trans_spd_act") + ":", sty, GUILayout.ExpandWidth(true)) || change)
                {
                    core.thrust.trans_spd_act  = (float)trans_spd.val;
                    GUIUtility.keyboardControl = 0;
                }
            }

            if (core.thrust.tmode != MechJebModuleThrustController.TMode.OFF)
            {
                GUILayout.Label(Localizer.Format("#MechJeb_Trans_current_spd") + MuMech.MuUtils.ToSI(core.thrust.trans_spd_act) + "m/s", GUILayout.ExpandWidth(true));
            }

            GUILayout.FlexibleSpace();

            GUIStyle tsty = new GUIStyle(GUI.skin.label);

            tsty.alignment = TextAnchor.UpperCenter;
            GUILayout.Label("Automation", tsty, GUILayout.ExpandWidth(true));

            sty.normal.textColor = sty.focused.textColor = sty.hover.textColor = sty.active.textColor = sty.onNormal.textColor = sty.onFocused.textColor = sty.onHover.textColor = sty.onActive.textColor = (abort != AbortStage.OFF) ? Color.red : Color.green;

            if (GUILayout.Button((abort != AbortStage.OFF) ? Localizer.Format("#MechJeb_Trans_NOPANIC") : Localizer.Format("#MechJeb_Trans_PANIC"), sty, GUILayout.ExpandWidth(true)))
            {
                PanicSwitch();
            }

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME);

            if (showingGuidance)
            {
                GUILayout.Label("The purple circle on the navball points along the ascent path.");
                if (GUILayout.Button("Stop showing navball guidance")) core.target.Unset();
            }
            else if (GUILayout.Button("Show navball ascent path guidance"))
            {
                core.target.SetDirectionTarget(TARGET_NAME);
            }

            if (autopilot != null)
            {
                if (autopilot.enabled)
                {
                    if (GUILayout.Button("Disengage autopilot")) autopilot.users.Remove(this);
                }
                else
                {
                    if (GUILayout.Button("Engage autopilot"))
                    {
                        autopilot.users.Add(this);
                    }
                }

                ascentPath = autopilot.ascentPath;

                GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km");
                autopilot.desiredInclination = desiredInclination;
            }

            GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º");

            core.thrust.limitToPreventOverheats = GUILayout.Toggle(core.thrust.limitToPreventOverheats, "Prevent overheats");
            core.thrust.limitToTerminalVelocity = GUILayout.Toggle(core.thrust.limitToTerminalVelocity, "Limit to terminal velocity");
            GUILayout.BeginHorizontal();
            core.thrust.limitAcceleration = GUILayout.Toggle(core.thrust.limitAcceleration, "Limit acceleration to", GUILayout.ExpandWidth(false));
            core.thrust.maxAcceleration.text = GUILayout.TextField(core.thrust.maxAcceleration.text, GUILayout.ExpandWidth(true));
            GUILayout.Label("m/s²", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();
            autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering");

            core.staging.AutostageInfoItem();

            core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp");

            if (autopilot != null && vessel.LandedOrSplashed)
            {
                if (core.target.NormalTargetExists)
                {
                    if (!launchingToPlane && !launchingToRendezvous)
                    {
                        GUILayout.BeginHorizontal();
                        if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false)))
                        {
                            launchingToRendezvous = true;
                        }
                        autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60));
                        GUILayout.Label("º", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();
                    }
                    if (!launchingToPlane && !launchingToRendezvous && GUILayout.Button("Launch into plane of target"))
                    {
                        launchingToPlane = true;
                    }
                }
                else
                {
                    launchingToPlane = launchingToRendezvous = false;
                    GUILayout.Label("Select a target for a timed launch.");
                }

                if (launchingToPlane || launchingToRendezvous)
                {
                    double tMinus;
                    if (launchingToPlane) tMinus = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.Orbit);
                    else tMinus = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.Orbit);

                    double launchTime = vesselState.time + tMinus;

                    core.warp.WarpToUT(launchTime);

                    if (launchingToPlane)
                    {
                        desiredInclination = core.target.Orbit.inclination;
                        desiredInclination *= Math.Sign(Vector3d.Dot(core.target.Orbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up)));
                    }

                    if (autopilot.enabled) core.warp.WarpToUT(launchTime);

                    GUILayout.Label("Launching to " + (launchingToPlane ? "target plane" : "rendezvous") + ": T-" + MuUtils.ToSI(tMinus, 0) + "s");
                    if (tMinus < 3 * vesselState.deltaT)
                    {
                        if (autopilot.enabled) Staging.ActivateNextStage();
                        launchingToPlane = launchingToRendezvous = false;
                    }

                    if (GUILayout.Button("Abort")) launchingToPlane = launchingToRendezvous = false;
                }

                if (autopilot.enabled)
                {
                    GUILayout.Label("Autopilot status: " + autopilot.status);
                }
            }

            MechJebModuleAscentPathEditor editor = core.GetComputerModule<MechJebModuleAscentPathEditor>();
            if (editor != null) editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path");

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            core.GetComputerModule<MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem();

            if (!core.attitude.useSAS)
            {
                core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto tunning");

                if (!core.attitude.Tf_autoTune)
                {
                    GUILayout.Label("Larger ship do better with a larger Tf");
                    GuiUtils.SimpleTextBox("Tf (s)", Tf);
                    Tf = Math.Max(0.01, Tf);
                }
                else
                {
            //            pid.Kd = kpFactor / Tf;
            //            pid.Kp = pid.Kd / (kiFactor * Math.Sqrt(2) * Tf);
            //            pid.Ki = pid.Kp / (kpFactor * Math.Sqrt(2) * Tf);
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf", GUILayout.ExpandWidth(true));
                    GUILayout.Label(core.attitude.Tf.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf range");
                    GuiUtils.SimpleTextBox("min", TfMin, "", 50);
                    TfMin = Math.Max(TfMin, 0.01);
                    GuiUtils.SimpleTextBox("max", TfMax, "", 50);
                    TfMax = Math.Max(TfMax, 0.01);
                    GUILayout.EndHorizontal();

                    GUILayout.Label("PID factors");
                    GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50);
                    kdFactor = Math.Max(kdFactor, 0.01);
                    GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50);
                    kpFactor = Math.Max(kpFactor, 0.01);
                    GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50);
                    kiFactor = Math.Max(kiFactor, 0.01);
                }

                core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode");
                core.rcs.rcsThrottle = GUILayout.Toggle(core.rcs.rcsThrottle, " RCS throttle when 0k thrust");

                GUILayout.BeginHorizontal();
                GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true));
                GUILayout.Label(core.attitude.pid.Kp.ToString("F3") + ", " +
                                core.attitude.pid.Ki.ToString("F3") + ", " +
                                core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("integral action.", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("PID Action", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true));
                GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d torque = new Vector3d(
                                                        vesselState.torqueAvailable.x + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle,
                                                        vesselState.torqueAvailable.y,
                                                        vesselState.torqueAvailable.z + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle
                                                );
                GUILayout.BeginHorizontal();
                GUILayout.Label("torque", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("|torque|", GUILayout.ExpandWidth(true));
                GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d inertia = Vector3d.Scale(
                                                        vesselState.angularMomentum.Sign(),
                                                        Vector3d.Scale(
                                                            Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum),
                                                            Vector3d.Scale(torque, vesselState.MoI).Invert()
                                                        )
                                                    );
                GUILayout.BeginHorizontal();
                GUILayout.Label("inertia", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true));
                GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d ratio = Vector3d.Scale(vesselState.MoI, torque.Invert());

                GUILayout.BeginHorizontal();
                GUILayout.Label("|MOI| / |Torque|", GUILayout.ExpandWidth(true));
                GUILayout.Label(ratio.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true));
                GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

            }

            GUILayout.EndVertical();

            if (!core.attitude.Tf_autoTune)
            {
                if (core.attitude.Tf != Tf)
                {
                    core.attitude.Tf = Tf;
                    core.attitude.setPIDParameters();
                }
            }
            else
            {
                if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax)
                {
                    core.attitude.TfMin = TfMin;
                    core.attitude.TfMax = TfMax;
                    core.attitude.setPIDParameters();
                }
                if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor)
                {
                    core.attitude.kpFactor = kpFactor;
                    core.attitude.kiFactor = kiFactor;
                    core.attitude.kdFactor = kdFactor;
                    core.attitude.setPIDParameters();
                }
            }
            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME);

            if (showingGuidance)
            {
                GUILayout.Label("The purple circle on the navball points along the ascent path.");
                if (GUILayout.Button("Stop showing navball guidance"))
                {
                    core.target.Unset();
                }
            }
            else if (GUILayout.Button("Show navball ascent path guidance"))
            {
                core.target.SetDirectionTarget(TARGET_NAME);
            }

            if (autopilot != null)
            {
                if (autopilot.enabled)
                {
                    if (GUILayout.Button("Disengage autopilot"))
                    {
                        autopilot.users.Remove(this);
                    }
                }
                else
                {
                    if (GUILayout.Button("Engage autopilot"))
                    {
                        autopilot.users.Add(this);
                    }
                }

                ascentPath = autopilot.ascentPath;

                GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km");
                autopilot.desiredInclination = desiredInclination;
            }

            GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º");

            core.thrust.LimitToPreventOverheatsInfoItem();
            core.thrust.LimitToTerminalVelocityInfoItem();
            core.thrust.LimitAccelerationInfoItem();
            core.thrust.LimitThrottleInfoItem();
            GUILayout.BeginHorizontal();
            autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, "Force Roll");
            if (autopilot.forceRoll)
            {
                GuiUtils.SimpleTextBox("climb", autopilot.verticalRoll, "º", 30f);
                GuiUtils.SimpleTextBox("turn", autopilot.turnRoll, "º", 30f);
            }
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            GUIStyle s = new GUIStyle(GUI.skin.toggle);

            if (autopilot.limitingAoA)
            {
                s.onHover.textColor = s.onNormal.textColor = Color.green;
            }
            autopilot.limitAoA    = GUILayout.Toggle(autopilot.limitAoA, "Limit AoA to", s, GUILayout.ExpandWidth(true));
            autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30));
            GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Space(25);
            if (autopilot.limitAoA)
            {
                GUIStyle sl = new GUIStyle(GUI.skin.label);
                if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure)
                {
                    sl.normal.textColor = sl.hover.textColor = Color.green;
                }
                GuiUtils.SimpleTextBox("Dynamic Pressure Fadeout", autopilot.aoALimitFadeoutPressure, "pa", 50, sl);
            }
            GUILayout.EndHorizontal();

            autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering");

            autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage");
            if (autopilot.autostage)
            {
                core.staging.AutostageSettingsInfoItem();
            }

            autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels, "Auto-deploy solar panels");

            core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp");

            if (autopilot != null && vessel.LandedOrSplashed)
            {
                if (core.target.NormalTargetExists)
                {
                    if (core.node.autowarp)
                    {
                        GUILayout.BeginHorizontal();
                        GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true));
                        autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60));
                        GUILayout.Label("s", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();
                    }
                    if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary)
                    {
                        GUILayout.BeginHorizontal();
                        if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false)))
                        {
                            launchingToRendezvous = true;
                            autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit));
                        }
                        autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60));
                        GUILayout.Label("º", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();

                        if (GUILayout.Button("Launch into plane of target"))
                        {
                            launchingToPlane = true;
                            autopilot.StartCountdown(vesselState.time +
                                                     LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit));
                        }
                        if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody)
                        {
                            if (GUILayout.Button("Launch at interplanetary window"))
                            {
                                launchingToInterplanetary = true;
                                //compute the desired launch date
                                OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT);
                                double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter);
                                //launch just before the window, but don't try to launch in the past
                                interplanetaryWindowUT -= 3 * desiredOrbitPeriod;
                                interplanetaryWindowUT  = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT);
                                autopilot.StartCountdown(interplanetaryWindowUT);
                            }
                        }
                    }
                }
                else
                {
                    launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                    GUILayout.Label("Select a target for a timed launch.");
                }

                if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous)
                {
                    string message = "";
                    if (launchingToInterplanetary)
                    {
                        message = "Launching at interplanetary window";
                    }
                    else if (launchingToPlane)
                    {
                        desiredInclination  = core.target.TargetOrbit.inclination;
                        desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up)));
                        message             = "Launching to target plane";
                    }
                    else if (launchingToRendezvous)
                    {
                        message = "Launching to rendezvous";
                    }

                    if (autopilot.tMinus > 3 * vesselState.deltaT)
                    {
                        message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1);
                    }

                    GUILayout.Label(message);

                    if (GUILayout.Button("Abort"))
                    {
                        launchingToInterplanetary = launchingToPlane = launchingToRendezvous = autopilot.timedLaunch = false;
                    }
                }
            }

            if (autopilot != null && autopilot.enabled)
            {
                GUILayout.Label("Autopilot status: " + autopilot.status);
            }

            if (!vessel.patchedConicsUnlocked())
            {
                GUILayout.Label("Warning: MechJeb is unable to circularize without an upgraded Tracking Station.");
            }

            MechJebModuleAscentPathEditor editor = core.GetComputerModule <MechJebModuleAscentPathEditor>();

            if (editor != null)
            {
                editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path");
            }

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            if (GUILayout.Button("Reset"))
            {
                core.attitude.ResetConfig();
                OnStart(PartModule.StartState.None);
            }

            core.GetComputerModule<MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem();

            if (!core.attitude.useSAS)
            {
                core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto-tuning");

                if (!core.attitude.Tf_autoTune)
                {
                    GUILayout.Label("Larger ship do better with a larger Tf");

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf (s)", GUILayout.ExpandWidth(true));
                    GUILayout.Label("P", GUILayout.ExpandWidth(false));
                    TfX.text = GUILayout.TextField(TfX.text, GUILayout.ExpandWidth(true), GUILayout.Width(40));
                    GUILayout.Label("Y", GUILayout.ExpandWidth(false));
                    TfY.text = GUILayout.TextField(TfY.text, GUILayout.ExpandWidth(true), GUILayout.Width(40));
                    GUILayout.Label("R", GUILayout.ExpandWidth(false));
                    TfZ.text = GUILayout.TextField(TfZ.text, GUILayout.ExpandWidth(true), GUILayout.Width(40));
                    GUILayout.EndHorizontal();

                    TfX = Math.Max(0.01, TfX);
                    TfY = Math.Max(0.01, TfY);
                    TfZ = Math.Max(0.01, TfZ);
                }
                else
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.TfV), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf range");
                    GuiUtils.SimpleTextBox("min", TfMin, "", 50);
                    TfMin = Math.Max(TfMin, 0.01);
                    GuiUtils.SimpleTextBox("max", TfMax, "", 50);
                    TfMax = Math.Max(TfMax, 0.01);
                    GUILayout.EndHorizontal();
                }

                GUILayout.Label("PID factors");
                GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50);
                kdFactor = Math.Max(kdFactor, 0.01);
                GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50);
                kpFactor = Math.Max(kpFactor, 0.01);
                GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50);
                kiFactor = Math.Max(kiFactor, 0.01);

                core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode");

                showInfos = GUILayout.Toggle(showInfos, "Show Numbers");
                if (showInfos)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Kp", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Kp), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Ki", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Ki), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Kd", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Kd), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Error", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.error * Mathf.Rad2Deg), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("integral action.", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("PID Action", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Axis Control ", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.AxisState, "F0"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Torque", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + core.attitude.torque.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(core.attitude.torque), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("torqueReactionSpeed", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + vesselState.torqueReactionSpeed.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vesselState.torqueReactionSpeed), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Inertia", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + core.attitude.inertia.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(core.attitude.inertia), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    Vector3d ratio = Vector3d.Scale(vesselState.MoI, core.attitude.torque.Invert());

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("MOI / torque", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + ratio.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(ratio), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("MOI", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + vesselState.MoI.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vesselState.MoI), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("MOI stock", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + vessel.MOI.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vessel.MOI), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Angular Velocity", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + vessel.angularVelocity.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vessel.angularVelocity), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true));
                    GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();
                }
            }

            MechJebModuleAttitudeController.useCoMVelocity = GUILayout.Toggle(MechJebModuleAttitudeController.useCoMVelocity, "Use CoM velocity instead of stock");

            MechJebModuleDebugArrows arrows = core.GetComputerModule<MechJebModuleDebugArrows>();

            GuiUtils.SimpleTextBox("Arrows length", arrows.arrowsLength, "", 50);

            arrows.seeThrough = GUILayout.Toggle(arrows.seeThrough, "Visible through object");
            GUILayout.BeginHorizontal();

            arrows.comSphereActive = GUILayout.Toggle(arrows.comSphereActive, "Display the CoM. Radius of ", GUILayout.ExpandWidth(false));
            arrows.comSphereRadius.text = GUILayout.TextField(arrows.comSphereRadius.text, GUILayout.Width(40));
            GUILayout.EndHorizontal();
            arrows.displayAtCoM = GUILayout.Toggle(arrows.displayAtCoM, "Arrows origins at the CoM");
            arrows.podSrfVelocityArrowActive = GUILayout.Toggle(arrows.podSrfVelocityArrowActive, "Pod Surface Velocity (yellow)");
            arrows.comSrfVelocityArrowActive = GUILayout.Toggle(arrows.comSrfVelocityArrowActive, "CoM Surface Velocity (green)");
            arrows.podObtVelocityArrowActive = GUILayout.Toggle(arrows.podObtVelocityArrowActive, "Pod Orbital Velocity (red)");
            arrows.comObtVelocityArrowActive = GUILayout.Toggle(arrows.comObtVelocityArrowActive, "CoM Orbital Velocity (orange)");
            arrows.forwardArrowActive = GUILayout.Toggle(arrows.forwardArrowActive, "Command Pod Forward (Navy Blue)");
            //arrows.avgForwardArrowActive = GUILayout.Toggle(arrows.avgForwardArrowActive, "Forward Avg (blue)");

            arrows.requestedAttitudeArrowActive = GUILayout.Toggle(arrows.requestedAttitudeArrowActive, "Requested Attitude (Gray)");

            arrows.debugArrowActive = GUILayout.Toggle(arrows.debugArrowActive, "Debug (Magenta)");

            GUILayout.EndVertical();

            if (!core.attitude.Tf_autoTune)
            {
                if (core.attitude.TfV.x != TfX || core.attitude.TfV.y != TfY || core.attitude.TfV.z != TfZ)
                {
                    core.attitude.TfV.x = TfX;
                    core.attitude.TfV.y = TfY;
                    core.attitude.TfV.z = TfZ;
                    core.attitude.setPIDParameters();
                }
            }
            else
            {
                if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax)
                {
                    core.attitude.TfMin = TfMin;
                    core.attitude.TfMax = TfMax;
                    core.attitude.setPIDParameters();
                }
                if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor)
                {
                    core.attitude.kpFactor = kpFactor;
                    core.attitude.kiFactor = kiFactor;
                    core.attitude.kdFactor = kdFactor;
                    core.attitude.setPIDParameters();
                }
            }
            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            if (btNormal == null)
            {
                btNormal = new GUIStyle(GUI.skin.button);
                btNormal.normal.textColor   = btNormal.focused.textColor = Color.white;
                btNormal.hover.textColor    = btNormal.active.textColor = Color.yellow;
                btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green;
                //btNormal.padding = new RectOffset(8, 8, 8, 8);

                btActive           = new GUIStyle(btNormal);
                btActive.active    = btActive.onActive;
                btActive.normal    = btActive.onNormal;
                btActive.onFocused = btActive.focused;
                btActive.hover     = btActive.onHover;

                btGreen = new GUIStyle(btNormal);
                btGreen.normal.textColor = Color.green;
                btGreen.fixedWidth       = 35;

                btWhite = new GUIStyle(btNormal);
                btWhite.normal.textColor = Color.white;
                btWhite.fixedWidth       = 35;

                btAuto                  = new GUIStyle(btNormal);
                btAuto.padding          = new RectOffset(8, 8, 8, 8);
                btAuto.normal.textColor = Color.red;
                btAuto.onActive         = btAuto.onFocused = btAuto.onHover = btAuto.onNormal = btAuto.active = btAuto.focused = btAuto.hover = btAuto.normal;
            }

            if (autopilot.enabled)
            {
                if (GUILayout.Button("Disengage autopilot", btActive))
                {
                    autopilot.users.Remove(this);
                }
            }
            else if (core.attitude.enabled && core.attitude.users.Count(u => !this.Equals(u)) > 0)
            {
                if (core.attitude.users.Contains(this))
                {
                    core.attitude.users.Remove(this);  // so we don't suddenly turn on when the other autopilot finishes
                }
                GUILayout.Button("Auto", btAuto, GUILayout.ExpandWidth(true));
            }
            else
            {
                if (GUILayout.Button("Engage autopilot"))
                {
                    autopilot.users.Add(this);
                }
            }

            GUILayout.BeginHorizontal();
            bool AltitudeHold = autopilot.AltitudeHoldEnabled;

            autopilot.AltitudeHoldEnabled = GUILayout.Toggle(autopilot.AltitudeHoldEnabled, "Altitude Hold", GUILayout.Width(140));
            if (AltitudeHold != autopilot.AltitudeHoldEnabled)
            {
                if (autopilot.AltitudeHoldEnabled)
                {
                    autopilot.EnableAltitudeHold();
                }
                else
                {
                    autopilot.DisableAltitudeHold();
                }
            }
            bool change = false;

            if (GUILayout.Button("-", GUILayout.Width(18)))
            {
                AltitudeTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            AltitudeTargettmp.text = GUILayout.TextField(AltitudeTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
            if (GUILayout.Button("+", GUILayout.Width(18)))
            {
                AltitudeTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            if (AltitudeTargettmp < 0)
            {
                AltitudeTargettmp = 0;
            }
            GUILayout.Label("m", GUILayout.ExpandWidth(true));
            if (change || GUILayout.Button("Set", autopilot.AltitudeTarget == AltitudeTargettmp ? btWhite : btGreen))
            {
                autopilot.AltitudeTarget = AltitudeTargettmp;
            }
            GUILayout.EndHorizontal();


            if (!autopilot.AltitudeHoldEnabled)
            {
                bool _VertSpeedHoldEnabled = autopilot.VertSpeedHoldEnabled;
                GUILayout.BeginHorizontal();
                autopilot.VertSpeedHoldEnabled = GUILayout.Toggle(autopilot.VertSpeedHoldEnabled, "Vertical Speed Hold", GUILayout.Width(140));
                if (_VertSpeedHoldEnabled != autopilot.VertSpeedHoldEnabled)
                {
                    if (autopilot.VertSpeedHoldEnabled)
                    {
                        autopilot.EnableVertSpeedHold();
                    }
                    else
                    {
                        autopilot.DisableVertSpeedHold();
                    }
                }
                change = false;
                if (GUILayout.Button("-", GUILayout.Width(18)))
                {
                    VertSpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                VertSpeedTargettmp.text = GUILayout.TextField(VertSpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
                if (GUILayout.Button("+", GUILayout.Width(18)))
                {
                    VertSpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                GUILayout.Label("m/s", GUILayout.ExpandWidth(true));
                if (change || GUILayout.Button("Set", autopilot.VertSpeedTarget == VertSpeedTargettmp ? btWhite : btGreen))
                {
                    autopilot.VertSpeedTarget = VertSpeedTargettmp;
                }
                GUILayout.EndHorizontal();
            }
            else
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("    Vertical Speed Limit", GUILayout.Width(140));
                change = false;
                if (GUILayout.Button("-", GUILayout.Width(18)))
                {
                    VertSpeedMaxtmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                VertSpeedMaxtmp.text = GUILayout.TextField(VertSpeedMaxtmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
                if (GUILayout.Button("+", GUILayout.Width(18)))
                {
                    VertSpeedMaxtmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                if (VertSpeedMaxtmp < 0)
                {
                    VertSpeedMaxtmp = 0;
                }
                GUILayout.Label("m/s", GUILayout.ExpandWidth(true));
                if (change || GUILayout.Button("Set", autopilot.VertSpeedMax == VertSpeedMaxtmp ? btWhite : btGreen))
                {
                    autopilot.VertSpeedMax = VertSpeedMaxtmp;
                }
                GUILayout.EndHorizontal();
            }


            GUILayout.BeginHorizontal();
            bool _HeadingHoldEnabled = autopilot.HeadingHoldEnabled;

            autopilot.HeadingHoldEnabled = GUILayout.Toggle(autopilot.HeadingHoldEnabled, "Heading Hold", GUILayout.Width(140));
            if (_HeadingHoldEnabled != autopilot.HeadingHoldEnabled)
            {
                if (autopilot.HeadingHoldEnabled)
                {
                    autopilot.EnableHeadingHold();
                }
                else
                {
                    autopilot.DisableHeadingHold();
                }
            }
            change = false;
            if (GUILayout.Button("-", GUILayout.Width(18)))
            {
                HeadingTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            HeadingTargettmp.text = GUILayout.TextField(HeadingTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
            if (GUILayout.Button("+", GUILayout.Width(18)))
            {
                HeadingTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            HeadingTargettmp = MuUtils.ClampDegrees360(HeadingTargettmp);
            GUILayout.Label("°", GUILayout.ExpandWidth(true));
            if (change || GUILayout.Button("Set", autopilot.HeadingTarget == HeadingTargettmp ? btWhite : btGreen))
            {
                autopilot.HeadingTarget = HeadingTargettmp;
            }
            GUILayout.EndHorizontal();


            if (!autopilot.HeadingHoldEnabled)
            {
                GUILayout.BeginHorizontal();
                autopilot.RollHoldEnabled = GUILayout.Toggle(autopilot.RollHoldEnabled, "Roll Hold", GUILayout.Width(140));
                change = false;
                if (GUILayout.Button("-", GUILayout.Width(18)))
                {
                    RollTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                RollTargettmp.text = GUILayout.TextField(RollTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
                if (GUILayout.Button("+", GUILayout.Width(18)))
                {
                    RollTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                RollTargettmp = MuUtils.Clamp(RollTargettmp, -90, 90);
                GUILayout.Label("°", GUILayout.ExpandWidth(true));
                if (change || GUILayout.Button("Set", autopilot.RollTarget == RollTargettmp ? btWhite : btGreen))
                {
                    autopilot.RollTarget = RollTargettmp;
                }
                GUILayout.EndHorizontal();
            }
            else
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("    Roll Limit ±", GUILayout.Width(140));
                change = false;
                if (GUILayout.Button("-", GUILayout.Width(18)))
                {
                    RollMaxtmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                RollMaxtmp.text = GUILayout.TextField(RollMaxtmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
                if (GUILayout.Button("+", GUILayout.Width(18)))
                {
                    RollMaxtmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
                }
                RollMaxtmp = MuUtils.Clamp(RollMaxtmp, -60, 60);
                GUILayout.Label("°", GUILayout.ExpandWidth(true));
                if (change || GUILayout.Button("Set", autopilot.RollMax == RollMaxtmp ? btWhite : btGreen))
                {
                    autopilot.RollMax = RollMaxtmp;
                }
                GUILayout.EndHorizontal();
            }


            GUILayout.BeginHorizontal();
            bool _AutoThrustCtrl = autopilot.SpeedHoldEnabled;

            autopilot.SpeedHoldEnabled = GUILayout.Toggle(autopilot.SpeedHoldEnabled, "Speed Hold", GUILayout.Width(140));
            if (autopilot.SpeedHoldEnabled != _AutoThrustCtrl)
            {
                if (autopilot.SpeedHoldEnabled)
                {
                    autopilot.EnableSpeedHold();
                }
                else
                {
                    autopilot.DisableSpeedHold();
                }
            }
            change = false;
            if (GUILayout.Button("-", GUILayout.Width(18)))
            {
                SpeedTargettmp.val -= (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            SpeedTargettmp.text = GUILayout.TextField(SpeedTargettmp.text, GUILayout.ExpandWidth(true), GUILayout.Width(60));
            if (GUILayout.Button("+", GUILayout.Width(18)))
            {
                SpeedTargettmp.val += (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); change = true;
            }
            if (SpeedTargettmp < 0)
            {
                SpeedTargettmp = 0;
            }
            GUILayout.Label("m/s", GUILayout.ExpandWidth(true));
            if (change || GUILayout.Button("Set", autopilot.SpeedTarget == SpeedTargettmp ? btWhite : btGreen))
            {
                autopilot.SpeedTarget = SpeedTargettmp;
            }
            GUILayout.EndHorizontal();


            if (!showpid)
            {
                if (GUILayout.Button("PID", GUILayout.Width(40)))
                {
                    showpid = true;
                }
            }
            else
            {
                if (GUILayout.Button("Hide PID", GUILayout.Width(140)))
                {
                    showpid = false;
                }
                GUILayout.BeginHorizontal();
                GUILayout.Label("Accceleration", GUILayout.ExpandWidth(true));
                GUILayout.Label("Kp", GUILayout.ExpandWidth(false));
                autopilot.AccKp.text = GUILayout.TextField(autopilot.AccKp.text, GUILayout.Width(40));
                GUILayout.Label("i", GUILayout.ExpandWidth(false));
                autopilot.AccKi.text = GUILayout.TextField(autopilot.AccKi.text, GUILayout.Width(40));
                GUILayout.Label("d", GUILayout.ExpandWidth(false));
                autopilot.AccKd.text = GUILayout.TextField(autopilot.AccKd.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
                if (autopilot.SpeedHoldEnabled)
                {
                    GUILayout.Label("error:" + autopilot.a_err.ToString("F2") + " Target:" + autopilot.RealAccelerationTarget.ToString("F2") + " Cur:" + autopilot.cur_acc.ToString("F2"), GUILayout.ExpandWidth(false));
                }

                GUILayout.BeginHorizontal();
                GUILayout.Label("VertSpeed", GUILayout.ExpandWidth(true));
                GUILayout.Label("Kp", GUILayout.ExpandWidth(false));
                autopilot.VerKp.text = GUILayout.TextField(autopilot.VerKp.text, GUILayout.Width(40));
                GUILayout.Label("i", GUILayout.ExpandWidth(false));
                autopilot.VerKi.text = GUILayout.TextField(autopilot.VerKi.text, GUILayout.Width(40));
                GUILayout.Label("d", GUILayout.ExpandWidth(false));
                autopilot.VerKd.text = GUILayout.TextField(autopilot.VerKd.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
                if (autopilot.VertSpeedHoldEnabled)
                {
                    GUILayout.Label("error:" + autopilot.v_err.ToString("F2") + " Target:" + autopilot.RealVertSpeedTarget.ToString("F2") + " Cur:" + vesselState.speedVertical.ToString("F2"), GUILayout.ExpandWidth(false));
                }

                GUILayout.BeginHorizontal();
                GUILayout.Label("Roll", GUILayout.ExpandWidth(true));
                GUILayout.Label("Kp", GUILayout.ExpandWidth(false));
                autopilot.RolKp.text = GUILayout.TextField(autopilot.RolKp.text, GUILayout.Width(40));
                GUILayout.Label("i", GUILayout.ExpandWidth(false));
                autopilot.RolKi.text = GUILayout.TextField(autopilot.RolKi.text, GUILayout.Width(40));
                GUILayout.Label("d", GUILayout.ExpandWidth(false));
                autopilot.RolKd.text = GUILayout.TextField(autopilot.RolKd.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("Yaw", GUILayout.ExpandWidth(true));
                GUILayout.Label("Kp", GUILayout.ExpandWidth(false));
                autopilot.YawKp.text = GUILayout.TextField(autopilot.YawKp.text, GUILayout.Width(40));
                GUILayout.Label("i", GUILayout.ExpandWidth(false));
                autopilot.YawKi.text = GUILayout.TextField(autopilot.YawKi.text, GUILayout.Width(40));
                GUILayout.Label("d", GUILayout.ExpandWidth(false));
                autopilot.YawKd.text = GUILayout.TextField(autopilot.YawKd.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();
                GUILayout.Label("Yaw Control Limit", GUILayout.ExpandWidth(false));
                autopilot.YawLimit.text = GUILayout.TextField(autopilot.YawLimit.text, GUILayout.Width(40));
                GUILayout.EndHorizontal();
            }
            base.WindowGUI(windowID);
        }
		public override void Drive(FlightCtrlState s) // TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to
		{ // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up -- should be done now?
			if (orbit.referenceBody != lastBody) { WaypointIndex = -1; Waypoints.Clear(); }
			MechJebWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null);
			
			var brake = vessel.ActionGroups[KSPActionGroup.Brakes]; // keep brakes locked if they are			
			curSpeed = Vector3d.Dot(vesselState.surfaceVelocity, vesselState.forward);
			
			CalculateTraction();
			speedIntAcc = speedPID.intAccum;
			
			if (wp != null && wp.Body == orbit.referenceBody)
			{
				if (ControlHeading)
				{
					heading.val = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1);
				}
				if (ControlSpeed)
				{
					var nextWP = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null));
					var distance = Vector3.Distance(vessel.CoM, wp.Position);
					if (wp.Target != null) { distance += (float)(wp.Target.srfSpeed * curSpeed) / 2; }
					//var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed
					var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed); // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed
					var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed :
					                (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) :
					                 (distance - wp.Radius > 50 ? turnSpeed.val : 1)));
					minSpeed = (wp.Quicksave ? 1 : minSpeed);
					// ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last)
					var brakeFactor = Math.Max((curSpeed - minSpeed) * 1, 3);
					var newSpeed = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / brakeFactor, minSpeed)); // brake when getting closer
					newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed); // reduce speed when turning a lot
//					if (LimitAcceleration) { newSpeed = curSpeed + Mathf.Clamp((float)(newSpeed - curSpeed), -1.5f, 0.5f); }
//					newSpeed = tgtSpeed + Mathf.Clamp((float)(newSpeed - tgtSpeed), -Time.deltaTime * 8f, Time.deltaTime * 2f);
					var radius = Math.Max(wp.Radius, 10);
					if (distance < radius)
					{
						if (WaypointIndex + 1 >= Waypoints.Count) // last waypoint
						{
							newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min();
							// ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons
							if (LoopWaypoints)
							{
								WaypointIndex = 0;
							}
							else
							{
								newSpeed = 0;
//								tgtSpeed.force(newSpeed);
								if (curSpeed < brakeSpeedLimit)
								{
									if (wp.Quicksave)
									{
										//if (s.mainThrottle > 0) { s.mainThrottle = 0; }
										if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
										{
											WaypointIndex = -1;
											ControlHeading = ControlSpeed = false;
											QuickSaveLoad.QuickSave();
										}
									}
									else
									{
										WaypointIndex = -1;
										ControlHeading = ControlSpeed = false;
									}
								}
//								else {
//									Debug.Log("Is this even getting called?");
//									WaypointIndex++;
//								}
							}
						}
						else
						{
							if (wp.Quicksave)
							{
								//if (s.mainThrottle > 0) { s.mainThrottle = 0; }
								newSpeed = 0;
//								tgtSpeed.force(newSpeed);
								if (curSpeed < brakeSpeedLimit)
								{
									if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
									{
										WaypointIndex++;
										QuickSaveLoad.QuickSave();
									}
								}
							}
							else
							{
								WaypointIndex++;
							}
						}
					}
					brake = brake || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < brakeSpeedLimit && newSpeed < brakeSpeedLimit);
					// ^ brake if needed to prevent rolling, hopefully
					tgtSpeed = (newSpeed >= 0 ? newSpeed : 0);
				}
			}
			
			if (ControlHeading)
			{
				headingPID.intAccum = Mathf.Clamp((float)headingPID.intAccum, -1, 1);

				double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y;
				headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading);
				if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel)
				{
					float spd = Mathf.Min((float)speed, (float)turnSpeed); // if a slower speed than the turnspeed is used also be more careful with the steering
					float limit = (Mathf.Abs((float)curSpeed) <= turnSpeed ? 1 : Mathf.Clamp((float)(spd / Mathf.Abs((float)curSpeed)), 0.35f, 1f));
					double act = headingPID.Compute(headingErr);
					s.wheelSteer = Mathf.Clamp((float)act, -limit, limit);
				}
			}
			
			// Brake if there is no controler (Pilot eject from seat)
			if (BrakeOnEject && vessel.GetReferenceTransformPart() == null)
			{
				s.wheelThrottle = 0;
//				vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true);
				brake = true;
			}
			else if (ControlSpeed)
			{
				speedPID.intAccum = Mathf.Clamp((float)speedPID.intAccum, -5, 5);

				speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed) - Vector3d.Dot(vesselState.surfaceVelocity, vesselState.forward);
				if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel)
				{
					float act = (float)speedPID.Compute(speedErr);
					s.wheelThrottle = (!LimitAcceleration ? Mathf.Clamp(act, -1, 1) : // I think I'm using these ( ? : ) a bit too much
						(traction == 0 ? 0 : (act < 0 ? Mathf.Clamp(act, -1f, 1f) : (lastThrottle + Mathf.Clamp(act - lastThrottle, -0.01f, 0.01f)) * (traction < tractionLimit ? -1 : 1))));
//						(lastThrottle + Mathf.Clamp(act, -0.01f, 0.01f)));
//					Debug.Log(s.wheelThrottle + Mathf.Clamp(act, -0.01f, 0.01f));
					if (curSpeed < 0 & s.wheelThrottle < 0) { s.wheelThrottle = 0; } // don't go backwards
					if (Mathf.Sign(act) + Mathf.Sign(s.wheelThrottle) == 0) { s.wheelThrottle = Mathf.Clamp(act, -1f, 1f); }
//					if (speedErr < -1 && StabilityControl && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) == 0) { // StabilityControl && traction > 50 && 
////						vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true);
//						brake = true;
//						foreach (Part p in wheels) {
//							if (p.GetModule<ModuleWheels.ModuleWheelDamage>().stressPercent >= 0.01) { // #TODO needs adaptive braking
//								brake = false;
//								break;
//							}
//						}
//					}
////					else if (!StabilityControl || traction <= 50 || speedErr > -0.2 || Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) {
////						vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, (GameSettings.BRAKES.GetKey() && vessel.isActiveVessel));
////					}
					lastThrottle = Mathf.Clamp(s.wheelThrottle, -1, 1);
				}
			}
			
			if (StabilityControl)
			{
				if (!core.attitude.users.Contains(this))
				{
					core.attitude.users.Add(this);
//					line.enabled = true;
				}
//				float scale = Vector3.Distance(FlightCamera.fetch.mainCamera.transform.position, vessel.CoM) / 900f;
//				line.SetPosition(0, vessel.CoM);
//				line.SetPosition(1, vessel.CoM + hit.normal * 5);
//				line.SetWidth(0, scale + 0.1f);
				var fSpeed = (float)curSpeed;
//				if (Mathf.Abs(fSpeed) >= turnSpeed * 0.75) {
				Vector3 fwd = (Vector3)(traction > 0 ? // V when the speed is low go for the vessels forward, else with a bit of velocity
//				                        ((Mathf.Abs(fSpeed) <= turnSpeed ? vesselState.forward : vesselState.surfaceVelocity / 4) - vessel.transform.right * s.wheelSteer) * Mathf.Sign(fSpeed) :
//				                        // ^ and then add the steering
				                        vesselState.forward * 4 - vessel.transform.right * s.wheelSteer * Mathf.Sign(fSpeed) : // and then add the steering
				                        vesselState.surfaceVelocity); // in the air so follow velocity
				Vector3.OrthoNormalize(ref norm, ref fwd);
				var quat = Quaternion.LookRotation(fwd, norm);
				
//				if (traction > 0 || speed <= turnSpeed) {
//					var u = new Vector3(0, 1, 0);
//
//					var q = FlightGlobals.ship_rotation;
//					var q_s = quat;
//
//					var q_u = new Quaternion(u.x, u.y, u.z, 0);
//					var a = Quaternion.Dot(q, q_s * q_u);
//					var q_qs = Quaternion.Dot(q, q_s);
//					var b = (a == 0) ? Math.Sign(q_qs) : (q_qs / a);
//					var g = b / Mathf.Sqrt((b * b) + 1);
//					var gu = Mathf.Sqrt(1 - (g * g)) * u;
//					var q_d = new Quaternion() { w = g, x = gu.x, y = gu.y, z = gu.z };
//					var n = q_s * q_d;
//
//					quat = n;
//				}
                if (vesselState.torqueAvailable.sqrMagnitude > 0)
				    core.attitude.attitudeTo(quat, AttitudeReference.INERTIAL, this);
//				}
			}
			
			if (BrakeOnEnergyDepletion)
			{
				var batteries = vessel.Parts.FindAll(p => p.Resources.Contains("ElectricCharge") && p.Resources["ElectricCharge"].flowState);
				var energyLeft = batteries.Sum(p => p.Resources["ElectricCharge"].amount) / batteries.Sum(p => p.Resources["ElectricCharge"].maxAmount); 
				var openSolars = vessel.mainBody.atmosphere && // true if in atmosphere and there are breakable solarpanels that aren't broken nor retracted
					vessel.FindPartModulesImplementing<ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable && p.panelState != ModuleDeployableSolarPanel.panelStates.BROKEN &&
					                                                                         p.panelState != ModuleDeployableSolarPanel.panelStates.RETRACTED).Count > 0;
				
				if (openSolars && energyLeft > 0.99)
				{
					vessel.FindPartModulesImplementing<ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable &&
					                                                                         p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).ForEach(p => p.Retract());
				}
				
				if (energyLeft < 0.05 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) { s.wheelThrottle = 0; } // save remaining energy by not using it for acceleration
				if (openSolars || energyLeft < 0.03) { tgtSpeed = 0; }
				
				if (curSpeed < brakeSpeedLimit && (energyLeft < 0.05 || openSolars))
				{
					brake = true;
				}

				if (curSpeed < 0.1 && energyLeft < 0.05 && !waitingForDaylight &&
				    vessel.FindPartModulesImplementing<ModuleDeployableSolarPanel>().FindAll(p => p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).Count > 0)
				{
					waitingForDaylight = true;
				}
			}
			
//			brake = brake && (s.wheelThrottle == 0); // release brake if the user or AP want to drive
			if (s.wheelThrottle != 0 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0)
			{
				brake = false; // the AP or user want to drive into the direction of momentum so release the brake
			}
			
			if (vessel.isActiveVessel)
			{
				if (GameSettings.BRAKES.GetKeyUp())
				{
					brake = false; // release the brakes if the user lets go of them
				}
				if (GameSettings.BRAKES.GetKey())
				{
					brake = true; // brake if the user brakes and we aren't about to flip
				}
			}

			tractionLimit = (double)Mathf.Clamp((float)tractionLimit, 0, 100);
			vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, brake && (StabilityControl && curSpeed > brakeSpeedLimit ? traction >= tractionLimit : true));
			// ^ brake but hopefully prevent flipping over, assuming the user set up the limit right
			if (brake && curSpeed < 0.1) { s.wheelThrottle = 0; }
		}
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            core.GetComputerModule <MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem();

            if (!core.attitude.useSAS)
            {
                core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto-tuning");

                if (!core.attitude.Tf_autoTune)
                {
                    GUILayout.Label("Larger ship do better with a larger Tf");
                    GuiUtils.SimpleTextBox("Tf (s)", Tf);
                    Tf = Math.Max(0.01, Tf);
                }
                else
                {
//            pid.Kd = kpFactor / Tf;
//            pid.Kp = pid.Kd / (kiFactor * Math.Sqrt(2) * Tf);
//            pid.Ki = pid.Kp / (kpFactor * Math.Sqrt(2) * Tf);
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf", GUILayout.ExpandWidth(true));
                    GUILayout.Label(core.attitude.Tf.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf range");
                    GuiUtils.SimpleTextBox("min", TfMin, "", 50);
                    TfMin = Math.Max(TfMin, 0.01);
                    GuiUtils.SimpleTextBox("max", TfMax, "", 50);
                    TfMax = Math.Max(TfMax, 0.01);
                    GUILayout.EndHorizontal();

                    GUILayout.Label("PID factors");
                    GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50);
                    kdFactor = Math.Max(kdFactor, 0.01);
                    GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50);
                    kpFactor = Math.Max(kpFactor, 0.01);
                    GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50);
                    kiFactor = Math.Max(kiFactor, 0.01);
                }

                core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode");

                showInfos = GUILayout.Toggle(showInfos, "Show Numbers");
                if (showInfos)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true));
                    GUILayout.Label(
                        core.attitude.pid.Kp.ToString("F3") + ", " +
                        core.attitude.pid.Ki.ToString("F3") + ", " +
                        core.attitude.pid.Kd.ToString("F3"),
                        GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("integral action.", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("PID Action", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true));
                    GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    Vector3d torque = vesselState.torqueAvailable + vesselState.torqueFromEngine * vessel.ctrlState.mainThrottle;

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("torque", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("|torque|", GUILayout.ExpandWidth(true));
                    GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    Vector3d inertia = Vector3d.Scale(
                        vesselState.angularMomentum.Sign(),
                        Vector3d.Scale(
                            Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum),
                            Vector3d.Scale(torque, vesselState.MoI).Invert()
                            )
                        );
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("inertia", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true));
                    GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    Vector3d ratio = Vector3d.Scale(vesselState.MoI, torque.Invert());

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("|MOI| / |Torque|", GUILayout.ExpandWidth(true));
                    GUILayout.Label(ratio.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true));
                    GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();
                }
            }

            MechJebModuleAttitudeController.useCoMVelocity = GUILayout.Toggle(MechJebModuleAttitudeController.useCoMVelocity, "Use CoM velocity instead of stock");

            MechJebModuleDebugArrows arrows = core.GetComputerModule <MechJebModuleDebugArrows>();


            GuiUtils.SimpleTextBox("Arrows length", arrows.arrowsLength, "", 50);

            arrows.seeThrough = GUILayout.Toggle(arrows.seeThrough, "Visible through object");
            GUILayout.BeginHorizontal();

            arrows.comSphereActive      = GUILayout.Toggle(arrows.comSphereActive, "Display the CoM. Radius of ", GUILayout.ExpandWidth(false));
            arrows.comSphereRadius.text = GUILayout.TextField(arrows.comSphereRadius.text, GUILayout.Width(40));
            GUILayout.EndHorizontal();
            arrows.displayAtCoM = GUILayout.Toggle(arrows.displayAtCoM, "Arrows origins at the CoM");
            arrows.podSrfVelocityArrowActive = GUILayout.Toggle(arrows.podSrfVelocityArrowActive, "Pod Surface Velocity (yellow)");
            arrows.comSrfVelocityArrowActive = GUILayout.Toggle(arrows.comSrfVelocityArrowActive, "CoM Surface Velocity (green)");
            arrows.podObtVelocityArrowActive = GUILayout.Toggle(arrows.podObtVelocityArrowActive, "Pod Orbital Velocity (red)");
            arrows.comObtVelocityArrowActive = GUILayout.Toggle(arrows.comObtVelocityArrowActive, "CoM Orbital Velocity (orange)");
            arrows.forwardArrowActive        = GUILayout.Toggle(arrows.forwardArrowActive, "Command Pod Forward (Navy Blue)");
            //arrows.avgForwardArrowActive = GUILayout.Toggle(arrows.avgForwardArrowActive, "Forward Avg (blue)");

            arrows.requestedAttitudeArrowActive = GUILayout.Toggle(arrows.requestedAttitudeArrowActive, "Requested Attitude (Gray)");

            arrows.debugArrowActive = GUILayout.Toggle(arrows.debugArrowActive, "Debug (Magenta)");


            GUILayout.EndVertical();

            if (!core.attitude.Tf_autoTune)
            {
                if (core.attitude.Tf != Tf)
                {
                    core.attitude.Tf = Tf;
                    core.attitude.setPIDParameters();
                }
            }
            else
            {
                if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax)
                {
                    core.attitude.TfMin = TfMin;
                    core.attitude.TfMax = TfMax;
                    core.attitude.setPIDParameters();
                }
                if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor)
                {
                    core.attitude.kpFactor = kpFactor;
                    core.attitude.kiFactor = kiFactor;
                    core.attitude.kdFactor = kdFactor;
                    core.attitude.setPIDParameters();
                }
            }
            base.WindowGUI(windowID);
        }
Example #30
0
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            core.GetComputerModule <MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem();

            if (!core.attitude.useSAS)
            {
                GUILayout.Label("Larger ship do better with a larger Tf");
                GuiUtils.SimpleTextBox("Tf (s)", Tf);
                Tf = Math.Max(0.01, Tf);

                core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode");

                GUILayout.BeginHorizontal();
                GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true));
                GUILayout.Label(core.attitude.pid.Kp.ToString("F3") + ", " +
                                core.attitude.pid.Ki.ToString("F3") + ", " +
                                core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("integral action.", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("PID Action", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true));
                GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d torque = new Vector3d(
                    vesselState.torqueAvailable.x + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle,
                    vesselState.torqueAvailable.y,
                    vesselState.torqueAvailable.z + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle
                    );
                GUILayout.BeginHorizontal();
                GUILayout.Label("torque", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("|torque|", GUILayout.ExpandWidth(true));
                GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d inertia = Vector3d.Scale(
                    vesselState.angularMomentum.Sign(),
                    Vector3d.Scale(
                        Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum),
                        Vector3d.Scale(torque, vesselState.MoI).Invert()
                        )
                    );
                GUILayout.BeginHorizontal();
                GUILayout.Label("inertia", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true));
                GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();
            }

            GUILayout.EndVertical();

            if ((core.attitude.Tf != Tf))
            {
                core.attitude.Tf = Tf;
                double Kd = 0.53 / Tf;
                double Kp = Kd / (3 * Math.Sqrt(2) * Tf);
                double Ki = Kp / (12 * Math.Sqrt(2) * Tf);
                core.attitude.pid = new PIDControllerV2(Kp, Ki, Kd, 1, -1);
            }
            base.WindowGUI(windowID);
        }
Example #31
0
 public override void OnStart(PartModule.StartState state)
 {
     Tf = new EditableDouble(core.attitude.Tf);
     base.OnStart(state);
 }
Example #32
0
        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();
        }
        protected override void WindowGUI(int windowID)
        {
            if (btNormal == null)
            {
                btNormal = new GUIStyle(GUI.skin.button);
                btNormal.normal.textColor = btNormal.focused.textColor = Color.white;
                btNormal.hover.textColor = btNormal.active.textColor = Color.yellow;
                btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green;
                btNormal.padding = new RectOffset(8, 8, 8, 8);

                btActive = new GUIStyle(btNormal);
                btActive.active = btActive.onActive;
                btActive.normal = btActive.onNormal;
                btActive.onFocused = btActive.focused;
                btActive.hover = btActive.onHover;

                btAuto = new GUIStyle(btNormal);
                btAuto.normal.textColor = Color.red;
                btAuto.onActive = btAuto.onFocused = btAuto.onHover = btAuto.onNormal = btAuto.active = btAuto.focused = btAuto.hover = btAuto.normal;
            }

            // If any other module use the attitude controler then let them do it
            if (core.attitude.enabled && core.attitude.users.Count(u => !this.Equals(u)) > 0)
            {
                if (autoDisableSmartASS)
                {
                    target = Target.OFF;
                    if (core.attitude.users.Contains(this)) core.attitude.users.Remove(this); // so we don't suddenly turn on when the other autopilot finishes
                }
                GUILayout.Button("AUTO", btAuto, GUILayout.ExpandWidth(true));
            }
            else
            {
                GUILayout.BeginVertical();

                GUILayout.BeginHorizontal();
                TargetButton(Target.OFF);
                TargetButton(Target.KILLROT);
                if (vessel.patchedConicsUnlocked())
                {
                    TargetButton(Target.NODE);
                }
                else
                {
                    GUILayout.Button("-", GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
                }
                GUILayout.EndHorizontal();

                GUILayout.Label("Mode:");
                GUILayout.BeginHorizontal();
                ModeButton(Mode.ORBITAL);
                ModeButton(Mode.SURFACE);
                ModeButton(Mode.TARGET);
                ModeButton(Mode.ADVANCED);
                GUILayout.EndHorizontal();

                switch (mode)
                {
                    case Mode.ORBITAL:

                        GUILayout.BeginHorizontal();
                        TargetButton(Target.PROGRADE);
                        TargetButton(Target.NORMAL_PLUS);
                        TargetButton(Target.RADIAL_PLUS);
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        TargetButton(Target.RETROGRADE);
                        TargetButton(Target.NORMAL_MINUS);
                        TargetButton(Target.RADIAL_MINUS);
                        GUILayout.EndHorizontal();

                        ForceRoll();

                        break;
                    case Mode.SURFACE:
                    	double val = (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); // change by 5 if the mod_key is held down, else by 1
                        GUILayout.BeginHorizontal();
                        TargetButton(Target.SURFACE_PROGRADE);
                        TargetButton(Target.SURFACE_RETROGRADE);
                        TargetButtonNoEngage(Target.SURFACE);
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        TargetButton(Target.HORIZONTAL_PLUS);
                        TargetButton(Target.HORIZONTAL_MINUS);
                        TargetButton(Target.VERTICAL_PLUS);
                        GUILayout.EndHorizontal();
                        if (target == Target.SURFACE) {
                            bool changed = false;
                        	GUILayout.BeginHorizontal();
                            forceYaw = GUILayout.Toggle(forceYaw, "", GUILayout.ExpandWidth(false));
                            GuiUtils.SimpleTextBox("HDG", srfHdg, "°", 37);
                            if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) {
                            	srfHdg -= val;
                                changed = true;
                            }
                            if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) {
                                srfHdg += val;
                                changed = true;
                            }
                            if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) {
                                srfHdg = 0;
                                changed = true;
                            }
                            if (GUILayout.Button("90", GUILayout.Width(35))) {
                                srfHdg = 90;
                                changed = true;
                            }
                            GUILayout.EndHorizontal();
                        	GUILayout.BeginHorizontal();
                            forcePitch = GUILayout.Toggle(forcePitch, "", GUILayout.ExpandWidth(false));
                            GuiUtils.SimpleTextBox("PIT", srfPit, "°", 37);
                            if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) {
                                srfPit -= val;
                                changed = true;
                            }
                            if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) {
                                srfPit += val;
                                changed = true;
                            }
                            if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) {
                                srfPit = 0;
                                changed = true;
                            }
                            if (GUILayout.Button("90", GUILayout.Width(35))) {
                                srfPit = 90;
                                changed = true;
                            }
                            GUILayout.EndHorizontal();
                        	GUILayout.BeginHorizontal();
                            forceRol = GUILayout.Toggle(forceRol, "", GUILayout.ExpandWidth(false));
                            GuiUtils.SimpleTextBox("ROL", srfRol, "°", 37);
                            if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) {
                                srfRol -= val;
                                changed = true;
                            }
                            if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) {
                                srfRol += val;
                                changed = true;
                            }
                            if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) {
                                srfRol = 0;
                                changed = true;
                            }
                            if (GUILayout.Button("180", GUILayout.Width(35))) {
                                srfRol = 180;
                                changed = true;
                            }
                            GUILayout.EndHorizontal();
                            if (GUILayout.Button("EXECUTE")) {
                                Engage();
                            }
                            if (changed)
                            {
                                Engage(false);
                            }
                            core.attitude.AxisControl(forcePitch, forceYaw, forceRol);
                        } else if (target == Target.SURFACE_PROGRADE || target == Target.SURFACE_RETROGRADE)
                        {
                            bool changed = false;
                            GUILayout.BeginHorizontal();
                            forceRol = GUILayout.Toggle(forceRol, "", GUILayout.ExpandWidth(false));
                            GuiUtils.SimpleTextBox("ROL", srfVelRol, "°", 37);
                            if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) {
                                srfVelRol -= val;
                                changed = true;
                            }
                            if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) {
                                srfVelRol += val;
                                changed = true;
                            }
                            if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) {
                                srfVelRol = -vesselState.vesselRoll.value;
                                changed = true;
                            }
                            if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) {
                                srfVelRol = 0;
                                changed = true;
                            }
                            GUILayout.EndHorizontal();
                            GUILayout.BeginHorizontal();
                            forcePitch = GUILayout.Toggle(forcePitch, "", GUILayout.ExpandWidth(false));
                            GuiUtils.SimpleTextBox("PIT", srfVelPit, "°", 37);
                            if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) {
                                srfVelPit -= val;
                                changed = true;
                            }
                            if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) {
                                srfVelPit += val;
                                changed = true;
                            }
                            if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) {
                                srfVelPit = vesselState.AoA.value;
                                changed = true;
                            }
                            if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) {
                                srfVelPit = 0;
                                changed = true;
                            }
                            GUILayout.EndHorizontal();
                            GUILayout.BeginHorizontal();
                            forceYaw = GUILayout.Toggle(forceYaw, "", GUILayout.ExpandWidth(false));
                            GuiUtils.SimpleTextBox("YAW", srfVelYaw, "°", 37);
                            if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) {
                                srfVelYaw -= val;
                                changed = true;
                            }
                            if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) {
                                srfVelYaw += val;
                                changed = true;
                            }
                            if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false))) {
                                srfVelYaw = -vesselState.AoS.value;
                                changed = true;
                            }
                            if (GUILayout.Button("0", GUILayout.ExpandWidth(false))) {
                                srfVelYaw = 0;
                                changed = true;
                            }
                            GUILayout.EndHorizontal();
                            if (GUILayout.Button("EXECUTE"))
                            {
                                Engage();
                            }
                            if (changed)
                            {
                                Engage(false);
                            }
                            core.attitude.AxisControl(forcePitch, forceYaw, forceRol);
                        }
                        break;
                    case Mode.TARGET:
                        if (core.target.NormalTargetExists)
                        {
                            GUILayout.BeginHorizontal();
                            TargetButton(Target.TARGET_PLUS);
                            TargetButton(Target.RELATIVE_PLUS);
                            TargetButton(Target.PARALLEL_PLUS);
                            GUILayout.EndHorizontal();
                            GUILayout.BeginHorizontal();
                            TargetButton(Target.TARGET_MINUS);
                            TargetButton(Target.RELATIVE_MINUS);
                            TargetButton(Target.PARALLEL_MINUS);
                            GUILayout.EndHorizontal();

                            ForceRoll();
                        }
                        else
                        {
                            GUILayout.Label("Please select a target");
                        }
                        break;
                    case Mode.ADVANCED:
                        GUILayout.Label("Reference:");
                        advReference = (AttitudeReference)GuiUtils.ComboBox.Box((int)advReference, ReferenceTexts, this);

                        GUILayout.Label("Direction:");
                        advDirection = (Vector6.Direction)GuiUtils.ComboBox.Box((int)advDirection, directionTexts, directionTexts);

                        ForceRoll();

                        if (GUILayout.Button("EXECUTE", btNormal, GUILayout.ExpandWidth(true)))
                        {
                            target = Target.ADVANCED;
                            Engage();
                        }
                        break;
                    case Mode.AUTO:
                        break;
                }

                GUILayout.EndVertical();
            }

            base.WindowGUI(windowID);
        }
        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);
        }
Example #35
0
        public EditableAngle(double angle)
        {
            angle = MuUtils.ClampDegrees180(angle);

            negative = (angle < 0);
            angle = Math.Abs(angle);
            degrees = (int)angle;
            angle -= degrees;
            minutes = (int)(60 * angle);
            angle -= minutes / 60;
            seconds = Math.Round(3600 * angle);
        }
Example #36
0
        protected override void WindowGUI(int windowID)
        {
            if (btNormal == null)
            {
                btNormal = new GUIStyle(GUI.skin.button);
                btNormal.normal.textColor   = btNormal.focused.textColor = Color.white;
                btNormal.hover.textColor    = btNormal.active.textColor = Color.yellow;
                btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green;
                btNormal.padding            = new RectOffset(8, 8, 8, 8);

                btActive           = new GUIStyle(btNormal);
                btActive.active    = btActive.onActive;
                btActive.normal    = btActive.onNormal;
                btActive.onFocused = btActive.focused;
                btActive.hover     = btActive.onHover;

                btAuto = new GUIStyle(btNormal);
                btAuto.normal.textColor = Color.red;
                btAuto.onActive         = btAuto.onFocused = btAuto.onHover = btAuto.onNormal = btAuto.active = btAuto.focused = btAuto.hover = btAuto.normal;
            }

            // If any other module use the attitude controler then let them do it
            if (core.attitude.enabled && core.attitude.users.Count(u => !this.Equals(u)) > 0)
            {
                if (autoDisableSmartASS)
                {
                    target = Target.OFF;
                    if (core.attitude.users.Contains(this))
                    {
                        core.attitude.users.Remove(this);                                     // so we don't suddenly turn on when the other autopilot finishes
                    }
                }
                GUILayout.Button("AUTO", btAuto, GUILayout.ExpandWidth(true));
            }
            else
            {
                GUILayout.BeginVertical();

                GUILayout.BeginHorizontal();
                TargetButton(Target.OFF);
                TargetButton(Target.KILLROT);
                if (vessel.patchedConicsUnlocked())
                {
                    TargetButton(Target.NODE);
                }
                else
                {
                    GUILayout.Button("-", GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
                }
                GUILayout.EndHorizontal();

                GUILayout.Label("Mode:");
                GUILayout.BeginHorizontal();
                ModeButton(Mode.ORBITAL);
                ModeButton(Mode.SURFACE);
                ModeButton(Mode.TARGET);
                ModeButton(Mode.ADVANCED);
                GUILayout.EndHorizontal();

                switch (mode)
                {
                case Mode.ORBITAL:

                    GUILayout.BeginHorizontal();
                    TargetButton(Target.PROGRADE);
                    TargetButton(Target.NORMAL_PLUS);
                    TargetButton(Target.RADIAL_PLUS);
                    GUILayout.EndHorizontal();
                    GUILayout.BeginHorizontal();
                    TargetButton(Target.RETROGRADE);
                    TargetButton(Target.NORMAL_MINUS);
                    TargetButton(Target.RADIAL_MINUS);
                    GUILayout.EndHorizontal();

                    ForceRoll();

                    break;

                case Mode.SURFACE:
                    double val = (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1);     // change by 5 if the mod_key is held down, else by 1
                    GUILayout.BeginHorizontal();
                    TargetButton(Target.SURFACE_PROGRADE);
                    TargetButton(Target.SURFACE_RETROGRADE);
                    TargetButtonNoEngage(Target.SURFACE);
                    GUILayout.EndHorizontal();
                    GUILayout.BeginHorizontal();
                    TargetButton(Target.HORIZONTAL_PLUS);
                    TargetButton(Target.HORIZONTAL_MINUS);
                    TargetButton(Target.VERTICAL_PLUS);
                    GUILayout.EndHorizontal();
                    if (target == Target.SURFACE)
                    {
                        bool changed = false;
                        GUILayout.BeginHorizontal();
                        forceYaw = GUILayout.Toggle(forceYaw, "", GUILayout.ExpandWidth(false));
                        GuiUtils.SimpleTextBox("HDG", srfHdg, "°", 37);
                        if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                        {
                            srfHdg -= val;
                            changed = true;
                        }
                        if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                        {
                            srfHdg += val;
                            changed = true;
                        }
                        if (GUILayout.Button("0", GUILayout.ExpandWidth(false)))
                        {
                            srfHdg  = 0;
                            changed = true;
                        }
                        if (GUILayout.Button("90", GUILayout.Width(35)))
                        {
                            srfHdg  = 90;
                            changed = true;
                        }
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        forcePitch = GUILayout.Toggle(forcePitch, "", GUILayout.ExpandWidth(false));
                        GuiUtils.SimpleTextBox("PIT", srfPit, "°", 37);
                        if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                        {
                            srfPit -= val;
                            changed = true;
                        }
                        if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                        {
                            srfPit += val;
                            changed = true;
                        }
                        if (GUILayout.Button("0", GUILayout.ExpandWidth(false)))
                        {
                            srfPit  = 0;
                            changed = true;
                        }
                        if (GUILayout.Button("90", GUILayout.Width(35)))
                        {
                            srfPit  = 90;
                            changed = true;
                        }
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        forceRol = GUILayout.Toggle(forceRol, "", GUILayout.ExpandWidth(false));
                        GuiUtils.SimpleTextBox("ROL", srfRol, "°", 37);
                        if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                        {
                            srfRol -= val;
                            changed = true;
                        }
                        if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                        {
                            srfRol += val;
                            changed = true;
                        }
                        if (GUILayout.Button("0", GUILayout.ExpandWidth(false)))
                        {
                            srfRol  = 0;
                            changed = true;
                        }
                        if (GUILayout.Button("180", GUILayout.Width(35)))
                        {
                            srfRol  = 180;
                            changed = true;
                        }
                        GUILayout.EndHorizontal();
                        if (GUILayout.Button("EXECUTE"))
                        {
                            Engage();
                        }
                        if (changed)
                        {
                            Engage(false);
                        }
                        core.attitude.AxisControl(forcePitch, forceYaw, forceRol);
                    }
                    else if (target == Target.SURFACE_PROGRADE || target == Target.SURFACE_RETROGRADE)
                    {
                        bool changed = false;
                        GUILayout.BeginHorizontal();
                        forceRol = GUILayout.Toggle(forceRol, "", GUILayout.ExpandWidth(false));
                        GuiUtils.SimpleTextBox("ROL", srfVelRol, "°", 37);
                        if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                        {
                            srfVelRol -= val;
                            changed    = true;
                        }
                        if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                        {
                            srfVelRol += val;
                            changed    = true;
                        }
                        if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false)))
                        {
                            srfVelRol = -vesselState.vesselRoll.value;
                            changed   = true;
                        }
                        if (GUILayout.Button("0", GUILayout.ExpandWidth(false)))
                        {
                            srfVelRol = 0;
                            changed   = true;
                        }
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        forcePitch = GUILayout.Toggle(forcePitch, "", GUILayout.ExpandWidth(false));
                        GuiUtils.SimpleTextBox("PIT", srfVelPit, "°", 37);
                        if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                        {
                            srfVelPit -= val;
                            changed    = true;
                        }
                        if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                        {
                            srfVelPit += val;
                            changed    = true;
                        }
                        if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false)))
                        {
                            srfVelPit = vesselState.AoA.value;
                            changed   = true;
                        }
                        if (GUILayout.Button("0", GUILayout.ExpandWidth(false)))
                        {
                            srfVelPit = 0;
                            changed   = true;
                        }
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        forceYaw = GUILayout.Toggle(forceYaw, "", GUILayout.ExpandWidth(false));
                        GuiUtils.SimpleTextBox("YAW", srfVelYaw, "°", 37);
                        if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                        {
                            srfVelYaw -= val;
                            changed    = true;
                        }
                        if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                        {
                            srfVelYaw += val;
                            changed    = true;
                        }
                        if (GUILayout.Button("CUR", GUILayout.ExpandWidth(false)))
                        {
                            srfVelYaw = -vesselState.AoS.value;
                            changed   = true;
                        }
                        if (GUILayout.Button("0", GUILayout.ExpandWidth(false)))
                        {
                            srfVelYaw = 0;
                            changed   = true;
                        }
                        GUILayout.EndHorizontal();
                        if (GUILayout.Button("EXECUTE"))
                        {
                            Engage();
                        }
                        if (changed)
                        {
                            Engage(false);
                        }
                        core.attitude.AxisControl(forcePitch, forceYaw, forceRol);
                    }
                    break;

                case Mode.TARGET:
                    if (core.target.NormalTargetExists)
                    {
                        GUILayout.BeginHorizontal();
                        TargetButton(Target.TARGET_PLUS);
                        TargetButton(Target.RELATIVE_PLUS);
                        TargetButton(Target.PARALLEL_PLUS);
                        GUILayout.EndHorizontal();
                        GUILayout.BeginHorizontal();
                        TargetButton(Target.TARGET_MINUS);
                        TargetButton(Target.RELATIVE_MINUS);
                        TargetButton(Target.PARALLEL_MINUS);
                        GUILayout.EndHorizontal();

                        ForceRoll();
                    }
                    else
                    {
                        GUILayout.Label("Please select a target");
                    }
                    break;

                case Mode.ADVANCED:
                    GUILayout.Label("Reference:");
                    advReference = (AttitudeReference)GuiUtils.ComboBox.Box((int)advReference, ReferenceTexts, this);

                    GUILayout.Label("Direction:");
                    advDirection = (Vector6.Direction)GuiUtils.ComboBox.Box((int)advDirection, directionTexts, directionTexts);

                    ForceRoll();

                    if (GUILayout.Button("EXECUTE", btNormal, GUILayout.ExpandWidth(true)))
                    {
                        target = Target.ADVANCED;
                        Engage();
                    }
                    break;

                case Mode.AUTO:
                    break;
                }

                GUILayout.EndVertical();
            }

            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            if (GUILayout.Button("Reset"))
            {
                core.attitude.ResetConfig();
                OnStart(PartModule.StartState.None);
            }

            core.GetComputerModule <MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem();

            if (!core.attitude.useSAS)
            {
                core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto-tuning");

                if (!core.attitude.Tf_autoTune)
                {
                    GUILayout.Label("Larger ship do better with a larger Tf");

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf (s)", GUILayout.ExpandWidth(true));
                    GUILayout.Label("P", GUILayout.ExpandWidth(false));
                    TfX.text = GUILayout.TextField(TfX.text, GUILayout.ExpandWidth(true), GUILayout.Width(40));
                    GUILayout.Label("Y", GUILayout.ExpandWidth(false));
                    TfY.text = GUILayout.TextField(TfY.text, GUILayout.ExpandWidth(true), GUILayout.Width(40));
                    GUILayout.Label("R", GUILayout.ExpandWidth(false));
                    TfZ.text = GUILayout.TextField(TfZ.text, GUILayout.ExpandWidth(true), GUILayout.Width(40));
                    GUILayout.EndHorizontal();

                    TfX = Math.Max(0.01, TfX);
                    TfY = Math.Max(0.01, TfY);
                    TfZ = Math.Max(0.01, TfZ);
                }
                else
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.TfV), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf range");
                    GuiUtils.SimpleTextBox("min", TfMin, "", 50);
                    TfMin = Math.Max(TfMin, 0.01);
                    GuiUtils.SimpleTextBox("max", TfMax, "", 50);
                    TfMax = Math.Max(TfMax, 0.01);
                    GUILayout.EndHorizontal();
                }

                GUILayout.Label("PID factors");
                GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50);
                kdFactor = Math.Max(kdFactor, 0.01);
                GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50);
                kpFactor = Math.Max(kpFactor, 0.01);
                GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50);
                kiFactor = Math.Max(kiFactor, 0.01);
                GuiUtils.SimpleTextBox("Deadband = ", deadband, "", 50);
                core.attitude.deadband = Math.Max(deadband, 0.0);

                core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode");

                //Lower value of "kWlimit" reduces maximum angular velocity
                double kWlimit     = core.attitude.kWlimit;
                var    nextkWlimit = new EditableDoubleMult(kWlimit, 0.01);
                GuiUtils.SimpleTextBox("Maximum Relative Angular Velocity", nextkWlimit, "%");
                nextkWlimit = (EditableDouble)GUILayout.HorizontalSlider((float)nextkWlimit, 0.0F, 1.0F);
                const int sliderPrecision = 3;
                if (Math.Round(Math.Abs(nextkWlimit - kWlimit), sliderPrecision) > 0)
                {
                    core.attitude.kWlimit = Math.Round(nextkWlimit, sliderPrecision);
                }

                showInfos = GUILayout.Toggle(showInfos, "Show Numbers");
                if (showInfos)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Kp", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Kp), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Ki", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Ki), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Kd", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.Kd), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Error", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.error * Mathf.Rad2Deg), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("integral action.", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("PID Action", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Axis Control ", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.AxisState, "F0"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Torque", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + core.attitude.torque.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(core.attitude.torque), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("torqueReactionSpeed", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + vesselState.torqueReactionSpeed.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vesselState.torqueReactionSpeed), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Inertia", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + core.attitude.inertia.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(core.attitude.inertia), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    Vector3d ratio = Vector3d.Scale(vesselState.MoI, core.attitude.torque.Invert());

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("MOI / torque", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + ratio.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(ratio), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("MOI", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + vesselState.MoI.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vesselState.MoI), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("MOI stock", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + vessel.MOI.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vessel.MOI), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Angular Velocity", GUILayout.ExpandWidth(true));
                    GUILayout.Label("|" + vessel.angularVelocity.magnitude.ToString("F3") + "| " + MuUtils.PrettyPrint(vessel.angularVelocity), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true));
                    GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();
                }
            }

            MechJebModuleAttitudeController.useCoMVelocity = GUILayout.Toggle(MechJebModuleAttitudeController.useCoMVelocity, "Use CoM velocity instead of stock");

            MechJebModuleDebugArrows arrows = core.GetComputerModule <MechJebModuleDebugArrows>();


            GuiUtils.SimpleTextBox("Arrows length", arrows.arrowsLength, "", 50);

            arrows.seeThrough = GUILayout.Toggle(arrows.seeThrough, "Visible through object");
            GUILayout.BeginHorizontal();

            arrows.comSphereActive      = GUILayout.Toggle(arrows.comSphereActive, "Display the CoM. Radius of ", GUILayout.ExpandWidth(false));
            arrows.comSphereRadius.text = GUILayout.TextField(arrows.comSphereRadius.text, GUILayout.Width(40));
            GUILayout.EndHorizontal();
            arrows.displayAtCoM = GUILayout.Toggle(arrows.displayAtCoM, "Arrows origins at the CoM");
            arrows.podSrfVelocityArrowActive = GUILayout.Toggle(arrows.podSrfVelocityArrowActive, "Pod Surface Velocity (yellow)");
            arrows.comSrfVelocityArrowActive = GUILayout.Toggle(arrows.comSrfVelocityArrowActive, "CoM Surface Velocity (green)");
            arrows.podObtVelocityArrowActive = GUILayout.Toggle(arrows.podObtVelocityArrowActive, "Pod Orbital Velocity (red)");
            arrows.comObtVelocityArrowActive = GUILayout.Toggle(arrows.comObtVelocityArrowActive, "CoM Orbital Velocity (orange)");
            arrows.forwardArrowActive        = GUILayout.Toggle(arrows.forwardArrowActive, "Command Pod Forward (electric blue)");
            //arrows.avgForwardArrowActive = GUILayout.Toggle(arrows.avgForwardArrowActive, "Forward Avg (blue)");

            arrows.requestedAttitudeArrowActive = GUILayout.Toggle(arrows.requestedAttitudeArrowActive, "Requested Attitude (gray)");

            arrows.debugArrowActive = GUILayout.Toggle(arrows.debugArrowActive, "Debug (magenta)");

            arrows.debugArrow2Active = GUILayout.Toggle(arrows.debugArrow2Active, "Debug (light blue)");


            GUILayout.EndVertical();

            if (!core.attitude.Tf_autoTune)
            {
                if (core.attitude.TfV.x != TfX || core.attitude.TfV.y != TfY || core.attitude.TfV.z != TfZ)
                {
                    core.attitude.TfV.x = TfX;
                    core.attitude.TfV.y = TfY;
                    core.attitude.TfV.z = TfZ;
                    core.attitude.setPIDParameters();
                }
            }
            else
            {
                if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax)
                {
                    core.attitude.TfMin = TfMin;
                    core.attitude.TfMax = TfMax;
                    core.attitude.setPIDParameters();
                }
                if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor)
                {
                    core.attitude.kpFactor = kpFactor;
                    core.attitude.kiFactor = kiFactor;
                    core.attitude.kdFactor = kdFactor;
                    core.attitude.setPIDParameters();
                }
            }
            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            core.GetComputerModule<MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem();

            if (!core.attitude.useSAS)
            {
                core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto-tuning");

                if (!core.attitude.Tf_autoTune)
                {
                    GUILayout.Label("Larger ship do better with a larger Tf");
                    GuiUtils.SimpleTextBox("Tf (s)", Tf);
                    Tf = Math.Max(0.01, Tf);
                }
                else
                {
            //            pid.Kd = kpFactor / Tf;
            //            pid.Kp = pid.Kd / (kiFactor * Math.Sqrt(2) * Tf);
            //            pid.Ki = pid.Kp / (kpFactor * Math.Sqrt(2) * Tf);
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf", GUILayout.ExpandWidth(true));
                    GUILayout.Label(core.attitude.Tf.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf range");
                    GuiUtils.SimpleTextBox("min", TfMin, "", 50);
                    TfMin = Math.Max(TfMin, 0.01);
                    GuiUtils.SimpleTextBox("max", TfMax, "", 50);
                    TfMax = Math.Max(TfMax, 0.01);
                    GUILayout.EndHorizontal();

                    GUILayout.Label("PID factors");
                    GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50);
                    kdFactor = Math.Max(kdFactor, 0.01);
                    GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50);
                    kpFactor = Math.Max(kpFactor, 0.01);
                    GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50);
                    kiFactor = Math.Max(kiFactor, 0.01);
                }

                core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode");

                showInfos = GUILayout.Toggle(showInfos, "Show Numbers");
                if (showInfos)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true));
                    GUILayout.Label(
                        core.attitude.pid.Kp.ToString("F3") + ", " +
                        core.attitude.pid.Ki.ToString("F3") + ", " +
                        core.attitude.pid.Kd.ToString("F3"),
                        GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("integral action.", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("PID Action", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true));
                    GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    Vector3d torque = vesselState.torqueAvailable + vesselState.torqueFromEngine * vessel.ctrlState.mainThrottle;

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("torque", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("|torque|", GUILayout.ExpandWidth(true));
                    GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    Vector3d inertia = Vector3d.Scale(
                        vesselState.angularMomentum.Sign(),
                        Vector3d.Scale(
                            Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum),
                            Vector3d.Scale(torque, vesselState.MoI).Invert()
                            )
                        );
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("inertia", GUILayout.ExpandWidth(true));
                    GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true));
                    GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    Vector3d ratio = Vector3d.Scale(vesselState.MoI, torque.Invert());

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("|MOI| / |Torque|", GUILayout.ExpandWidth(true));
                    GUILayout.Label(ratio.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true));
                    GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();
                }
            }

            MechJebModuleAttitudeController.useCoMVelocity = GUILayout.Toggle(MechJebModuleAttitudeController.useCoMVelocity, "Use CoM velocity instead of stock");

            MechJebModuleDebugArrows arrows = core.GetComputerModule<MechJebModuleDebugArrows>();

            GuiUtils.SimpleTextBox("Arrows length", arrows.arrowsLength, "", 50);

            arrows.seeThrough = GUILayout.Toggle(arrows.seeThrough, "Visible through object");
            GUILayout.BeginHorizontal();

            arrows.comSphereActive = GUILayout.Toggle(arrows.comSphereActive, "Display the CoM. Radius of ", GUILayout.ExpandWidth(false));
            arrows.comSphereRadius.text = GUILayout.TextField(arrows.comSphereRadius.text, GUILayout.Width(40));
            GUILayout.EndHorizontal();
            arrows.displayAtCoM = GUILayout.Toggle(arrows.displayAtCoM, "Arrows origins at the CoM");
            arrows.podSrfVelocityArrowActive = GUILayout.Toggle(arrows.podSrfVelocityArrowActive, "Pod Surface Velocity (yellow)");
            arrows.comSrfVelocityArrowActive = GUILayout.Toggle(arrows.comSrfVelocityArrowActive, "CoM Surface Velocity (green)");
            arrows.podObtVelocityArrowActive = GUILayout.Toggle(arrows.podObtVelocityArrowActive, "Pod Orbital Velocity (red)");
            arrows.comObtVelocityArrowActive = GUILayout.Toggle(arrows.comObtVelocityArrowActive, "CoM Orbital Velocity (orange)");
            arrows.forwardArrowActive = GUILayout.Toggle(arrows.forwardArrowActive, "Command Pod Forward (Navy Blue)");
            //arrows.avgForwardArrowActive = GUILayout.Toggle(arrows.avgForwardArrowActive, "Forward Avg (blue)");

            arrows.requestedAttitudeArrowActive = GUILayout.Toggle(arrows.requestedAttitudeArrowActive, "Requested Attitude (Gray)");

            arrows.debugArrowActive = GUILayout.Toggle(arrows.debugArrowActive, "Debug (Magenta)");

            GUILayout.EndVertical();

            if (!core.attitude.Tf_autoTune)
            {
                if (core.attitude.Tf != Tf)
                {
                    core.attitude.Tf = Tf;
                    core.attitude.setPIDParameters();
                }
            }
            else
            {
                if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax)
                {
                    core.attitude.TfMin = TfMin;
                    core.attitude.TfMax = TfMax;
                    core.attitude.setPIDParameters();
                }
                if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor)
                {
                    core.attitude.kpFactor = kpFactor;
                    core.attitude.kiFactor = kiFactor;
                    core.attitude.kdFactor = kdFactor;
                    core.attitude.setPIDParameters();
                }
            }
            base.WindowGUI(windowID);
        }
        // TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to
        public override void Drive(FlightCtrlState s)
        {
            // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up
            if (orbit.referenceBody != lastBody) { WaypointIndex = -1; Waypoints.Clear(); }
            MechJebRoverWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null);

            var curSpeed = vesselState.speedSurface;
            etaSpeed.value = curSpeed;

            if (wp != null && wp.Body == orbit.referenceBody) {
                if (controlHeading) {
                    heading = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1);
                }
                if (controlSpeed) {
                    var nextWP = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null));
                    var distance = Vector3.Distance(vessel.CoM, wp.Position);
                    //var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed
                    var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed); // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed
                    var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed :
                                    (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) :
                                     (distance - wp.Radius > 50 ? turnSpeed.val : 1)));
                    minSpeed = (wp.Quicksave ? 0 : minSpeed);
                    // ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last)
                    var brakeFactor = Math.Max((curSpeed - minSpeed) * 1, 3);
                    var newSpeed = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / brakeFactor, minSpeed)); // brake when getting closer
                    newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed); // reduce speed when turning a lot
                    var radius = Math.Max(wp.Radius, 10 / 0.8); // alternative radius so negative radii can still make it go full speed through waypoints for navigation reasons
                    if (distance < radius) {
                        if (WaypointIndex + 1 >= Waypoints.Count) { // last waypoint
                            newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min();
                            // ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons
                            if (LoopWaypoints) {
                                WaypointIndex = 0;
                            }
                            else {
                                newSpeed = -0.25;
                                tgtSpeed.force(newSpeed);
                                if (curSpeed < 0.85) {
                                    if (wp.Quicksave) {
                                        if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR) {
                                            WaypointIndex = -1;
                                            controlHeading = controlSpeed = false;
                                            QuickSaveLoad.QuickSave();
                                        }
                                    }
                                    else {
                                        WaypointIndex = -1;
                                        controlHeading = controlSpeed = false;
                                    }
                                }
            //								else {
            //									Debug.Log("Is this even getting called?");
            //									WaypointIndex++;
            //								}
                            }
                        }
                        else {
                            if (wp.Quicksave) {
                                newSpeed = -0.25;
                                tgtSpeed.force(newSpeed);
                                if (curSpeed < 0.85) {
                                    if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR) {
                                        WaypointIndex++;
                                        QuickSaveLoad.QuickSave();
                                    }
                                }
                            }
                            else {
                                WaypointIndex++;
                            }
                        }
                    }
                    vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, (GameSettings.BRAKES.GetKey() && vessel.isActiveVessel) || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < 0.85 && newSpeed < 0.85));
                    // ^ brake if needed to prevent rolling, hopefully
                    tgtSpeed.value = Math.Round(newSpeed, 1);
                }
            }

            if (controlHeading)
            {
                if (heading != headingLast)
                {
                    headingPID.Reset();
                    headingLast = heading;
                }

                double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y;
                headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading);
                if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    float spd = Mathf.Min((float)speed, (float)turnSpeed); // if a slower speed than the turnspeed is used also be more careful with the steering
                    float limit = (curSpeed <= turnSpeed ? 1 : Mathf.Clamp((float)((spd * spd) / (curSpeed * curSpeed)), 0.2f, 1f));
                    double act = headingPID.Compute(headingErr);
                    s.wheelSteer = Mathf.Clamp((float)act, -limit, limit);
                }
            }
            // Brake if there is no controler (Pilot eject from seat)
            if (brakeOnEject && vessel.GetReferenceTransformPart() == null)
            {
                s.wheelThrottle = 0;
                vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true);
            }
            else if (controlSpeed)
            {
                if (speed != speedLast)
                {
                    speedPID.Reset();
                    speedLast = speed;
                }

                speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed.value) - Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.forward);
                if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    double act = speedPID.Compute(speedErr);
                    s.wheelThrottle = Mathf.Clamp((float)act, -1, 1);
                }
            }
        }
Example #40
0
        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);
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            if (showingGuidance)
            {
                GUILayout.Label("The purple circle on the navball points along the ascent path.");
                if (GUILayout.Button("Stop showing navball guidance")) core.target.Unset();
            }
            else if (GUILayout.Button("Show navball ascent path guidance"))
            {
                core.target.SetDirectionTarget(TARGET_NAME);
            }

            if (autopilot != null)
            {
                if (autopilot.enabled)
                {
                    if (GUILayout.Button("Disengage autopilot")) autopilot.users.Remove(this);
                }
                else
                {
                    if (GUILayout.Button("Engage autopilot"))
                    {
                        autopilot.users.Add(this);
                    }
                }

                ascentPath = autopilot.ascentPath;

                GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km");
                autopilot.desiredInclination = desiredInclination;
            }

            GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º");

            core.thrust.LimitToPreventOverheatsInfoItem();
            core.thrust.LimitToTerminalVelocityInfoItem();
            core.thrust.LimitToMaxDynamicPressureInfoItem();
            core.thrust.LimitAccelerationInfoItem();
            core.thrust.LimitThrottleInfoItem();
            core.thrust.LimiterMinThrottleInfoItem();
            GUILayout.BeginHorizontal();
            autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, "Force Roll");
            if (autopilot.forceRoll)
            {
                GuiUtils.SimpleTextBox("climb", autopilot.verticalRoll, "º", 30f);
                GuiUtils.SimpleTextBox("turn", autopilot.turnRoll, "º", 30f);
            }
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            GUIStyle s = new GUIStyle(GUI.skin.toggle);
            if (autopilot.limitingAoA) s.onHover.textColor = s.onNormal.textColor = Color.green;
            autopilot.limitAoA = GUILayout.Toggle(autopilot.limitAoA, "Limit AoA to", s, GUILayout.ExpandWidth(true));
            autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30));
            GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Space(25);
            if (autopilot.limitAoA) {
                GUIStyle sl = new GUIStyle(GUI.skin.label);
                if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure)
                    sl.normal.textColor = sl.hover.textColor = Color.green;
                GuiUtils.SimpleTextBox("Dynamic Pressure Fadeout", autopilot.aoALimitFadeoutPressure, "pa", 50, sl);
            }
            GUILayout.EndHorizontal();

            autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering");

            autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage");
            if (autopilot.autostage) core.staging.AutostageSettingsInfoItem();

            autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels, "Auto-deploy solar panels");

            core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp");

            if (autopilot != null && vessel.LandedOrSplashed)
            {
                if (core.target.NormalTargetExists)
                {
                    if (core.node.autowarp)
                    {
                        GUILayout.BeginHorizontal();
                        GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true));
                        autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60));
                        GUILayout.Label("s", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();
                    }
                    if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary)
                    {
                        GUILayout.BeginHorizontal();
                        if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false)))
                        {
                            launchingToRendezvous = true;
                            autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit));
                        }
                        autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60));
                        GUILayout.Label("º", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();

                        if (GUILayout.Button("Launch into plane of target"))
                        {
                            launchingToPlane = true;
                            autopilot.StartCountdown( vesselState.time +
                                LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit));
                        }
                        if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody)
                        {
                            if (GUILayout.Button("Launch at interplanetary window"))
                            {
                                launchingToInterplanetary = true;
                                //compute the desired launch date
                                OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT);
                                double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter);
                                //launch just before the window, but don't try to launch in the past
                                interplanetaryWindowUT -= 3 * desiredOrbitPeriod;
                                interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT);
                                autopilot.StartCountdown(interplanetaryWindowUT);
                            }
                        }
                    }
                }
                else
                {
                    launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                    GUILayout.Label("Select a target for a timed launch.");
                }

                if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous)
                {
                    string message = "";
                    if (launchingToInterplanetary)
                    {
                        message = "Launching at interplanetary window";
                    }
                    else if (launchingToPlane)
                    {
                        desiredInclination = core.target.TargetOrbit.inclination;
                        desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up)));
                        message = "Launching to target plane";
                    }
                    else if (launchingToRendezvous)
                    {
                        message = "Launching to rendezvous";
                    }

                    if (autopilot.tMinus > 3 * vesselState.deltaT)
                    {
                        message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1);
                    }

                    GUILayout.Label(message);

                    if (GUILayout.Button("Abort")) launchingToInterplanetary = launchingToPlane = launchingToRendezvous = autopilot.timedLaunch = false;
                }
            }

            if (autopilot != null && autopilot.enabled)
            {
                GUILayout.Label("Autopilot status: " + autopilot.status);
            }

            if (!vessel.patchedConicsUnlocked())
            {
                GUILayout.Label("Warning: MechJeb is unable to circularize without an upgraded Tracking Station.");
            }

            MechJebModuleAscentPathEditor editor = core.GetComputerModule<MechJebModuleAscentPathEditor>();
            if (editor != null) editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path");

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
        public void setPIDParameters()
        {
            if (rcsManualPID)
            {
                pid.Kd = Kd;
                pid.Kp = Kp;
                pid.Ki = Ki;
            }
            else
            {
                Tf = Math.Max(Tf, 0.02);

                pid.Kd = 0.53 / Tf;
                pid.Kp = pid.Kd / (3 * Math.Sqrt(2) * Tf);
                pid.Ki = pid.Kp / (12 * Math.Sqrt(2) * Tf);

                Kd.val = pid.Kd;
                Kp.val = pid.Kp;
                Ki.val = pid.Ki;
            }
        }
        void DriveCircularizationBurn(FlightCtrlState s)
        {
            if (placedCircularizeNode)
            {
                if (!vessel.patchedConicSolver.maneuverNodes.Any())
                {
                    MechJebModuleFlightRecorder recorder = core.GetComputerModule<MechJebModuleFlightRecorder>();
                    if (recorder != null) launchPhaseAngle = recorder.phaseAngleFromMark;

                    //finished circularize
                    this.users.Clear();
                    return;
                }
            }
            else
            {
                //place circularization node
                vessel.RemoveAllManeuverNodes();
                double UT = orbit.NextApoapsisTime(vesselState.time);
                Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT);
                vessel.PlaceManeuverNode(orbit, dV, UT);
                placedCircularizeNode = true;

                core.node.ExecuteOneNode(this);
            }

            if (core.node.burnTriggered) status = "Circularizing";
            else status = "Coasting to circularization burn";
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME);

            if (showingGuidance)
            {
                GUILayout.Label("The purple circle on the navball points along the ascent path.");
                if (GUILayout.Button("Stop showing navball guidance"))
                {
                    core.target.Unset();
                }
            }
            else if (GUILayout.Button("Show navball ascent path guidance"))
            {
                core.target.SetDirectionTarget(TARGET_NAME);
            }

            if (autopilot != null)
            {
                if (autopilot.enabled)
                {
                    if (GUILayout.Button("Disengage autopilot"))
                    {
                        autopilot.users.Remove(this);
                    }
                }
                else
                {
                    if (GUILayout.Button("Engage autopilot"))
                    {
                        autopilot.users.Add(this);
                    }
                }

                ascentPath = autopilot.ascentPath;

                GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km");
                autopilot.desiredInclination = desiredInclination;
            }

            GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º");

            core.thrust.LimitToPreventOverheatsInfoItem();
            core.thrust.LimitToTerminalVelocityInfoItem();
            core.thrust.LimitAccelerationInfoItem();
            core.thrust.LimitThrottleInfoItem();
            autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering");

            autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage");
            if (autopilot.autostage)
            {
                core.staging.AutostageSettingsInfoItem();
            }

            core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp");

            if (autopilot != null && vessel.LandedOrSplashed)
            {
                if (core.target.NormalTargetExists)
                {
                    if (core.node.autowarp)
                    {
                        GUILayout.BeginHorizontal();
                        GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true));
                        autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60));
                        GUILayout.Label("s", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();
                    }
                    if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary)
                    {
                        GUILayout.BeginHorizontal();
                        if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false)))
                        {
                            launchingToRendezvous = true;
                            lastTMinus            = 999;
                        }
                        autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60));
                        GUILayout.Label("º", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();

                        if (GUILayout.Button("Launch into plane of target"))
                        {
                            launchingToPlane = true;
                            lastTMinus       = 999;
                        }
                        if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody)
                        {
                            if (GUILayout.Button("Launch at interplanetary window"))
                            {
                                launchingToInterplanetary = true;
                                lastTMinus = 999;
                                //compute the desired launch date
                                OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT);
                                double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter);
                                //launch just before the window, but don't try to launch in the past
                                interplanetaryWindowUT -= 3 * desiredOrbitPeriod;
                                interplanetaryWindowUT  = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT);
                            }
                        }
                    }
                }
                else
                {
                    launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                    GUILayout.Label("Select a target for a timed launch.");
                }

                if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous)
                {
                    double tMinus  = 0;
                    string message = "";
                    if (launchingToInterplanetary)
                    {
                        tMinus  = interplanetaryWindowUT - vesselState.time;
                        message = "Launching at interplanetary window";
                    }
                    else if (launchingToPlane)
                    {
                        tMinus              = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit);
                        desiredInclination  = core.target.TargetOrbit.inclination;
                        desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up)));
                        message             = "Launching to target plane";
                    }
                    else if (launchingToRendezvous)
                    {
                        tMinus  = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit);
                        message = "Launching to rendezvous";
                    }

                    double launchTime = vesselState.time + tMinus;

                    if (tMinus < 3 * vesselState.deltaT || (tMinus > 10.0 && lastTMinus < 1.0))
                    {
                        if (autopilot.enabled)
                        {
                            Staging.ActivateNextStage();
                        }
                        launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                    }
                    else
                    {
                        message += ": T-" + MuUtils.ToSI(tMinus, 0) + "s";
                        if (autopilot.enabled && core.node.autowarp)
                        {
                            core.warp.WarpToUT(launchTime - autopilot.warpCountDown);
                        }
                    }

                    GUILayout.Label(message);

                    lastTMinus = tMinus;

                    if (GUILayout.Button("Abort"))
                    {
                        launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                    }
                }
            }

            if (autopilot != null && autopilot.enabled)
            {
                GUILayout.Label("Autopilot status: " + autopilot.status);
            }

            MechJebModuleAscentPathEditor editor = core.GetComputerModule <MechJebModuleAscentPathEditor>();

            if (editor != null)
            {
                editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path");
            }

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
        public void setPIDParameters()
        {
            if (Tf < 2 * TimeWarp.fixedDeltaTime)
                Tf = 2 * TimeWarp.fixedDeltaTime;

            pid.Kd = 0.53 / Tf;
            pid.Kp = pid.Kd / (3 * Math.Sqrt(2) * Tf);
            pid.Ki = pid.Kp / (12 * Math.Sqrt(2) * Tf);
        }
Example #46
0
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME);

            if (showingGuidance)
            {
                GUILayout.Label("The purple circle on the navball points along the ascent path.");
                if (GUILayout.Button("Stop showing navball guidance"))
                {
                    core.target.Unset();
                }
            }
            else if (GUILayout.Button("Show navball ascent path guidance"))
            {
                core.target.SetDirectionTarget(TARGET_NAME);
            }

            if (autopilot != null)
            {
                if (autopilot.enabled)
                {
                    if (GUILayout.Button("Disengage autopilot"))
                    {
                        autopilot.users.Remove(this);
                    }
                }
                else
                {
                    if (GUILayout.Button("Engage autopilot"))
                    {
                        autopilot.users.Add(this);
                    }
                }

                ascentPath = autopilot.ascentPath;

                GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km");
                autopilot.desiredInclination = desiredInclination;
            }

            GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º");

            core.thrust.limitToPreventOverheats = GUILayout.Toggle(core.thrust.limitToPreventOverheats, "Prevent overheats");
            core.thrust.limitToTerminalVelocity = GUILayout.Toggle(core.thrust.limitToTerminalVelocity, "Limit to terminal velocity");
            GUILayout.BeginHorizontal();
            core.thrust.limitAcceleration    = GUILayout.Toggle(core.thrust.limitAcceleration, "Limit acceleration to", GUILayout.ExpandWidth(false));
            core.thrust.maxAcceleration.text = GUILayout.TextField(core.thrust.maxAcceleration.text, GUILayout.ExpandWidth(true));
            GUILayout.Label("m/s²", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();
            autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering");

            core.staging.AutostageInfoItem();

            core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp");

            if (autopilot != null && vessel.LandedOrSplashed)
            {
                if (core.target.NormalTargetExists)
                {
                    if (!launchingToPlane && !launchingToRendezvous)
                    {
                        GUILayout.BeginHorizontal();
                        if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false)))
                        {
                            launchingToRendezvous = true;
                        }
                        autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60));
                        GUILayout.Label("º", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();
                    }
                    if (!launchingToPlane && !launchingToRendezvous && GUILayout.Button("Launch into plane of target"))
                    {
                        launchingToPlane = true;
                    }
                }
                else
                {
                    launchingToPlane = launchingToRendezvous = false;
                    GUILayout.Label("Select a target for a timed launch.");
                }

                if (launchingToPlane || launchingToRendezvous)
                {
                    double tMinus;
                    if (launchingToPlane)
                    {
                        tMinus = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.Orbit);
                    }
                    else
                    {
                        tMinus = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.Orbit);
                    }

                    double launchTime = vesselState.time + tMinus;

                    core.warp.WarpToUT(launchTime);

                    if (launchingToPlane)
                    {
                        desiredInclination  = core.target.Orbit.inclination;
                        desiredInclination *= Math.Sign(Vector3d.Dot(core.target.Orbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up)));
                    }

                    if (autopilot.enabled)
                    {
                        core.warp.WarpToUT(launchTime);
                    }

                    GUILayout.Label("Launching to " + (launchingToPlane ? "target plane" : "rendezvous") + ": T-" + MuUtils.ToSI(tMinus, 0) + "s");
                    if (tMinus < 3 * vesselState.deltaT)
                    {
                        if (autopilot.enabled)
                        {
                            Staging.ActivateNextStage();
                        }
                        launchingToPlane = launchingToRendezvous = false;
                    }

                    if (GUILayout.Button("Abort"))
                    {
                        launchingToPlane = launchingToRendezvous = false;
                    }
                }

                if (autopilot.enabled)
                {
                    GUILayout.Label("Autopilot status: " + autopilot.status);
                }
            }

            MechJebModuleAscentPathEditor editor = core.GetComputerModule <MechJebModuleAscentPathEditor>();

            if (editor != null)
            {
                editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path");
            }

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
Example #47
0
 void GizmoUpdateHandler(Vector3d dV, double UT)
 {
     prograde = dV.z;
     radialPlus = dV.x;
     normalPlus = dV.y;
 }
        protected override void WindowGUI(int windowID)
        {
            GUIStyle sty = new GUIStyle(GUI.skin.button);
            sty.normal.textColor = sty.focused.textColor = Color.white;
            sty.hover.textColor = sty.active.textColor = Color.yellow;
            sty.onNormal.textColor = sty.onFocused.textColor = sty.onHover.textColor = sty.onActive.textColor = Color.green;
            sty.padding = new RectOffset(8, 8, 8, 8);

            GUILayout.BeginVertical();

            if ((core.thrust.users.Count > 1) && !core.thrust.users.Contains(this))
            {
                if (!autoMode)
                {
                    windowPos = new Rect(windowPos.x, windowPos.y, 10, 10);
                    autoMode = true;
                }

                sty.normal.textColor = Color.red;
                sty.onActive = sty.onFocused = sty.onHover = sty.onNormal = sty.active = sty.focused = sty.hover = sty.normal;
                GUILayout.Button("AUTO", sty, GUILayout.ExpandWidth(true));
            }
            else
            {
                if (autoMode)
                {
                    windowPos = new Rect(windowPos.x, windowPos.y, 10, 10);
                    autoMode = false;
                }

                MechJebModuleThrustController.TMode newMode = (MechJebModuleThrustController.TMode)GUILayout.SelectionGrid((int)core.thrust.tmode, trans_texts, 2, sty);
                SetMode(newMode);

                float val = (GameSettings.MODIFIER_KEY.GetKey() ? 5 : 1); // change by 5 if the mod_key is held down, else by 1 -- would be better if it actually worked...

                core.thrust.trans_kill_h = GUILayout.Toggle(core.thrust.trans_kill_h, "Kill H/S", GUILayout.ExpandWidth(true));
                GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
                GuiUtils.SimpleTextBox("Speed", trans_spd, "", 37);
                bool change = false;
                if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                {
                    trans_spd -= val;
                    change = true;
                }
                if (GUILayout.Button("0", GUILayout.ExpandWidth(false)))
                {
                    trans_spd = 0;
                    change = true;
                }
                if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                {
                    trans_spd += val;
                    change = true;
                }
                GUILayout.EndHorizontal();

                if (GUILayout.Button("EXECUTE", sty, GUILayout.ExpandWidth(true)) || change)
                {
                    core.thrust.trans_spd_act = (float)trans_spd.val;
                    GUIUtility.keyboardControl = 0;
                }
            }

            if (core.thrust.tmode != MechJebModuleThrustController.TMode.OFF)
            {
                GUILayout.Label("Active speed: " + MuMech.MuUtils.ToSI(core.thrust.trans_spd_act) + "m/s", GUILayout.ExpandWidth(true));
            }

            GUILayout.FlexibleSpace();

            GUIStyle tsty = new GUIStyle(GUI.skin.label);
            tsty.alignment = TextAnchor.UpperCenter;
            GUILayout.Label("Automation", tsty, GUILayout.ExpandWidth(true));

            sty.normal.textColor = sty.focused.textColor = sty.hover.textColor = sty.active.textColor = sty.onNormal.textColor = sty.onFocused.textColor = sty.onHover.textColor = sty.onActive.textColor = (abort != AbortStage.OFF) ? Color.red : Color.green;

            if (GUILayout.Button((abort != AbortStage.OFF) ? "DON'T PANIC!" : "PANIC!!!", sty, GUILayout.ExpandWidth(true)))
            {
                PanicSwitch();
            }

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
Example #49
0
        string[] snapStrings = new string[] { Localizer.Format("#MechJeb_NodeEd_Snap1"), Localizer.Format("#MechJeb_NodeEd_Snap2"), Localizer.Format("#MechJeb_NodeEd_Snap3"), Localizer.Format("#MechJeb_NodeEd_Snap4"), Localizer.Format("#MechJeb_NodeEd_Snap5"), Localizer.Format("#MechJeb_NodeEd_Snap6") };//"periapsis""apoapsis""AN with target""DN with target""equatorial AN""equatorial DN"

        void GizmoUpdateHandler(Vector3d dV, double UT)
        {
            prograde   = dV.z;
            radialPlus = dV.x;
            normalPlus = dV.y;
        }
 public override void OnStart(PartModule.StartState state)
 {
     Tf = new EditableDouble(core.attitude.Tf);
     base.OnStart(state);
 }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            core.GetComputerModule <MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem();

            if (!core.attitude.useSAS)
            {
                core.attitude.Tf_autoTune = GUILayout.Toggle(core.attitude.Tf_autoTune, " Tf auto tunning");

                if (!core.attitude.Tf_autoTune)
                {
                    GUILayout.Label("Larger ship do better with a larger Tf");
                    GuiUtils.SimpleTextBox("Tf (s)", Tf);
                    Tf = Math.Max(0.01, Tf);
                }
                else
                {
//            pid.Kd = kpFactor / Tf;
//            pid.Kp = pid.Kd / (kiFactor * Math.Sqrt(2) * Tf);
//            pid.Ki = pid.Kp / (kpFactor * Math.Sqrt(2) * Tf);
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf", GUILayout.ExpandWidth(true));
                    GUILayout.Label(core.attitude.Tf.ToString("F3"), GUILayout.ExpandWidth(false));
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Tf range");
                    GuiUtils.SimpleTextBox("min", TfMin, "", 50);
                    TfMin = Math.Max(TfMin, 0.01);
                    GuiUtils.SimpleTextBox("max", TfMax, "", 50);
                    TfMax = Math.Max(TfMax, 0.01);
                    GUILayout.EndHorizontal();

                    GUILayout.Label("PID factors");
                    GuiUtils.SimpleTextBox("Kd = ", kdFactor, " / Tf", 50);
                    kdFactor = Math.Max(kdFactor, 0.01);
                    GuiUtils.SimpleTextBox("Kp = pid.Kd / (", kpFactor, " * Math.Sqrt(2) * Tf)", 50);
                    kpFactor = Math.Max(kpFactor, 0.01);
                    GuiUtils.SimpleTextBox("Ki = pid.Kp / (", kiFactor, " * Math.Sqrt(2) * Tf)", 50);
                    kiFactor = Math.Max(kiFactor, 0.01);
                }

                core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode");
                core.rcs.rcsThrottle   = GUILayout.Toggle(core.rcs.rcsThrottle, " RCS throttle when 0k thrust");

                GUILayout.BeginHorizontal();
                GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true));
                GUILayout.Label(core.attitude.pid.Kp.ToString("F3") + ", " +
                                core.attitude.pid.Ki.ToString("F3") + ", " +
                                core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("integral action.", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("PID Action", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true));
                GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d torque = new Vector3d(
                    vesselState.torqueAvailable.x + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle,
                    vesselState.torqueAvailable.y,
                    vesselState.torqueAvailable.z + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle
                    );
                GUILayout.BeginHorizontal();
                GUILayout.Label("torque", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("|torque|", GUILayout.ExpandWidth(true));
                GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d inertia = Vector3d.Scale(
                    vesselState.angularMomentum.Sign(),
                    Vector3d.Scale(
                        Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum),
                        Vector3d.Scale(torque, vesselState.MoI).Invert()
                        )
                    );
                GUILayout.BeginHorizontal();
                GUILayout.Label("inertia", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true));
                GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d ratio = Vector3d.Scale(vesselState.MoI, torque.Invert());

                GUILayout.BeginHorizontal();
                GUILayout.Label("|MOI| / |Torque|", GUILayout.ExpandWidth(true));
                GUILayout.Label(ratio.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("fixedDeltaTime", GUILayout.ExpandWidth(true));
                GUILayout.Label(TimeWarp.fixedDeltaTime.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();
            }

            GUILayout.EndVertical();

            if (!core.attitude.Tf_autoTune)
            {
                if (core.attitude.Tf != Tf)
                {
                    core.attitude.Tf = Tf;
                    core.attitude.setPIDParameters();
                }
            }
            else
            {
                if (core.attitude.TfMin != TfMin || core.attitude.TfMax != TfMax)
                {
                    core.attitude.TfMin = TfMin;
                    core.attitude.TfMax = TfMax;
                    core.attitude.setPIDParameters();
                }
                if (core.attitude.kpFactor != kpFactor || core.attitude.kiFactor != kiFactor || core.attitude.kdFactor != kdFactor)
                {
                    core.attitude.kpFactor = kpFactor;
                    core.attitude.kiFactor = kiFactor;
                    core.attitude.kdFactor = kdFactor;
                    core.attitude.setPIDParameters();
                }
            }
            base.WindowGUI(windowID);
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            core.GetComputerModule<MechJebModuleCustomWindowEditor>().registry.Find(i => i.id == "Toggle:AttitudeController.useSAS").DrawItem();

            if (!core.attitude.useSAS)
            {
                GUILayout.Label("Larger ship do better with a larger Tf");
                GuiUtils.SimpleTextBox("Tf (s)", Tf);
                Tf = Math.Max(0.01, Tf);

                core.attitude.RCS_auto = GUILayout.Toggle(core.attitude.RCS_auto, " RCS auto mode");

                GUILayout.BeginHorizontal();
                GUILayout.Label("Kp, Ki, Kd", GUILayout.ExpandWidth(true));
                GUILayout.Label(core.attitude.pid.Kp.ToString("F3") + ", " +
                                core.attitude.pid.Ki.ToString("F3") + ", " +
                                core.attitude.pid.Kd.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("prop. action.", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.propAct), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("deriv. action", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.derivativeAct), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("integral action.", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pid.intAccum), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("PID Action", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(core.attitude.pidAction), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("AttitudeRollMatters ", GUILayout.ExpandWidth(true));
                GUILayout.Label(core.attitude.attitudeRollMatters ? "true" : "false", GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d torque = new Vector3d(
                                                        vesselState.torqueAvailable.x + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle,
                                                        vesselState.torqueAvailable.y,
                                                        vesselState.torqueAvailable.z + vesselState.torqueThrustPYAvailable * vessel.ctrlState.mainThrottle
                                                );
                GUILayout.BeginHorizontal();
                GUILayout.Label("torque", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(torque), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("|torque|", GUILayout.ExpandWidth(true));
                GUILayout.Label(torque.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                Vector3d inertia = Vector3d.Scale(
                                                        vesselState.angularMomentum.Sign(),
                                                        Vector3d.Scale(
                                                            Vector3d.Scale(vesselState.angularMomentum, vesselState.angularMomentum),
                                                            Vector3d.Scale(torque, vesselState.MoI).Invert()
                                                        )
                                                    );
                GUILayout.BeginHorizontal();
                GUILayout.Label("inertia", GUILayout.ExpandWidth(true));
                GUILayout.Label(MuUtils.PrettyPrint(inertia), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("|inertia|", GUILayout.ExpandWidth(true));
                GUILayout.Label(inertia.magnitude.ToString("F3"), GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();
            }

            GUILayout.EndVertical();

            if ((core.attitude.Tf != Tf))
            {
                core.attitude.Tf = Tf;
                double Kd = 0.53 / Tf;
                double Kp = Kd / (3 * Math.Sqrt(2) * Tf);
                double Ki = Kp / (12 * Math.Sqrt(2) * Tf);
                core.attitude.pid = new PIDControllerV2(Kp, Ki, Kd, 1, -1);
            }
            base.WindowGUI(windowID);
        }
        public override void Drive(FlightCtrlState s) // TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to
        {                                             // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up -- should be done now?
            if (orbit.referenceBody != lastBody)
            {
                WaypointIndex = -1; Waypoints.Clear();
            }
            MechJebWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null);

            var brake = vessel.ActionGroups[KSPActionGroup.Brakes];             // keep brakes locked if they are

            curSpeed = Vector3d.Dot(vessel.srf_velocity, vesselState.forward);

            CalculateTraction();
            speedIntAcc = speedPID.intAccum;

            if (wp != null && wp.Body == orbit.referenceBody)
            {
                if (ControlHeading)
                {
                    heading = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1);
                }
                if (ControlSpeed)
                {
                    var nextWP   = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null));
                    var distance = Vector3.Distance(vessel.CoM, wp.Position);
                    if (wp.Target != null)
                    {
                        distance += (float)(wp.Target.srfSpeed * curSpeed) / 2;
                    }
                    //var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed
                    var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed);                     // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed
                    var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed :
                                    (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) :
                                     (distance - wp.Radius > 50 ? turnSpeed.val : 1)));
                    minSpeed = (wp.Quicksave ? 1 : minSpeed);
                    // ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last)
                    var brakeFactor = Math.Max((curSpeed - minSpeed) * 1, 3);
                    var newSpeed    = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / brakeFactor, minSpeed));        // brake when getting closer
                    newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed);                     // reduce speed when turning a lot
                    if (LimitAcceleration)
                    {
                        newSpeed = curSpeed + Mathf.Clamp((float)(newSpeed - curSpeed), -1.5f, 0.5f);
                    }
//					newSpeed = tgtSpeed + Mathf.Clamp((float)(newSpeed - tgtSpeed), -Time.deltaTime * 8f, Time.deltaTime * 2f);
                    var radius = Math.Max(wp.Radius, 10);
                    if (distance < radius)
                    {
                        if (WaypointIndex + 1 >= Waypoints.Count)                         // last waypoint
                        {
                            newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min();
                            // ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons
                            if (LoopWaypoints)
                            {
                                WaypointIndex = 0;
                            }
                            else
                            {
                                newSpeed = 0;
//								tgtSpeed.force(newSpeed);
                                if (curSpeed < brakeSpeedLimit)
                                {
                                    if (wp.Quicksave)
                                    {
                                        //if (s.mainThrottle > 0) { s.mainThrottle = 0; }
                                        if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                                        {
                                            WaypointIndex  = -1;
                                            ControlHeading = ControlSpeed = false;
                                            QuickSaveLoad.QuickSave();
                                        }
                                    }
                                    else
                                    {
                                        WaypointIndex  = -1;
                                        ControlHeading = ControlSpeed = false;
                                    }
                                }
//								else {
//									Debug.Log("Is this even getting called?");
//									WaypointIndex++;
//								}
                            }
                        }
                        else
                        {
                            if (wp.Quicksave)
                            {
                                //if (s.mainThrottle > 0) { s.mainThrottle = 0; }
                                newSpeed = 0;
//								tgtSpeed.force(newSpeed);
                                if (curSpeed < brakeSpeedLimit)
                                {
                                    if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                                    {
                                        WaypointIndex++;
                                        QuickSaveLoad.QuickSave();
                                    }
                                }
                            }
                            else
                            {
                                WaypointIndex++;
                            }
                        }
                    }
                    brake = brake || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < brakeSpeedLimit && newSpeed < brakeSpeedLimit);
                    // ^ brake if needed to prevent rolling, hopefully
                    tgtSpeed = (newSpeed >= 0 ? newSpeed : 0);
                }
            }

            if (ControlHeading)
            {
                headingPID.intAccum = Mathf.Clamp((float)headingPID.intAccum, -1, 1);

                double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y;
                headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading);
                if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    float  spd   = Mathf.Min((float)speed, (float)turnSpeed);                  // if a slower speed than the turnspeed is used also be more careful with the steering
                    float  limit = (Mathf.Abs((float)curSpeed) <= turnSpeed ? 1 : Mathf.Clamp((float)(spd / Mathf.Abs((float)curSpeed)), 0.35f, 1f));
                    double act   = headingPID.Compute(headingErr);
                    s.wheelSteer = Mathf.Clamp((float)act, -limit, limit);
                }
            }

            // Brake if there is no controler (Pilot eject from seat)
            if (BrakeOnEject && vessel.GetReferenceTransformPart() == null)
            {
                s.wheelThrottle = 0;
//				vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true);
                brake = true;
            }
            else if (ControlSpeed)
            {
                speedPID.intAccum = Mathf.Clamp((float)speedPID.intAccum, -5, 5);

                speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed) - Vector3d.Dot(vessel.srf_velocity, vesselState.forward);
                if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    float act = (float)speedPID.Compute(speedErr);
                    s.wheelThrottle = !LimitAcceleration?Mathf.Clamp((float)act, -1, 1) :                       // I think I'm using these ( ? : ) a bit too much
                                          (traction == 0 ? 0 : (act < 0 ? Mathf.Clamp(act, -1f, 1f) : (lastThrottle + Mathf.Clamp(act - lastThrottle, -0.005f, 0.005f)) * (traction < tractionLimit ? -1 : 1)));

                    if (curSpeed < 0 & s.wheelThrottle < 0)
                    {
                        s.wheelThrottle = 0;
                    }                                                                                                        // don't go backwards
//					if (Mathf.Sign(act) + Mathf.Sign(s.wheelThrottle) == 0) { s.wheelThrottle = Mathf.Clamp(act, -1f, 1f); }
                    if (speedErr < -1 && StabilityControl && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) == 0) // StabilityControl && traction > 50 &&
//						vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true);
                    {
                        brake = true;
                    }
//					else if (!stabilityControl || traction <= 50 || speedErr > -0.2 || Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) {
//						vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, (GameSettings.BRAKES.GetKey() && vessel.isActiveVessel));
//					}
                    lastThrottle = s.wheelThrottle;
                }
            }

            if (StabilityControl)
            {
                if (!core.attitude.users.Contains(this))
                {
                    core.attitude.users.Add(this);
//					line.enabled = true;
                }
//				float scale = Vector3.Distance(FlightCamera.fetch.mainCamera.transform.position, vessel.CoM) / 900f;
//				line.SetPosition(0, vessel.CoM);
//				line.SetPosition(1, vessel.CoM + hit.normal * 5);
//				line.SetWidth(0, scale + 0.1f);
                var fSpeed = (float)curSpeed;
//				if (Mathf.Abs(fSpeed) >= turnSpeed * 0.75) {
                Vector3 fwd = (Vector3)(traction > 0 ?                 // V when the speed is low go for the vessels forward, else with a bit of velocity
//				                        ((Mathf.Abs(fSpeed) <= turnSpeed ? vesselState.forward : vessel.srf_velocity / 4) - vessel.transform.right * s.wheelSteer) * Mathf.Sign(fSpeed) :
//				                        // ^ and then add the steering
                                        vesselState.forward * 4 - vessel.transform.right * s.wheelSteer * Mathf.Sign(fSpeed) : // and then add the steering
                                        vessel.srf_velocity);                                                                  // in the air so follow velocity
                Vector3.OrthoNormalize(ref norm, ref fwd);
                var quat = Quaternion.LookRotation(fwd, norm);

//				if (traction > 0 || speed <= turnSpeed) {
//					var u = new Vector3(0, 1, 0);
//
//					var q = FlightGlobals.ship_rotation;
//					var q_s = quat;
//
//					var q_u = new Quaternion(u.x, u.y, u.z, 0);
//					var a = Quaternion.Dot(q, q_s * q_u);
//					var q_qs = Quaternion.Dot(q, q_s);
//					var b = (a == 0) ? Math.Sign(q_qs) : (q_qs / a);
//					var g = b / Mathf.Sqrt((b * b) + 1);
//					var gu = Mathf.Sqrt(1 - (g * g)) * u;
//					var q_d = new Quaternion() { w = g, x = gu.x, y = gu.y, z = gu.z };
//					var n = q_s * q_d;
//
//					quat = n;
//				}

                core.attitude.attitudeTo(quat, AttitudeReference.INERTIAL, this);
//				}
            }

            if (BrakeOnEnergyDepletion)
            {
                var batteries  = vessel.Parts.FindAll(p => p.Resources.Contains("ElectricCharge") && p.Resources["ElectricCharge"].flowState);
                var energyLeft = batteries.Sum(p => p.Resources["ElectricCharge"].amount) / batteries.Sum(p => p.Resources["ElectricCharge"].maxAmount);
                var openSolars = vessel.mainBody.atmosphere &&                 // true if in atmosphere and there are breakable solarpanels that aren't broken nor retracted
                                 vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable && p.panelState != ModuleDeployableSolarPanel.panelStates.BROKEN &&
                                                                                                           p.panelState != ModuleDeployableSolarPanel.panelStates.RETRACTED).Count > 0;

                if (openSolars && energyLeft > 0.99)
                {
                    vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable &&
                                                                                              p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).ForEach(p => p.Retract());
                }

                if (energyLeft < 0.05 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0)
                {
                    s.wheelThrottle = 0;
                }                                                                                                                                 // save remaining energy by not using it for acceleration
                if (openSolars || energyLeft < 0.03)
                {
                    tgtSpeed = 0;
                }

                if (curSpeed < brakeSpeedLimit && (energyLeft < 0.05 || openSolars))
                {
                    brake = true;
                }

                if (curSpeed < 0.1 && energyLeft < 0.05 && !waitingForDaylight &&
                    vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).Count > 0)
                {
                    waitingForDaylight = true;
                }
            }

//			brake = brake && (s.wheelThrottle == 0); // release brake if the user or AP want to drive
            if (s.wheelThrottle != 0 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0)
            {
                brake = false;                 // the AP or user want to drive into the direction of momentum so release the brake
            }

            if (vessel.isActiveVessel)
            {
                if (GameSettings.BRAKES.GetKeyUp())
                {
                    brake = false;                     // release the brakes if the user lets go of them
                }
                if (GameSettings.BRAKES.GetKey())
                {
                    brake = true;                     // brake if the user brakes and we aren't about to flip
                }
            }

            tractionLimit = (double)Mathf.Clamp((float)tractionLimit, 0, 100);
            vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, brake && (StabilityControl && curSpeed > brakeSpeedLimit ? traction >= tractionLimit : true));
            // ^ brake but hopefully prevent flipping over, assuming the user set up the limit right
            if (brake && curSpeed < 0.1)
            {
                s.wheelThrottle = 0;
            }
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME);

            if (showingGuidance)
            {
                GUILayout.Label("The purple circle on the navball points along the ascent path.");
                if (GUILayout.Button("Stop showing navball guidance")) core.target.Unset();
            }
            else if (GUILayout.Button("Show navball ascent path guidance"))
            {
                core.target.SetDirectionTarget(TARGET_NAME);
            }

            if (autopilot != null)
            {
                if (autopilot.enabled)
                {
                    if (GUILayout.Button("Disengage autopilot")) autopilot.users.Remove(this);
                }
                else
                {
                    if (GUILayout.Button("Engage autopilot"))
                    {
                        autopilot.users.Add(this);
                    }
                }

                ascentPath = autopilot.ascentPath;

                GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km");
                autopilot.desiredInclination = desiredInclination;
            }

            GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º");

            core.thrust.LimitToPreventOverheatsInfoItem();
            core.thrust.LimitToTerminalVelocityInfoItem();
            core.thrust.LimitAccelerationInfoItem();
            core.thrust.LimitThrottleInfoItem();
            autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering");

            autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage");
            if (autopilot.autostage) core.staging.AutostageSettingsInfoItem();

            core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp");

            if (autopilot != null && vessel.LandedOrSplashed)
            {
                if (core.target.NormalTargetExists)
                {
                    if (core.node.autowarp)
                    {
                        GUILayout.BeginHorizontal();
                        GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true));
                        autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60));
                        GUILayout.Label("s", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();
                    }
                    if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary)
                    {
                        GUILayout.BeginHorizontal();
                        if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false)))
                        {
                            launchingToRendezvous = true;
                            lastTMinus = 999;
                        }
                        autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60));
                        GUILayout.Label("º", GUILayout.ExpandWidth(false));
                        GUILayout.EndHorizontal();

                        if (GUILayout.Button("Launch into plane of target"))
                        {
                            launchingToPlane = true;
                            lastTMinus = 999;
                        }
                        if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody)
                        {
                            if (GUILayout.Button("Launch at interplanetary window"))
                            {
                                launchingToInterplanetary = true;
                                lastTMinus = 999;
                                //compute the desired launch date
                                OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT);
                                double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter);
                                //launch just before the window, but don't try to launch in the past
                                interplanetaryWindowUT -= 3 * desiredOrbitPeriod;
                                interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT);
                            }
                        }
                    }
                }
                else
                {
                    launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                    GUILayout.Label("Select a target for a timed launch.");
                }

                if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous)
                {
                    double tMinus = 0;
                    string message = "";
                    if (launchingToInterplanetary)
                    {
                        tMinus = interplanetaryWindowUT - vesselState.time;
                        message = "Launching at interplanetary window";
                    }
                    else if (launchingToPlane)
                    {
                        tMinus = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit);
                        desiredInclination = core.target.TargetOrbit.inclination;
                        desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up)));
                        message = "Launching to target plane";
                    }
                    else if (launchingToRendezvous)
                    {
                        tMinus = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit);
                        message = "Launching to rendezvous";
                    }

                    double launchTime = vesselState.time + tMinus;

                    if (tMinus < 3 * vesselState.deltaT || (tMinus > 10.0 && lastTMinus < 1.0))
                    {
                        if (autopilot.enabled) Staging.ActivateNextStage();
                        launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                    }
                    else
                    {
                        message += ": T-" + MuUtils.ToSI(tMinus, 0) + "s";
                        if (autopilot.enabled && core.node.autowarp) core.warp.WarpToUT(launchTime - autopilot.warpCountDown);
                    }

                    GUILayout.Label(message);

                    lastTMinus = tMinus;

                    if (GUILayout.Button("Abort")) launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false;
                }
            }

            if (autopilot != null && autopilot.enabled)
            {
                GUILayout.Label("Autopilot status: " + autopilot.status);
            }

            MechJebModuleAscentPathEditor editor = core.GetComputerModule<MechJebModuleAscentPathEditor>();
            if (editor != null) editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path");

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }