//
// Kerbal Engineer Redux
//
// Copyright (C) 2015 CYBUTEK
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
namespace KerbalEngineer.Flight.Readouts.Rendezvous
{
using System;
using Extensions;
using Helpers;
public class RendezvousProcessor : IUpdatable, IUpdateRequest
{
private static readonly RendezvousProcessor instance = new RendezvousProcessor();
private Orbit originOrbit;
private Orbit targetOrbit;
///
/// Gets the target's altitude above its reference body.
///
public static double AltitudeSeaLevel { get; private set; }
///
/// Gets the angle from the origin position to the ascending node.
///
public static double AngleToAscendingNode { get; private set; }
///
/// Gets the angle from the origin position to the descending node.
///
public static double AngleToDescendingNode { get; private set; }
///
/// Gets the target's apoapsis above its reference body.
///
public static double ApoapsisHeight { get; private set; }
///
/// Gets the distance from the origin position to the target position.
///
public static double Distance { get; private set; }
///
/// Gets the current instance of the rendezvous processor.
///
public static RendezvousProcessor Instance
{
get
{
return instance;
}
}
///
/// Gets the difference in angle from the origin position to where it is most efficient to burn for an encounter.
///
public static double InterceptAngle { get; private set; }
///
/// Gets the orbital period of the target orbit.
///
public static double OrbitalPeriod { get; private set; }
///
/// Gets the target's periapsis above its reference body.
///
public static double PeriapsisHeight { get; private set; }
///
/// Gets the difference in angle from the origin position to the target position based on a common reference.
///
public static double PhaseAngle { get; private set; }
///
/// Gets the angular difference between the origin and target orbits.
///
public static double RelativeInclination { get; private set; }
///
/// Gets the relative orbital speed between the vessel and target.
///
public static double RelativeSpeed { get; private set; }
///
/// Gets the relative orbital velocity between the vessel and target.
///
public static double RelativeVelocity { get; private set; }
///
/// Gets the semi-major axis of the target orbit.
///
public static double SemiMajorAxis { get; private set; }
///
/// Gets the semi-minor axis of the target orbit.
///
public static double SemiMinorAxis { get; private set; }
///
/// Gets whether the details are ready to be shown.
///
public static bool ShowDetails { get; private set; }
///
/// Gets the target's time to apoapsis.
///
public static double TimeToApoapsis { get; private set; }
///
/// Gets the time it will take to reach the ascending node.
///
public static double TimeToAscendingNode { get; private set; }
///
/// Gets the time it will take to reach the descending node.
///
public static double TimeToDescendingNode { get; private set; }
///
/// Gets the target's time to periapsis.
///
public static double TimeToPeriapsis { get; private set; }
///
/// Gets and sets whether the updatable object should be updated.
///
public bool UpdateRequested { get; set; }
///
/// Request and update to calculate the details.
///
public static void RequestUpdate()
{
instance.UpdateRequested = true;
}
///
/// Updates the details by recalculating if requested.
///
public void Update()
{
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;
}
ShowDetails = true;
targetOrbit = FlightGlobals.fetch.VesselTarget.GetOrbit();
originOrbit = (FlightGlobals.ship_orbit.referenceBody == Planetarium.fetch.Sun ||
FlightGlobals.ship_orbit.referenceBody == FlightGlobals.ActiveVessel.targetObject.GetOrbit().referenceBody)
? FlightGlobals.ship_orbit
: FlightGlobals.ship_orbit.referenceBody.orbit;
RelativeInclination = originOrbit.GetRelativeInclination(targetOrbit);
RelativeVelocity = FlightGlobals.ship_tgtSpeed;
RelativeSpeed = FlightGlobals.ship_obtSpeed - targetOrbit.orbitalSpeed;
PhaseAngle = originOrbit.GetPhaseAngle(targetOrbit);
InterceptAngle = CalcInterceptAngle();
TimeToAscendingNode = originOrbit.GetTimeToVector(GetAscendingNode());
TimeToDescendingNode = originOrbit.GetTimeToVector(GetDescendingNode());
AngleToAscendingNode = originOrbit.GetAngleToVector(GetAscendingNode());
AngleToDescendingNode = originOrbit.GetAngleToVector(GetDescendingNode());
AltitudeSeaLevel = targetOrbit.altitude;
ApoapsisHeight = targetOrbit.ApA;
PeriapsisHeight = targetOrbit.PeA;
TimeToApoapsis = targetOrbit.timeToAp;
TimeToPeriapsis = targetOrbit.timeToPe;
SemiMajorAxis = targetOrbit.semiMajorAxis;
SemiMinorAxis = targetOrbit.semiMinorAxis;
Distance = Vector3d.Distance(targetOrbit.pos, originOrbit.pos);
OrbitalPeriod = targetOrbit.period;
}
private double CalcInterceptAngle()
{
double originRadius = (originOrbit.semiMinorAxis + originOrbit.semiMajorAxis) * 0.5;
double targetRadius = (targetOrbit.semiMinorAxis + targetOrbit.semiMajorAxis) * 0.5;
double angle = 180.0 * (1.0 - Math.Pow((originRadius + targetRadius) / (2.0 * targetRadius), 1.5));
angle = PhaseAngle - angle;
return RelativeInclination < 90.0 ? AngleHelper.Clamp360(angle) : AngleHelper.Clamp360(360.0 - (180.0 - angle));
}
private Vector3d GetAscendingNode()
{
return Vector3d.Cross(targetOrbit.GetOrbitNormal(), originOrbit.GetOrbitNormal());
}
private Vector3d GetDescendingNode()
{
return Vector3d.Cross(originOrbit.GetOrbitNormal(), targetOrbit.GetOrbitNormal());
}
}
}