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 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 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() { 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; } }