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();
        }
Exemple #5
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;
            }
        }