public override void Draw()
        {
#if DEBUG
            if (ToOrbit != null)
            {
                Utils.GLVec(Body.position, ToOrbit.Target.xzy, Color.green);
                Utils.GLVec(Body.position, VesselOrbit.getRelativePositionAtUT(VSL.Physics.UT + VesselOrbit.timeToAp).xzy, Color.magenta);
                Utils.GLVec(Body.position, VesselOrbit.GetOrbitNormal().normalized.xzy *Body.Radius * 1.1, Color.cyan);
                Utils.GLVec(Body.position, Vector3d.Cross(VesselOrbit.pos, ToOrbit.Target).normalized.xzy *Body.Radius * 1.1, Color.red);
            }
#endif
            if (stage == Stage.None)
            {
                if (Utils.ButtonSwitch("ToOrbit", ShowOptions,
                                       "Achieve a circular orbit with desired radius and inclination",
                                       GUILayout.ExpandWidth(true)))
                {
                    toggle_orbit_editor();
                }
            }
            else if (GUILayout.Button(new GUIContent("ToOrbit", "Change target orbit or abort"),
                                      Styles.danger_button, GUILayout.ExpandWidth(true)))
            {
                toggle_orbit_editor();
            }
        }
		public bool GravityTurn(double ApA_offset, double gturn_curve, double dist2vel, double Dtol)
		{
			UpdateTargetPosition();
			VSL.Engines.ActivateNextStageOnFlameout();
			dApA = TargetR-VesselOrbit.ApR;
			var vel  = Vector3d.zero;
			var cApV = VesselOrbit.getRelativePositionAtUT(VSL.Physics.UT+VesselOrbit.timeToAp);
			var hv   = Vector3d.Exclude(VesselOrbit.pos, target-VesselOrbit.pos).normalized;
			var arc  = Utils.ProjectionAngle(cApV, target, hv)*Mathf.Deg2Rad*cApV.magnitude;
			ErrorThreshold.Value = CorrectOnlyAltitude? dApA : dApA+arc;
			ApoapsisReached |= dApA < Dtol;
			THR.CorrectThrottle = ApoapsisReached;
			if(!ErrorThreshold)
			{
				var startF = Utils.Clamp((VSL.Altitude.Absolute-GravityTurnStart)/GLB.ORB.GTurnOffset, 0, 1);
				if(dApA > Dtol)
					vel += CorrectOnlyAltitude && ApoapsisReached? 
						VesselOrbit.vel.normalized.xzy*dApA :
						VSL.Physics.Up.xzy*dApA*gturn_curve;
				if(arc > Dtol && (!ApoapsisReached || !CorrectOnlyAltitude))
				{
					var hvel = Utils.ClampL(arc-dApA*gturn_curve, 0)*startF;
					if(Body.atmosphere) hvel *= Math.Sqrt(Utils.Clamp(VSL.Altitude.Absolute/Body.atmosphereDepth, 0, 1));
					vel += hv*hvel;
				}
				vel *= VSL.Physics.StG/Utils.G0*dist2vel;
				if(!vel.IsZero())
				{
					var norm = VesselOrbit.GetOrbitNormal();
					var dFi = (90-Vector3d.Angle(norm, target))*Mathf.Deg2Rad;
					vel += norm*Math.Sin(dFi)*vel.magnitude*startF
						*Utils.Clamp(VSL.VerticalSpeed.Absolute/VSL.Physics.G-MinClimbTime, 0, 100)
						*Utils.ClampL(Vector3d.Dot(hv, VesselOrbit.vel.normalized), 0);
				}
				vel = vel.xzy;
				CircularizationOffset = -1;
				if(Executor.Execute(vel, Utils.Clamp(1-VSL.Torque.MaxCurrent.AA_rad, 0.1f, 1)))
				{
					if(CFG.AT.Not(Attitude.KillRotation)) 
					{
						CFG.BR.OnIfNot(BearingMode.Auto);
						BRC.ForwardDirection = hv.xzy;
					}
					Status("Gravity turn...");
					return true;
				}
			}
			Status("Coasting...");
			CFG.BR.OffIfOn(BearingMode.Auto);
			CFG.AT.OnIfNot(Attitude.KillRotation);
			THR.Throttle = 0;
			if(CircularizationOffset < 0)
			{
				ApAUT = VSL.Physics.UT+VesselOrbit.timeToAp;
				CircularizationOffset = VSL.Engines.TTB((float)TrajectoryCalculator.dV4C(VesselOrbit, hV(ApAUT), ApAUT).magnitude)/2;
			}
			return VesselOrbit.timeToAp > ApA_offset+CircularizationOffset &&
				Body.atmosphere && VesselOrbit.radius < Body.Radius+Body.atmosphereDepth;
		}
Exemplo n.º 3
0
        protected Vector3d Node2OrbitDeltaV(Vector3d NodeDeltaV, double StartUT)
        {
            var norm     = VesselOrbit.GetOrbitNormal().normalized;
            var prograde = hV(StartUT).normalized;
            var radial   = Vector3d.Cross(prograde, norm).normalized;

            return(radial * NodeDeltaV.x + norm * NodeDeltaV.y + prograde * NodeDeltaV.z);
        }
        Vector3d correct_dV(Vector3d dV, double UT)
        {
            var v  = VesselOrbit.getOrbitalVelocityAtUT(UT);
            var nV = dV + v;

            return(QuaternionD.AngleAxis(-inclination_error(VesselOrbit.inclination),
                                         VesselOrbit.getRelativePositionAtUT(UT)) * nV - v);
        }
Exemplo n.º 5
0
        protected override void fine_tune_approach()
        {
            update_landing_trajecotry();
            var V = VesselOrbit.getOrbitalVelocityAtUT(VSL.Physics.UT + CorrectionOffset).magnitude;

            ComputeTrajectory(new LandingSiteCorrector(this, V, LTRJ.Dtol / 2));
            stage      = Stage.CorrectTrajectory;
            trajectory = null;
        }
        protected override void fine_tune_approach()
        {
            trajectory = null;
            stage      = Stage.CorrectTrajectory;
            double angle = 0;
            double V     = VesselOrbit.getOrbitalVelocityAtUT(VSL.Physics.UT + LTRJ.CorrectionOffset).magnitude;

            setup_calculation((o, b) => orbit_correction(o, b, ref angle, ref V, LTRJ.CorrectionOffset));
        }
Exemplo n.º 7
0
        //Node: radial, normal, prograde
        protected Vector3d Orbit2NodeDeltaV(Vector3d OrbitDeltaV, double StartUT)
        {
            var norm     = VesselOrbit.GetOrbitNormal().normalized;
            var prograde = hV(StartUT).normalized;
            var radial   = Vector3d.Cross(prograde, norm).normalized;

            return(new Vector3d(Vector3d.Dot(OrbitDeltaV, radial),
                                Vector3d.Dot(OrbitDeltaV, norm),
                                Vector3d.Dot(OrbitDeltaV, prograde)));
        }
 protected void update_state(float Dtol)
 {
     hvdir = Vector3d.Exclude(VesselOrbit.pos, VesselOrbit.vel).normalized;
     htdir = Vector3d.Exclude(VesselOrbit.pos, target - VesselOrbit.pos).normalized;
     ApV   = VesselOrbit.getRelativePositionAtUT(VSL.Physics.UT + VesselOrbit.timeToAp);
     dApA  = Utils.ClampL(TargetR - VesselOrbit.ApR, 0);
     dArc  = Utils.ClampL(Utils.ProjectionAngle(ApV, target, htdir) * ToOrbitAutopilot.C.Dtol, 0);
     ErrorThreshold.Value = CorrectOnlyAltitude ? dApA : dApA + dArc;
     ApoapsisReached     |= dApA < Dtol;
     CourseOnTarget       = Vector3d.Dot(htdir, hvdir) > 0.1;
 }
        void start_orbit()
        {
            ToOrbit = null;
            var dV      = Vector3d.zero;
            var old     = VesselOrbit;
            var StartUT = VSL.Physics.UT + CorrectionOffset;

            CFG.BR.OffIfOn(BearingMode.Auto);
            update_trajectory();
            if (VesselOrbit.PeR < MinPeR)
            {
                StartUT = Math.Min(trajectory.AtTargetUT, VSL.Physics.UT + (VesselOrbit.ApAhead()? VesselOrbit.timeToAp : CorrectionOffset));
                if (trajectory.DistanceToTarget < REN.ApproachThreshold * 2 && StartUT.Equals(trajectory.AtTargetUT))
                {                 //approach is close enough to directly match orbits
                    match_orbits();
                    return;
                }
                var transfer_time = Utils.ClampL(TargetOrbit.period * (0.25 - AngleDelta(VesselOrbit, TargetOrbit, StartUT) / 360), 1);
                var solver        = new LambertSolver(VesselOrbit, TargetOrbit.getRelativePositionAtUT(StartUT + transfer_time), StartUT);
                dV = solver.dV4Transfer(transfer_time);
                var trj = new RendezvousTrajectory(VSL, dV, StartUT, CFG.Target, MinPeR, transfer_time);
                if (!dV.IsZero() && !trj.KillerOrbit)
                {                 //approach orbit is possible
                    compute_start_orbit(StartUT);
                    return;
                }
                //starting from circular orbit and proceeding to TTR fitting...
                StartUT = VesselOrbit.ApAhead()? VSL.Physics.UT + VesselOrbit.timeToAp : VSL.Physics.UT + CorrectionOffset;
                dV      = dV4C(old, hV(StartUT), StartUT);
                old     = NewOrbit(old, dV, StartUT);
            }
            else if (trajectory.RelDistanceToTarget < REN.CorrectionStart || TargetLoaded)
            {
                if (trajectory.RelDistanceToTarget > REN.CorrectionStart / 4 && !TargetLoaded)
                {
                    fine_tune_approach();
                }
                else
                {
                    match_orbits();
                }
                return;
            }
            //compute orbit with desired TTR and activate maneuver autopilot
            dV += dV4TTR(old, TargetOrbit, REN.MaxTTR, REN.MaxDeltaV, MinPeR, StartUT);
            if (!dV.IsZero())
            {
                add_node(dV, StartUT);
                CFG.AP1.On(Autopilot1.Maneuver);
            }
            stage = Stage.StartOrbit;
        }
        protected LandingTrajectory fixed_inclination_orbit(LandingTrajectory old, LandingTrajectory best,
                                                            ref Vector3d dir, ref double V, float start_offset)
        {
            var StartUT = VSL.Physics.UT + start_offset;

            if (old != null)
            {
                V  += old.DeltaR * (1 - CFG.Target.AngleTo(VSL) / Math.PI * 0.9) * Body.GeeASL;
                dir = Quaternion.AngleAxis((float)old.DeltaFi, VSL.Physics.Up.xzy) * dir;
            }
            return(new LandingTrajectory(VSL, dir * V - VesselOrbit.getOrbitalVelocityAtUT(StartUT), StartUT,
                                         CFG.Target, old == null? TargetAltitude : old.TargetAltitude));
        }
        protected LandingTrajectory orbit_correction(LandingTrajectory old, LandingTrajectory best, ref double angle, ref double V, float start_offset)
        {
            var StartUT = VSL.Physics.UT + start_offset;

            if (old != null)
            {
                V     += old.DeltaR * (1 - CFG.Target.AngleTo(VSL) / Math.PI * 0.9) * Body.GeeASL;
                angle += old.DeltaFi;
            }
            var vel = VesselOrbit.getOrbitalVelocityAtUT(StartUT);

            return(new LandingTrajectory(VSL, QuaternionD.AngleAxis(angle, VSL.Physics.Up.xzy) * vel.normalized * V - vel, StartUT,
                                         CFG.Target, old == null? TargetAltitude : old.TargetAltitude));
        }
 protected Vector3d tune_needed_vel(Vector3d needed_vel, Vector3d pg_vel, double startF)
 {
     if (CourseOnTarget)
     {
         norm_correction.Update((float)(90 - Utils.Angle2(VesselOrbit.GetOrbitNormal(), target)));
         needed_vel = QuaternionD.AngleAxis(norm_correction.Action, VesselOrbit.pos) * needed_vel;
     }
     else
     {
         norm_correction.Update(0);
     }
     return(startF < 1 ?
            needed_vel.magnitude * Vector3d.Lerp(pg_vel.normalized,
                                                 needed_vel.normalized,
                                                 startF)
                       : needed_vel);
 }
Exemplo n.º 13
0
		IEnumerator<YieldInstruction> compute_initial_eccentricity()
		{
//			Log("Calculating initial orbit eccentricity...");//debug
			var tPos = CFG.Target.RelOrbPos(Body);
			var UT = VSL.Physics.UT +
				AngleDelta(VesselOrbit, tPos, VSL.Physics.UT)/360*VesselOrbit.period;
			var vPos = VesselOrbit.getRelativePositionAtUT(UT);
			var vVel = VesselOrbit.getOrbitalVelocityAtUT(UT);
			var dir = Vector3d.Exclude(vPos, vVel);
            var ini_dV = dV4Pe(VesselOrbit, (Body.Radius+TargetAltitude)*0.999, UT);
			var trj = new LandingTrajectory(VSL, ini_dV, UT, CFG.Target, TargetAltitude);
			var atmo_curve = trj.GetAtmosphericCurve(5);
			var maxV = vVel.magnitude;
			var minV = 0.0;
			var dV = 0.0;
			dir = -dir.normalized;
			var in_plane = Math.Abs(90-Vector3.Angle(tPos, VesselOrbit.GetOrbitNormal())) < 5;
//			Log("in plane {}, ini dV {}\nini trj:\n{}", in_plane, ini_dV, trj);//debug
			yield return null;
			while(maxV-minV > 1)
			{
				dV = (maxV+minV)/2;
				trj = new LandingTrajectory(VSL, ini_dV+dir*dV, UT, CFG.Target, trj.TargetAltitude);
				atmo_curve = trj.GetAtmosphericCurve(5);
//				Log("dV: {} : {} : {} m/s\ntrj:\n{}", minV, dV, maxV, trj);//debug
				if(!trj.NotEnoughFuel && (in_plane || trj.DeltaR < 0) &&
				   (atmo_curve != null &&
				    (will_overheat(atmo_curve) ||
				     atmo_curve[atmo_curve.Count-1].DynamicPressure > DEO.MaxDynPressure) ||
				    !Body.atmosphere && trj.LandingAngle < DEO.MinLandingAngle))
					minV = dV;
				else maxV = dV;
				yield return null;
			}
			currentEcc = trj.Orbit.eccentricity;
			dEcc = currentEcc/DEO.EccSteps;
//			Log("currentEcc: {}, dEcc {}", currentEcc, dEcc);//debug
		}
Exemplo n.º 14
0
 protected Vector3d hV(double UT)
 {
     return(VesselOrbit.hV(UT));
 }
Exemplo n.º 15
0
        public void DeorbitCallback(Multiplexer.Command cmd)
        {
            switch (cmd)
            {
            case Multiplexer.Command.Resume:
//				Utils.Log("Resuming: stage {}, landing_stage {}, landing {}", stage, landing_stage, landing);//debug
                if (!check_patched_conics())
                {
                    return;
                }
                NeedRadarWhenMooving();
                if (stage == Stage.None && !landing)
                {
                    goto case Multiplexer.Command.On;
                }
                else if (VSL.HasManeuverNode)
                {
                    CFG.AP1.OnIfNot(Autopilot1.Maneuver);
                }
                break;

            case Multiplexer.Command.On:
                reset();
                if (!check_patched_conics())
                {
                    return;
                }
                if (!setup())
                {
                    CFG.AP2.Off(); return;
                }
                if (VesselOrbit.PeR < Body.Radius)
                {
                    Status("red", "Already deorbiting. Trying to correct course and land.");
                    fine_tune_approach();
                }
                else
                {
//					Log("Calculating initial orbit eccentricity...");//debug
                    var tPos = CFG.Target.RelOrbPos(Body);
                    var UT   = VSL.Physics.UT +
                               AngleDelta(VesselOrbit, tPos, VSL.Physics.UT) / 360 * VesselOrbit.period;
                    var vPos    = VesselOrbit.getRelativePositionAtUT(UT);
                    var dir     = Vector3d.Exclude(vPos, tPos - vPos);
                    var ini_orb = CircularOrbit(dir, UT);
                    var ini_dV  = ini_orb.getOrbitalVelocityAtUT(UT) - VesselOrbit.getOrbitalVelocityAtUT(UT) + dV4Pe(ini_orb, Body.Radius * 0.9, UT);
                    var trj     = new LandingTrajectory(VSL, ini_dV, UT, CFG.Target, TargetAltitude);
                    var dV      = 10.0;
                    dir = -dir.normalized;
                    while (trj.Orbit.eccentricity < DEO.StartEcc)
                    {
//						Log("\ndV: {}m/s\nini trj:\n{}", dV, trj);//debug
                        if (trj.DeltaR > 0)
                        {
                            break;
                        }
                        trj = new LandingTrajectory(VSL, ini_dV + dir * dV, UT, CFG.Target, trj.TargetAltitude);
                        dV += 10;
                    }
                    if (trj.Orbit.eccentricity > DEO.StartEcc)
                    {
                        currentEcc = DEO.StartEcc;
                        if (Body.atmosphere)
                        {
                            currentEcc =
                                Utils.ClampH(currentEcc * (2.1 - Utils.ClampH(VSL.Torque.MaxPossible.AngularDragResistance / Body.atmDensityASL * DEO.AngularDragF, 1)), DEO.MaxEcc);
                        }
                    }
                    else
                    {
                        currentEcc = Utils.ClampL(trj.Orbit.eccentricity - DEO.dEcc, DEO.dEcc);
                    }
//					Log("currentEcc: {}, dEcc {}", currentEcc, DEO.dEcc);//debug
                    if (Globals.Instance.AutosaveBeforeLanding)
                    {
                        Utils.SaveGame(VSL.vessel.vesselName.Replace(" ", "_") + "-before_landing");
                    }
                    compute_landing_trajectory();
                }
                goto case Multiplexer.Command.Resume;

            case Multiplexer.Command.Off:
                UnregisterFrom <Radar>();
                reset();
                break;
            }
        }
Exemplo n.º 16
0
        protected override void Update()
        {
            switch (stage)
            {
            case Stage.Start:
                if (VSL.LandedOrSplashed)
                {
                    stage = Stage.Liftoff;
                }
                else
                {
                    ToOrbit.StartGravityTurn();
                    stage = Stage.GravityTurn;
                }
                break;

            case Stage.Liftoff:
                if (ToOrbit.Liftoff())
                {
                    break;
                }
                stage = Stage.GravityTurn;
                break;

            case Stage.GravityTurn:
                update_inclination_limits();
                var norm = VesselOrbit.GetOrbitNormal();
                var ApV  = VesselOrbit.getRelativePositionAtUT(VSL.Physics.UT + VesselOrbit.timeToAp);
                var arcT = AngleDelta(VesselOrbit, ToOrbit.Target);
                if (arcT > 0 && arcT < AngleDelta(VesselOrbit, ApV))
                {
                    ApV.Normalize();
                    var chord = ApV * VesselOrbit.radius - VesselOrbit.pos;
                    var alpha = inclination_correction(VesselOrbit.inclination, chord.magnitude);
                    ToOrbit.Target = QuaternionD.AngleAxis(alpha, Vector3d.Cross(norm, ApV))
                                     * ApV * ToOrbit.TargetR;
                }
                else
                {
                    var n           = Vector3d.Cross(VesselOrbit.pos, ToOrbit.Target.normalized);
                    var inclination = Math.Acos(n.z / n.magnitude) * Mathf.Rad2Deg;
                    var chord       = Vector3d.Exclude(norm, ToOrbit.Target).normalized *VesselOrbit.radius - VesselOrbit.pos;
                    var alpha       = inclination_correction(inclination, chord.magnitude);
                    ToOrbit.Target = QuaternionD.AngleAxis(alpha, Vector3d.Cross(norm, VesselOrbit.pos))
                                     * ToOrbit.Target;
                }
                if (ToOrbit.GravityTurn(ManeuverOffset, ORB.GTurnCurve, ORB.Dist2VelF, ORB.Dtol))
                {
                    break;
                }
                CFG.BR.OffIfOn(BearingMode.Auto);
                var ApAUT = VSL.Physics.UT + VesselOrbit.timeToAp;
                if (ApR > MinPeR + ORB.RadiusOffset)
                {
                    change_ApR(ApAUT);
                }
                else
                {
                    circularize(ApAUT);
                }
                break;

            case Stage.ChangeApA:
                TmpStatus("Achieving target apoapsis...");
                if (CFG.AP1[Autopilot1.Maneuver])
                {
                    break;
                }
                circularize(VSL.Physics.UT + VesselOrbit.timeToAp);
                stage = Stage.Circularize;
                break;

            case Stage.Circularize:
                TmpStatus("Circularization...");
                if (CFG.AP1[Autopilot1.Maneuver])
                {
                    break;
                }
                Disable();
                ClearStatus();
                break;
            }
        }
        protected override void Update()
        {
            switch (stage)
            {
            case Stage.Start:
                if (VSL.LandedOrSplashed || VSL.VerticalSpeed.Absolute < 5)
                {
                    stage = Stage.Liftoff;
                }
                else
                {
                    ToOrbit.StartGravityTurn();
                    stage = Stage.GravityTurn;
                }
                break;

            case Stage.Liftoff:
                if (ToOrbit.Liftoff())
                {
                    break;
                }
                stage = Stage.GravityTurn;
                break;

            case Stage.GravityTurn:
                update_inclination_limits();
                var norm        = VesselOrbit.GetOrbitNormal();
                var needed_norm = Vector3d.Cross(VesselOrbit.pos, ToOrbit.Target.normalized);
                var norm2norm   = Math.Abs(Utils.Angle2(norm, needed_norm) - 90);
                if (norm2norm > 60)
                {
                    var ApV    = VesselOrbit.getRelativePositionAtUT(VSL.Physics.UT + VesselOrbit.timeToAp);
                    var arcApA = AngleDelta(VesselOrbit, ApV);
                    var arcT   = AngleDelta(VesselOrbit, ToOrbit.Target);
                    if (arcT > 0 && arcT < arcApA)
                    {
                        ApV.Normalize();
                        var chord = ApV * VesselOrbit.radius - VesselOrbit.pos;
                        var alpha = inclination_correction(VesselOrbit.inclination, chord.magnitude);
                        var axis  = Vector3d.Cross(norm, ApV);
                        ToOrbit.Target = QuaternionD.AngleAxis(alpha, axis) * ApV * ToOrbit.TargetR;
                    }
                    else
                    {
                        var inclination = Math.Acos(needed_norm.z / needed_norm.magnitude) * Mathf.Rad2Deg;
                        var chord       = Vector3d.Exclude(norm, ToOrbit.Target).normalized *VesselOrbit.radius - VesselOrbit.pos;
                        var alpha       = inclination_correction(inclination, chord.magnitude);
                        var axis        = Vector3d.Cross(norm, VesselOrbit.pos.normalized);
                        if (arcT < 0)
                        {
                            alpha = -alpha;
                        }
                        ToOrbit.Target = QuaternionD.AngleAxis(alpha, axis) * ToOrbit.Target;
                    }
                }
                if (ToOrbit.GravityTurn(C.Dtol))
                {
                    break;
                }
                CFG.BR.OffIfOn(BearingMode.Auto);
                var ApAUT = VSL.Physics.UT + VesselOrbit.timeToAp;
                if (ApR > ToOrbit.MaxApR)
                {
                    change_ApR(ApAUT);
                }
                else
                {
                    circularize(ApAUT);
                }
                break;

            case Stage.ChangeApA:
                TmpStatus("Achieving target apoapsis...");
                if (CFG.AP1[Autopilot1.Maneuver])
                {
                    break;
                }
                circularize(VSL.Physics.UT + VesselOrbit.timeToAp);
                stage = Stage.Circularize;
                break;

            case Stage.Circularize:
                TmpStatus("Circularization...");
                if (CFG.AP1[Autopilot1.Maneuver])
                {
                    break;
                }
                Disable();
                ClearStatus();
                break;
            }
        }
        protected override void Update()
        {
            switch (stage)
            {
            case Stage.Start:
                if (VSL.LandedOrSplashed || VSL.VerticalSpeed.Absolute < 5)
                {
                    stage = Stage.Liftoff;
                }
                else
                {
                    ToOrbit.StartGravityTurn();
                    inclinationPID.Reset();
                    stage = Stage.GravityTurn;
                }
                break;

            case Stage.Liftoff:
                if (ToOrbit.Liftoff())
                {
                    break;
                }
                inclinationPID.Reset();
                stage = Stage.GravityTurn;
                break;

            case Stage.GravityTurn:
                update_inclination_limits();
                var orbitNormal      = VesselOrbit.GetOrbitNormal();
                var targetNormalized = ToOrbit.Target.normalized;
                var vsl2TargetNormal = Vector3d.Cross(VesselOrbit.pos, targetNormalized);
                var norm2norm        = Math.Abs(Utils.Angle2(orbitNormal, vsl2TargetNormal) - 90);
                if (norm2norm > 60)
                {
                    var ApV     = VesselOrbit.getRelativePositionAtUT(VSL.Physics.UT + VesselOrbit.timeToAp);
                    var arcApA  = Utils.Angle2(VesselOrbit.pos, ApV);
                    var arcApAT = Utils.Angle2(ApV, ToOrbit.Target);
                    if (arcApAT < arcApA)
                    {
                        ToOrbit.Target = QuaternionD.AngleAxis(arcApA - arcApAT, vsl2TargetNormal) * ToOrbit.Target;
                    }
                    var inclination = Math.Acos(vsl2TargetNormal.z / vsl2TargetNormal.magnitude) * Mathf.Rad2Deg;
                    inclinationPID.Update((float)inclination_error(inclination));
                    var axis = Vector3d.Cross(vsl2TargetNormal, targetNormalized);
                    ToOrbit.Target = QuaternionD.AngleAxis(inclinationPID.Action, axis) * ToOrbit.Target;
                }
                if (ToOrbit.GravityTurn(C.Dtol))
                {
                    break;
                }
                CFG.BR.OffIfOn(BearingMode.Auto);
                var ApAUT = VSL.Physics.UT + VesselOrbit.timeToAp;
                if (ApR > ToOrbit.MaxApR)
                {
                    change_ApR(ApAUT);
                }
                else
                {
                    circularize(ApAUT);
                }
                break;

            case Stage.ChangeApA:
                TmpStatus("Achieving target apoapsis...");
                if (CFG.AP1[Autopilot1.Maneuver])
                {
                    break;
                }
                circularize(VSL.Physics.UT + VesselOrbit.timeToAp);
                stage = Stage.Circularize;
                break;

            case Stage.Circularize:
                TmpStatus("Circularization...");
                if (CFG.AP1[Autopilot1.Maneuver])
                {
                    break;
                }
                Disable();
                ClearStatus();
                break;
            }
        }
Exemplo n.º 19
0
        protected bool do_land()
        {
            if (VSL.LandedOrSplashed)
            {
                THR.Throttle = 0;
                SetTarget();
                ClearStatus();
                CFG.AP2.Off();
                return(true);
            }
            VSL.Engines.ActivateEngines();
            if (VSL.Engines.MaxThrustM.Equals(0) && !VSL.Engines.HaveNextStageEngines)
            {
                landing_stage = LandingStage.HardLanding;
            }
            landing_deadzone = VSL.Geometry.D + CFG.Target.AbsRadius;
            if (VSL.vessel.dynamicPressurekPa > 0)
            {
                if (!dP_up_timer.RunIf(VSL.Controls.AttitudeError > last_Err ||
                                       Mathf.Abs(VSL.Controls.AttitudeError - last_Err) < 0.01f))
                {
                    dP_down_timer.RunIf(VSL.Controls.AttitudeError < last_Err &&
                                        VSL.vessel.dynamicPressurekPa < last_dP);
                }
            }
            else
            {
                dP_threshold = LTRJ.MaxDPressure;
            }
            rel_dP   = VSL.vessel.dynamicPressurekPa / dP_threshold;
            last_Err = VSL.Controls.AttitudeError;
            float    rel_Ve;
            double   terminal_velocity;
            Vector3d brake_pos, brake_vel, obt_vel;

            switch (landing_stage)
            {
            case LandingStage.Wait:
                Status("Preparing for deceleration...");
                THR.Throttle = 0;
                update_trajectory();
                nose_to_target();
                rel_altitude_if_needed();
                obt_vel   = VesselOrbit.getOrbitalVelocityAtUT(trajectory.BrakeStartUT);
                brake_pos = VesselOrbit.getRelativePositionAtUT(trajectory.BrakeStartUT);
                brake_vel = corrected_brake_velocity(obt_vel, brake_pos);
                brake_vel = corrected_brake_direction(brake_vel, brake_pos.xzy);
                CFG.AT.OnIfNot(Attitude.Custom);
                ATC.SetThrustDirW(brake_vel);
                VSL.Info.Countdown = trajectory.BrakeEndUT - VSL.Physics.UT - 1
                                     - Math.Max(MatchVelocityAutopilot.BrakingOffset((float)obt_vel.magnitude, VSL, out VSL.Info.TTB),
                                                LTRJ.MinBrakeOffset * (1 - Utils.ClampH(Body.atmDensityASL, 1)));
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                if (obstacle_ahead(trajectory) > 0)
                {
                    decelerate(true); break;
                }
                if (VSL.Info.Countdown <= rel_dP)
                {
                    decelerate(false); break;
                }
                if (VSL.Controls.CanWarp)
                {
                    VSL.Controls.WarpToTime = VSL.Physics.UT + VSL.Info.Countdown;
                }
                else
                {
                    VSL.Controls.StopWarp();
                }
                break;

            case LandingStage.Decelerate:
                rel_altitude_if_needed();
                update_trajectory();
                nose_to_target();
                if (Working)
                {
                    Status("red", "Possible collision detected.");
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                    Executor.Execute(VSL.Physics.Up * 10);
                    if (obstacle_ahead(trajectory) > 0)
                    {
                        CollisionTimer.Reset(); break;
                    }
                    if (!CollisionTimer.TimePassed)
                    {
                        break;
                    }
                    start_landing();
                    break;
                }
                else
                {
                    Status("white", "Decelerating. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    compute_terminal_velocity();
                    if (VSL.Controls.HaveControlAuthority)
                    {
                        DecelerationTimer.Reset();
                    }
                    if (Vector3d.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.WorldPos(Body) - VSL.Physics.wCoM) < 0)
                    {
                        if (Executor.Execute(-VSL.vessel.srf_velocity, LTRJ.BrakeEndSpeed))
                        {
                            break;
                        }
                    }
                    else if (!DecelerationTimer.TimePassed &&
                             trajectory.DistanceToTarget > landing_deadzone &&
                             Vector3d.Dot(CFG.Target.VectorTo(trajectory.SurfacePoint, Body), VSL.HorizontalSpeed.Vector) > 0)
                    {
                        brake_vel = corrected_brake_velocity(VesselOrbit.vel, VesselOrbit.pos);
                        brake_vel = corrected_brake_direction(brake_vel, VesselOrbit.pos.xzy);
                        //this is nice smoothing, but is dangerous on a low decending trajectory
                        VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        if (VSL.Info.Countdown - VSL.Torque.MaxCurrent.TurnTime - VSL.vessel.dynamicPressurekPa > VSL.Info.TTB)
                        {
                            brake_vel = brake_vel.normalized * VSL.HorizontalSpeed.Absolute * Utils.ClampH(trajectory.DistanceToTarget / CFG.Target.DistanceTo(VSL.vessel), 1);
                        }
                        if (Executor.Execute(-brake_vel, (float)Utils.ClampL(LTRJ.BrakeEndSpeed * Body.GeeASL, GLB.THR.MinDeltaV)))
                        {
                            break;
                        }
                    }
                }
                landing_stage = LandingStage.Coast;
                break;

            case LandingStage.Coast:
                Status("white", "Coasting. Landing site error: {0}", Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                THR.Throttle = 0;
                update_trajectory();
                nose_to_target();
                setup_for_deceleration();
                terminal_velocity = compute_terminal_velocity();
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                correct_landing_site();
                VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                VSL.Info.Countdown -= Math.Max(VSL.Info.TTB + VSL.Torque.NoEngines.TurnTime + VSL.vessel.dynamicPressurekPa, TRJ.ManeuverOffset);
                if (VSL.Info.Countdown <= 0)
                {
                    Working = false;
                    rel_Ve  = VSL.Engines.RelVeASL;
                    if (rel_Ve <= 0)
                    {
                        Message(10, "Not enough thrust to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    if (!(VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                    {
                        Message(10, "Lacking control authority to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve);
                    if (!CheatOptions.InfinitePropellant &&
                        (fuel_needed >= fuel_left ||
                         VSL.Engines.MaxHoverTimeASL(fuel_left - fuel_needed) < LTRJ.HoverTimeThreshold))
                    {
                        Message(10, "Not enough fuel to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    landing_stage = LandingStage.SoftLanding;
                }
                break;

            case LandingStage.HardLanding:
                Status("yellow", "Emergency Landing...");
                set_destination_vector();
                update_trajectory();
                VSL.BrakesOn();
                CFG.BR.Off();
                setup_for_deceleration();
                terminal_velocity = compute_terminal_velocity();
                if (VSL.Engines.MaxThrustM > 0 &&
                    (VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                {
                    rel_Ve = VSL.Engines.RelVeASL;
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = rel_Ve > 0? VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve) : fuel_left * 2;
                    VSL.Info.Countdown -= fuel_left > fuel_needed?
                                          VSL.Engines.TTB((float)terminal_velocity) :
                                              VSL.Engines.TTB(VSL.Engines.DeltaV(fuel_left));

                    if ((VSL.Info.Countdown < 0 &&
                         (!VSL.OnPlanetParams.HaveParachutes ||
                          VSL.OnPlanetParams.ParachutesActive && VSL.OnPlanetParams.ParachutesDeployed)))
                    {
                        THR.Throttle = VSL.VerticalSpeed.Absolute < -5? 1 : VSL.OnPlanetParams.GeeVSF;
                    }
                    else
                    {
                        THR.Throttle = 0;
                    }
                    Status("yellow", "Not enough fuel to land properly.\nWill deceletate as much as possible before impact...");
                }
                if (Body.atmosphere && VSL.OnPlanetParams.HaveUsableParachutes)
                {
                    VSL.OnPlanetParams.ActivateParachutes();
                    if (!VSL.OnPlanetParams.ParachutesActive)
                    {
                        ATC.SetCustomRotationW(VSL.Geometry.MaxAreaDirection, VSL.Physics.Up);
                        StageTimer.RunIf(Body.atmosphere &&                         //!VSL.Controls.HaveControlAuthority &&
                                         VSL.vessel.currentStage - 1 > VSL.OnPlanetParams.NearestParachuteStage &&
                                         VSL.vessel.dynamicPressurekPa > LTRJ.DropBallastThreshold * PressureASL &&
                                         VSL.vessel.mach > LTRJ.MachThreshold);
                        if (CFG.AutoParachutes)
                        {
                            Status("yellow", "Waiting for safe speed to deploy parachutes.\n" +
                                   "Trying to decelerate using drag...");
                        }
                        else
                        {
                            Status("red", "Automatic parachute deployment is disabled.\nActivate parachutes manually when needed.");
                        }
                    }
                }
                if (!VSL.OnPlanetParams.HaveParachutes &&
                    !VSL.Engines.HaveNextStageEngines &&
                    (VSL.Engines.MaxThrustM.Equals(0) || !VSL.Controls.HaveControlAuthority))
                {
                    if (Body.atmosphere)
                    {
                        ATC.SetCustomRotationW(VSL.Geometry.MaxAreaDirection, VSL.Physics.Up);
                    }
                    Status("red", "Crash is imminent.\nImpact speed: {0}", Utils.formatBigValue((float)terminal_velocity, "m/s"));
                }
                break;

            case LandingStage.SoftLanding:
                THR.Throttle = 0;
                set_destination_vector();
                update_trajectory();
                setup_for_deceleration();
                compute_terminal_velocity();
                nose_to_target();
                if (Working)
                {
                    Status("white", "Final deceleration. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    ATC.SetThrustDirW(correction_direction());
                    if (VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        var brake_spd  = Mathf.Max(VSL.HorizontalSpeed.Absolute, -VSL.VerticalSpeed.Absolute);
                        var min_thrust = Utils.Clamp(brake_spd / (VSL.Engines.MaxAccel - VSL.Physics.G) /
                                                     Utils.ClampL((float)VSL.Info.Countdown, 0.01f),
                                                     VSL.OnPlanetParams.GeeVSF, 1);
                        THR.Throttle = Utils.Clamp(brake_spd / LTRJ.BrakeThrustThreshod, min_thrust, 1);
                    }
                    else
                    {
                        THR.Throttle = 1;
                    }
                    if (VSL.vessel.srfSpeed > LTRJ.BrakeEndSpeed)
                    {
                        Working = THR.Throttle.Equals(1) || VSL.Info.Countdown < 10;
                        break;
                    }
                }
                else
                {
                    var turn_time = VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError);
                    correct_attitude_with_thrusters(turn_time);
                    correct_landing_site();
                    VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                    VSL.Info.Countdown -= VSL.Info.TTB + turn_time + LTRJ.FinalBrakeOffset;
                    if (VSL.Controls.InvAlignmentFactor > 0.5)
                    {
                        Status("white", "Final deceleration: correcting attitude.\nLanding site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    }
                    else
                    {
                        Status("white", "Final deceleration: waiting for the burn.\nLanding site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    }
                    Working = VSL.Info.Countdown <= 0 || VSL.vessel.srfSpeed < LTRJ.BrakeEndSpeed;
                    break;
                }
                THR.Throttle = 0;
                if (CFG.Target.DistanceTo(VSL.vessel) - VSL.Geometry.R > LTRJ.Dtol)
                {
                    approach();
                }
                else
                {
                    land();
                }
                break;

            case LandingStage.Approach:
                Status("Approaching the target...");
                set_destination_vector();
                if (!CFG.Nav[Navigation.GoToTarget])
                {
                    land();
                }
                break;

            case LandingStage.Land:
                set_destination_vector();
                break;
            }
            return(false);
        }
        protected override void Update()
        {
            if (!IsActive)
            {
                CFG.AP2.OffIfOn(Autopilot2.BallisticJump); return;
            }
            if (landing)
            {
                do_land(); return;
            }
            switch (stage)
            {
            case Stage.Start:
                CFG.HF.OnIfNot(HFlight.Stop);
                CFG.AltitudeAboveTerrain = true;
                CFG.VF.OnIfNot(VFlight.AltitudeControl);
                if (VSL.LandedOrSplashed || VSL.Altitude.Relative < StartAltitude)
                {
                    CFG.DesiredAltitude = StartAltitude;
                }
                else
                {
                    CFG.DesiredAltitude = VSL.Altitude.Relative;
                }
                if (VSL.Altitude.Relative > StartAltitude - 5)
                {
                    compute_initial_trajectory();
                }
                else
                {
                    Status("Gaining initial altitude...");
                }
                break;

            case Stage.Compute:
                if (!trajectory_computed())
                {
                    break;
                }
                var obst = obstacle_ahead(trajectory);
                if (obst > 0)
                {
                    StartAltitude += (float)obst + BJ.ObstacleOffset;
                    stage          = Stage.Start;
                }
                else if (check_initial_trajectory())
                {
                    accelerate();
                }
                else
                {
                    stage = Stage.Wait;
                }
                break;

            case Stage.Wait:
                if (!string.IsNullOrEmpty(TCAGui.StatusMessage))
                {
                    break;
                }
                accelerate();
                break;

            case Stage.Accelerate:
                if (!VSL.HasManeuverNode)
                {
                    CFG.AP2.Off(); break;
                }
                if (VSL.Controls.AlignmentFactor > 0.9 || !CFG.VSCIsActive)
                {
                    CFG.DisableVSC();
                    if (!Executor.Execute(VSL.FirstManeuverNode.GetBurnVector(VesselOrbit), 10))
                    {
                        fine_tune_approach();
                    }
                    Status("white", "Accelerating...");
                }
                break;

            case Stage.CorrectTrajectory:
                if (!trajectory_computed())
                {
                    break;
                }
                add_correction_node_if_needed();
                stage = Stage.Coast;
                break;

            case Stage.Coast:
                var ap_ahead = VesselOrbit.ApAhead();
                if (CFG.AP1[Autopilot1.Maneuver])
                {
                    if (ap_ahead)
                    {
                        Status("Correcting trajectory...");
                        break;
                    }
                }
                Status("Coasting...");
                if (ap_ahead && !correct_trajectory())
                {
                    break;
                }
                stage = Stage.None;
                start_landing();
                break;
            }
        }
Exemplo n.º 21
0
        protected bool do_land()
        {
            if (VSL.LandedOrSplashed)
            {
                stop_aerobraking();
                THR.Throttle = 0;
                SetTarget();
                ClearStatus();
                CFG.AP2.Off();
                return(true);
            }
            update_trajectory();
            VSL.Engines.ActivateEngines();
            NoEnginesTimer.RunIf(VSL.Engines.MaxThrustM.Equals(0) && !VSL.Engines.HaveNextStageEngines);
            landing_deadzone = VSL.Geometry.D + CFG.Target.AbsRadius;
            if (VSL.vessel.dynamicPressurekPa > 0)
            {
                if (!dP_up_timer.RunIf(VSL.Controls.AttitudeError > last_Err ||
                                       Mathf.Abs(VSL.Controls.AttitudeError - last_Err) < 0.01f))
                {
                    dP_down_timer.RunIf(VSL.Controls.AttitudeError < last_Err &&
                                        VSL.vessel.dynamicPressurekPa < last_dP);
                }
            }
            else
            {
                dP_threshold = LTRJ.MaxDPressure;
            }
            rel_dP   = VSL.vessel.dynamicPressurekPa / dP_threshold;
            last_Err = VSL.Controls.AttitudeError;
            float    rel_Ve;
            Vector3d brake_pos, brake_vel, obt_vel;
            var      vessel_within_range   = CFG.Target.DistanceTo(VSL.vessel) < LTRJ.Dtol;
            var      vessel_after_target   = Vector3.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.VectorTo(VSL.vessel)) >= 0;
            var      target_within_range   = trajectory.DistanceToTarget < LTRJ.Dtol;
            var      landing_before_target = trajectory.DeltaR > 0;
            var      terminal_velocity     = compute_terminal_velocity();;

            switch (landing_stage)
            {
            case LandingStage.Wait:
                Status("Preparing for deceleration...");
                THR.Throttle = 0;
                nose_to_target();
                rel_altitude_if_needed();
                obt_vel   = VesselOrbit.getOrbitalVelocityAtUT(trajectory.BrakeStartUT);
                brake_pos = VesselOrbit.getRelativePositionAtUT(trajectory.BrakeStartUT);
                brake_vel = corrected_brake_velocity(obt_vel, brake_pos);
                brake_vel = corrected_brake_direction(brake_vel, brake_pos.xzy);
                CFG.AT.OnIfNot(Attitude.Custom);
                ATC.SetThrustDirW(brake_vel);
                var offset = MatchVelocityAutopilot.BrakingOffset((float)obt_vel.magnitude, VSL, out VSL.Info.TTB);
                offset             = Mathf.Lerp(VSL.Info.TTB, offset, Utils.Clamp(VSL.Engines.TMR - 0.1f, 0, 1));
                VSL.Info.Countdown = trajectory.BrakeEndUT - VSL.Physics.UT - 1
                                     - Math.Max(offset, LTRJ.MinBrakeOffset * (1 - Utils.ClampH(Body.atmDensityASL, 1)));
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                if (obstacle_ahead(trajectory) > 0)
                {
                    decelerate(true); break;
                }
                if (VSL.Info.Countdown <= rel_dP ||
                    will_overheat(trajectory.GetAtmosphericCurve(5, VSL.Physics.UT + TRJ.ManeuverOffset)))
                {
                    decelerate(false); break;
                }
                if (VSL.Controls.CanWarp)
                {
                    VSL.Controls.WarpToTime = VSL.Physics.UT + VSL.Info.Countdown;
                }
                else
                {
                    VSL.Controls.StopWarp();
                }
                if (CorrectTarget && VSL.Info.Countdown < CorrectionOffset)
                {
                    scan_for_landing_site();
                }
                break;

            case LandingStage.Decelerate:
                rel_altitude_if_needed();
                CFG.BR.Off();
                if (Working)
                {
                    Status("red", "Possible collision detected.");
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                    Executor.Execute(VSL.Physics.Up * 10);
                    if (obstacle_ahead(trajectory) > 0)
                    {
                        CollisionTimer.Reset(); break;
                    }
                    if (!CollisionTimer.TimePassed)
                    {
                        break;
                    }
                    start_landing();
                    break;
                }
                else
                {
                    Status("white", "Decelerating. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    if (CorrectTarget)
                    {
                        scan_for_landing_site();
                    }
                    do_aerobraking_if_requested();
                    if (VSL.Controls.HaveControlAuthority)
                    {
                        DecelerationTimer.Reset();
                    }
                    if (Vector3d.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.WorldPos(Body) - VSL.Physics.wCoM) < 0)
                    {
                        if (Executor.Execute(-VSL.vessel.srf_velocity, LTRJ.BrakeEndSpeed))
                        {
                            break;
                        }
                    }
                    else if (!DecelerationTimer.TimePassed &&
                             trajectory.DistanceToTarget > landing_deadzone &&
                             Vector3d.Dot(CFG.Target.VectorTo(trajectory.SurfacePoint, Body), VSL.HorizontalSpeed.Vector) > 0)
                    {
                        THR.Throttle = 0;
                        brake_vel    = corrected_brake_velocity(VesselOrbit.vel, VesselOrbit.pos);
                        brake_vel    = corrected_brake_direction(brake_vel, VesselOrbit.pos.xzy);
                        VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        var aerobraking = rel_dP > 0 && VSL.OnPlanetParams.ParachutesActive;
                        if (!vessel_after_target)
                        {
                            var overheating = rel_dP > 0 &&
                                              VSL.vessel.Parts.Any(p =>
                                                                   p.temperature / p.maxTemp > PhysicsGlobals.TemperatureGaugeThreshold ||
                                                                   p.skinTemperature / p.skinMaxTemp > PhysicsGlobals.TemperatureGaugeThreshold);
                            if (!overheating)
                            {
                                ATC.SetThrustDirW(brake_vel);
                                THR.Throttle = CFG.Target.DistanceTo(VSL.vessel) > trajectory.DistanceToTarget?
                                               (float)Utils.ClampH(trajectory.DistanceToTarget / LTRJ.Dtol / 2, 1) : 1;
                            }
                            else
                            {
                                THR.Throttle = 1;
                            }
                        }
                        if (THR.Throttle > 0 || aerobraking)
                        {
                            break;
                        }
                    }
                }
                if (landing_before_target ||
                    target_within_range && !vessel_within_range)
                {
                    stop_aerobraking();
                }
                landing_stage = LandingStage.Coast;
                break;

            case LandingStage.Coast:
                Status("white", "Coasting. Landing site error: {0}", Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                THR.Throttle = 0;
                nose_to_target();
                setup_for_deceleration();
                if (correct_landing_site())
                {
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                }
                if (landing_before_target ||
                    target_within_range && !vessel_within_range)
                {
                    stop_aerobraking();
                }
                VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                VSL.Info.Countdown -= Math.Max(VSL.Info.TTB + VSL.Torque.NoEngines.TurnTime + VSL.vessel.dynamicPressurekPa, ManeuverOffset);
                if (VSL.Info.Countdown > 0)
                {
                    if (THR.Throttle.Equals(0))
                    {
                        warp_to_coundown();
                    }
                }
                else
                {
                    Working = false;
                    rel_Ve  = VSL.Engines.RelVeASL;
                    if (rel_Ve <= 0)
                    {
                        Message(10, "Not enough thrust for powered landing.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    if (!(VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                    {
                        Message(10, "Lacking control authority to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    var fuel_left         = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed       = VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve);
                    var needed_hover_time = LandASAP? LTRJ.HoverTimeThreshold / 5 : LTRJ.HoverTimeThreshold;
                    if (!CheatOptions.InfinitePropellant &&
                        (fuel_needed >= fuel_left ||
                         VSL.Engines.MaxHoverTimeASL(fuel_left - fuel_needed) < needed_hover_time))
                    {
                        Message(10, "Not enough fuel for powered landing.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
//						Log("Hard Landing. Trajectory:\n{}", trajectory);//debug
                        break;
                    }
                    landing_stage = LandingStage.SoftLanding;
//					Log("Soft Landing. Trajectory:\n{}", trajectory);//debug
                }
                break;

            case LandingStage.HardLanding:
                Status("yellow", VSL.OnPlanetParams.ParachutesActive?
                       "Landing on parachutes..." : "Emergency Landing...");
                set_destination_vector();
                CFG.BR.Off();
                var not_too_hot = VSL.vessel.externalTemperature < VSL.Physics.MinMaxTemperature;
                if (not_too_hot)
                {
                    setup_for_deceleration();
                }

                if (VSL.Engines.MaxThrustM > 0 &&
                    (VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                {
                    rel_Ve = VSL.Engines.RelVeASL;
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = rel_Ve > 0? VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve) : fuel_left * 2;
                    VSL.Info.Countdown -= fuel_left > fuel_needed?
                                          VSL.Engines.TTB((float)terminal_velocity) :
                                              VSL.Engines.TTB(VSL.Engines.DeltaV(fuel_left));

                    if ((VSL.Info.Countdown < 0 &&
                         (!VSL.OnPlanetParams.HaveParachutes ||
                          VSL.OnPlanetParams.ParachutesActive && VSL.OnPlanetParams.ParachutesDeployed)))
                    {
                        THR.Throttle = VSL.VerticalSpeed.Absolute < -5? 1 : VSL.OnPlanetParams.GeeVSF;
                    }
                    else if (VSL.Info.Countdown > 0.5f)
                    {
                        THR.Throttle = 0;
                    }
                    Status("yellow", "Not enough fuel for powered landing.\nWill deceletate as much as possible before impact.");
                }
                if (Body.atmosphere && VSL.OnPlanetParams.HaveUsableParachutes)
                {
                    if (vessel_within_range || vessel_after_target ||
                        trajectory.BrakeEndUT - VSL.Physics.UT < LTRJ.ParachutesDeployOffset)
                    {
                        VSL.OnPlanetParams.ActivateParachutesASAP();
                    }
                    else
                    {
                        VSL.OnPlanetParams.ActivateParachutesBeforeUnsafe();
                    }
                    if (!VSL.OnPlanetParams.ParachutesActive)
                    {
                        //don't push our luck when it's too hot outside
                        if (not_too_hot)
                        {
                            brake_with_drag();
                        }
                        else
                        {
                            CFG.AT.Off();
                            CFG.StabilizeFlight = false;
                            VSL.vessel.ActionGroups.SetGroup(KSPActionGroup.SAS, false);
                        }
                        StageTimer.RunIf(Body.atmosphere &&                         //!VSL.Controls.HaveControlAuthority &&
                                         VSL.vessel.currentStage - 1 > VSL.OnPlanetParams.NearestParachuteStage &&
                                         VSL.vessel.dynamicPressurekPa > LTRJ.DropBallastThreshold * PressureASL &&
                                         VSL.vessel.mach > LTRJ.MachThreshold);
                        if (CFG.AutoParachutes)
                        {
                            Status("yellow", "Waiting for the right moment to deploy parachutes...");
                        }
                        else
                        {
                            Status("red", "Automatic parachute deployment is disabled.\nActivate parachutes manually when needed.");
                        }
                    }
                }
                if (Body.atmosphere)
                {
                    VSL.BrakesOn();
                }
                if (!VSL.OnPlanetParams.HaveParachutes &&
                    !VSL.Engines.HaveNextStageEngines &&
                    (VSL.Engines.MaxThrustM.Equals(0) || !VSL.Controls.HaveControlAuthority))
                {
                    if (Body.atmosphere && not_too_hot)
                    {
                        brake_with_drag();
                    }
                    Status("red", "Crash is imminent.\nVertical impact speed: {0}", Utils.formatBigValue((float)terminal_velocity, "m/s"));
                }
                break;

            case LandingStage.SoftLanding:
                CFG.BR.Off();
                THR.Throttle = 0;
                set_destination_vector();
                setup_for_deceleration();
                if (vessel_within_range || vessel_after_target ||
                    trajectory.BrakeEndUT - VSL.Physics.UT < LTRJ.ParachutesDeployOffset)
                {
                    do_aerobraking_if_requested(true);
                }
                var turn_time = VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError);
                if (!Working)
                {
                    correct_landing_site();
                    correct_attitude_with_thrusters(turn_time);
                    VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                    //VSL.Engines.OnPlanetTTB(VSL.vessel.srf_velocity, VSL.Physics.Up);
                    VSL.Info.Countdown -= VSL.Info.TTB + turn_time;
                    Working             = VSL.Info.Countdown <= 0 || VSL.vessel.srfSpeed < LTRJ.BrakeEndSpeed;        //TODO: is this correct?
                    if (!Working)
                    {
                        if (VSL.Controls.InvAlignmentFactor > 0.5)
                        {
                            Status("white", "Final deceleration: correcting attitude.\nLanding site error: {0}",
                                   Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        }
                        else
                        {
                            Status("white", "Final deceleration: waiting for the burn.\nLanding site error: {0}",
                                   Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        }
                        break;
                    }
                }
                if (Working)
                {
                    ATC.SetThrustDirW(correction_direction());
                    if (!VSL.Controls.HaveControlAuthority)
                    {
                        correct_attitude_with_thrusters(turn_time);
                        if (!VSL.Torque.HavePotentialControlAuthority)
                        {
                            landing_stage = LandingStage.HardLanding;
                        }
                        break;
                    }
                    if (vessel_within_range || VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        var brake_spd  = -VSL.VerticalSpeed.Absolute;
                        var min_thrust = Utils.Clamp(brake_spd / (VSL.Engines.MaxAccel - VSL.Physics.G) /
                                                     Utils.ClampL((float)VSL.Info.Countdown, 0.01f),
                                                     VSL.OnPlanetParams.GeeVSF, 1);
                        THR.Throttle = Utils.Clamp(brake_spd / LTRJ.BrakeThrustThreshod, min_thrust, 1);
                    }
                    else
                    {
                        THR.Throttle = 1;
                    }
                    if (vessel_within_range && VSL.Altitude.Relative > GLB.LND.StopAtH * VSL.Geometry.D ||
                        VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        VSL.Info.Countdown -= VSL.Info.TTB + turn_time;
                        Working             = THR.Throttle > 0.7 || VSL.Info.Countdown < 10;
                        Status("white", "Final deceleration. Landing site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        break;
                    }
                }
                THR.Throttle = 0;
                if (LandASAP)
                {
                    landing_stage = LandingStage.LandHere;
                }
                else
                {
                    stop_aerobraking();
                    if (CFG.Target.DistanceTo(VSL.vessel) - VSL.Geometry.R > LTRJ.Dtol)
                    {
                        approach();
                    }
                    else
                    {
                        land();
                    }
                }
                break;

            case LandingStage.LandHere:
                Status("lime", "Landing...");
                CFG.BR.Off();
                CFG.BlockThrottle        = true;
                CFG.AltitudeAboveTerrain = true;
                CFG.VF.On(VFlight.AltitudeControl);
                CFG.HF.OnIfNot(HFlight.Stop);
                if (CFG.DesiredAltitude >= 0 && !VSL.HorizontalSpeed.MoovingFast)
                {
                    CFG.DesiredAltitude = 0;
                }
                else
                {
                    CFG.DesiredAltitude = Utils.ClampL(VSL.Altitude.Relative / 2, VSL.Geometry.H * 2);
                }
                break;

            case LandingStage.Approach:
                Status("Approaching the target...");
                set_destination_vector();
                if (!CFG.Nav[Navigation.GoToTarget])
                {
                    land();
                }
                break;

            case LandingStage.Land:
                set_destination_vector();
                break;
            }
            return(false);
        }