/*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(); }
/*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 }
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(); }
public void Start() { fetch_ = this; }
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); }
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(); }
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(); }
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; } }
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); }
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(); }
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"); } } }
internal void FixedUpdate() => Trajectory.DebugTelemetry();
public FARModel(Trajectory trajectory, CelestialBody body, MethodInfo CalculateVesselAeroForces) : base(trajectory, body) { FARAPI_CalculateVesselAeroForces = CalculateVesselAeroForces; }
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(); }
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(); }
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"); } }
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(); }
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) { }