Example #1
0
        private static bool GetClosestVessel(Orbit refP, Orbit tgtP)
        {
            if (refP == null || tgtP == null)
            {
                return(false);
            }

            if (refP.referenceBody != tgtP.referenceBody)
            {
                return(false);
            }

            if (!Orbit.PeApIntersects(refP, tgtP, 20000))
            {
                return(false);
            }

            double d1  = 0;
            double d2  = 0;
            double dT1 = 0;
            double d4  = 0;
            double dT2 = 0;
            double d6  = 0;
            int    i1  = 0;

            int intersects = Orbit.FindClosestPoints(refP, tgtP, ref d1, ref d2, ref dT1, ref d4, ref dT2, ref d6, 0.001, 10, ref i1);

            double UT1 = refP.StartUT + refP.GetDTforTrueAnomaly(dT1, 0);
            double UT2 = refP.StartUT + refP.GetDTforTrueAnomaly(dT2, 0);

            if (intersects > 1)
            {
                double dist1 = double.MaxValue;

                if (PatchedConics.TAIsWithinPatchBounds(UT1, refP))
                {
                    Vector3d refClosest1 = refP.getRelativePositionAtUT(UT1);
                    Vector3d tgtClosest1 = tgtP.getRelativePositionAtUT(UT1);

                    dist1 = (refClosest1 - tgtClosest1).magnitude;
                }

                double dist2 = double.MaxValue;

                if (PatchedConics.TAIsWithinPatchBounds(UT2, refP))
                {
                    Vector3d refClosest2 = refP.getRelativePositionAtUT(UT2);
                    Vector3d tgtClosest2 = tgtP.getRelativePositionAtUT(UT2);

                    dist2 = (refClosest2 - tgtClosest2).magnitude;
                }

                if (dist1 > double.MaxValue - 1000 && dist2 > double.MaxValue - 1000)
                {
                    return(false);
                }

                bool first = dist1 < dist2;

                if (first)
                {
                    _closestDist = dist1;
                    _closestTime = UT1;

                    Vector3d refVel = refP.getOrbitalVelocityAtUT(UT1);
                    Vector3d tgtVel = tgtP.getOrbitalVelocityAtUT(UT1);

                    _closestRelVel = (refVel - tgtVel).magnitude;
                }
                else
                {
                    _closestDist = dist2;
                    _closestTime = UT2;

                    Vector3d refVel = refP.getOrbitalVelocityAtUT(UT2);
                    Vector3d tgtVel = tgtP.getOrbitalVelocityAtUT(UT2);

                    _closestRelVel = (refVel - tgtVel).magnitude;
                }

                return(true);
            }
            else
            {
                if (!PatchedConics.TAIsWithinPatchBounds(UT1, refP))
                {
                    UT1 = double.MaxValue;
                }

                if (!PatchedConics.TAIsWithinPatchBounds(UT2, refP))
                {
                    UT2 = double.MaxValue;
                }

                if (UT1 > double.MaxValue - 1000 && UT2 > double.MaxValue - 1000)
                {
                    return(false);
                }

                double useUT = UT1 < UT2 ? UT1 : UT2;

                Vector3d refClosest = refP.getRelativePositionAtUT(useUT);
                Vector3d tgtClosest = tgtP.getRelativePositionAtUT(useUT);

                Vector3d refVel = refP.getOrbitalVelocityAtUT(useUT);
                Vector3d tgtVel = tgtP.getOrbitalVelocityAtUT(useUT);

                _closestDist   = (refClosest - tgtClosest).magnitude;
                _closestRelVel = (refVel - tgtVel).magnitude;
                _closestTime   = useUT;

                return(true);
            }
        }
Example #2
0
        public static double closestVessel(double UT, Orbit o, Orbit tgt, bool closest, double min, double max)
        {
            double appUT = 0;

            if (o.referenceBody != tgt.referenceBody)
            {
                return(0);
            }

            if (!Orbit.PeApIntersects(o, tgt, 20000))
            {
                return(0);
            }

            double d1  = 0;
            double d2  = 0;
            double dT1 = 0;
            double d4  = 0;
            double dT2 = 0;
            double d6  = 0;
            int    i1  = 0;

            int intersects = Orbit.FindClosestPoints(o, tgt, ref d1, ref d2, ref dT1, ref d4, ref dT2, ref d6, 0.001, 10, ref i1);

            double UT1 = o.StartUT + o.GetDTforTrueAnomaly(dT1, 0);
            double UT2 = o.StartUT + o.GetDTforTrueAnomaly(dT2, 0);

            if (intersects > 1)
            {
                double dist1 = double.MaxValue;

                if (PatchedConics.TAIsWithinPatchBounds(UT1, o))
                {
                    Vector3d refClosest1 = o.getRelativePositionAtUT(UT1);
                    Vector3d tgtClosest1 = tgt.getRelativePositionAtUT(UT1);

                    dist1 = (refClosest1 - tgtClosest1).magnitude;
                }

                double dist2 = double.MaxValue;

                if (PatchedConics.TAIsWithinPatchBounds(UT2, o))
                {
                    Vector3d refClosest2 = o.getRelativePositionAtUT(UT2);
                    Vector3d tgtClosest2 = tgt.getRelativePositionAtUT(UT2);

                    dist2 = (refClosest2 - tgtClosest2).magnitude;
                }

                if (dist1 > double.MaxValue - 1000 && dist2 > double.MaxValue - 1000)
                {
                    return(0);
                }

                appUT = dist1 < dist2 ? UT1 : UT2;

                if (closest)
                {
                    return(appUT);
                }

                if (appUT >= min && appUT <= max)
                {
                    return(appUT);
                }

                appUT = dist1 < dist2 ? UT2 : UT1;

                if (appUT >= min && appUT <= max)
                {
                    return(appUT);
                }
            }
            else
            {
                if (!PatchedConics.TAIsWithinPatchBounds(UT1, o))
                {
                    UT1 = double.MaxValue;
                }

                if (!PatchedConics.TAIsWithinPatchBounds(UT2, o))
                {
                    UT2 = double.MaxValue;
                }

                if (UT1 > double.MaxValue - 1000 && UT2 > double.MaxValue - 1000)
                {
                    return(0);
                }

                appUT = UT1 < UT2 ? UT1 : UT2;

                return(appUT);
            }

            return(0);
        }
Example #3
0
        public static void Add(Kerbulator kalc)
        {
            // Planets
            foreach (CelestialBody b in FlightGlobals.Bodies)
            {
                if (b.name == "Sun")
                {
                    AddCelestialBody(kalc, b, "Kerbol");
                }
                else
                {
                    AddCelestialBody(kalc, b, b.name);
                }
            }

            Vessel v      = FlightGlobals.ActiveVessel;
            Orbit  orbit1 = v.orbit;

            if (v != null)
            {
                // Current orbit
                AddOrbit(kalc, orbit1, "Craft");

                // Current position in carthesian coordinates
                AddVector3d(kalc, "Craft.Pos", v.GetWorldPos3D());

                // Navball (thank you MechJeb source)
                Vector3d   CoM                   = v.findWorldCenterOfMass();
                Vector3d   up                    = (CoM - v.mainBody.position).normalized;
                Vector3d   north                 = Vector3d.Exclude(up, (v.mainBody.position + v.mainBody.transform.up * (float)v.mainBody.Radius) - CoM).normalized;
                Quaternion rotationSurface       = Quaternion.LookRotation(north, up);
                Quaternion rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(v.GetTransform().rotation) * rotationSurface);
                Vector3d   velocityVesselOrbit   = v.orbit.GetVel();
                Vector3d   velocityVesselSurface = velocityVesselOrbit - v.mainBody.getRFrmVel(CoM);

                AddDouble(kalc, "Navball.Heading", rotationVesselSurface.eulerAngles.y);
                AddDouble(kalc, "Navball.Pitch", (rotationVesselSurface.eulerAngles.x > 180) ? (360.0 - rotationVesselSurface.eulerAngles.x) : -rotationVesselSurface.eulerAngles.x);
                AddDouble(kalc, "Navball.Roll", (rotationVesselSurface.eulerAngles.z > 180) ? (rotationVesselSurface.eulerAngles.z - 360.0) : rotationVesselSurface.eulerAngles.z);
                AddDouble(kalc, "Navball.OrbitalVelocity", velocityVesselOrbit.magnitude);
                AddDouble(kalc, "Navball.SurfaceVelocity", velocityVesselSurface.magnitude);
                AddDouble(kalc, "Navball.VerticalVelocity", Vector3d.Dot(velocityVesselSurface, up));

                // Current time
                double UT = (double)Planetarium.GetUniversalTime();
                AddDouble(kalc, "UT", UT);

                // Reference body
                AddCelestialBody(kalc, v.orbit.referenceBody, "Parent");

                // Target
                if (FlightGlobals.fetch.VesselTarget != null)
                {
                    ITargetable target = FlightGlobals.fetch.VesselTarget;
                    Orbit       orbit2 = target.GetOrbit();

                    // Target Orbit
                    AddOrbit(kalc, orbit2, "Target");

                    // Intersection with target orbit
                    double CD             = 0.0;
                    double CCD            = 0.0;
                    double FFp            = 0.0;
                    double FFs            = 0.0;
                    double SFp            = 0.0;
                    double SFs            = 0.0;
                    int    iterationCount = 0;
                    Orbit.FindClosestPoints(orbit1, orbit2, ref CD, ref CCD, ref FFp, ref FFs, ref SFp, ref SFs, 0.0, 100, ref iterationCount);
                    double T1 = orbit1.GetDTforTrueAnomaly(FFp, 0.0);
                    double T2 = orbit1.GetDTforTrueAnomaly(SFp, 0.0);
                    AddDouble(kalc, "Craft.Inter1.dt", T1);
                    AddDouble(kalc, "Craft.Inter1.Δt", T1);
                    AddDouble(kalc, "Craft.Inter1.Sep", (orbit1.getPositionAtUT(T1 + UT) - orbit2.getPositionAtUT(T1 + UT)).magnitude);
                    AddDouble(kalc, "Craft.Inter1.TrueAnomaly", orbit1.TrueAnomalyAtUT(T1 + UT));
                    AddDouble(kalc, "Craft.Inter1.θ", orbit1.TrueAnomalyAtUT(T1 + UT));
                    AddDouble(kalc, "Craft.Inter2.dt", T2);
                    AddDouble(kalc, "Craft.Inter2.Δt", T2);
                    AddDouble(kalc, "Craft.Inter2.Sep", (orbit1.getPositionAtUT(T2 + UT) - orbit2.getPositionAtUT(T2 + UT)).magnitude);
                    AddDouble(kalc, "Craft.Inter2.TrueAnomaly", orbit2.TrueAnomalyAtUT(T2 + UT));
                    AddDouble(kalc, "Craft.Inter2.θ", orbit2.TrueAnomalyAtUT(T2 + UT));
                }
            }
        }
Example #4
0
        /// <summary>
        ///     Updates the details by recalculating if requested.
        /// </summary>
        public void Update()
        {
            ITargetable    target = null;
            global::Vessel vessel = null;

            landedSamePlanet = false;
            isLanded         = false;
            overrideANDN     = false;
            overrideANDNRev  = false;

            if (HighLogic.LoadedSceneIsFlight)
            {
                if (FlightGlobals.fetch == null ||
                    FlightGlobals.fetch.VesselTarget == null ||
                    FlightGlobals.ActiveVessel == null ||
                    FlightGlobals.ActiveVessel.targetObject == null ||
                    FlightGlobals.ActiveVessel.targetObject.GetOrbit() == null ||
                    FlightGlobals.ship_orbit == null ||
                    FlightGlobals.ship_orbit.referenceBody == null)
                {
                    ShowDetails = false;
                    return;
                }
                else
                {
                    target = FlightGlobals.ActiveVessel.targetObject;
                    vessel = FlightGlobals.ActiveVessel;
                }
                TrackingStationSource = null;
            }
            else if (HighLogic.LoadedScene == GameScenes.TRACKSTATION)
            {
                if (PlanetariumCamera.fetch.target.type == MapObject.ObjectType.CelestialBody)
                {
                    target = PlanetariumCamera.fetch.target.celestialBody;
                }
                else if (PlanetariumCamera.fetch.target.type == MapObject.ObjectType.Vessel)
                {
                    target = PlanetariumCamera.fetch.target.vessel;
                }

                if (TrackingStationSource != null)
                {
                    vessel = TrackingStationSource.GetVessel();
                }
                else
                {
                    TrackingStationSource = target;
                }
            }

            activeTarget = target;

            if (target == null)
            {
                ShowDetails = false;
                return;
            }

            ShowDetails = true;

            var actualSourceOrbit = vessel != null ? vessel.orbit : TrackingStationSource.GetOrbit();
            var actualTargetOrbit = target.GetOrbit();

            if (target is global::Vessel)
            {
                targetVessel = (global::Vessel)target;
            }
            else
            {
                targetVessel = null;
            }

            activeVessel = vessel;

            if (actualSourceOrbit == null)
            {
                //  Debug.Log("Source orbit is null!");
                TrackingStationSource = null;
                ShowDetails           = false;
                return;
            }

            if (actualTargetOrbit == null)
            {
                // Debug.Log("Target orbit is null!");
                ShowDetails = false;
                return;
            }

            isLanded = vessel != null && vessel.LandedOrSplashed;
            bool targetLanded = (target is global::Vessel && ((global::Vessel)target).LandedOrSplashed);

            landedSamePlanet = isLanded && targetLanded && actualSourceOrbit.referenceBody == actualTargetOrbit.referenceBody;

            var originOrbit = isLanded ? actualSourceOrbit.referenceBody.orbit : actualSourceOrbit;
            var targetOrbit = targetLanded ? actualTargetOrbit.referenceBody.orbit : actualTargetOrbit;

            if ((!isLanded && !targetLanded) || (actualSourceOrbit.referenceBody != actualTargetOrbit.referenceBody))
            {
                findConcentricParents(ref originOrbit, ref targetOrbit);
            }

            if (originOrbit == targetOrbit && !landedSamePlanet)
            {
                targetOrbit = actualTargetOrbit;
                originOrbit = null;
            }

            { //These are not 'rendezvous' calculations, just raw data about the target object.
                AltitudeSeaLevel    = targetOrbit.altitude;
                ApoapsisHeight      = targetOrbit.ApA;
                PeriapsisHeight     = targetOrbit.PeA;
                TimeToApoapsis      = targetOrbit.timeToAp;
                TimeToPeriapsis     = targetOrbit.timeToPe;
                SemiMajorAxis       = targetOrbit.semiMajorAxis;
                SemiMinorAxis       = targetOrbit.semiMinorAxis;
                OrbitalPeriod       = targetOrbit.period;
                RelativeInclination = targetOrbit.inclination;
            }

            { //Set everything else 0 incase some are not valid.
                TimeToAscendingNode   = 0;
                TimeToDescendingNode  = 0;
                AngleToAscendingNode  = 0;
                AngleToDescendingNode = 0;

                RelativeVelocity    = 0;
                RelativeSpeed       = 0;
                PhaseAngle          = 0;
                InterceptAngle      = 0;
                TimeToTransferAngle = 0;

                AngleToPlane[0] = 0;
                TimeToPlane[0]  = 0;
                AngleToPlane[1] = 0;
                TimeToPlane[1]  = 0;
                Distance        = 0;

                TimeTilEncounter      = double.NaN;
                SeparationAtEncounter = double.NaN;
                SpeedAtEncounter      = double.NaN;

                Orbital.ManoeuvreNode.ManoeuvreProcessor.PostBurnRelativeInclination = 0;
            }


            if (originOrbit != null)   //Actually calculating an encounter with 2 different things.

            {
                overrideANDN       = isLanded && actualSourceOrbit.referenceBody == targetOrbit.referenceBody;
                overrideANDNRev    = targetLanded && !isLanded && actualTargetOrbit.referenceBody == actualSourceOrbit.referenceBody && target.GetVessel() != null;
                bodyRotationPeriod = actualSourceOrbit.referenceBody.rotationPeriod;

                if (landedSamePlanet)   //this should only occur when landed targeting something else landed on same body.

                {
                    AltitudeSeaLevel = target.GetVessel().altitude;
                    ApoapsisHeight   = 0;
                    PeriapsisHeight  = 0;
                    TimeToApoapsis   = 0;
                    TimeToPeriapsis  = 0;
                    SemiMajorAxis    = 0;
                    SemiMinorAxis    = 0;
                    Distance         = Vector3d.Distance(target.GetVessel().GetWorldPos3D(), vessel.GetWorldPos3D());
                    OrbitalPeriod    = bodyRotationPeriod;
                }
                else if (overrideANDN)    //launching

                {
                    if (vessel != null)
                    {
                        AngleToPlane   = CalcAngleToPlane(vessel.GetOrbit().referenceBody, vessel.latitude, vessel.longitude, targetOrbit);
                        TimeToPlane[0] = (AngleToPlane[0] / 360) * vessel.GetOrbit().referenceBody.rotationPeriod;
                        TimeToPlane[1] = (AngleToPlane[1] / 360) * vessel.GetOrbit().referenceBody.rotationPeriod;
                    }

                    RelativeInclination = targetOrbit.inclination;
                    PhaseAngle          = OrbitExtensions.GetPhaseAngle(actualSourceOrbit, actualTargetOrbit); //this works for some reason.
                }
                else if (overrideANDNRev)                                                                      //landing

                {
                    global::Vessel tgt = target.GetVessel();

                    if (vessel != null)
                    {
                        AngleToPlane   = CalcAngleToPlane(vessel.GetOrbit().referenceBody, tgt.latitude, tgt.longitude, originOrbit);
                        TimeToPlane[0] = (AngleToPlane[0] / 360) * vessel.GetOrbit().referenceBody.rotationPeriod;
                        TimeToPlane[1] = (AngleToPlane[1] / 360) * vessel.GetOrbit().referenceBody.rotationPeriod;
                    }

                    RelativeInclination = originOrbit.inclination;
                    Distance            = Vector3d.Distance(target.GetVessel().GetWorldPos3D(), vessel.GetWorldPos3D());
                    AltitudeSeaLevel    = tgt.altitude;
                    PhaseAngle          = OrbitExtensions.GetPhaseAngle(actualSourceOrbit, actualTargetOrbit); //this works for some reason.
                }
                else                                                                                           //standard 2 orbits

                {
                    RelativeInclination = OrbitExtensions.GetRelativeInclination(originOrbit, targetOrbit);



                    if (FlightGlobals.ActiveVessel == null || FlightGlobals.ActiveVessel.patchedConicSolver == null ||
                        FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes == null ||
                        FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0)
                    {
                    }
                    else
                    {
                        var node = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0];
                        if (node != null && node.nextPatch != null)
                        {
                            Orbital.ManoeuvreNode.ManoeuvreProcessor.PostBurnRelativeInclination = OrbitExtensions.GetRelativeInclination(node.nextPatch, FlightGlobals.ActiveVessel.targetObject.GetOrbit());
                        }
                    }



                    RelativeSpeed    = originOrbit.GetRelativeVel().magnitude - target.GetObtVelocity().magnitude;
                    RelativeVelocity = (originOrbit.GetRelativeVel() - target.GetObtVelocity()).magnitude;

                    // FlightGlobals.ship_tgtVelocity = FlightGlobals.ship_obtVelocity - this.VesselTarget.GetObtVelocity();
                    // FlightGlobals.ship_tgtSpeed = FlightGlobals.ship_tgtVelocity.magnitude;

                    PhaseAngle     = OrbitExtensions.GetPhaseAngle(originOrbit, targetOrbit);
                    InterceptAngle = CalcInterceptAngle(targetOrbit, originOrbit);

                    double tspd = 360 / targetOrbit.period;
                    double sspd = 360 / originOrbit.period;

                    if (PhaseAngle < 0)
                    {
                        double diff = InterceptAngle - PhaseAngle;
                        if (diff < 0)
                        {
                            diff += 360;
                        }
                        if (diff > 340)
                        {
                            diff -= 360;
                        }
                        TimeToTransferAngle = sspd == tspd ? 0 : diff / (tspd - sspd);
                    }
                    else
                    {
                        double diff = PhaseAngle - InterceptAngle;
                        if (diff < 0)
                        {
                            diff += 360;
                        }
                        if (diff > 340)
                        {
                            diff -= 360;
                        }
                        TimeToTransferAngle = sspd == tspd ? 0 : diff / (sspd - tspd);
                    }


                    TimeToAscendingNode   = OrbitExtensions.GetTimeToVector(originOrbit, GetAscendingNode(targetOrbit, originOrbit));
                    TimeToDescendingNode  = OrbitExtensions.GetTimeToVector(originOrbit, GetDescendingNode(targetOrbit, originOrbit));
                    AngleToAscendingNode  = OrbitExtensions.GetAngleToVector(originOrbit, GetAscendingNode(targetOrbit, originOrbit));
                    AngleToDescendingNode = OrbitExtensions.GetAngleToVector(originOrbit, GetDescendingNode(targetOrbit, originOrbit));

                    Distance = Vector3d.Distance(targetOrbit.pos, originOrbit.pos);


                    //From OrbitTargeter
                    double tOne = 0;
                    if (target is CelestialBody)
                    {
                        Vector3d relativePositionAtUT  = originOrbit.getRelativePositionAtUT(originOrbit.closestTgtApprUT);
                        Vector3d relativePositionAtUT2 = targetOrbit.getRelativePositionAtUT(originOrbit.closestTgtApprUT);
                        double   separation            = (relativePositionAtUT - relativePositionAtUT2).magnitude;
                        tOne = originOrbit.closestTgtApprUT;
                    }
                    else
                    {
                        double num3       = 0.0;
                        double num4       = 0.0;
                        double num5       = 0.0;
                        double eVs        = 0.0;
                        double num6       = 0.0;
                        double eVs2       = 0.0;
                        int    iterations = 0;
                        int    num7       = Orbit.FindClosestPoints(originOrbit, targetOrbit, ref num3, ref num4, ref num5, ref eVs, ref num6, ref eVs2, 0.0001, 20, ref iterations);
                        tOne = originOrbit.StartUT + originOrbit.GetDTforTrueAnomaly(num5, 0.0);
                        double tTwo = originOrbit.StartUT + originOrbit.GetDTforTrueAnomaly(num6, 0.0);
                        if (tOne > tTwo)
                        {
                            UtilMath.SwapValues(ref tOne, ref tTwo);
                            UtilMath.SwapValues(ref num5, ref num6);
                            UtilMath.SwapValues(ref eVs, ref eVs2);
                        }
                    }

                    if (tOne > originOrbit.StartUT)
                    {
                        TimeTilEncounter      = tOne - originOrbit.StartUT;
                        SeparationAtEncounter = (originOrbit.getPositionAtUT(tOne) - targetOrbit.getPositionAtUT(tOne)).magnitude;
                        SpeedAtEncounter      = Math.Abs(originOrbit.getOrbitalSpeedAt(tOne) - targetOrbit.getOrbitalSpeedAt(tOne));
                    }
                }
            }

            if (actualTargetOrbit != targetOrbit)
            {
                targetDisplay = findNameForOrbit(targetOrbit, target);
            }
            else
            {
                targetDisplay = null;
            }

            if (originOrbit == null)
            {
                sourceDisplay = "N/A";
            }
            else if (actualSourceOrbit != originOrbit || HighLogic.LoadedScene == GameScenes.TRACKSTATION)
            {
                sourceDisplay = findNameForOrbit(originOrbit, vessel != null ? vessel : TrackingStationSource);
            }
            else
            {
                sourceDisplay = null;
            }
        }
Example #5
0
        public static void Add(Kerbulator kalc)
        {
            // Planets
            foreach (CelestialBody b in FlightGlobals.Bodies)
            {
                if (b.name == "Sun")
                {
                    AddCelestialBody(kalc, b, "Sun");
                    AddCelestialBody(kalc, b, "Kerbol");
                }
                else
                {
                    AddCelestialBody(kalc, b, b.name);
                }
            }

            // Current time
            double UT = (double)Planetarium.GetUniversalTime();

            AddDouble(kalc, "UT", UT);

            Vessel v = FlightGlobals.ActiveVessel;

            if (v != null)
            {
                // Mission time
                AddDouble(kalc, "MissionTime", v.missionTime);

                // Current orbit
                Orbit orbit1 = v.orbit;
                AddOrbit(kalc, orbit1, "Craft");

                // Navball (thank you MechJeb source)
                Vector3    CoM                   = v.CoM;
                Vector3    up                    = v.up;
                Vector3    north                 = v.north;
                Quaternion rotationSurface       = Quaternion.LookRotation(north, up);
                Quaternion rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(v.GetTransform().rotation) * rotationSurface);
                Vector3    velocityVesselOrbit   = v.orbit.GetVel();
                Vector3    velocityVesselSurface = velocityVesselOrbit - v.mainBody.getRFrmVel(CoM);

                AddDouble(kalc, "Navball.Heading", rotationVesselSurface.eulerAngles.y);
                AddDouble(kalc, "Navball.Pitch", (rotationVesselSurface.eulerAngles.x > 180) ? (360.0 - rotationVesselSurface.eulerAngles.x) : -rotationVesselSurface.eulerAngles.x);
                AddDouble(kalc, "Navball.Roll", (rotationVesselSurface.eulerAngles.z > 180) ? (rotationVesselSurface.eulerAngles.z - 360.0) : rotationVesselSurface.eulerAngles.z);
                AddDouble(kalc, "Navball.OrbitalVelocity", velocityVesselOrbit.magnitude);
                AddDouble(kalc, "Navball.SurfaceVelocity", v.srfSpeed);
                AddDouble(kalc, "Navball.VerticalVelocity", v.verticalSpeed);

                // Reference body
                AddCelestialBody(kalc, v.orbit.referenceBody, "Parent");

                // Target
                if (FlightGlobals.fetch.VesselTarget != null)
                {
                    ITargetable target = FlightGlobals.fetch.VesselTarget;
                    Orbit       orbit2 = target.GetOrbit();

                    // Target Orbit
                    AddOrbit(kalc, orbit2, "Target");

                    // Intersection with target orbit
                    double CD             = 0.0;
                    double CCD            = 0.0;
                    double FFp            = 0.0;
                    double FFs            = 0.0;
                    double SFp            = 0.0;
                    double SFs            = 0.0;
                    int    iterationCount = 0;
                    Orbit.FindClosestPoints(orbit1, orbit2, ref CD, ref CCD, ref FFp, ref FFs, ref SFp, ref SFs, 0.0, 100, ref iterationCount);
                    double t1 = orbit1.GetDTforTrueAnomaly(FFp, 0.0);
                    double t2 = orbit1.GetDTforTrueAnomaly(SFp, 0.0);
                    double T1 = Math.Min(t1, t2);
                    double T2 = Math.Max(t1, t2);

                    AddDouble(kalc, "Craft.Inter1.dt", T1);
                    AddDouble(kalc, "Craft.Inter1.Δt", T1);
                    AddDouble(kalc, "Craft.Inter1.Sep", (orbit1.getPositionAtUT(T1 + UT) - orbit2.getPositionAtUT(T1 + UT)).magnitude);
                    AddDouble(kalc, "Craft.Inter1.TrueAnomaly", orbit1.TrueAnomalyAtUT(T1 + UT) * (180 / Math.PI));
                    AddDouble(kalc, "Craft.Inter1.θ", orbit1.TrueAnomalyAtUT(T1 + UT) * (180 / Math.PI));
                    AddDouble(kalc, "Craft.Inter2.dt", T2);
                    AddDouble(kalc, "Craft.Inter2.Δt", T2);
                    AddDouble(kalc, "Craft.Inter2.Sep", (orbit1.getPositionAtUT(T2 + UT) - orbit2.getPositionAtUT(T2 + UT)).magnitude);
                    AddDouble(kalc, "Craft.Inter2.TrueAnomaly", orbit2.TrueAnomalyAtUT(T2 + UT) * (180 / Math.PI));
                    AddDouble(kalc, "Craft.Inter2.θ", orbit2.TrueAnomalyAtUT(T2 + UT) * (180 / Math.PI));
                    // Relative Ascending and Descending Nodes, Inclination
                    AddDouble(kalc, "Craft.Rel.AN", orbit1.GetTrueAnomalyOfZupVector(Vector3.Cross(orbit2.GetOrbitNormal(), orbit1.GetOrbitNormal())) * (180 / Math.PI));
                    AddDouble(kalc, "Craft.Rel.DN", orbit1.GetTrueAnomalyOfZupVector(Vector3.Cross(orbit1.GetOrbitNormal(), orbit2.GetOrbitNormal())) * (180 / Math.PI));
                    AddDouble(kalc, "Craft.Rel.Inc", Vector3.Angle(orbit1.GetOrbitNormal(), orbit2.GetOrbitNormal()));
                }
            }
        }