Наследование: UnityEngine.MonoBehaviour
Пример #1
0
        /*public override void OnSave(ConfigNode node)
         * {
         *  if (node == null)
         *      return;
         *
         *  Util.DebugLog("Node: {0}", node.name);
         *
         *  //node.AddValue("version", Version);                       // save version
         * }*/

        internal void Update()
        {
            if (Util.IsPaused || Settings == null || !Util.IsFlight)
            {
                return;
            }

            if (AttachedVessel != FlightGlobals.ActiveVessel)
            {
                AttachVessel();
            }

            Trajectory.Update();
            MapOverlay.Update();
            FlightOverlay.Update();
            NavBallOverlay.Update();
            MainGUI.Update();
        }
Пример #2
0
        /*public override void OnSave(ConfigNode node)
         * {
         *  if (node == null)
         *      return;
         *
         *  Util.DebugLog("Node: {0}", node.name);
         *
         *  //node.AddValue("version", Version);                       // save version
         * }*/

        internal void Update()
        {
            if (Util.IsPaused || Settings == null || !Util.IsFlight)
            {
                return;
            }

            if (AttachedVessel != FlightGlobals.ActiveVessel)
            {
                AttachVessel();
            }

            Trajectory.Update();
            MapOverlay.Update();
            FlightOverlay.Update();
            NavBallOverlay.Update();
            MainGUI.Update();
            if (!Settings.NewGui)
#pragma warning disable CS0618 // Type or member is obsolete
            {
                OldGUI.Update();
            }
#pragma warning restore CS0618 // Type or member is obsolete
        }
Пример #3
0
        internal void Update()
        {
            if (Util.IsPaused || Settings == null || !Util.IsFlight)
            {
                return;
            }

            foreach (var vessel in FlightGlobals.VesselsLoaded)
            {
                if (vessel.FindPartModuleImplementing <ModuleCommand>() != null &&
                    (Settings.MultiTrajectories || vessel == FlightGlobals.ActiveVessel) &&
                    LoadedVesselsTrajectories.All(t => t.AttachedVessel != vessel))
                {
                    AttachVessel(vessel);
                }
            }

            for (var i = LoadedVesselsTrajectories.Count - 1; i >= 0; i--)
            {
                Trajectory trajectory = LoadedVesselsTrajectories[i];
                if (trajectory.AttachedVessel.FindPartModuleImplementing <ModuleCommand>() == null ||
                    (!Settings.MultiTrajectories && trajectory.AttachedVessel != FlightGlobals.ActiveVessel) ||
                    FlightGlobals.VesselsLoaded.All(v => v != trajectory.AttachedVessel))
                {
                    trajectory.Destroy();
                    LoadedVesselsTrajectories.RemoveAt(i);
                }
            }

            foreach (var trajectory in LoadedVesselsTrajectories)
            {
                trajectory.Update();
            }

            MainGUI.Update();
        }
Пример #4
0
 public void Start()
 {
     fetch_ = this;
 }
Пример #5
0
        private static Vector2d GetCorrection()
        {
            if (!Trajectories.IsVesselAttached)
            {
                return(Vector2d.zero);
            }

            Vector3d?     targetPosition = TargetProfile.WorldPosition;
            CelestialBody body           = TargetProfile.Body;

            if (!targetPosition.HasValue || patch == null || !patch.ImpactPosition.HasValue || patch.StartingState.ReferenceBody != body || !patch.IsAtmospheric)
            {
                return(Vector2d.zero);
            }

            // Get impact position, or, if some point over the trajectory has not enough clearance, smoothly interpolate to that point depending on how much clearance is missing
            Vector3d impactPosition = patch.ImpactPosition.Value;

            foreach (Trajectory.Point p in patch.AtmosphericTrajectory)
            {
                double neededClearance  = 600.0d;
                double missingClearance = neededClearance - (p.pos.magnitude - body.Radius - p.groundAltitude);
                if (missingClearance > 0.0d)
                {
                    if (Vector3d.Distance(p.pos, patch.RawImpactPosition.Value) > 3000.0d)
                    {
                        double   coeff      = missingClearance / neededClearance;
                        Vector3d rotatedPos = p.pos;
                        if (!Settings.BodyFixedMode)
                        {
                            rotatedPos = Trajectory.CalculateRotatedPosition(body, p.pos, p.time);
                        }
                        impactPosition = impactPosition * (1.0d - coeff) + rotatedPos * coeff;
                    }
                    break;
                }
            }

            Vector3d right  = Vector3d.Cross(patch.ImpactVelocity.Value, impactPosition).normalized;
            Vector3d behind = Vector3d.Cross(right, impactPosition).normalized;

            Vector3d offset    = targetPosition.Value - impactPosition;
            Vector2d offsetDir = new Vector2d(Vector3d.Dot(right, offset), Vector3d.Dot(behind, offset));

            offsetDir *= 0.00005d; // 20km <-> 1 <-> 45° (this is purely indicative, no physical meaning, it would be very complicated to compute an actual correction angle as it depends on the spacecraft behavior in the atmosphere ; a small angle will suffice for a plane, but even a big angle might do almost nothing for a rocket)

            Vector3d pos = Trajectories.AttachedVessel.GetWorldPos3D() - body.position;
            Vector3d vel = Trajectories.AttachedVessel.obt_velocity - body.getRFrmVel(body.position + pos); // air velocity

            double plannedAngleOfAttack = (double)DescentProfile.GetAngleOfAttack(body, pos, vel);

            if (plannedAngleOfAttack < Util.HALF_PI)
            {
                offsetDir.y = -offsetDir.y; // behavior is different for prograde or retrograde entry
            }
            double maxCorrection = 1.0d;

            offsetDir.x = Util.Clamp(offsetDir.x, -maxCorrection, maxCorrection);
            offsetDir.y = Util.Clamp(offsetDir.y, -maxCorrection, maxCorrection);

            return(offsetDir);
        }
Пример #6
0
        private void initMeshFromOrbit(Vector3 bodyPosition, Mesh mesh, Orbit orbit, double startTime, double duration, Color color)
        {
            int steps = 128;

            Vector3 camPos = ScaledSpace.ScaledToLocalSpace(MapView.MapCamera.transform.position) - bodyPosition;

            double prevTA   = orbit.TrueAnomalyAtUT(startTime);
            double prevTime = startTime;

            double[] stepUT = new double[steps * 4];
            int      utIdx  = 0;
            double   maxDT  = Math.Max(1.0, duration / (double)steps);
            double   maxDTA = 2.0 * Math.PI / (double)steps;

            stepUT[utIdx++] = startTime;
            while (true)
            {
                double time = prevTime + maxDT;
                for (int count = 0; count < 100; ++count)
                {
                    if (count == 99)
                    {
                        Debug.Log("WARNING: infinite loop? (Trajectories.MapOverlay.initMeshFromOrbit)");
                    }
                    double ta = orbit.TrueAnomalyAtUT(time);
                    while (ta < prevTA)
                    {
                        ta += 2.0 * Math.PI;
                    }
                    if (ta - prevTA <= maxDTA)
                    {
                        prevTA = ta;
                        break;
                    }
                    time = (prevTime + time) * 0.5;
                }

                if (time > startTime + duration - (time - prevTime) * 0.5)
                {
                    break;
                }

                prevTime = time;

                stepUT[utIdx++] = time;
                if (utIdx >= stepUT.Length - 1)
                {
                    //Util.PostSingleScreenMessage("ut overflow", "ut overflow");
                    break; // this should never happen, but better stop than overflow if it does
                }
            }
            stepUT[utIdx++] = startTime + duration;

            var vertices  = new Vector3[utIdx * 2 + 2];
            var triangles = new int[utIdx * 6];

            Vector3 prevMeshPos = Util.SwapYZ(orbit.getRelativePositionAtUT(startTime - duration / (double)steps));

            for (int i = 0; i < utIdx; ++i)
            {
                double time = stepUT[i];

                Vector3 curMeshPos = Util.SwapYZ(orbit.getRelativePositionAtUT(time));
                if (Settings.fetch.BodyFixedMode)
                {
                    curMeshPos = Trajectory.calculateRotatedPosition(orbit.referenceBody, curMeshPos, time);
                }

                // compute an "up" vector that is orthogonal to the trajectory orientation and to the camera vector (used to correctly orient quads to always face the camera)
                Vector3 up = Vector3.Cross(curMeshPos - prevMeshPos, camPos - curMeshPos).normalized *(lineWidth * Vector3.Distance(camPos, curMeshPos));

                // add a segment to the trajectory mesh
                vertices[i * 2 + 0] = curMeshPos - up;
                vertices[i * 2 + 1] = curMeshPos + up;

                if (i > 0)
                {
                    int idx = (i - 1) * 6;
                    triangles[idx + 0] = (i - 1) * 2 + 0;
                    triangles[idx + 1] = (i - 1) * 2 + 1;
                    triangles[idx + 2] = i * 2 + 1;

                    triangles[idx + 3] = (i - 1) * 2 + 0;
                    triangles[idx + 4] = i * 2 + 1;
                    triangles[idx + 5] = i * 2 + 0;
                }

                prevMeshPos = curMeshPos;
            }

            var colors = new Color[vertices.Length];

            for (int i = 0; i < colors.Length; ++i)
            {
                //if (color.g < 0.5)
                colors[i] = color;

                /*else
                 *  colors[i] = new Color(0, (float)i / (float)colors.Length, 1.0f - (float)i / (float)colors.Length);*/
            }

            for (int i = 0; i < vertices.Length; ++i)
            {
                vertices[i] = ScaledSpace.LocalToScaledSpace(vertices[i] + bodyPosition);
            }

            mesh.Clear();
            mesh.vertices  = vertices;
            mesh.colors    = colors;
            mesh.triangles = triangles;
            mesh.RecalculateBounds();
        }
Пример #7
0
        private void initMeshFromTrajectory(Vector3 bodyPosition, Mesh mesh, Trajectory.Point[] trajectory, Color color)
        {
            var vertices = new Vector3[trajectory.Length * 2];
            var triangles = new int[(trajectory.Length-1) * 6];

            Vector3 camPos = ScaledSpace.ScaledToLocalSpace(MapView.MapCamera.transform.position) - bodyPosition;

            Vector3 prevMeshPos = trajectory[0].pos - (trajectory[1].pos-trajectory[0].pos);
            for(int i = 0; i < trajectory.Length; ++i)
            {
                Vector3 curMeshPos = trajectory[i].pos;
                // the fixed-body rotation transformation has already been applied in AddPatch.

                // compute an "up" vector that is orthogonal to the trajectory orientation and to the camera vector (used to correctly orient quads to always face the camera)
                Vector3 up = Vector3.Cross(curMeshPos - prevMeshPos, camPos - curMeshPos).normalized * (lineWidth * Vector3.Distance(camPos, curMeshPos));

                // add a segment to the trajectory mesh
                vertices[i * 2 + 0] = curMeshPos - up;
                vertices[i * 2 + 1] = curMeshPos + up;

                if (i > 0)
                {
                    int idx = (i - 1) * 6;
                    triangles[idx + 0] = (i - 1) * 2 + 0;
                    triangles[idx + 1] = (i - 1) * 2 + 1;
                    triangles[idx + 2] = i * 2 + 1;

                    triangles[idx + 3] = (i - 1) * 2 + 0;
                    triangles[idx + 4] = i * 2 + 1;
                    triangles[idx + 5] = i * 2 + 0;
                }

                prevMeshPos = curMeshPos;
            }

            var colors = new Color[vertices.Length];
            for (int i = 0; i < colors.Length; ++i)
                colors[i] = color;

            for (int i = 0; i < vertices.Length; ++i)
            {
                vertices[i] = ScaledSpace.LocalToScaledSpace(vertices[i] + bodyPosition);
            }

            mesh.Clear();
            mesh.vertices = vertices;
            mesh.colors = colors;
            mesh.triangles = triangles;
            mesh.RecalculateBounds();
        }
Пример #8
0
        internal static void Update()
        {
            line.enabled         = false;
            impact_cross.enabled = false;
            target_cross.enabled = false;

            if (!Settings.DisplayTrajectories ||
                Util.IsMap ||
                !Settings.DisplayTrajectoriesInFlight ||
                Trajectory.Patches.Count == 0)
            {
                return;
            }

            line.Clear();
            line.Add(Trajectories.AttachedVessel.GetWorldPos3D());

            lastPatch    = Trajectory.Patches[Trajectory.Patches.Count - 1];
            bodyPosition = lastPatch.StartingState.ReferenceBody.position;
            if (lastPatch.IsAtmospheric)
            {
                for (uint i = 0; i < lastPatch.AtmosphericTrajectory.Length; ++i)
                {
                    vertex = lastPatch.AtmosphericTrajectory[i].pos + bodyPosition;
                    line.Add(vertex);
                }
            }
            else
            {
                time           = lastPatch.StartingState.Time;
                time_increment = (lastPatch.EndTime - lastPatch.StartingState.Time) / DEFAULT_VERTEX_COUNT;
                orbit          = lastPatch.SpaceOrbit;
                for (uint i = 0; i < DEFAULT_VERTEX_COUNT; ++i)
                {
                    vertex = Util.SwapYZ(orbit.getRelativePositionAtUT(time));
                    if (Settings.BodyFixedMode)
                    {
                        vertex = Trajectory.CalculateRotatedPosition(orbit.referenceBody, vertex, time);
                    }

                    vertex += bodyPosition;

                    line.Add(vertex);

                    time += time_increment;
                }
            }

            line.enabled = true;

            // red impact cross
            if (lastPatch.ImpactPosition != null)
            {
                impact_cross.Position = lastPatch.ImpactPosition.Value + bodyPosition;
                impact_cross.Body     = lastPatch.StartingState.ReferenceBody;
                impact_cross.enabled  = true;
            }
            else
            {
                impact_cross.Position = null;
                impact_cross.Body     = null;
            }

            // green target cross
            if (TargetProfile.WorldPosition != null)
            {
                target_cross.Position = TargetProfile.WorldPosition.Value + TargetProfile.Body.position;
                target_cross.Body     = TargetProfile.Body;
                target_cross.enabled  = true;
            }
            else
            {
                target_cross.Position = null;
                target_cross.Body     = null;
            }
        }
Пример #9
0
        private static Vector2 GetCorrection()
        {
            var vessel = FlightGlobals.ActiveVessel;

            if (vessel == null)
            {
                return(new Vector2(0, 0));
            }

            Vector3?      targetPosition = Trajectory.Target.WorldPosition;
            var           patch          = Trajectory.fetch.Patches.LastOrDefault();
            CelestialBody body           = Trajectory.Target.Body;

            if (!targetPosition.HasValue || patch == null || !patch.ImpactPosition.HasValue || patch.StartingState.ReferenceBody != body || !patch.IsAtmospheric)
            {
                return(new Vector2(0, 0));
            }

            // Get impact position, or, if some point over the trajectory has not enough clearance, smoothly interpolate to that point depending on how much clearance is missing
            Vector3 impactPosition = patch.ImpactPosition.Value;

            foreach (var p in patch.AtmosphericTrajectory)
            {
                float neededClearance  = 600.0f;
                float missingClearance = neededClearance - (p.pos.magnitude - (float)body.Radius - p.groundAltitude);
                if (missingClearance > 0.0f)
                {
                    if (Vector3.Distance(p.pos, patch.RawImpactPosition.Value) > 3000.0f)
                    {
                        float   coeff      = missingClearance / neededClearance;
                        Vector3 rotatedPos = p.pos;
                        if (!Settings.fetch.BodyFixedMode)
                        {
                            rotatedPos = Trajectory.CalculateRotatedPosition(body, p.pos, p.time);
                        }
                        impactPosition = impactPosition * (1.0f - coeff) + rotatedPos * coeff;
                    }
                    break;
                }
            }

            Vector3 right  = Vector3.Cross(patch.ImpactVelocity.Value, impactPosition).normalized;
            Vector3 behind = Vector3.Cross(right, impactPosition).normalized;

            Vector3 offset    = targetPosition.Value - impactPosition;
            Vector2 offsetDir = new Vector2(Vector3.Dot(right, offset), Vector3.Dot(behind, offset));

            offsetDir *= 0.00005f; // 20km <-> 1 <-> 45° (this is purely indicative, no physical meaning, it would be very complicated to compute an actual correction angle as it depends on the spacecraft behavior in the atmosphere ; a small angle will suffice for a plane, but even a big angle might do almost nothing for a rocket)

            Vector3d pos = vessel.GetWorldPos3D() - body.position;
            Vector3d vel = vessel.obt_velocity - body.getRFrmVel(body.position + pos); // air velocity
            float    plannedAngleOfAttack = (float)DescentProfile.fetch.GetAngleOfAttack(body, pos, vel);

            if (plannedAngleOfAttack < Math.PI * 0.5f)
            {
                offsetDir.y = -offsetDir.y; // behavior is different for prograde or retrograde entry
            }
            float maxCorrection = 1.0f;

            offsetDir.x = Mathf.Clamp(offsetDir.x, -maxCorrection, maxCorrection);
            offsetDir.y = Mathf.Clamp(offsetDir.y, -maxCorrection, maxCorrection);

            return(offsetDir);
        }
Пример #10
0
        private void MainWindow(int id)
        {
            Trajectory traj      = Trajectory.fetch;
            var        lastPatch = traj.patches.LastOrDefault();

            GUILayout.BeginHorizontal();
            Settings.fetch.DisplayTrajectories = GUILayout.Toggle(Settings.fetch.DisplayTrajectories, "Display trajectory", GUILayout.Width(125));

            // check that we have patched conics. If not, apologize to the user and return.
            if (Settings.fetch.DisplayTrajectories && !isPatchedConicsAvailable())
            {
                ScreenMessages.PostScreenMessage(
                    "Can't show trajectory because patched conics are not available." +
                    " Please update your tracking station facility.");
                Settings.fetch.DisplayTrajectories = false;
                return;
            }

            if (Settings.fetch.DisplayTrajectories)
            {
                Settings.fetch.DisplayCompleteTrajectory = GUILayout.Toggle(Settings.fetch.DisplayCompleteTrajectory, "complete", GUILayout.Width(70));
            }
            GUILayout.EndHorizontal();

            Settings.fetch.BodyFixedMode = GUILayout.Toggle(Settings.fetch.BodyFixedMode, "Body-fixed mode");

            GUILayout.Label("Max G-force: " + (traj.MaxAccel / 9.81).ToString("0.00"));
            if (lastPatch != null && lastPatch.impactPosition.HasValue)
            {
                Vector3 up      = lastPatch.impactPosition.Value.normalized;
                Vector3 vel     = lastPatch.impactVelocity - lastPatch.startingState.referenceBody.getRFrmVel(lastPatch.impactPosition.Value + lastPatch.startingState.referenceBody.position);
                float   vVelMag = Vector3.Dot(vel, up);
                Vector3 vVel    = up * vVelMag;
                float   hVelMag = (vel - vVel).magnitude;
                GUILayout.Label("Impact: V = " + vVelMag.ToString("0.0") + "m/s, H = " + hVelMag.ToString("0.0") + "m/s");
            }
            else
            {
                GUILayout.Label("Impact velocity: -");
            }
            GUILayout.Space(10);

            if (Settings.fetch.DisplayTargetGUI = ToggleGroup(Settings.fetch.DisplayTargetGUI, "Target"))
            {
                GUI.enabled = traj.targetPosition.HasValue;
                if (GUILayout.Button("Unset target"))
                {
                    Trajectory.SetTarget();
                }
                GUI.enabled = true;

                GUILayout.BeginHorizontal();
                var patch = traj.patches.LastOrDefault();
                GUI.enabled = (patch != null && patch.impactPosition.HasValue);
                if (GUILayout.Button("Set current impact", GUILayout.Width(150)))
                {
                    Trajectory.SetTarget(patch.startingState.referenceBody, patch.impactPosition);
                }
                GUI.enabled = true;
                if (GUILayout.Button("Set KSC", GUILayout.Width(70)))
                {
                    var body = FlightGlobals.Bodies.SingleOrDefault(b => b.isHomeWorld);
                    if (body != null)
                    {
                        Vector3d worldPos = body.GetWorldSurfacePosition(-0.04860002, -74.72425635, 2.0);
                        Trajectory.SetTarget(body, worldPos - body.position);
                    }
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                coords = GUILayout.TextField(coords, GUILayout.Width(170));
                if (GUILayout.Button(new GUIContent("Set", "Enter target latitude and longitude, separated by a comma"), GUILayout.Width(50)))
                {
                    string[] latLng = coords.Split(new char[] { ',', ';' });
                    var      body   = FlightGlobals.currentMainBody;
                    if (latLng.Length == 2 && body != null)
                    {
                        double lat, lng;
                        if (Double.TryParse(latLng[0].Trim(), out lat) && Double.TryParse(latLng[1].Trim(), out lng))
                        {
                            Vector3d worldPos = body.GetWorldSurfacePosition(lat, lng, 2.0);
                            Trajectory.SetTarget(body, worldPos - body.position);
                        }
                    }
                }
                GUILayout.EndHorizontal();
            }
            GUILayout.Space(10);

            GUILayout.BeginHorizontal();
            bool descentProfileGroup = Settings.fetch.DisplayDescentProfileGUI = ToggleGroup(Settings.fetch.DisplayDescentProfileGUI, "Descent profile", 120);

            DescentProfile.fetch.DoQuickControlsGUI();
            GUILayout.EndHorizontal();
            if (descentProfileGroup)
            {
                DescentProfile.fetch.DoGUI();
            }
            GUILayout.Space(10);

            if (Settings.fetch.DisplaySettingsGUI = ToggleGroup(Settings.fetch.DisplaySettingsGUI, "Settings"))
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("Max patches", GUILayout.Width(100));
                Settings.fetch.MaxPatchCount = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)Settings.fetch.MaxPatchCount, 3, 10, GUILayout.Width(100)));
                GUILayout.Label(Settings.fetch.MaxPatchCount.ToString(), GUILayout.Width(15));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("Max frames per patch", GUILayout.Width(100));
                Settings.fetch.MaxFramesPerPatch = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)Settings.fetch.MaxFramesPerPatch, 1, 50, GUILayout.Width(100)));
                GUILayout.Label(Settings.fetch.MaxFramesPerPatch.ToString(), GUILayout.Width(15));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                Settings.fetch.AutoUpdateAerodynamicModel = GUILayout.Toggle(Settings.fetch.AutoUpdateAerodynamicModel, new GUIContent("Auto update", "Auto-update of the aerodynamic model. For example if a part is decoupled, the model needs to be updated. This is independent from trajectory update."));
                if (GUILayout.Button("Update now"))
                {
                    traj.InvalidateAerodynamicModel();
                }
                GUILayout.EndHorizontal();

                if (ToolbarManager.ToolbarAvailable)
                {
                    Settings.fetch.UseBlizzyToolbar = GUILayout.Toggle(Settings.fetch.UseBlizzyToolbar, new GUIContent("Use Blizzy's toolbar", "Will take effect after restart"));
                }

                //Settings.fetch.AutoPilotAvailable = GUILayout.Toggle(Settings.fetch.AutoPilotAvailable, new GUIContent("Unlock auto-pilot (EXPERIMENTAL)", "Enables the auto-pilot interface. This is experimental, subject to change, and might crash your spaceplanes more often than not."));
                Settings.fetch.AutoPilotAvailable = false; // auto-pilot disabled because it's incompatible with Remote Tech in its current implementation (and has some other bugs anyway)

                if (FlightGlobals.ActiveVessel != null)
                {
                    GUILayout.Label("Position:");
                    GUILayout.BeginHorizontal();
                    var body     = FlightGlobals.ActiveVessel.mainBody;
                    var worldPos = FlightGlobals.ActiveVessel.GetWorldPos3D();
                    GUILayout.Label("lat=" + body.GetLatitude(worldPos).ToString("000.000000"), GUILayout.Width(110));
                    GUILayout.Label("lng=" + body.GetLongitude(worldPos).ToString("000.000000"), GUILayout.Width(110));
                    GUILayout.EndHorizontal();
                }

                GUILayout.Label("Aerodynamic model: " + VesselAerodynamicModel.AerodynamicModelName);
                GUILayout.BeginHorizontal();
                GUILayout.Label("Perf: " + (traj.ComputationTime * 1000.0f).ToString("0.0") + "ms (" + (traj.ComputationTime / traj.GameFrameTime * 100.0f).ToString("0") + "%)", GUILayout.Width(120));
                GUILayout.Label(traj.ErrorCount + " error(s)", GUILayout.Width(80));
                GUILayout.EndHorizontal();
            }

            tooltip = GUI.tooltip;

            GUI.DragWindow();
        }
Пример #11
0
        private static void AttachVessel(Vessel vessel)
        {
            Util.DebugLog("Loading profiles for vessel: " + vessel);

            Trajectory trajectory = new Trajectory(vessel);

            if (trajectory.AttachedVessel == null)
            {
                Util.DebugLog("No vessel");
                trajectory.DescentProfile.Clear();
                trajectory.TargetProfile.Clear();
                trajectory.TargetProfile.ManualText = "";
            }
            else
            {
                LoadedVesselsTrajectories.Add(trajectory);
                TrajectoriesVesselSettings module = trajectory.AttachedVessel.Parts.SelectMany(p => p.Modules.OfType <TrajectoriesVesselSettings>()).FirstOrDefault();
                if (module == null)
                {
                    Util.DebugLog("No TrajectoriesVesselSettings module");
                    trajectory.DescentProfile.Clear();
                    trajectory.TargetProfile.Clear();
                    trajectory.TargetProfile.ManualText = "";
                }
                else if (!module.Initialized)
                {
                    Util.DebugLog("Initializing TrajectoriesVesselSettings module");
                    trajectory.DescentProfile.Clear();
                    trajectory.DescentProfile.Save(module);
                    trajectory.TargetProfile.Clear();
                    trajectory.TargetProfile.ManualText = "";
                    trajectory.TargetProfile.Save(module);
                    module.Initialized = true;
                    Util.Log("New vessel, profiles created");
                }
                else
                {
                    Util.DebugLog("Reading profile settings...");
                    // descent profile
                    if (trajectory.DescentProfile.Ready)
                    {
                        trajectory.DescentProfile.AtmosEntry.AngleRad    = module.EntryAngle;
                        trajectory.DescentProfile.AtmosEntry.Horizon     = module.EntryHorizon;
                        trajectory.DescentProfile.HighAltitude.AngleRad  = module.HighAngle;
                        trajectory.DescentProfile.HighAltitude.Horizon   = module.HighHorizon;
                        trajectory.DescentProfile.LowAltitude.AngleRad   = module.LowAngle;
                        trajectory.DescentProfile.LowAltitude.Horizon    = module.LowHorizon;
                        trajectory.DescentProfile.FinalApproach.AngleRad = module.GroundAngle;
                        trajectory.DescentProfile.FinalApproach.Horizon  = module.GroundHorizon;
                        trajectory.DescentProfile.RefreshGui();
                    }

                    // target profile
                    trajectory.TargetProfile.SetFromLocalPos(FlightGlobals.Bodies.FirstOrDefault(b => b.name == module.TargetBody),
                                                             new Vector3d(module.TargetPosition_x, module.TargetPosition_y, module.TargetPosition_z));
                    trajectory.TargetProfile.ManualText = module.ManualTargetTxt;

                    Util.Log("Profiles loaded");
                }
            }
        }
Пример #12
0
 internal void FixedUpdate() => Trajectory.DebugTelemetry();
 public FARModel(Trajectory trajectory, CelestialBody body, MethodInfo CalculateVesselAeroForces)
     : base(trajectory, body)
 {
     FARAPI_CalculateVesselAeroForces = CalculateVesselAeroForces;
 }
Пример #14
0
        private void initMeshFromTrajectory(Vector3 bodyPosition, Mesh mesh, Trajectory.Point[] trajectory, Color color)
        {
            var vertices = new Vector3[trajectory.Length * 2];
            var uvs = new Vector2[trajectory.Length * 2];
            var triangles = new int[(trajectory.Length-1) * 6];

            Vector3 prevMeshPos = trajectory[0].pos - (trajectory[1].pos-trajectory[0].pos) + bodyPosition;
            for(int i = 0; i < trajectory.Length; ++i)
            {
                // the fixed-body rotation transformation has already been applied in AddPatch.
                Vector3 curMeshPos = trajectory[i].pos + bodyPosition;

                // add a segment to the trajectory mesh
                MakeRibbonEdge(prevMeshPos, curMeshPos, lineWidth, vertices, i * 2);
                uvs[i * 2 + 0] = new Vector2(0.8f, 0);
                uvs[i * 2 + 1] = new Vector2(0.8f, 1);

                if (i > 0)
                {
                    int idx = (i - 1) * 6;
                    triangles[idx + 0] = (i - 1) * 2 + 0;
                    triangles[idx + 1] = (i - 1) * 2 + 1;
                    triangles[idx + 2] = i * 2 + 1;

                    triangles[idx + 3] = (i - 1) * 2 + 0;
                    triangles[idx + 4] = i * 2 + 1;
                    triangles[idx + 5] = i * 2 + 0;
                }

                prevMeshPos = curMeshPos;
            }

            var colors = new Color[vertices.Length];
            for (int i = 0; i < colors.Length; ++i)
                colors[i] = color;

            mesh.Clear();
            mesh.vertices = vertices;
            mesh.uv = uvs;
            mesh.colors = colors;
            mesh.triangles = triangles;
            mesh.RecalculateBounds();
        }
Пример #15
0
        private void FixedUpdate()
        {
            line.enabled           = false;
            targetingCross.enabled = false;

            if (!Settings.fetch.DisplayTrajectories ||
                Util.IsMap ||
                !Settings.fetch.DisplayTrajectoriesInFlight ||
                Trajectory.fetch.Patches.Count == 0)
            {
                return;
            }

            line.Vertices.Clear();

            Trajectory.Patch lastPatch    = Trajectory.fetch.Patches[Trajectory.fetch.Patches.Count - 1];
            Vector3d         bodyPosition = lastPatch.StartingState.ReferenceBody.position;

            if (lastPatch.IsAtmospheric)
            {
                for (uint i = 0; i < lastPatch.AtmosphericTrajectory.Length; ++i)
                {
                    Vector3 vertex = lastPatch.AtmosphericTrajectory[i].pos + bodyPosition;
                    line.Vertices.Add(vertex);
                }
            }
            else
            {
                double time           = lastPatch.StartingState.Time;
                double time_increment = (lastPatch.EndTime - lastPatch.StartingState.Time) / defaultVertexCount;
                Orbit  orbit          = lastPatch.SpaceOrbit;
                for (uint i = 0; i < defaultVertexCount; ++i)
                {
                    Vector3 vertex = Util.SwapYZ(orbit.getRelativePositionAtUT(time));
                    if (Settings.fetch.BodyFixedMode)
                    {
                        vertex = Trajectory.CalculateRotatedPosition(orbit.referenceBody, vertex, time);
                    }

                    vertex += bodyPosition;

                    line.Vertices.Add(vertex);

                    time += time_increment;
                }
            }

            line.Body    = lastPatch.StartingState.ReferenceBody;
            line.enabled = true;

            if (lastPatch.ImpactPosition != null)
            {
                targetingCross.ImpactPosition = lastPatch.ImpactPosition.Value;
                targetingCross.ImpactBody     = lastPatch.StartingState.ReferenceBody;
                targetingCross.enabled        = true;
            }
            else
            {
                targetingCross.ImpactPosition = null;
                targetingCross.ImpactBody     = null;
            }
        }
        private static void InitMeshFromOrbit(Vector3 bodyPosition, Mesh mesh, Orbit orbit, double startTime, double duration, Color color)
        {
            int steps = 128;

            double prevTA   = orbit.TrueAnomalyAtUT(startTime);
            double prevTime = startTime;

            double[] stepUT = new double[steps * 4];
            int      utIdx  = 0;
            double   maxDT  = Math.Max(1.0, duration / steps);
            double   maxDTA = 2.0 * Math.PI / steps;

            stepUT[utIdx++] = startTime;
            while (true)
            {
                double time = prevTime + maxDT;
                for (int count = 0; count < 100; ++count)
                {
                    if (count == 99)
                    {
                        Util.LogWarning("Infinite loop in map view renderer");
                    }
                    double ta = orbit.TrueAnomalyAtUT(time);
                    while (ta < prevTA)
                    {
                        ta += 2.0 * Math.PI;
                    }
                    if (ta - prevTA <= maxDTA)
                    {
                        prevTA = ta;
                        break;
                    }
                    time = (prevTime + time) * 0.5;
                }

                if (time > startTime + duration - (time - prevTime) * 0.5)
                {
                    break;
                }

                prevTime = time;

                stepUT[utIdx++] = time;
                if (utIdx >= stepUT.Length - 1)
                {
                    Util.DebugLogWarning("UT overflow");
                    break; // this should never happen, but better stop than overflow if it does
                }
            }
            stepUT[utIdx++] = startTime + duration;

            Vector3[] vertices  = new Vector3[utIdx * 2 + 2];
            Vector2[] uvs       = new Vector2[utIdx * 2 + 2];
            int[]     triangles = new int[utIdx * 6];

            Vector3d prevMeshPos = orbit.getRelativePositionAtUT(startTime - duration / steps).SwapYZ() + bodyPosition;

            for (int i = 0; i < utIdx; ++i)
            {
                double time = stepUT[i];

                Vector3d curMeshPos = orbit.getRelativePositionAtUT(time).SwapYZ();
                if (Settings.BodyFixedMode)
                {
                    curMeshPos = Trajectory.CalculateRotatedPosition(orbit.referenceBody, curMeshPos, time);
                }
                curMeshPos += bodyPosition;

                // add a segment to the trajectory mesh
                MakeRibbonEdge(prevMeshPos, curMeshPos, line_width, vertices, i * 2);
                uvs[i * 2 + 0] = new Vector2(0.8f, 0);
                uvs[i * 2 + 1] = new Vector2(0.8f, 1);

                if (i > 0)
                {
                    int idx = (i - 1) * 6;
                    triangles[idx + 0] = (i - 1) * 2 + 0;
                    triangles[idx + 1] = (i - 1) * 2 + 1;
                    triangles[idx + 2] = i * 2 + 1;

                    triangles[idx + 3] = (i - 1) * 2 + 0;
                    triangles[idx + 4] = i * 2 + 1;
                    triangles[idx + 5] = i * 2 + 0;
                }

                prevMeshPos = curMeshPos;
            }

            Color[] colors = new Color[vertices.Length];
            for (int i = 0; i < colors.Length; ++i)
            {
                //if (color.g < 0.5)
                colors[i] = color;

                /*else
                 *  colors[i] = new Color(0, (float)i / (float)colors.Length, 1.0f - (float)i / (float)colors.Length);*/
            }

            mesh.Clear();
            mesh.vertices  = vertices;
            mesh.uv        = uvs;
            mesh.colors    = colors;
            mesh.triangles = triangles;
            mesh.RecalculateBounds();
            mesh.MarkDynamic();
        }
Пример #17
0
        private void FixedUpdate()
        {
            if (Settings.fetch.NewGui)
            {
                return;
            }

            float t = Time.realtimeSinceStartup;

            if (t < lastStringRenderTime + stringRenderInterval)
            {
                return;
            }

            lastStringRenderTime = t;

            Trajectory traj = Trajectory.fetch;

            Trajectory.Patch lastPatch     = traj.Patches.LastOrDefault();
            CelestialBody    lastPatchBody = lastPatch?.StartingState.ReferenceBody;
            CelestialBody    targetBody    = Trajectory.Target.Body;

            guistring_gForce = (traj.MaxAccel / 9.81).ToString("0.00");

            if (lastPatch != null && lastPatch.ImpactPosition.HasValue)
            {
                Vector3 up      = lastPatch.ImpactPosition.Value.normalized;
                Vector3 vel     = lastPatch.ImpactVelocity.Value - lastPatchBody.getRFrmVel(lastPatch.ImpactPosition.Value + lastPatchBody.position);
                float   vVelMag = Vector3.Dot(vel, up);
                Vector3 vVel    = up * vVelMag;
                float   hVelMag = (vel - vVel).magnitude;

                guistring_impactVelocity = String.Format("Impact: V = {0,6:F0}m/s, H = {1,6:F0}m/s", -vVelMag, hVelMag);
            }
            else
            {
                guistring_impactVelocity = "";
            }

            if (Settings.fetch.DisplayTargetGUI)
            {
                if (lastPatchBody != null && targetBody != null && lastPatch.ImpactPosition.HasValue &&
                    lastPatchBody == targetBody && Trajectory.Target.WorldPosition.HasValue)
                {
                    // Get Latitude and Longitude from impact position
                    double impactLat;
                    double impatLon;
                    double impactAlt;

                    // Get Latitude and Longitude from impact position
                    impactPos = lastPatch.ImpactPosition.Value + lastPatchBody.position;
                    lastPatchBody.GetLatLonAlt(impactPos, out impactLat, out impatLon, out impactAlt);

                    // Get Latitude and Longitude for target position
                    double targetLat;
                    double targetLon;
                    double targetAlt;
                    targetPos = Trajectory.Target.WorldPosition.Value + targetBody.position;
                    targetBody.GetLatLonAlt(targetPos, out targetLat, out targetLon, out targetAlt);

                    float targetDistance = (float)(Util.DistanceFromLatitudeAndLongitude(targetBody.Radius + impactAlt,
                                                                                         impactLat, impatLon, targetLat, targetLon) / 1e3);

                    float targetDistanceNorth = (float)(Util.DistanceFromLatitudeAndLongitude(targetBody.Radius + impactAlt,
                                                                                              impactLat, targetLon, targetLat, targetLon) / 1e3) * ((targetLat - impactLat) < 0 ? -1.0f : +1.0f);

                    float targetDistanceEast = (float)(Util.DistanceFromLatitudeAndLongitude(targetBody.Radius + impactAlt,
                                                                                             targetLat, impatLon, targetLat, targetLon) / 1e3) * ((targetLon - impatLon) < 0 ? -1.0f : +1.0f);

                    // format distance to target string
                    guistring_targetDistance = String.Format("{0,6:F1}km | {1}: {2,6:F1}km | {3}: {4,6:F1}km",
                                                             targetDistance,
                                                             targetDistanceNorth > 0.0f ? 'N' : 'S',
                                                             Math.Abs(targetDistanceNorth),
                                                             targetDistanceEast > 0.0f ? 'E' : 'W',
                                                             Math.Abs(targetDistanceEast));
                }
                else
                {
                    guistring_targetDistance = "";
                }
            }

            if (FlightGlobals.ActiveVessel != null)
            {
                var body = FlightGlobals.ActiveVessel.mainBody;

                guistring_Latitude  = body.GetLatitude(FlightGlobals.ActiveVessel.GetWorldPos3D()).ToString("000.000000");
                guistring_Longitude = body.GetLongitude(FlightGlobals.ActiveVessel.GetWorldPos3D()).ToString("000.000000");
            }
        }
Пример #18
0
 public void Start()
 {
     fetch_ = this;
 }
Пример #19
0
        private void MainWindow(int id)
        {
            Trajectory traj = Trajectory.fetch;

            GUILayout.BeginHorizontal();

            Settings.fetch.DisplayTrajectories = GUILayout.Toggle(Settings.fetch.DisplayTrajectories, "Show trajectory", GUILayout.Width(125));

            Settings.fetch.DisplayTrajectoriesInFlight = GUILayout.Toggle(Settings.fetch.DisplayTrajectoriesInFlight, "In-Flight");

            // check that we have patched conics. If not, apologize to the user and return.
            if (Settings.fetch.DisplayTrajectories && !Util.IsPatchedConicsAvailable)
            {
                ScreenMessages.PostScreenMessage(
                    "Can't show trajectory because patched conics are not available." +
                    " Please update your tracking station facility.");
                Settings.fetch.DisplayTrajectories = false;
                return;
            }

            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();

            Settings.fetch.BodyFixedMode = GUILayout.Toggle(Settings.fetch.BodyFixedMode, "Body-fixed mode");

            if (Settings.fetch.DisplayTrajectories)
            {
                Settings.fetch.DisplayCompleteTrajectory = GUILayout.Toggle(Settings.fetch.DisplayCompleteTrajectory, "complete", GUILayout.Width(70));
            }

            GUILayout.EndHorizontal();

            GUILayout.Label("Max G-force: " + guistring_gForce);

            GUILayout.Label(guistring_impactVelocity);
            GUILayout.Space(10);


            if (Settings.fetch.DisplayTargetGUI = ToggleGroup(Settings.fetch.DisplayTargetGUI, "Target"))
            {
                GUI.enabled = Trajectory.Target.WorldPosition.HasValue;

                GUILayout.Label(guistring_targetDistance);

                if (GUILayout.Button("Unset target"))
                {
                    Trajectory.Target.Clear();
                }
                GUI.enabled = true;

                GUILayout.BeginHorizontal();
                var patch = traj.Patches.LastOrDefault();
                GUI.enabled = (patch != null && patch.ImpactPosition.HasValue);
                if (GUILayout.Button("Set current impact", GUILayout.Width(150)))
                {
                    if (patch.ImpactPosition.HasValue)
                    {
                        Trajectory.Target.SetFromWorldPos(patch.StartingState.ReferenceBody, patch.ImpactPosition.Value);
                    }
                }
                GUI.enabled = true;
                if (GUILayout.Button("Set KSC", GUILayout.Width(70)))
                {
                    var homebody = FlightGlobals.GetHomeBody();

                    double latitude  = SpaceCenter.Instance.Latitude;
                    double longitude = SpaceCenter.Instance.Longitude;

                    if (homebody != null)
                    {
                        Trajectory.Target.SetFromLatLonAlt(homebody, latitude, longitude);
                    }
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();

                Vessel targetVessel = FlightGlobals.fetch.VesselTarget?.GetVessel();
                GUI.enabled = (patch != null && targetVessel != null && targetVessel.Landed
                               // && targetVessel.lastBody == patch.startingState.referenceBody
                               );
                if (GUILayout.Button("Target vessel"))
                {
                    Trajectory.Target.SetFromWorldPos(targetVessel.lastBody, targetVessel.GetWorldPos3D() - targetVessel.lastBody.position);
                    ScreenMessages.PostScreenMessage("Targeting vessel " + targetVessel.GetName());
                }

                FinePrint.Waypoint navigationWaypoint = FlightGlobals.ActiveVessel?.navigationWaypoint;
                GUI.enabled = (navigationWaypoint != null);
                if (GUILayout.Button("Active waypoint"))
                {
                    Trajectory.Target.SetFromLatLonAlt(navigationWaypoint.celestialBody,
                                                       navigationWaypoint.latitude, navigationWaypoint.longitude, navigationWaypoint.altitude);
                    ScreenMessages.PostScreenMessage("Targeting waypoint " + navigationWaypoint.name);
                }
                GUILayout.EndHorizontal();

                GUI.enabled = true;

                GUILayout.BeginHorizontal();
                coords = GUILayout.TextField(Trajectory.Target.ManualText, GUILayout.Width(170));
                if (coords != Trajectory.Target.ManualText)
                {
                    Trajectory.Target.ManualText = coords;
                    Trajectory.Target.Save();
                }
                if (GUILayout.Button(new GUIContent("Set",
                                                    "Enter target latitude and longitude, separated by a comma, in decimal format (with a dot for decimal separator)"),
                                     GUILayout.Width(50)))
                {
                    string[] latLng = coords.Split(new char[] { ',', ';' });
                    var      body   = FlightGlobals.currentMainBody;
                    if (latLng.Length == 2 && body != null)
                    {
                        double lat;
                        double lng;
                        if (double.TryParse(latLng[0].Trim(), out lat) && double.TryParse(latLng[1].Trim(), out lng))
                        {
                            Trajectory.Target.SetFromLatLonAlt(body, lat, lng);
                        }
                    }
                }
                GUILayout.EndHorizontal();
            }

            GUILayout.Space(10);

            GUILayout.BeginHorizontal();
            bool descentProfileGroup = Settings.fetch.DisplayDescentProfileGUI = ToggleGroup(Settings.fetch.DisplayDescentProfileGUI, "Descent profile", 120);

            DescentProfile.fetch.DoQuickControlsGUI();
            GUILayout.EndHorizontal();
            if (descentProfileGroup)
            {
                DescentProfile.fetch.DoGUI();
            }
            GUILayout.Space(10);

            if (Settings.fetch.DisplaySettingsGUI = ToggleGroup(Settings.fetch.DisplaySettingsGUI, "Settings"))
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("Max patches", GUILayout.Width(100));
                Settings.fetch.MaxPatchCount = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)Settings.fetch.MaxPatchCount, 3, 10, GUILayout.Width(100)));
                GUILayout.Label(Settings.fetch.MaxPatchCount.ToString(), GUILayout.Width(15));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("Max frames per patch", GUILayout.Width(100));
                Settings.fetch.MaxFramesPerPatch = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)Settings.fetch.MaxFramesPerPatch, 1, 50, GUILayout.Width(100)));
                GUILayout.Label(Settings.fetch.MaxFramesPerPatch.ToString(), GUILayout.Width(15));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                Settings.fetch.UseCache = GUILayout.Toggle(Settings.fetch.UseCache, new GUIContent("Use Cache", "Toggle cache usage. Trajectory will be more precise when cache disabled, but computation time will be higher. It's not recommended to keep it unchecked, unless your CPU can handle the load."), GUILayout.Width(80));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                Settings.fetch.AutoUpdateAerodynamicModel = GUILayout.Toggle(Settings.fetch.AutoUpdateAerodynamicModel, new GUIContent("Auto update", "Auto-update of the aerodynamic model. For example if a part is decoupled, the model needs to be updated. This is independent from trajectory update."));
                if (GUILayout.Button("Update now"))
                {
                    traj.InvalidateAerodynamicModel();
                }
                GUILayout.EndHorizontal();

                if (ToolbarManager.ToolbarAvailable)
                {
                    Settings.fetch.UseBlizzyToolbar = GUILayout.Toggle(Settings.fetch.UseBlizzyToolbar, new GUIContent("Use Blizzy's toolbar", "Will take effect after restart"));
                }

                if (FlightGlobals.ActiveVessel != null)
                {
                    GUILayout.Label("Position:");
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("lat=" + guistring_Latitude, GUILayout.Width(110));
                    GUILayout.Label("lng=" + guistring_Longitude, GUILayout.Width(110));
                    GUILayout.EndHorizontal();
                }

                GUILayout.Label("Aerodynamic model: " + traj.AerodynamicModelName);
                GUILayout.BeginHorizontal();
                GUILayout.Label(String.Format("Perf: {0,5:F1}ms ({1,4:F1})%",
                                              traj.ComputationTime * 1000.0f,
                                              traj.ComputationTime / traj.GameFrameTime * 100.0f
                                              ), GUILayout.Width(130));
                GUILayout.Label(traj.ErrorCount + " error(s)", GUILayout.Width(80));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                if (GUILayout.Toggle(Settings.fetch.NewGui, new GUIContent("New Gui", "Swap to the New Gui")))
                {
                    Settings.fetch.NewGui         = true;
                    Settings.fetch.MainGUIEnabled = true;
                    Settings.fetch.GUIEnabled     = false;
                    InputLockManager.RemoveControlLock("TrajectoriesFlightLock");
                    clickThroughLocked = false;
                }
                else
                {
                    Settings.fetch.NewGui         = false;
                    Settings.fetch.MainGUIEnabled = false;
                    Settings.fetch.GUIEnabled     = true;
                }
                GUILayout.EndHorizontal();
            }

            tooltip = GUI.tooltip;

            GUI.DragWindow();
        }
Пример #20
0
        private void MainWindow(int id)
        {
            Trajectory traj      = Trajectory.fetch;
            var        lastPatch = traj.patches.LastOrDefault();

            GUILayout.BeginHorizontal();
            Settings.fetch.DisplayTrajectories = GUILayout.Toggle(Settings.fetch.DisplayTrajectories, "Display trajectory", GUILayout.Width(125));

            // check that we have patched conics. If not, apologize to the user and return.
            if (Settings.fetch.DisplayTrajectories && !isPatchedConicsAvailable())
            {
                ScreenMessages.PostScreenMessage(
                    "Can't show trajectory because patched conics are not available." +
                    " Please update your tracking station facility.");
                Settings.fetch.DisplayTrajectories = false;
                return;
            }

            if (Settings.fetch.DisplayTrajectories)
            {
                Settings.fetch.DisplayCompleteTrajectory = GUILayout.Toggle(Settings.fetch.DisplayCompleteTrajectory, "complete", GUILayout.Width(70));
            }
            GUILayout.EndHorizontal();

            Settings.fetch.BodyFixedMode = GUILayout.Toggle(Settings.fetch.BodyFixedMode, "Body-fixed mode");
            GUILayout.Label("marcus lat long alt: " + FlightGlobals.ActiveVessel.latitude + " - " + FlightGlobals.ActiveVessel.longitude + " - " + FlightGlobals.ActiveVessel.altitude);
            GUILayout.Label("marcus body: " + FlightGlobals.ActiveVessel.mainBody.name + " - " + FlightGlobals.currentMainBody.name);
            GUILayout.Label("marcus GetWorldPos3D: " + FlightGlobals.ActiveVessel.GetWorldPos3D());
            GUILayout.Label("marcus GetWorldSurfacePosition: " + FlightGlobals.currentMainBody.GetWorldSurfacePosition(FlightGlobals.ActiveVessel.latitude, FlightGlobals.ActiveVessel.longitude, FlightGlobals.ActiveVessel.altitude));
            GUILayout.Label("body position: " + FlightGlobals.currentMainBody.position);
            GUILayout.Label("Max G-force: " + (traj.MaxAccel / 9.81).ToString("0.00"));
            //FlightGlobals.Bodies.ForEach((CelestialBody obj) =>
            //{ if (obj.name == "Sun")
            //	{
            //		GUILayout.Label("body (" + obj.name + "):" + obj.position);
            //	}
            //}	);
            if (lastPatch != null && lastPatch.impactPosition.HasValue)
            {
                Vector3 up      = lastPatch.impactPosition.Value.normalized;
                Vector3 vel     = lastPatch.impactVelocity.Value - lastPatch.startingState.referenceBody.getRFrmVel(lastPatch.impactPosition.Value + lastPatch.startingState.referenceBody.position);
                float   vVelMag = Vector3.Dot(vel, up);
                Vector3 vVel    = up * vVelMag;
                float   hVelMag = (vel - vVel).magnitude;
                GUILayout.Label("Impact: V = " + vVelMag.ToString("0.0") + "m/s, H = " + hVelMag.ToString("0.0") + "m/s");
            }
            else
            {
                GUILayout.Label("Impact velocity: -");
            }
            GUILayout.Space(10);

            if (Settings.fetch.DisplayTargetGUI = ToggleGroup(Settings.fetch.DisplayTargetGUI, "Target"))
            {
                GUI.enabled = traj.targetPosition.HasValue;
                if (GUILayout.Button("Unset target"))
                {
                    traj.SetTarget();
                }
                GUI.enabled = true;

                GUILayout.BeginHorizontal();
                var patch = traj.patches.LastOrDefault();
                GUI.enabled = (patch != null && patch.impactPosition.HasValue);
                if (GUILayout.Button("Set current impact", GUILayout.Width(150)))
                {
                    traj.SetTarget(patch.startingState.referenceBody, patch.impactPosition);
                }
                GUI.enabled = true;
                if (GUILayout.Button("Set KSC", GUILayout.Width(70)))
                {
                    var body = FlightGlobals.Bodies.SingleOrDefault(b => b.isHomeWorld);
                    if (body != null)
                    {
                        Vector3d worldPos = body.GetWorldSurfacePosition(-0.04860002, -74.72425635, 2.0);
                        traj.SetTarget(body, worldPos - body.position);
                    }
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                coords = GUILayout.TextField(coords, GUILayout.Width(170));
                if (GUILayout.Button(new GUIContent("Set", "Enter target latitude and longitude, separated by a comma, in decimal format (with a dot for decimal separator)"), GUILayout.Width(50)))
                {
                    string[] latLng = coords.Split(new char[] { ',', ';' });
                    var      body   = FlightGlobals.currentMainBody;
                    if (latLng.Length == 2 && body != null)
                    {
                        double lat, lng;
                        if (Double.TryParse(latLng[0].Trim(), out lat) && Double.TryParse(latLng[1].Trim(), out lng))
                        {
                            Vector3d relPos   = body.GetWorldSurfacePosition(lat, lng, 2.0) - body.position;
                            double   altitude = Trajectory.GetGroundAltitude(body, relPos) + body.Radius;
                            traj.SetTarget(body, relPos * (altitude / relPos.magnitude));
                        }
                    }
                }
                GUILayout.EndHorizontal();
            }
            GUILayout.Space(10);

            GUILayout.BeginHorizontal();
            bool descentProfileGroup = Settings.fetch.DisplayDescentProfileGUI = ToggleGroup(Settings.fetch.DisplayDescentProfileGUI, "Descent profile", 120);

            DescentProfile.fetch.DoQuickControlsGUI();
            GUILayout.EndHorizontal();
            if (descentProfileGroup)
            {
                DescentProfile.fetch.DoGUI();
            }
            GUILayout.Space(10);

            if (Settings.fetch.DisplaySettingsGUI = ToggleGroup(Settings.fetch.DisplaySettingsGUI, "Settings"))
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("Max patches", GUILayout.Width(100));
                Settings.fetch.MaxPatchCount = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)Settings.fetch.MaxPatchCount, 3, 10, GUILayout.Width(100)));
                GUILayout.Label(Settings.fetch.MaxPatchCount.ToString(), GUILayout.Width(15));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                GUILayout.Label("Max frames per patch", GUILayout.Width(100));
                Settings.fetch.MaxFramesPerPatch = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)Settings.fetch.MaxFramesPerPatch, 1, 50, GUILayout.Width(100)));
                GUILayout.Label(Settings.fetch.MaxFramesPerPatch.ToString(), GUILayout.Width(15));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                Settings.fetch.UseCache = GUILayout.Toggle(Settings.fetch.UseCache, new GUIContent("Use Cache", "Toggle cache usage. Trajectory will be more precise when cache disabled, but computation time will be higher. It's not recommended to keep it unchecked, unless your CPU can handle the load."), GUILayout.Width(80));
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                Settings.fetch.AutoUpdateAerodynamicModel = GUILayout.Toggle(Settings.fetch.AutoUpdateAerodynamicModel, new GUIContent("Auto update", "Auto-update of the aerodynamic model. For example if a part is decoupled, the model needs to be updated. This is independent from trajectory update."));
                if (GUILayout.Button("Update now"))
                {
                    traj.InvalidateAerodynamicModel();
                }
                GUILayout.EndHorizontal();

                if (ToolbarManager.ToolbarAvailable)
                {
                    Settings.fetch.UseBlizzyToolbar = GUILayout.Toggle(Settings.fetch.UseBlizzyToolbar, new GUIContent("Use Blizzy's toolbar", "Will take effect after restart"));
                }

                if (FlightGlobals.ActiveVessel != null)
                {
                    GUILayout.Label("Position:");
                    GUILayout.BeginHorizontal();
                    var body     = FlightGlobals.ActiveVessel.mainBody;
                    var worldPos = FlightGlobals.ActiveVessel.GetWorldPos3D();
                    GUILayout.Label("lat=" + body.GetLatitude(worldPos).ToString("000.000000"), GUILayout.Width(110));
                    GUILayout.Label("lng=" + body.GetLongitude(worldPos).ToString("000.000000"), GUILayout.Width(110));
                    GUILayout.EndHorizontal();
                }

                GUILayout.Label("Aerodynamic model: " + traj.AerodynamicModelName);
                GUILayout.BeginHorizontal();
                GUILayout.Label("Perf: " + (traj.ComputationTime * 1000.0f).ToString("0.0") + "ms (" + (traj.ComputationTime / traj.GameFrameTime * 100.0f).ToString("0") + "%)", GUILayout.Width(120));
                GUILayout.Label(traj.ErrorCount + " error(s)", GUILayout.Width(80));
                GUILayout.EndHorizontal();
            }

            tooltip = GUI.tooltip;

            GUI.DragWindow();
        }
 public StockModel(Trajectory trajectory, CelestialBody body) : base(trajectory, body)
 {
 }