/// <summary> /// Gets the descending node of orbit. /// </summary> /// <param name="desc">The desc.</param> /// <returns><c>true</c> if descending node exists, otherwise <c>false</c></returns> public bool GetDescendingNode(out Vector3d desc) { var norm = CelestialBodyUtils.CrossProduct(OrbitNormal, EclipticNormal); var s = CelestialBodyUtils.DotProduct(CelestialBodyUtils.CrossProduct(norm, SemiMajorAxisBasis), OrbitNormal) < 0; var ecc = 0d; var trueAnom = Vector3d.Angle(norm, -CenterPoint) * Mathd.Deg2Rad; if (Eccentricity < 1) { var cosT = Math.Cos(trueAnom); ecc = Math.Acos((Eccentricity + cosT) / (1d + Eccentricity * cosT)); if (s) { ecc = Mathd.PI_2 - ecc; } } else { trueAnom = Vector3d.Angle(norm, CenterPoint) * Mathd.Deg2Rad; if (trueAnom >= Mathd.Acos(-1d / Eccentricity)) { desc = new Vector3d(); return(false); } var cosT = Math.Cos(trueAnom); ecc = CelestialBodyUtils.Acosh((Eccentricity + cosT) / (1 + Eccentricity * cosT)) * (s ? -1 : 1); } desc = GetFocalPositionAtEccentricAnomaly(ecc); return(true); }
public bool GetAscendingNode(out Vector3d asc) { var norm = CelestialBodyUtils.CrossProduct(orbitNormal, eclipticNormal); var s = CelestialBodyUtils.DotProduct(CelestialBodyUtils.CrossProduct(norm, semiMajorAxisBasis), orbitNormal) < 0; var ecc = 0d; var trueAnom = Vector3d.Angle(norm, centerPoint) * Mathd.Deg2Rad; if (eccentricity < 1) { var cosT = System.Math.Cos(trueAnom); ecc = System.Math.Acos((eccentricity + cosT) / (1d + eccentricity * cosT)); if (!s) { ecc = Mathd.PI_2 - ecc; } } else { trueAnom = Vector3d.Angle(-norm, centerPoint) * Mathd.Deg2Rad; if (trueAnom >= Mathd.Acos(-1d / eccentricity)) { asc = new Vector3d(); return(false); } var cosT = System.Math.Cos(trueAnom); ecc = CelestialBodyUtils.Acosh((eccentricity + cosT) / (1 + eccentricity * cosT)) * (!s ? -1 : 1); } asc = GetFocalPositionAtEccentricAnomaly(ecc); return(true); }
/// <summary> /// Draw two crossing lines in scene view. /// </summary> private static void DrawX(Vector3 pos, float size, Color col, Vector3 normal, Vector3 up) { Handles.color = col; Vector3 right = CelestialBodyUtils.CrossProduct(up, normal).normalized; Handles.DrawLine(pos + up * size, pos - up * size); Handles.DrawLine(pos + right * size, pos - right * size); }
public static Vector3[] CalcOrbitPoints(Vector3 attractorPos, Vector3 bodyPos, double attractorMass, double bodyMass, Vector3 relVelocity, double gConst, int pointsCount) { if (pointsCount < 3 || pointsCount > 10000) { return(new Vector3[0]); } var focusPoint = CalcCenterOfMass(attractorPos, attractorMass, bodyPos, bodyMass); var radiusVector = bodyPos - focusPoint; var radiusVectorMagnitude = radiusVector.magnitude; var orbitNormal = CelestialBodyUtils.CrossProduct(radiusVector, relVelocity); var MG = (attractorMass + bodyMass) * gConst; var eccVector = CelestialBodyUtils.CrossProduct(relVelocity, orbitNormal) / (float)MG - radiusVector / radiusVectorMagnitude; var focalParameter = orbitNormal.sqrMagnitude / MG; var eccentricity = eccVector.magnitude; var minorAxisNormal = -CelestialBodyUtils.CrossProduct(orbitNormal, eccVector).normalized; var majorAxisNormal = -CelestialBodyUtils.CrossProduct(orbitNormal, minorAxisNormal).normalized; orbitNormal.Normalize(); double orbitCompressionRatio; double semiMajorAxys; double semiMinorAxys; Vector3 relFocusPoint; Vector3 centerPoint; if (eccentricity < 1) { orbitCompressionRatio = 1 - eccentricity * eccentricity; semiMajorAxys = focalParameter / orbitCompressionRatio; semiMinorAxys = semiMajorAxys * System.Math.Sqrt(orbitCompressionRatio); relFocusPoint = (float)semiMajorAxys * eccVector; centerPoint = focusPoint - relFocusPoint; } else { orbitCompressionRatio = eccentricity * eccentricity - 1f; semiMajorAxys = focalParameter / orbitCompressionRatio; semiMinorAxys = semiMajorAxys * System.Math.Sqrt(orbitCompressionRatio); relFocusPoint = -(float)semiMajorAxys * eccVector; centerPoint = focusPoint - relFocusPoint; } var points = new Vector3[pointsCount]; double eccVar = 0f; for (int i = 0; i < pointsCount; i++) { Vector3 result = eccentricity < 1 ? new Vector3((float)(System.Math.Sin(eccVar) * semiMinorAxys), -(float)(System.Math.Cos(eccVar) * semiMajorAxys)) : new Vector3((float)(System.Math.Sinh(eccVar) * semiMinorAxys), (float)(System.Math.Cosh(eccVar) * semiMajorAxys)); eccVar += Mathf.PI * 2f / (float)(pointsCount - 1); points[i] = minorAxisNormal * result.x + majorAxisNormal * result.y + centerPoint; } return(points); }
private void DrawInclinationMarkForBody(CelestialBody body, float scale) { var norm = CelestialBodyUtils.CrossProduct((Vector3)body.OrbitData.OrbitNormal, (Vector3)_simControl.EclipticNormal); Handles.color = Color.white; var p = CelestialBodyUtils.CrossProduct(norm, (Vector3)_simControl.EclipticNormal).normalized; Handles.DrawLine((Vector3)body.OrbitFocusPoint, (Vector3)body.OrbitFocusPoint + p * 3f * scale); Handles.DrawLine((Vector3)body.OrbitFocusPoint, (Vector3)body.OrbitFocusPoint + CelestialBodyUtils.RotateVectorByAngle(p, (float)body.OrbitData.Inclination, -norm.normalized) * 3f * scale); Handles.DrawWireArc((Vector3)body.OrbitFocusPoint, -norm, p, (float)(body.OrbitData.Inclination * Mathd.Rad2Deg), 1f * scale); DrawLabelScaled((Vector3)body.OrbitFocusPoint + p * scale, (body.OrbitData.Inclination * Mathd.Rad2Deg).ToString("0") + "\u00B0", Color.white, 10); }
/// <summary> /// Draw simple arrow in scene window at given world coordinates /// </summary> private static void DrawArrow(Vector3 from, Vector3 to, Color col, Vector3 normal) { var dir = to - from; float dist = dir.magnitude; var dirNorm = dir / dist; //normalized vector float headSize = dist / 6f; var _colBefore = Handles.color; Handles.color = col; Vector3 sideNormal = CelestialBodyUtils.CrossProduct(dir, normal).normalized; Handles.DrawLine(from, from + dirNorm * (dist - headSize)); Handles.DrawLine(from + dirNorm * (dist - headSize) + sideNormal * headSize / 2f, from + dirNorm * (dist - headSize) - sideNormal * headSize / 2f); Handles.DrawLine(from + dirNorm * (dist - headSize) + sideNormal * headSize / 2f, from + dir); Handles.DrawLine(from + dirNorm * (dist - headSize) - sideNormal * headSize / 2f, from + dir); Handles.color = _colBefore; }
/// <summary> /// Calculates the full state of orbit from current body position, attractor position, attractor mass, velocity, and gravConstant. /// </summary> public void CalculateNewOrbitData() { IsDirty = false; var MG = AttractorMass * GravitationalConstant; AttractorDistance = Position.magnitude; var angularMomentumVector = CelestialBodyUtils.CrossProduct(Position, Velocity); OrbitNormal = angularMomentumVector.normalized; Vector3d eccVector; // Check if zero lenght. if (OrbitNormal.sqrMagnitude < 0.9 || OrbitNormal.sqrMagnitude > 1.1) { OrbitNormal = CelestialBodyUtils.CrossProduct(Position, EclipticUp).normalized; eccVector = new Vector3d(); } else { eccVector = CelestialBodyUtils.CrossProduct(Velocity, angularMomentumVector) / MG - Position / AttractorDistance; } OrbitNormalDotEclipticNormal = CelestialBodyUtils.DotProduct(OrbitNormal, EclipticNormal); FocalParameter = angularMomentumVector.sqrMagnitude / MG; Eccentricity = eccVector.magnitude; EnergyTotal = Velocity.sqrMagnitude - 2 * MG / AttractorDistance; SemiMinorAxisBasis = CelestialBodyUtils.CrossProduct(angularMomentumVector, eccVector).normalized; if (SemiMinorAxisBasis.sqrMagnitude < 0.5) { SemiMinorAxisBasis = CelestialBodyUtils.CrossProduct(OrbitNormal, Position).normalized; } SemiMajorAxisBasis = CelestialBodyUtils.CrossProduct(OrbitNormal, SemiMinorAxisBasis).normalized; Inclination = Vector3d.Angle(OrbitNormal, EclipticNormal) * Mathd.Deg2Rad; if (Eccentricity < 1) { OrbitCompressionRatio = 1 - Eccentricity * Eccentricity; SemiMajorAxis = FocalParameter / OrbitCompressionRatio; SemiMinorAxis = SemiMajorAxis * Math.Sqrt(OrbitCompressionRatio); CenterPoint = -SemiMajorAxis * eccVector; Period = Mathd.PI_2 * Mathd.Sqrt(Mathd.Pow(SemiMajorAxis, 3) / MG); Apoapsis = CenterPoint + SemiMajorAxisBasis * SemiMajorAxis; Periapsis = CenterPoint - SemiMajorAxisBasis * SemiMajorAxis; PeriapsisDistance = Periapsis.magnitude; ApoapsisDistance = Apoapsis.magnitude; TrueAnomaly = Vector3d.Angle(Position, -SemiMajorAxisBasis) * Mathd.Deg2Rad; if (CelestialBodyUtils.DotProduct(CelestialBodyUtils.CrossProduct(Position, SemiMajorAxisBasis), OrbitNormal) < 0) { TrueAnomaly = Mathd.PI_2 - TrueAnomaly; } EccentricAnomaly = CelestialBodyUtils.ConvertTrueToEccentricAnomaly(TrueAnomaly, Eccentricity); MeanAnomaly = EccentricAnomaly - Eccentricity * Math.Sin(EccentricAnomaly); } else { OrbitCompressionRatio = Eccentricity * Eccentricity - 1; SemiMajorAxis = FocalParameter / OrbitCompressionRatio; SemiMinorAxis = SemiMajorAxis * Math.Sqrt(OrbitCompressionRatio); CenterPoint = SemiMajorAxis * eccVector; Period = double.PositiveInfinity; Apoapsis = new Vector3d(double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity); Periapsis = CenterPoint + SemiMajorAxisBasis * (SemiMajorAxis); PeriapsisDistance = Periapsis.magnitude; ApoapsisDistance = double.PositiveInfinity; TrueAnomaly = Vector3d.Angle(Position, eccVector) * Mathd.Deg2Rad; if (CelestialBodyUtils.DotProduct(CelestialBodyUtils.CrossProduct(Position, SemiMajorAxisBasis), OrbitNormal) < 0) { TrueAnomaly = -TrueAnomaly; } EccentricAnomaly = CelestialBodyUtils.ConvertTrueToEccentricAnomaly(TrueAnomaly, Eccentricity); MeanAnomaly = Math.Sinh(EccentricAnomaly) * Eccentricity - EccentricAnomaly; } }
public void CalculateNewOrbitData() { isDirty = false; var MG = attractorMass * gravConst; attractorDistance = position.magnitude; var angularMomentumVector = CelestialBodyUtils.CrossProduct(position, velocity); orbitNormal = angularMomentumVector.normalized; Vector3d eccVector; if (orbitNormal.sqrMagnitude < 0.9 || orbitNormal.sqrMagnitude > 1.1) //check if zero lenght { orbitNormal = CelestialBodyUtils.CrossProduct(position, eclipticUp).normalized; eccVector = new Vector3d(); } else { eccVector = CelestialBodyUtils.CrossProduct(velocity, angularMomentumVector) / MG - position / attractorDistance; } orbitNormalDotEclipticNormal = CelestialBodyUtils.DotProduct(orbitNormal, eclipticNormal); focalParameter = angularMomentumVector.sqrMagnitude / MG; eccentricity = eccVector.magnitude; //if (debug) { // string format = "0.0000000000"; // Debug.Log( // "ECC: " + eccVector.ToString(format) + " LEN: " + eccVector.magnitude.ToString(format) + "\n" + // "POS: " + position.ToString(format) + " LEN: " + position.magnitude.ToString(format) + "\n" + // "POSNORM: " + ( position / attractorDistance ).ToString(format) + " LEN: " + ( position / attractorDistance ).magnitude.ToString(format) + "\n" + // "VEL: " + velocity.ToString(format) + " LEN: " + velocity.magnitude.ToString(format) + "\n" + // "POScrossVEL: " + angularMomentumVector.ToString(format) + " LEN: " + angularMomentumVector.magnitude.ToString(format) + "\n" // ); //} energyTotal = velocity.sqrMagnitude - 2 * MG / attractorDistance; semiMinorAxisBasis = CelestialBodyUtils.CrossProduct(angularMomentumVector, eccVector).normalized; if (semiMinorAxisBasis.sqrMagnitude < 0.5) { semiMinorAxisBasis = CelestialBodyUtils.CrossProduct(orbitNormal, position).normalized; } semiMajorAxisBasis = CelestialBodyUtils.CrossProduct(orbitNormal, semiMinorAxisBasis).normalized; inclination = Vector3d.Angle(orbitNormal, eclipticNormal) * Mathd.Deg2Rad; if (eccentricity < 1) { orbitCompressionRatio = 1 - eccentricity * eccentricity; semiMajorAxis = focalParameter / orbitCompressionRatio; semiMinorAxis = semiMajorAxis * System.Math.Sqrt(orbitCompressionRatio); centerPoint = -semiMajorAxis * eccVector; period = Mathd.PI_2 * Mathd.Sqrt(Mathd.Pow(semiMajorAxis, 3) / MG); apoapsis = centerPoint + semiMajorAxisBasis * semiMajorAxis; periapsis = centerPoint - semiMajorAxisBasis * semiMajorAxis; periapsisDistance = periapsis.magnitude; apoapsisDistance = apoapsis.magnitude; trueAnomaly = Vector3d.Angle(position, -semiMajorAxisBasis) * Mathd.Deg2Rad; if (CelestialBodyUtils.DotProduct(CelestialBodyUtils.CrossProduct(position, semiMajorAxisBasis), orbitNormal) < 0) { trueAnomaly = Mathd.PI_2 - trueAnomaly; } eccentricAnomaly = CelestialBodyUtils.ConvertTrueToEccentricAnomaly(trueAnomaly, eccentricity); meanAnomaly = eccentricAnomaly - eccentricity * System.Math.Sin(eccentricAnomaly); } else { orbitCompressionRatio = eccentricity * eccentricity - 1; semiMajorAxis = focalParameter / orbitCompressionRatio; semiMinorAxis = semiMajorAxis * System.Math.Sqrt(orbitCompressionRatio); centerPoint = semiMajorAxis * eccVector; period = double.PositiveInfinity; apoapsis = new Vector3d(double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity); periapsis = centerPoint + semiMajorAxisBasis * (semiMajorAxis); periapsisDistance = periapsis.magnitude; apoapsisDistance = double.PositiveInfinity; trueAnomaly = Vector3d.Angle(position, eccVector) * Mathd.Deg2Rad; if (CelestialBodyUtils.DotProduct(CelestialBodyUtils.CrossProduct(position, semiMajorAxisBasis), orbitNormal) < 0) { trueAnomaly = -trueAnomaly; } eccentricAnomaly = CelestialBodyUtils.ConvertTrueToEccentricAnomaly(trueAnomaly, eccentricity); meanAnomaly = System.Math.Sinh(eccentricAnomaly) * eccentricity - eccentricAnomaly; } }