private void RenderSyncUI(GUIStyle sty, GUIStyle but)
        {
            if (!CheckVessel())
            {
                _flyByWire = false;
                Mode       = UIMode.SELECTED;
            }

            if (GUILayout.Button("Sync Orbits", but, GUILayout.ExpandWidth(true)))
            {
                Mode       = UIMode.SELECTED;
                _flyByWire = false;
            }

            GUILayout.EndVertical();

            GUILayout.BeginHorizontal();
            for (int i = 0; i < NumberOfPredictedSyncPoints; i++)
            {
                if (i != (int)SyncMode)
                {
                    continue;
                }

                if (GUILayout.Button(SyncMode.ToString(), but, GUILayout.ExpandWidth(true)))
                {
                    if (i == NumberOfPredictedSyncPoints - 1)
                    {
                        SyncMode = 0;
                    }
                    else
                    {
                        SyncMode = SyncMode + 1;
                    }
                }
                //GUILayout.Box(SyncMode.ToString(),but);
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginVertical();

            GUILayout.Box("Orbit		ShipToR		TgtToR ", GUILayout.ExpandWidth(true));
            for (int i = 0; i < 4; i++)
            {
                GUILayout.Box(_syncString[i]);
            }

            GUILayout.Label("Closest Approach on Orbit " + _closestApproachOrbit.ToString(), sty);
            GUILayout.Label("Min Separation (sec) : " + _minimumPredictedTimeFromTarget.ToString("f1"), sty);

            if (automation == true)
            {
                if (GUILayout.Button(_autoPhaser ? _autoPhaserState.ToString() : "Auto Sync", but, GUILayout.ExpandWidth(true)))
                {
                    _autoPhaser      = !_autoPhaser;
                    _autoPhaserState = AutoPhaserState.Step1WaitForTargetApsis;
                }
            }
        }
Example #2
0
    private void RenderSyncUI(GUIStyle sty)
    {
        if (!CheckVessel())
        {
            _flyByWire = false;
            Mode = UIMode.SELECTED;
        }

        if (GUILayout.Button("Sync Orbits", sty, GUILayout.ExpandWidth(true)))
        {
            Mode = UIMode.SELECTED;
            _flyByWire = false;
        }

        GUILayout.EndVertical();

        GUILayout.BeginHorizontal();
        for (int i = 0; i < NumberOfPredictedSyncPoints; i++)
        {
            if (i != (int) SyncMode)
                continue;

            if (GUILayout.Button(" ", sty, GUILayout.ExpandWidth(true)))
            {
                if (i == NumberOfPredictedSyncPoints - 1) SyncMode = 0;
                else SyncMode = SyncMode + 1;
            }
            GUILayout.Box(SyncMode.ToString());
        }
        GUILayout.EndHorizontal();
        GUILayout.BeginVertical();

        GUILayout.Box("Orbit		ShipToR		TgtToR ", sty, GUILayout.ExpandWidth(true));
        for (int i = 0; i < 4; i++)
            GUILayout.Box(_syncString[i]);

        GUILayout.Box("Closest Approach on Orbit " + _closestApproachOrbit.ToString());
        GUILayout.Box("Min Separation (sec) : " + _minimumPredictedTimeFromTarget.ToString("f1"));

        if(GUILayout.Button(_autoPhaser ? _autoPhaserState.ToString() : "Auto Sync", sty, GUILayout.ExpandWidth(true)))
        {
            _autoPhaser = !_autoPhaser;
            _autoPhaserState = AutoPhaserState.Step1WaitForTargetApsis;
        }
    }
Example #3
0
    private void DriveShip(FlightCtrlState controls)
    {
        if(!CheckVessel())
            return;

        Vessel selectedVessel = FlightGlobals.Vessels[_selectedVesselIndex] as Vessel;

        if(_autoAlign)
        {
            // Is it time to burn? Find soonest node.
            double timeToBurnAN = vessel.orbit.GetTimeToRelAN(selectedVessel.orbit);
            double timeToBurnDN = vessel.orbit.GetTimeToRelDN(selectedVessel.orbit);

            bool ascendingSoonest = timeToBurnAN < timeToBurnDN;
            double timeToBurnNode = ascendingSoonest ? timeToBurnAN : timeToBurnDN;

            // Figure out which way we want to burn to adjust our inclination.
            _flyByWire = true;
            if(!_autoAlignBurnTriggered)
            {
                if (_relativeInclination < 0.0)
                    PointAt = ascendingSoonest ? Orient.Normal : Orient.AntiNormal;
                else
                    PointAt = ascendingSoonest ? Orient.AntiNormal : Orient.Normal;
            }

            // Do a burn just ahead of the ascending node - in the 5 seconds preceding.
            if ((timeToBurnNode < 10.0 || _autoAlignBurnTriggered) && _headingError.magnitude < 5.0 && Math.Abs(_relativeInclination) > 0.01)
            {
                _autoAlignBurnTriggered = true;
                if (Math.Abs(_relativeInclination) > 0.1)
                {
                    controls.mainThrottle = 1.0f;
                }
                else
                {
                    controls.mainThrottle = 0.25f;
                }
            }
            else
            {
                controls.mainThrottle = 0.0f;
            }

            if (Math.Abs(_relativeInclination) < 0.02)
            {
                _autoAlignBurnTriggered = false;
                _autoAlign = false;
            }
        }

        if (_autoPhaser)
        {
            switch(_autoPhaserState)
            {
                case AutoPhaserState.Step1WaitForTargetApsis:
                    double timeLeft = CalculateTimeTillNextTargetApsis();

                    // Set the PointAt based on who is faster at that point in time.
                    _flyByWire = true;
                    if (vessel.orbit.getOrbitalVelocityAt(timeLeft) > selectedVessel.orbit.getOrbitalVelocityAt(timeLeft))
                        PointAt = Orient.Retrograde;
                    else
                        PointAt = Orient.Prograde;

                    // Advance if it's time.
                    if (timeLeft < 5.0)
                    {
                        _autoPhaserState = AutoPhaserState.Step2BurnToMatchNextApsis;
                        _autoPhaserVelocityGoal = selectedVessel.orbit.getOrbitalVelocityAt(CalculateTimeTillFurtherTargetApsis());
                        _autoPhaseBurnComplete = false;
                    }
                    break;

                case AutoPhaserState.Step2BurnToMatchNextApsis:
                    double predictedVelocity = vessel.orbit.getOrbitalVelocityAt(CalculateTimeTillFurtherTargetApsis());
                    if (_headingError.magnitude < 5.0 && !_autoPhaseBurnComplete)
                    {
                        controls.mainThrottle = 1;
                    }
                    else
                    {
                        controls.mainThrottle = 0;
                    }

                    // Advance to next state if we hit our goal.
                    if (Math.Abs(predictedVelocity - _autoPhaserVelocityGoal) < 10)
                    {
                        _autoPhaseBurnComplete = true;
                        controls.mainThrottle = 0;

                    }

                    // Wait till we pass the apsis so we don't double advance.
                    if (_autoPhaseBurnComplete && CalculateTimeTillNextTargetApsis() > 10.0)
                        _autoPhaserState = AutoPhaserState.Step3WaitForTargetApsis;
                    break;

                case AutoPhaserState.Step3WaitForTargetApsis:
                    timeLeft = CalculateTimeTillNextTargetApsis();

                    // Set the PointAt based on who is faster at that point in time.
                    _flyByWire = true;
                    PointAt = Orient.Prograde;

                    // Advance if it's time.
                    if (timeLeft < 5.0)
                    {
                        _autoPhaserState = AutoPhaserState.Step4BurnToRendezvous;
                    }

                    break;

                case AutoPhaserState.Step4BurnToRendezvous:

                    // TODO: Make sure we are only considering the apsis that
                    // is spatially similar to ours, otherwise we get in sync
                    // orbitally but go into step 5 super far away.
                    double timeToRendezvous = 0.0, minDeltaT = 0.0;
                    CalculateNearestRendezvousInSeconds(out timeToRendezvous, out minDeltaT);

                    if (minDeltaT > 5)
                        controls.mainThrottle = 0.25f;
                    else
                    {
                        controls.mainThrottle = 0.0f;
                        _autoPhaserState = AutoPhaserState.Step5WaitForRendezvous;
                    }
                    break;

                case AutoPhaserState.Step5WaitForRendezvous:
                    timeToRendezvous = 0.0;
                    minDeltaT = 0.0;
                    CalculateNearestRendezvousInSeconds(out timeToRendezvous, out minDeltaT);

                    if(timeToRendezvous < 2)
                        _autoPhaserState = AutoPhaserState.Step6BurnToMatchVelocity;

                    break;

                case AutoPhaserState.Step6BurnToMatchVelocity:
                    if(_relativeVelocity.magnitude > 5)
                    {
                        _flyByWire = true;
                        PointAt = Orient.RelativeVelocityAway;

                        if(_headingError.magnitude < 5)
                        {
                            if (_relativeVelocity.magnitude > 15)
                                controls.mainThrottle = 1.0f;
                            else
                                controls.mainThrottle = 0.2f;
                        }

                    }
                    else
                    {
                        // All done!
                        controls.mainThrottle = 0.0f;
                        _autoPhaser = false;
                    }
                    break;

            }
        }

        if(_killRelativeVelocity)
        {
            controls.X = Mathf.Clamp(-_localRelativeVelocity.x * 8.0f, -1.0f, 1.0f);
            controls.Y = Mathf.Clamp(-_localRelativeVelocity.z * 8.0f, -1.0f, 1.0f);
            controls.Z = Mathf.Clamp(-_localRelativeVelocity.y * 8.0f, -1.0f, 1.0f);

            if (_localRelativeVelocity.magnitude < 0.1)
                _killRelativeVelocity = false;
        }
        else if (_homeOnRelativePosition)
        {
            Vector3 targetGoalPos = new Vector3(0.0f, 2.0f, 0.0f);
            targetGoalPos = selectedVessel.transform.localToWorldMatrix.MultiplyPoint(targetGoalPos);
            targetGoalPos = vessel.transform.worldToLocalMatrix.MultiplyPoint(targetGoalPos);

            Vector3 relPos = targetGoalPos;
            Vector4 goalVel = Vector3.zero;

            float velGoal = 0.1f;

            if (_targetDistance > 2.0f)
                velGoal = 0.3f;
            else if (_targetDistance > 10.0f)
                velGoal = 0.5f;
            else if (_targetDistance > 50.0f)
                velGoal = 1.0f;
            else if (_targetDistance > 150.0f)
                velGoal = 3.0f;

            if(Mathf.Abs(relPos.x) > 0.01f)
                goalVel.x = -Mathf.Sign(relPos.x) * velGoal;

            if (Mathf.Abs(relPos.y) > 0.01f)
                goalVel.y = -Mathf.Sign(relPos.y) * velGoal;

            if (Mathf.Abs(relPos.z) > 0.01f)
                goalVel.z = -Mathf.Sign(relPos.z) * velGoal;

            controls.X = Mathf.Clamp((goalVel.x - _localRelativeVelocity.x) * 8.0f, -1, 1);
            controls.Y = Mathf.Clamp((goalVel.z - _localRelativeVelocity.z) * 8.0f, -1, 1);
            controls.Z = Mathf.Clamp((goalVel.y - _localRelativeVelocity.y) * 8.0f, -1, 1);
        }

        if (!_flyByWire)
            return;

        Quaternion tgt = Quaternion.LookRotation(_tgtFwd, _tgtUp);
        Quaternion delta =
            Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.transform.rotation) * tgt);

        _headingError =
            new Vector3((delta.eulerAngles.x > 180) ? (delta.eulerAngles.x - 360.0F) : delta.eulerAngles.x,
                        (delta.eulerAngles.y > 180) ? (delta.eulerAngles.y - 360.0F) : delta.eulerAngles.y,
                        (delta.eulerAngles.z > 180) ? (delta.eulerAngles.z - 360.0F) : delta.eulerAngles.z) / 180.0F;
        _integral += _headingError * TimeWarp.fixedDeltaTime;
        _deriv = (_headingError - _prevErr) / TimeWarp.fixedDeltaTime;
        _act = Kp * _headingError + Ki * _integral + Kd * _deriv;
        _prevErr = _headingError;

        controls.pitch = Mathf.Clamp(controls.pitch + _act.x, -1.0F, 1.0F);
        controls.yaw = Mathf.Clamp(controls.yaw - _act.y, -1.0F, 1.0F);
        controls.roll = Mathf.Clamp(controls.roll + _act.z, -1.0F, 1.0F);
    }
        private void DriveShip(FlightCtrlState controls)
        {
            if (!CheckVessel())
            {
                return;
            }

            Vessel selectedVessel = FlightGlobals.Vessels[_selectedVesselIndex] as Vessel;

            if (_autoAlign)
            {
                // Is it time to burn? Find soonest node.
                double timeToBurnAN = part.vessel.orbit.GetTimeToRelAN(selectedVessel.orbit);
                double timeToBurnDN = part.vessel.orbit.GetTimeToRelDN(selectedVessel.orbit);

                bool   ascendingSoonest = timeToBurnAN < timeToBurnDN;
                double timeToBurnNode   = ascendingSoonest ? timeToBurnAN : timeToBurnDN;


                if (timeToBurnNode > 30)
                {
                    core.warpTo(this, timeToBurnNode - 30, warpLookaheadTimes);
                }

                // Figure out which way we want to burn to adjust our inclination.
                _flyByWire = true;
                if (!_autoAlignBurnTriggered)
                {
                    if (_relativeInclination < 0.0)
                    {
                        PointAt = ascendingSoonest ? Orient.Normal : Orient.AntiNormal;
                    }
                    else
                    {
                        PointAt = ascendingSoonest ? Orient.AntiNormal : Orient.Normal;
                    }
                }

                // Do a burn just ahead of the ascending node - in the 5 seconds preceding.
                if ((timeToBurnNode < 10.0 || _autoAlignBurnTriggered) && _headingError.magnitude < 5.0 && Math.Abs(_relativeInclination) > 0.01)
                {
                    _autoAlignBurnTriggered = true;
                    if (Math.Abs(_relativeInclination) > 0.1)
                    {
                        controls.mainThrottle = 1.0f;
                    }
                    else
                    {
                        controls.mainThrottle = 0.25f;
                    }
                }
                else
                {
                    controls.mainThrottle = 0.0f;
                }

                if (Math.Abs(_relativeInclination) < 0.02)
                {
                    _autoAlignBurnTriggered = false;
                    _autoAlign = false;
                }
            }

            if (_autoPhaser)
            {
                switch (_autoPhaserState)
                {
                case AutoPhaserState.Step1WaitForTargetApsis:
                    double timeLeft = CalculateTimeTillNextTargetApsis();

                    // Set the PointAt based on who is faster at that point in time.
                    _flyByWire = true;
                    if (part.vessel.orbit.getOrbitalSpeedAt(timeLeft) > selectedVessel.orbit.getOrbitalSpeedAt(timeLeft))
                    {
                        PointAt = Orient.Retrograde;
                    }
                    else
                    {
                        PointAt = Orient.Prograde;
                    }

                    // Advance if it's time.
                    if (timeLeft < 5.0)
                    {
                        _autoPhaserState        = AutoPhaserState.Step2BurnToMatchNextApsis;
                        _autoPhaserVelocityGoal = selectedVessel.orbit.getOrbitalSpeedAt(CalculateTimeTillFurtherTargetApsis());
                        _autoPhaseBurnComplete  = false;
                    }
                    break;

                case AutoPhaserState.Step2BurnToMatchNextApsis:
                    double predictedVelocity = part.vessel.orbit.getOrbitalSpeedAt(CalculateTimeTillFurtherTargetApsis());
                    if (_headingError.magnitude < 5.0 && !_autoPhaseBurnComplete)
                    {
                        controls.mainThrottle = 1;
                    }
                    else
                    {
                        controls.mainThrottle = 0;
                    }

                    // Advance to next state if we hit our goal.
                    if (Math.Abs(predictedVelocity - _autoPhaserVelocityGoal) < 10)
                    {
                        _autoPhaseBurnComplete = true;
                        controls.mainThrottle  = 0;
                    }

                    // Wait till we pass the apsis so we don't double advance.
                    if (_autoPhaseBurnComplete && CalculateTimeTillNextTargetApsis() > 10.0)
                    {
                        _autoPhaserState = AutoPhaserState.Step3WaitForTargetApsis;
                    }
                    break;

                case AutoPhaserState.Step3WaitForTargetApsis:
                    timeLeft = CalculateTimeTillNextTargetApsis();

                    // Set the PointAt based on who is faster at that point in time.
                    _flyByWire = true;
                    PointAt    = Orient.Prograde;

                    // Advance if it's time.
                    if (timeLeft < 5.0)
                    {
                        _autoPhaserState = AutoPhaserState.Step4BurnToRendezvous;
                    }

                    break;

                case AutoPhaserState.Step4BurnToRendezvous:

                    // TODO: Make sure we are only considering the apsis that
                    // is spatially similar to ours, otherwise we get in sync
                    // orbitally but go into step 5 super far away.
                    double timeToRendezvous = 0.0, minDeltaT = 0.0;
                    CalculateNearestRendezvousInSeconds(out timeToRendezvous, out minDeltaT);

                    if (minDeltaT > 5)
                    {
                        controls.mainThrottle = 0.25f;
                    }
                    else
                    {
                        controls.mainThrottle = 0.0f;
                        _autoPhaserState      = AutoPhaserState.Step5WaitForRendezvous;
                    }
                    break;

                case AutoPhaserState.Step5WaitForRendezvous:
                    timeToRendezvous = 0.0;
                    minDeltaT        = 0.0;
                    CalculateNearestRendezvousInSeconds(out timeToRendezvous, out minDeltaT);

                    if (timeToRendezvous < 2)
                    {
                        _autoPhaserState = AutoPhaserState.Step6BurnToMatchVelocity;
                    }

                    break;

                case AutoPhaserState.Step6BurnToMatchVelocity:
                    if (_relativeVelocity.magnitude > 5)
                    {
                        _flyByWire = true;
                        PointAt    = Orient.RelativeVelocityAway;

                        if (_headingError.magnitude < 5)
                        {
                            if (_relativeVelocity.magnitude > 15)
                            {
                                controls.mainThrottle = 1.0f;
                            }
                            else
                            {
                                controls.mainThrottle = 0.2f;
                            }
                        }
                    }
                    else
                    {
                        // All done!
                        controls.mainThrottle = 0.0f;
                        _autoPhaser           = false;
                    }
                    break;
                }
            }

            if (_killRelativeVelocity)
            {
                controls.X = Mathf.Clamp(-_localRelativeVelocity.x * 8.0f, -1.0f, 1.0f);
                controls.Y = Mathf.Clamp(-_localRelativeVelocity.z * 8.0f, -1.0f, 1.0f);
                controls.Z = Mathf.Clamp(-_localRelativeVelocity.y * 8.0f, -1.0f, 1.0f);

                if (_localRelativeVelocity.magnitude < 0.1)
                {
                    _killRelativeVelocity = false;
                }
            }
            else if (_homeOnRelativePosition)
            {
                Vector3 targetGoalPos = new Vector3(0.0f, 2.0f, 0.0f);
                targetGoalPos = selectedVessel.transform.localToWorldMatrix.MultiplyPoint(targetGoalPos);
                targetGoalPos = part.vessel.transform.worldToLocalMatrix.MultiplyPoint(targetGoalPos);

                Vector3 relPos  = targetGoalPos;
                Vector4 goalVel = Vector3.zero;

                float velGoal = 0.1f;

                if (_targetDistance > 2.0f)
                {
                    velGoal = 0.3f;
                }
                else if (_targetDistance > 10.0f)
                {
                    velGoal = 0.5f;
                }
                else if (_targetDistance > 50.0f)
                {
                    velGoal = 1.0f;
                }
                else if (_targetDistance > 150.0f)
                {
                    velGoal = 3.0f;
                }

                if (Mathf.Abs(relPos.x) > 0.01f)
                {
                    goalVel.x = -Mathf.Sign(relPos.x) * velGoal;
                }

                if (Mathf.Abs(relPos.y) > 0.01f)
                {
                    goalVel.y = -Mathf.Sign(relPos.y) * velGoal;
                }

                if (Mathf.Abs(relPos.z) > 0.01f)
                {
                    goalVel.z = -Mathf.Sign(relPos.z) * velGoal;
                }

                controls.X = Mathf.Clamp((goalVel.x - _localRelativeVelocity.x) * 8.0f, -1, 1);
                controls.Y = Mathf.Clamp((goalVel.z - _localRelativeVelocity.z) * 8.0f, -1, 1);
                controls.Z = Mathf.Clamp((goalVel.y - _localRelativeVelocity.y) * 8.0f, -1, 1);
            }

            if (!_flyByWire)
            {
                return;
            }

            Quaternion tgt   = Quaternion.LookRotation(_tgtFwd, _tgtUp);
            Quaternion delta =
                Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(part.vessel.transform.rotation) * tgt);

            _headingError =
                new Vector3((delta.eulerAngles.x > 180) ? (delta.eulerAngles.x - 360.0F) : delta.eulerAngles.x,
                            (delta.eulerAngles.y > 180) ? (delta.eulerAngles.y - 360.0F) : delta.eulerAngles.y,
                            (delta.eulerAngles.z > 180) ? (delta.eulerAngles.z - 360.0F) : delta.eulerAngles.z) / 180.0F;
            _integral += _headingError * TimeWarp.fixedDeltaTime;
            _deriv     = (_headingError - _prevErr) / TimeWarp.fixedDeltaTime;
            _act       = Kp * _headingError + Ki * _integral + Kd * _deriv;
            _prevErr   = _headingError;

            controls.pitch = Mathf.Clamp(controls.pitch + _act.x, -1.0F, 1.0F);
            controls.yaw   = Mathf.Clamp(controls.yaw - _act.y, -1.0F, 1.0F);
            controls.roll  = Mathf.Clamp(controls.roll + _act.z, -1.0F, 1.0F);
        }