IntCollection: an indexabled, packed numeric data type for storing very small numbers inside very large ones.
IntCollection: an indexabled, packed numeric data type for storing very small numbers inside very large ones.

file:b/IntCollection.cs (new)
  //
  // IntCollection.cs
  //
  // Author:
  // toadicus <>
  //
  // Copyright (c) 2013 toadicus
  //
  // 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 <http://www.gnu.org/licenses/>.
  using System;
 
  namespace VOID
  {
  public class IntCollection : IVOID_SaveValue
  {
  public static implicit operator long(IntCollection c)
  {
  return c.collection;
  }
 
  protected long mask;
 
  public long collection { get; protected set; }
  public ushort maxCount { get; protected set; }
  public ushort wordLength { get; protected set; }
 
  public Type type { get { return typeof(long); } }
  public object AsType { get { return this.collection; } }
 
  public void SetValue(object v)
  {
  this.collection = (long)v;
  }
 
  public IntCollection (ushort wordLength = 4, long initialCollection = 0)
  {
  this.collection = initialCollection;
  this.wordLength = wordLength;
  this.maxCount = (ushort)((sizeof(long) * 8 - 1) / wordLength);
  this.mask = ((1 << this.wordLength) - 1);
  }
 
  public ushort this[int idx]
  {
  get {
  if (idx < 0) {
  idx += this.maxCount;
  }
 
  if (idx >= maxCount || idx < 0) {
  throw new IndexOutOfRangeException ();
  }
 
  idx *= wordLength;
 
  return (ushort)((this.collection & (this.mask << idx)) >> idx);
  }
  set {
  Console.WriteLine (value);
  if (idx < 0) {
  idx += this.maxCount;
  }
 
  if (idx >= maxCount || idx < 0) {
  throw new IndexOutOfRangeException ();
  }
 
  idx *= wordLength;
 
  long packvalue = value & this.mask;
  Console.WriteLine (packvalue);
 
  this.collection &= ~(this.mask << idx);
  this.collection |= packvalue << idx;
  }
  }
  }
  }
 
 
file:a/Tools.cs -> file:b/Tools.cs
// //
// Tools.cs // Tools.cs
// //
// Author: // Author:
// toadicus // toadicus
// //
// Copyright (c) 2013 toadicus // Copyright (c) 2013 toadicus
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux. // This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.
// Engineer Redux (c) 2013 cybutek // Engineer Redux (c) 2013 cybutek
// Used by permission. // Used by permission.
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
   
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public static class VOIDLabels public static class VOIDLabels
{ {
public static string void_primary = "Primary"; public static string void_primary = "Primary";
public static string void_altitude_asl = "Altitude (ASL)"; public static string void_altitude_asl = "Altitude (ASL)";
public static string void_velocity = "Velocity"; public static string void_velocity = "Velocity";
public static string void_apoapsis = "Apoapsis"; public static string void_apoapsis = "Apoapsis";
public static string void_periapsis = "Periapsis"; public static string void_periapsis = "Periapsis";
} }
   
public static class Tools public static class Tools
{ {
// Toadicus edit: Added re-implementation of the CBAttributeMap.GetAtt function that does not fire a debug message to the game screen. // Toadicus edit: Added re-implementation of the CBAttributeMap.GetAtt function that does not fire a debug message to the game screen.
public static CBAttributeMap.MapAttribute Toadicus_GetAtt(Vessel vessel) public static CBAttributeMap.MapAttribute Toadicus_GetAtt(Vessel vessel)
{ {
CBAttributeMap.MapAttribute mapAttribute; CBAttributeMap.MapAttribute mapAttribute;
   
try try
{ {
CBAttributeMap BiomeMap = vessel.mainBody.BiomeMap; CBAttributeMap BiomeMap = vessel.mainBody.BiomeMap;
double lat = vessel.latitude * Math.PI / 180d; double lat = vessel.latitude * Math.PI / 180d;
double lon = vessel.longitude * Math.PI / 180d; double lon = vessel.longitude * Math.PI / 180d;
   
lon -= Math.PI / 2d; lon -= Math.PI / 2d;
   
if (lon < 0d) if (lon < 0d)
{ {
lon += 2d * Math.PI; lon += 2d * Math.PI;
} }
   
float v = (float)(lat / Math.PI) + 0.5f; float v = (float)(lat / Math.PI) + 0.5f;
float u = (float)(lon / (2d * Math.PI)); float u = (float)(lon / (2d * Math.PI));
   
Color pixelBilinear = BiomeMap.Map.GetPixelBilinear (u, v); Color pixelBilinear = BiomeMap.Map.GetPixelBilinear (u, v);
mapAttribute = BiomeMap.defaultAttribute; mapAttribute = BiomeMap.defaultAttribute;
   
if (BiomeMap.Map != null) if (BiomeMap.Map != null)
{ {
if (BiomeMap.exactSearch) if (BiomeMap.exactSearch)
{ {
for (int i = 0; i < BiomeMap.Attributes.Length; ++i) for (int i = 0; i < BiomeMap.Attributes.Length; ++i)
{ {
if (pixelBilinear == BiomeMap.Attributes[i].mapColor) if (pixelBilinear == BiomeMap.Attributes[i].mapColor)
{ {
mapAttribute = BiomeMap.Attributes[i]; mapAttribute = BiomeMap.Attributes[i];
} }
} }
} }
else else
{ {
float zero = 0; float zero = 0;
float num = 1 / zero; float num = 1 / zero;
for (int j = 0; j < BiomeMap.Attributes.Length; ++j) for (int j = 0; j < BiomeMap.Attributes.Length; ++j)
{ {
Color mapColor = BiomeMap.Attributes [j].mapColor; Color mapColor = BiomeMap.Attributes [j].mapColor;
float sqrMagnitude = ((Vector4)(mapColor - pixelBilinear)).sqrMagnitude; float sqrMagnitude = ((Vector4)(mapColor - pixelBilinear)).sqrMagnitude;
if (sqrMagnitude < num) if (sqrMagnitude < num)
{ {
bool testCase = true; bool testCase = true;
if (BiomeMap.nonExactThreshold != -1) if (BiomeMap.nonExactThreshold != -1)
{ {
testCase = (sqrMagnitude < BiomeMap.nonExactThreshold); testCase = (sqrMagnitude < BiomeMap.nonExactThreshold);
} }
if (testCase) if (testCase)
{ {
mapAttribute = BiomeMap.Attributes[j]; mapAttribute = BiomeMap.Attributes[j];
num = sqrMagnitude; num = sqrMagnitude;
} }
} }
} }
} }
} }
} }
catch (NullReferenceException) catch (NullReferenceException)
{ {
mapAttribute = new CBAttributeMap.MapAttribute(); mapAttribute = new CBAttributeMap.MapAttribute();
mapAttribute.name = "N/A"; mapAttribute.name = "N/A";
} }
   
return mapAttribute; return mapAttribute;
} }
   
public static string GetLongitudeString(Vessel vessel, string format="F4") public static string GetLongitudeString(Vessel vessel, string format="F4")
{ {
string dir_long = "W"; string dir_long = "W";
double v_long = vessel.longitude; double v_long = vessel.longitude;
   
v_long = FixDegreeDomain(v_long); v_long = FixDegreeDomain(v_long);
   
if (v_long < -180d) if (v_long < -180d)
{ {
v_long += 360d; v_long += 360d;
} }
if (v_long >= 180) if (v_long >= 180)
{ {
v_long -= 360d; v_long -= 360d;
} }
   
if (v_long > 0) dir_long = "E"; if (v_long > 0) dir_long = "E";
   
return string.Format("{0}° {1}", Math.Abs(v_long).ToString(format), dir_long); return string.Format("{0}° {1}", Math.Abs(v_long).ToString(format), dir_long);
} }
   
public static string GetLatitudeString(Vessel vessel, string format="F4") public static string GetLatitudeString(Vessel vessel, string format="F4")
{ {
string dir_lat = "S"; string dir_lat = "S";
double v_lat = vessel.latitude; double v_lat = vessel.latitude;
if (v_lat > 0) dir_lat = "N"; if (v_lat > 0) dir_lat = "N";
   
return string.Format("{0}° {1}", Math.Abs(v_lat).ToString(format), dir_lat); return string.Format("{0}° {1}", Math.Abs(v_lat).ToString(format), dir_lat);
} }
   
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
   
//For MuMech_get_heading() //For MuMech_get_heading()
public class MuMech_MovingAverage public class MuMech_MovingAverage
{ {
private double[] store; private double[] store;
private int storeSize; private int storeSize;
private int nextIndex = 0; private int nextIndex = 0;
   
public double value public double value
{ {
get get
{ {
double tmp = 0; double tmp = 0;
foreach (double i in store) foreach (double i in store)
{ {
tmp += i; tmp += i;
} }
return tmp / storeSize; return tmp / storeSize;
} }
set set
{ {
store[nextIndex] = value; store[nextIndex] = value;
nextIndex = (nextIndex + 1) % storeSize; nextIndex = (nextIndex + 1) % storeSize;
} }
} }
   
public MuMech_MovingAverage(int size = 10, double startingValue = 0) public MuMech_MovingAverage(int size = 10, double startingValue = 0)
{ {
storeSize = size; storeSize = size;
store = new double[size]; store = new double[size];
force(startingValue); force(startingValue);
} }
   
public void force(double newValue) public void force(double newValue)
{ {
for (int i = 0; i < storeSize; i++) for (int i = 0; i < storeSize; i++)
{ {
store[i] = newValue; store[i] = newValue;
} }
} }
   
public static implicit operator double(MuMech_MovingAverage v) public static implicit operator double(MuMech_MovingAverage v)
{ {
return v.value; return v.value;
} }
   
public override string ToString() public override string ToString()
{ {
return value.ToString(); return value.ToString();
} }
   
public string ToString(string format) public string ToString(string format)
{ {
return value.ToString(format); return value.ToString(format);
} }
} }
   
//From http://svn.mumech.com/KSP/trunk/MuMechLib/VOID.vesselState.cs //From http://svn.mumech.com/KSP/trunk/MuMechLib/VOID.vesselState.cs
public static double MuMech_get_heading(Vessel vessel) public static double MuMech_get_heading(Vessel vessel)
{ {
Vector3d CoM = vessel.findWorldCenterOfMass(); Vector3d CoM = vessel.findWorldCenterOfMass();
Vector3d up = (CoM - vessel.mainBody.position).normalized; Vector3d up = (CoM - vessel.mainBody.position).normalized;
Vector3d north = Vector3d.Exclude(up, (vessel.mainBody.position + vessel.mainBody.transform.up * (float)vessel.mainBody.Radius) - CoM).normalized; Vector3d north = Vector3d.Exclude(
  up,
Quaternion rotationSurface = Quaternion.LookRotation(north, up); (vessel.mainBody.position +
Quaternion rotationvesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.transform.rotation) * rotationSurface); vessel.mainBody.transform.up * (float)vessel.mainBody.Radius
MuMech_MovingAverage vesselHeading = new MuMech_MovingAverage(); ) - CoM).normalized;
vesselHeading.value = rotationvesselSurface.eulerAngles.y;  
return vesselHeading.value * 10; // *10 by me Quaternion rotationSurface = Quaternion.LookRotation(north, up);
} Quaternion rotationvesselSurface = Quaternion.Inverse(
  Quaternion.Euler(90, 0, 0) *
//From http://svn.mumech.com/KSP/trunk/MuMechLib/MuUtils.cs Quaternion.Inverse(vessel.transform.rotation) *
public static string MuMech_ToSI(double d) rotationSurface);
{  
int digits = 2; return rotationvesselSurface.eulerAngles.y;
double exponent = Math.Log10(Math.Abs(d)); }
if (Math.Abs(d) >= 1)  
{ //From http://svn.mumech.com/KSP/trunk/MuMechLib/MuUtils.cs
switch ((int)Math.Floor(exponent)) public static string MuMech_ToSI(
{ double d, int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue
case 0: )
case 1: {
case 2: float exponent = (float)Math.Log10(Math.Abs(d));
return d.ToString("F" + digits); exponent = Mathf.Clamp(exponent, (float)MinMagnitude, (float)MaxMagnitude);
case 3:  
case 4: if (exponent >= 0)
case 5: {
return (d / 1e3).ToString("F" + digits) + "k"; switch ((int)Math.Floor(exponent))
case 6: {
case 7: case 0:
case 8: case 1:
return (d / 1e6).ToString("F" + digits) + "M"; case 2:
case 9: return d.ToString("F" + digits);
case 10: case 3:
case 11: case 4:
return (d / 1e9).ToString("F" + digits) + "G"; case 5:
case 12: return (d / 1e3).ToString("F" + digits) + "k";
case 13: case 6:
case 14: case 7:
return (d / 1e12).ToString("F" + digits) + "T"; case 8:
case 15: return (d / 1e6).ToString("F" + digits) + "M";
case 16: case 9:
case 17: case 10:
return (d / 1e15).ToString("F" + digits) + "P"; case 11:
case 18: return (d / 1e9).ToString("F" + digits) + "G";
case 19: case 12:
case 20: case 13:
return (d / 1e18).ToString("F" + digits) + "E"; case 14:
case 21: return (d / 1e12).ToString("F" + digits) + "T";
case 22: case 15:
case 23: case 16:
return (d / 1e21).ToString("F" + digits) + "Z"; case 17:
default: return (d / 1e15).ToString("F" + digits) + "P";
return (d / 1e24).ToString("F" + digits) + "Y"; case 18:
} case 19:
} case 20:
else if (Math.Abs(d) > 0) return (d / 1e18).ToString("F" + digits) + "E";
{ case 21:
switch ((int)Math.Floor(exponent)) case 22:
{ case 23:
case -1: return (d / 1e21).ToString("F" + digits) + "Z";
case -2: default:
case -3: return (d / 1e24).ToString("F" + digits) + "Y";
return (d * 1e3).ToString("F" + digits) + "m"; }
case -4: }
case -5: else if (exponent < 0)
case -6: {
return (d * 1e6).ToString("F" + digits) + "μ"; switch ((int)Math.Floor(exponent))
case -7: {
case -8: case -1:
case -9: case -2:
return (d * 1e9).ToString("F" + digits) + "n"; case -3:
case -10: return (d * 1e3).ToString("F" + digits) + "m";
case -11: case -4:
case -12: case -5:
return (d * 1e12).ToString("F" + digits) + "p"; case -6:
case -13: return (d * 1e6).ToString("F" + digits) + "μ";
case -14: case -7:
case -15: case -8:
return (d * 1e15).ToString("F" + digits) + "f"; case -9:
case -16: return (d * 1e9).ToString("F" + digits) + "n";
case -17: case -10:
case -18: case -11:
return (d * 1e18).ToString("F" + digits) + "a"; case -12:
case -19: return (d * 1e12).ToString("F" + digits) + "p";
case -20: case -13:
case -21: case -14:
return (d * 1e21).ToString("F" + digits) + "z"; case -15:
default: return (d * 1e15).ToString("F" + digits) + "f";
return (d * 1e24).ToString("F" + digits) + "y"; case -16:
} case -17:
} case -18:
else return (d * 1e18).ToString("F" + digits) + "a";
{ case -19:
return "0"; case -20:
} case -21:
} return (d * 1e21).ToString("F" + digits) + "z";
  default:
public static string ConvertInterval(double seconds) return (d * 1e24).ToString("F" + digits) + "y";
{ }
string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:D2}.{5:D1}s"; }
string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:D2}.{4:D1}s"; else
string format_3 = "{0:D2}h {1:D2}m {2:D2}.{3:D1}s"; {
  return "0";
  }
  }
   
  public static string ConvertInterval(double seconds)
  {
  string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:D2}.{5:D1}s";
  string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:D2}.{4:D1}s";
  string format_3 = "{0:D2}h {1:D2}m {2:D2}.{3:D1}s";
   
TimeSpan interval; TimeSpan interval;
   
try try
{ {
interval = TimeSpan.FromSeconds(seconds); interval = TimeSpan.FromSeconds(seconds);
} }
catch (OverflowException) catch (OverflowException)
{ {
return "NaN"; return "NaN";
} }
   
int years = interval.Days / 365; int years = interval.Days / 365;
   
string output; string output;
if (years > 0) if (years > 0)
{ {
output = string.Format(format_1, output = string.Format(format_1,
years, years,
interval.Days - (years * 365), // subtract years * 365 for accurate day count interval.Days - (years * 365), // subtract years * 365 for accurate day count
interval.Hours, interval.Hours,
interval.Minutes, interval.Minutes,
interval.Seconds, interval.Seconds,
interval.Milliseconds.ToString().Substring(0, 1)); interval.Milliseconds.ToString().Substring(0, 1));
} }
else if (interval.Days > 0) else if (interval.Days > 0)
{ {
output = string.Format(format_2, output = string.Format(format_2,
interval.Days, interval.Days,
interval.Hours, interval.Hours,
interval.Minutes, interval.Minutes,
interval.Seconds, interval.Seconds,
interval.Milliseconds.ToString().Substring(0, 1)); interval.Milliseconds.ToString().Substring(0, 1));
} }
else else
{ {
output = string.Format(format_3, output = string.Format(format_3,
interval.Hours, interval.Hours,
interval.Minutes, interval.Minutes,
interval.Seconds, interval.Seconds,
interval.Milliseconds.ToString().Substring(0, 1)); interval.Milliseconds.ToString().Substring(0, 1));
} }
return output; return output;
} }
   
public static string UppercaseFirst(string s) public static string UppercaseFirst(string s)
{ {
if (string.IsNullOrEmpty(s)) if (string.IsNullOrEmpty(s))
{ {
return string.Empty; return string.Empty;
} }
char[] a = s.ToCharArray(); char[] a = s.ToCharArray();
a[0] = char.ToUpper(a[0]); a[0] = char.ToUpper(a[0]);
return new string(a); return new string(a);
} }
   
//transfer angles //transfer angles
   
public static double Nivvy_CalcTransferPhaseAngle(double r_current, double r_target, double grav_param) public static double Nivvy_CalcTransferPhaseAngle(double r_current, double r_target, double grav_param)
{ {
double T_target = (2 * Math.PI) * Math.Sqrt(Math.Pow((r_target / 1000), 3) / (grav_param / 1000000000)); double T_target = (2 * Math.PI) * Math.Sqrt(Math.Pow((r_target / 1000), 3) / (grav_param / 1000000000));
double T_transfer = (2 * Math.PI) * Math.Sqrt(Math.Pow((((r_target / 1000) + (r_current / 1000)) / 2), 3) / (grav_param / 1000000000)); double T_transfer = (2 * Math.PI) * Math.Sqrt(Math.Pow((((r_target / 1000) + (r_current / 1000)) / 2), 3) / (grav_param / 1000000000));
return 360 * (0.5 - (T_transfer / (2 * T_target))); return 360 * (0.5 - (T_transfer / (2 * T_target)));
} }
   
public static double Younata_DeltaVToGetToOtherBody(double mu, double r1, double r2) public static double Younata_DeltaVToGetToOtherBody(double mu, double r1, double r2)
{ {
/* /*
def deltaVToGetToOtherBody(mu, r1, r2): def deltaVToGetToOtherBody(mu, r1, r2):
# mu = gravity param of common orbiting body of r1 and r2 # mu = gravity param of common orbiting body of r1 and r2
# (e.g. for mun to minmus, mu is kerbin's gravity param # (e.g. for mun to minmus, mu is kerbin's gravity param
# r1 = initial body's orbit radius # r1 = initial body's orbit radius
# r2 = target body's orbit radius # r2 = target body's orbit radius
# return value is km/s # return value is km/s
sur1 = math.sqrt(mu / r1) sur1 = math.sqrt(mu / r1)
sr1r2 = math.sqrt(float(2*r2)/float(r1+r2)) sr1r2 = math.sqrt(float(2*r2)/float(r1+r2))
mult = sr1r2 - 1 mult = sr1r2 - 1
return sur1 * mult return sur1 * mult
*/ */
double sur1, sr1r2, mult; double sur1, sr1r2, mult;
sur1 = Math.Sqrt(mu / r1); sur1 = Math.Sqrt(mu / r1);
sr1r2 = Math.Sqrt((2 * r2) / (r1 + r2)); sr1r2 = Math.Sqrt((2 * r2) / (r1 + r2));
mult = sr1r2 - 1; mult = sr1r2 - 1;
return sur1 * mult; return sur1 * mult;
} }
   
public static double Younata_DeltaVToExitSOI(double mu, double r1, double r2, double v) public static double Younata_DeltaVToExitSOI(double mu, double r1, double r2, double v)
{ {
/* /*
def deltaVToExitSOI(mu, r1, r2, v): def deltaVToExitSOI(mu, r1, r2, v):
# mu = gravity param of current body # mu = gravity param of current body
# r1 = current orbit radius # r1 = current orbit radius
# r2 = SOI radius # r2 = SOI radius
# v = SOI exit velocity # v = SOI exit velocity
foo = r2 * (v**2) - 2 * mu foo = r2 * (v**2) - 2 * mu
bar = r1 * foo + (2 * r2 * mu) bar = r1 * foo + (2 * r2 * mu)
r = r1*r2 r = r1*r2
return math.sqrt(bar / r) return math.sqrt(bar / r)
*/ */
double foo = r2 * Math.Pow(v, 2) - 2 * mu; double foo = r2 * Math.Pow(v, 2) - 2 * mu;
double bar = r1 * foo + (2 * r2 * mu); double bar = r1 * foo + (2 * r2 * mu);
double r = r1 * r2; double r = r1 * r2;
return Math.Sqrt(bar / r); return Math.Sqrt(bar / r);
} }
   
public static double Younata_TransferBurnPoint(double r, double v, double angle, double mu) public static double Younata_TransferBurnPoint(double r, double v, double angle, double mu)
{ {
/* /*
def transferBurnPoint(r, v, angle, mu): def transferBurnPoint(r, v, angle, mu):
# r = parking orbit radius # r = parking orbit radius
# v = ejection velocity # v = ejection velocity
# angle = phase angle (from function phaseAngle()) # angle = phase angle (from function phaseAngle())
# mu = gravity param of current body. # mu = gravity param of current body.
epsilon = ((v**2)/2) - (mu / r) epsilon = ((v**2)/2) - (mu / r)
h = r * v * math.sin(angle) h = r * v * math.sin(angle)
e = math.sqrt(1 + ((2 * epsilon * h**2)/(mu**2))) e = math.sqrt(1 + ((2 * epsilon * h**2)/(mu**2)))
theta = math.acos(1.0 / e) theta = math.acos(1.0 / e)
degrees = theta * (180.0 / math.pi) degrees = theta * (180.0 / math.pi)
return 180 - degrees return 180 - degrees
*/ */
double epsilon, h, ee, theta, degrees; double epsilon, h, ee, theta, degrees;
epsilon = (Math.Pow(v, 2) / 2) - (mu / r); epsilon = (Math.Pow(v, 2) / 2) - (mu / r);
h = r * v * Math.Sin(angle); h = r * v * Math.Sin(angle);
ee = Math.Sqrt(1 + ((2 * epsilon * Math.Pow(h, 2)) / Math.Pow(mu, 2))); ee = Math.Sqrt(1 + ((2 * epsilon * Math.Pow(h, 2)) / Math.Pow(mu, 2)));
theta = Math.Acos(1.0 / ee); theta = Math.Acos(1.0 / ee);
degrees = theta * (180.0 / Math.PI); degrees = theta * (180.0 / Math.PI);
return 180 - degrees; return 180 - degrees;
// returns the ejection angle // returns the ejection angle
} }
   
public static double Adammada_CurrrentPhaseAngle(double body_LAN, double body_orbitPct, double origin_LAN, double origin_orbitPct) public static double Adammada_CurrrentPhaseAngle(double body_LAN, double body_orbitPct, double origin_LAN, double origin_orbitPct)
{ {
double angle = (body_LAN / 360 + body_orbitPct) - (origin_LAN / 360 + origin_orbitPct); double angle = (body_LAN / 360 + body_orbitPct) - (origin_LAN / 360 + origin_orbitPct);
if (angle > 1) angle = angle - 1; if (angle > 1) angle = angle - 1;
if (angle < 0) angle = angle + 1; if (angle < 0) angle = angle + 1;
if (angle > 0.5) angle = angle - 1; if (angle > 0.5) angle = angle - 1;
angle = angle * 360; angle = angle * 360;
return angle; return angle;
} }
   
public static double Adammada_CurrentEjectionAngle(double vessel_long, double origin_rotAngle, double origin_LAN, double origin_orbitPct) public static double Adammada_CurrentEjectionAngle(double vessel_long, double origin_rotAngle, double origin_LAN, double origin_orbitPct)
{ {
//double eangle = ((FlightGlobals.ActiveVOID.vessel.longitude + orbiting.rotationAngle) - (orbiting.orbit.LAN / 360 + orbiting.orbit.orbitPercent) * 360); //double eangle = ((FlightGlobals.ActiveVOID.vessel.longitude + orbiting.rotationAngle) - (orbiting.orbit.LAN / 360 + orbiting.orbit.orbitPercent) * 360);
double eangle = ((vessel_long + origin_rotAngle) - (origin_LAN / 360 + origin_orbitPct) * 360); double eangle = ((vessel_long + origin_rotAngle) - (origin_LAN / 360 + origin_orbitPct) * 360);
   
while (eangle < 0) eangle = eangle + 360; while (eangle < 0) eangle = eangle + 360;
while (eangle > 360) eangle = eangle - 360; while (eangle > 360) eangle = eangle - 360;
if (eangle < 270) eangle = 90 - eangle; if (eangle < 270) eangle = 90 - eangle;
else eangle = 450 - eangle; else eangle = 450 - eangle;
return eangle; return eangle;
} }
   
public static double mrenigma03_calcphase(Vessel vessel, CelestialBody target) //calculates phase angle between the current body and target body public static double mrenigma03_calcphase(Vessel vessel, CelestialBody target) //calculates phase angle between the current body and target body
{ {
Vector3d vecthis = new Vector3d(); Vector3d vecthis = new Vector3d();
Vector3d vectarget = new Vector3d(); Vector3d vectarget = new Vector3d();
vectarget = target.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); vectarget = target.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
   
if ((vessel.mainBody.name == "Sun") || (vessel.mainBody.referenceBody.referenceBody.name == "Sun")) if ((vessel.mainBody.name == "Sun") || (vessel.mainBody.referenceBody.referenceBody.name == "Sun"))
{ {
vecthis = vessel.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); vecthis = vessel.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
} }
else else
{ {
vecthis = vessel.mainBody.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); vecthis = vessel.mainBody.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
} }
   
vecthis = Vector3d.Project(new Vector3d(vecthis.x, 0, vecthis.z), vecthis); vecthis = Vector3d.Project(new Vector3d(vecthis.x, 0, vecthis.z), vecthis);
vectarget = Vector3d.Project(new Vector3d(vectarget.x, 0, vectarget.z), vectarget); vectarget = Vector3d.Project(new Vector3d(vectarget.x, 0, vectarget.z), vectarget);
   
Vector3d prograde = new Vector3d(); Vector3d prograde = new Vector3d();
prograde = Quaternion.AngleAxis(90, Vector3d.forward) * vecthis; prograde = Quaternion.AngleAxis(90, Vector3d.forward) * vecthis;
   
double phase = Vector3d.Angle(vecthis, vectarget); double phase = Vector3d.Angle(vecthis, vectarget);
   
if (Vector3d.Angle(prograde, vectarget) > 90) phase = 360 - phase; if (Vector3d.Angle(prograde, vectarget) > 90) phase = 360 - phase;
   
return (phase + 360) % 360; return (phase + 360) % 360;
} }
   
public static double FixAngleDomain(double Angle, bool Degrees = false) public static double FixAngleDomain(double Angle, bool Degrees = false)
{ {
double Extent = 2d * Math.PI; double Extent = 2d * Math.PI;
if (Degrees) { if (Degrees) {
Extent = 360d; Extent = 360d;
} }
   
Angle = Angle % (Extent); Angle = Angle % (Extent);
if (Angle < 0d) if (Angle < 0d)
{ {
Angle += Extent; Angle += Extent;
} }
   
return Angle; return Angle;
} }
   
public static double FixDegreeDomain(double Angle) public static double FixDegreeDomain(double Angle)
{ {
return FixAngleDomain (Angle, true); return FixAngleDomain (Angle, true);
} }
   
public static double adjustCurrPhaseAngle(double transfer_angle, double curr_phase) public static double adjustCurrPhaseAngle(double transfer_angle, double curr_phase)
{ {
if (transfer_angle < 0) if (transfer_angle < 0)
{ {
if (curr_phase > 0) return (-1 * (360 - curr_phase)); if (curr_phase > 0) return (-1 * (360 - curr_phase));
else if (curr_phase < 0) return curr_phase; else if (curr_phase < 0) return curr_phase;
} }
else if (transfer_angle > 0) else if (transfer_angle > 0)
{ {
if (curr_phase > 0) return curr_phase; if (curr_phase > 0) return curr_phase;
else if (curr_phase < 0) return (360 + curr_phase); else if (curr_phase < 0) return (360 + curr_phase);
} }
return curr_phase; return curr_phase;
} }
   
public static double adjust_current_ejection_angle(double curr_ejection) public static double adjust_current_ejection_angle(double curr_ejection)
{ {
//curr_ejection WILL need to be adjusted once for all transfers as it returns values ranging -180 to 180 //curr_ejection WILL need to be adjusted once for all transfers as it returns values ranging -180 to 180
// need 0-360 instead // need 0-360 instead
// //
// ie i have -17 in the screenshot // ie i have -17 in the screenshot
// need it to show 343 // need it to show 343
// //
// do this // do this
// //
// if < 0, add curr to 360 // 360 + (-17) = 343 // if < 0, add curr to 360 // 360 + (-17) = 343
// else its good as it is // else its good as it is
   
if (curr_ejection < 0) return 360 + curr_ejection; if (curr_ejection < 0) return 360 + curr_ejection;
else return curr_ejection; else return curr_ejection;
   
} }
   
public static double adjust_transfer_ejection_angle(double trans_ejection, double trans_phase) public static double adjust_transfer_ejection_angle(double trans_ejection, double trans_phase)
{ {
// if transfer_phase_angle < 0 its a lower transfer // if transfer_phase_angle < 0 its a lower transfer
//180 + curr_ejection //180 + curr_ejection
// else if transfer_phase_angle > 0 its good as it is // else if transfer_phase_angle > 0 its good as it is
   
if (trans_phase < 0) return 180 + trans_ejection; if (trans_phase < 0) return 180 + trans_ejection;
else return trans_ejection; else return trans_ejection;
   
} }
   
public static double TrueAltitude(Vessel vessel) public static double TrueAltitude(Vessel vessel)
{ {
double trueAltitude = vessel.orbit.altitude - vessel.terrainAltitude; double trueAltitude = vessel.orbit.altitude - vessel.terrainAltitude;
   
// HACK: This assumes that on worlds with oceans, all water is fixed at 0 m, and water covers the whole surface at 0 m. // HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,
  // and water covers the whole surface at 0 m.
if (vessel.terrainAltitude < 0 && vessel.mainBody.ocean ) if (vessel.terrainAltitude < 0 && vessel.mainBody.ocean )
{ {
trueAltitude = vessel.orbit.altitude; trueAltitude = vessel.orbit.altitude;
} }
   
return trueAltitude; return trueAltitude;
} }
   
public static string get_heading_text(double heading) public static string get_heading_text(double heading)
{ {
if (heading > 348.75 || heading <= 11.25) return "N"; if (heading > 348.75 || heading <= 11.25) return "N";
else if (heading > 11.25 && heading <= 33.75) return "NNE"; else if (heading > 11.25 && heading <= 33.75) return "NNE";
else if (heading > 33.75 && heading <= 56.25) return "NE"; else if (heading > 33.75 && heading <= 56.25) return "NE";
else if (heading > 56.25 && heading <= 78.75) return "ENE"; else if (heading > 56.25 && heading <= 78.75) return "ENE";
else if (heading > 78.75 && heading <= 101.25) return "E"; else if (heading > 78.75 && heading <= 101.25) return "E";
else if (heading > 101.25 && heading <= 123.75) return "ESE"; else if (heading > 101.25 && heading <= 123.75) return "ESE";
else if (heading > 123.75 && heading <= 146.25) return "SE"; else if (heading > 123.75 && heading <= 146.25) return "SE";
else if (heading > 146.25 && heading <= 168.75) return "SSE"; else if (heading > 146.25 && heading <= 168.75) return "SSE";
else if (heading > 168.75 && heading <= 191.25) return "S"; else if (heading > 168.75 && heading <= 191.25) return "S";
else if (heading > 191.25 && heading <= 213.75) return "SSW"; else if (heading > 191.25 && heading <= 213.75) return "SSW";
else if (heading > 213.75 && heading <= 236.25) return "SW"; else if (heading > 213.75 && heading <= 236.25) return "SW";
else if (heading > 236.25 && heading <= 258.75) return "WSW"; else if (heading > 236.25 && heading <= 258.75) return "WSW";
else if (heading > 258.75 && heading <= 281.25) return "W"; else if (heading > 258.75 && heading <= 281.25) return "W";
else if (heading > 281.25 && heading <= 303.75) return "WNW"; else if (heading > 281.25 && heading <= 303.75) return "WNW";
else if (heading > 303.75 && heading <= 326.25) return "NW"; else if (heading > 303.75 && heading <= 326.25) return "NW";
else if (heading > 326.25 && heading <= 348.75) return "NNW"; else if (heading > 326.25 && heading <= 348.75) return "NNW";
else return ""; else return "";
} }
   
   
   
public static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel) public static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Phase angle (curr/trans):"); GUILayout.Label("Phase angle (curr/trans):");
GUILayout.Label(Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + Tools.Nivvy_CalcTransferPhaseAngle(vessel.orbit.semiMajorAxis, body.orbit.semiMajorAxis, vessel.mainBody.gravParameter).ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + Tools.Nivvy_CalcTransferPhaseAngle(vessel.orbit.semiMajorAxis, body.orbit.semiMajorAxis, vessel.mainBody.gravParameter).ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Transfer velocity:"); GUILayout.Label("Transfer velocity:");
GUILayout.Label((Tools.Younata_DeltaVToGetToOtherBody((vessel.mainBody.gravParameter / 1000000000), (vessel.orbit.semiMajorAxis / 1000), (body.orbit.semiMajorAxis / 1000)) * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label((Tools.Younata_DeltaVToGetToOtherBody((vessel.mainBody.gravParameter / 1000000000), (vessel.orbit.semiMajorAxis / 1000), (body.orbit.semiMajorAxis / 1000)) * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
public static void display_transfer_angles_PLANET2PLANET(CelestialBody body, Vessel vessel) public static void display_transfer_angles_PLANET2PLANET(CelestialBody body, Vessel vessel)
{ {
double dv1 = Tools.Younata_DeltaVToGetToOtherBody((vessel.mainBody.referenceBody.gravParameter / 1000000000), (vessel.mainBody.orbit.semiMajorAxis / 1000), (body.orbit.semiMajorAxis / 1000)); double dv1 = Tools.Younata_DeltaVToGetToOtherBody((vessel.mainBody.referenceBody.gravParameter / 1000000000), (vessel.mainBody.orbit.semiMajorAxis / 1000), (body.orbit.semiMajorAxis / 1000));
double dv2 = Tools.Younata_DeltaVToExitSOI((vessel.mainBody.gravParameter / 1000000000), (vessel.orbit.semiMajorAxis / 1000), (vessel.mainBody.sphereOfInfluence / 1000), Math.Abs(dv1)); double dv2 = Tools.Younata_DeltaVToExitSOI((vessel.mainBody.gravParameter / 1000000000), (vessel.orbit.semiMajorAxis / 1000), (vessel.mainBody.sphereOfInfluence / 1000), Math.Abs(dv1));
   
double trans_ejection_angle = Tools.Younata_TransferBurnPoint((vessel.orbit.semiMajorAxis / 1000), dv2, (Math.PI / 2.0), (vessel.mainBody.gravParameter / 1000000000)); double trans_ejection_angle = Tools.Younata_TransferBurnPoint((vessel.orbit.semiMajorAxis / 1000), dv2, (Math.PI / 2.0), (vessel.mainBody.gravParameter / 1000000000));
double curr_ejection_angle = Tools.Adammada_CurrentEjectionAngle(FlightGlobals.ActiveVessel.longitude, FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent); double curr_ejection_angle = Tools.Adammada_CurrentEjectionAngle(FlightGlobals.ActiveVessel.longitude, FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent);
   
double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(vessel.mainBody.orbit.semiMajorAxis, body.orbit.semiMajorAxis, vessel.mainBody.referenceBody.gravParameter) % 360; double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(vessel.mainBody.orbit.semiMajorAxis, body.orbit.semiMajorAxis, vessel.mainBody.referenceBody.gravParameter) % 360;
double curr_phase_angle = Tools.Adammada_CurrrentPhaseAngle(body.orbit.LAN, body.orbit.orbitPercent, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent); double curr_phase_angle = Tools.Adammada_CurrrentPhaseAngle(body.orbit.LAN, body.orbit.orbitPercent, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent);
   
double adj_phase_angle = Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle); double adj_phase_angle = Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle);
double adj_trans_ejection_angle = Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle); double adj_trans_ejection_angle = Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle);
double adj_curr_ejection_angle = Tools.adjust_current_ejection_angle(curr_ejection_angle); double adj_curr_ejection_angle = Tools.adjust_current_ejection_angle(curr_ejection_angle);
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Phase angle (curr/trans):"); GUILayout.Label("Phase angle (curr/trans):");
GUILayout.Label(adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Ejection angle (curr/trans):"); GUILayout.Label("Ejection angle (curr/trans):");
GUILayout.Label(adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Transfer velocity:"); GUILayout.Label("Transfer velocity:");
GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
public static void display_transfer_angles_PLANET2MOON(CelestialBody body, Vessel vessel) public static void display_transfer_angles_PLANET2MOON(CelestialBody body, Vessel vessel)
{ {
double dv1 = Tools.Younata_DeltaVToGetToOtherBody((vessel.mainBody.gravParameter / 1000000000), (vessel.orbit.semiMajorAxis / 1000), (body.orbit.semiMajorAxis / 1000)); double dv1 = Tools.Younata_DeltaVToGetToOtherBody((vessel.mainBody.gravParameter / 1000000000), (vessel.orbit.semiMajorAxis / 1000), (body.orbit.semiMajorAxis / 1000));
   
double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(vessel.orbit.semiMajorAxis, body.orbit.semiMajorAxis, vessel.mainBody.gravParameter); double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(vessel.orbit.semiMajorAxis, body.orbit.semiMajorAxis, vessel.mainBody.gravParameter);
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Phase angle (curr/trans):"); GUILayout.Label("Phase angle (curr/trans):");
GUILayout.Label(Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Transfer velocity:"); GUILayout.Label("Transfer velocity:");
GUILayout.Label((dv1 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label((dv1 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
public static void display_transfer_angles_MOON2MOON(CelestialBody body, Vessel vessel) public static void display_transfer_angles_MOON2MOON(CelestialBody body, Vessel vessel)
{ {
double dv1 = Tools.Younata_DeltaVToGetToOtherBody((vessel.mainBody.referenceBody.gravParameter / 1000000000), (vessel.mainBody.orbit.semiMajorAxis / 1000), (body.orbit.semiMajorAxis / 1000)); double dv1 = Tools.Younata_DeltaVToGetToOtherBody((vessel.mainBody.referenceBody.gravParameter / 1000000000), (vessel.mainBody.orbit.semiMajorAxis / 1000), (body.orbit.semiMajorAxis / 1000));
double dv2 = Tools.Younata_DeltaVToExitSOI((vessel.mainBody.gravParameter / 1000000000), (vessel.orbit.semiMajorAxis / 1000), (vessel.mainBody.sphereOfInfluence / 1000), Math.Abs(dv1)); double dv2 = Tools.Younata_DeltaVToExitSOI((vessel.mainBody.gravParameter / 1000000000), (vessel.orbit.semiMajorAxis / 1000), (vessel.mainBody.sphereOfInfluence / 1000), Math.Abs(dv1));
double trans_ejection_angle = Tools.Younata_TransferBurnPoint((vessel.orbit.semiMajorAxis / 1000), dv2, (Math.PI / 2.0), (vessel.mainBody.gravParameter / 1000000000)); double trans_ejection_angle = Tools.Younata_TransferBurnPoint((vessel.orbit.semiMajorAxis / 1000), dv2, (Math.PI / 2.0), (vessel.mainBody.gravParameter / 1000000000));
   
double curr_phase_angle = Tools.Adammada_CurrrentPhaseAngle(body.orbit.LAN, body.orbit.orbitPercent, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent); double curr_phase_angle = Tools.Adammada_CurrrentPhaseAngle(body.orbit.LAN, body.orbit.orbitPercent, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent);
double curr_ejection_angle = Tools.Adammada_CurrentEjectionAngle(FlightGlobals.ActiveVessel.longitude, FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent); double curr_ejection_angle = Tools.Adammada_CurrentEjectionAngle(FlightGlobals.ActiveVessel.longitude, FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent);
   
double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(vessel.mainBody.orbit.semiMajorAxis, body.orbit.semiMajorAxis, vessel.mainBody.referenceBody.gravParameter) % 360; double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(vessel.mainBody.orbit.semiMajorAxis, body.orbit.semiMajorAxis, vessel.mainBody.referenceBody.gravParameter) % 360;
   
double adj_phase_angle = Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle); double adj_phase_angle = Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle);
//double adj_ejection_angle = adjustCurrEjectionAngle(trans_phase_angle, curr_ejection_angle); //double adj_ejection_angle = adjustCurrEjectionAngle(trans_phase_angle, curr_ejection_angle);
   
//new stuff //new stuff
// //
double adj_trans_ejection_angle = Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle); double adj_trans_ejection_angle = Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle);
double adj_curr_ejection_angle = Tools.adjust_current_ejection_angle(curr_ejection_angle); double adj_curr_ejection_angle = Tools.adjust_current_ejection_angle(curr_ejection_angle);
// //
// //
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Phase angle (curr/trans):"); GUILayout.Label("Phase angle (curr/trans):");
GUILayout.Label(adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Ejection angle (curr/trans):"); GUILayout.Label("Ejection angle (curr/trans):");
GUILayout.Label(adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Transfer velocity:"); GUILayout.Label("Transfer velocity:");
GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
// This implementation is adapted from FARGUIUtils.ClampToScreen // This implementation is adapted from FARGUIUtils.ClampToScreen
public static Rect ClampRectToScreen(Rect window, int xMargin, int yMargin) public static Rect ClampRectToScreen(Rect window, int xMargin, int yMargin)
{ {
window.x = Mathf.Clamp (window.x, xMargin - window.width, Screen.width - xMargin); window.x = Mathf.Clamp (window.x, xMargin - window.width, Screen.width - xMargin);
window.y = Mathf.Clamp (window.y, yMargin - window.height, Screen.height - yMargin); window.y = Mathf.Clamp (window.y, yMargin - window.height, Screen.height - yMargin);
   
return window; return window;
} }
   
public static Rect ClampRectToScreen(Rect window, int Margin) public static Rect ClampRectToScreen(Rect window, int Margin)
{ {
return ClampRectToScreen(window, Margin, Margin); return ClampRectToScreen(window, Margin, Margin);
} }
   
public static Rect ClampRectToScreen(Rect window) public static Rect ClampRectToScreen(Rect window)
{ {
return ClampRectToScreen (window, 30); return ClampRectToScreen (window, 30);
} }
   
public static Vector2 ClampV2ToScreen(Vector2 vec, uint xMargin, uint yMargin) public static Vector2 ClampV2ToScreen(Vector2 vec, uint xMargin, uint yMargin)
{ {
vec.x = Mathf.Clamp (vec.x, xMargin, Screen.width - xMargin); vec.x = Mathf.Clamp (vec.x, xMargin, Screen.width - xMargin);
vec.y = Mathf.Clamp (vec.y, yMargin, Screen.height - yMargin); vec.y = Mathf.Clamp (vec.y, yMargin, Screen.height - yMargin);
   
return vec; return vec;
} }
   
public static Vector2 ClampV2ToScreen(Vector2 vec, uint Margin) public static Vector2 ClampV2ToScreen(Vector2 vec, uint Margin)
{ {
return ClampV2ToScreen(vec, Margin, Margin); return ClampV2ToScreen(vec, Margin, Margin);
} }
   
public static Vector2 ClampV2ToScreen(Vector2 vec) public static Vector2 ClampV2ToScreen(Vector2 vec)
{ {
return ClampV2ToScreen (vec, 15); return ClampV2ToScreen (vec, 15);
} }
   
// UNDONE: This seems messy. Can we clean it up? // UNDONE: This seems messy. Can we clean it up?
public static Rect DockToWindow(Rect icon, Rect window) public static Rect DockToWindow(Rect icon, Rect window)
{ {
// We can't set the x and y of the center point directly, so build a new vector. // We can't set the x and y of the center point directly, so build a new vector.
Vector2 center = new Vector2 (); Vector2 center = new Vector2 ();
   
// If we are near the top or bottom of the screen... // If we are near the top or bottom of the screen...
if (window.yMax > Screen.height - icon.height || if (window.yMax > Screen.height - icon.height ||
window.yMin < icon.height window.yMin < icon.height
) )
{ {
// If we are in a corner... // If we are in a corner...
if (window.xMax > Screen.width - icon.width || if (window.xMax > Screen.width - icon.width ||
window.xMin < icon.width window.xMin < icon.width
) )
{ {
// If it is a top corner, put the icon below the window. // If it is a top corner, put the icon below the window.
if (window.yMax < Screen.height / 2) if (window.yMax < Screen.height / 2)
{ {
center.y = window.yMax + icon.height / 2; center.y = window.yMax + icon.height / 2;
} }
// If it is a bottom corner, put the icon above the window. // If it is a bottom corner, put the icon above the window.
else else
{ {
center.y = window.yMin - icon.height / 2; center.y = window.yMin - icon.height / 2;
} }
} }
// If we are not in a corner... // If we are not in a corner...
else else
{ {
// If we are along the top edge, align the icon's top edge with the top edge of the window // If we are along the top edge, align the icon's top edge with the top edge of the window
if (window.yMax > Screen.height / 2) if (window.yMax > Screen.height / 2)
{ {
center.y = window.yMax - icon.height / 2; center.y = window.yMax - icon.height / 2;
} }
// If we are along the bottom edge, align the icon's bottom edge with the bottom edge of the window // If we are along the bottom edge, align the icon's bottom edge with the bottom edge of the window
else else
{ {
center.y = window.yMin + icon.height / 2; center.y = window.yMin + icon.height / 2;
} }
} }
   
// At the top or bottom, if we are towards the right, put the icon to the right of the window // At the top or bottom, if we are towards the right, put the icon to the right of the window
if (window.center.x < Screen.width / 2) if (window.center.x < Screen.width / 2)
{ {
center.x = window.xMin - icon.width / 2; center.x = window.xMin - icon.width / 2;
} }
// At the top or bottom, if we are towards the left, put the icon to the left of the window // At the top or bottom, if we are towards the left, put the icon to the left of the window
else else
{ {
center.x = window.xMax + icon.width / 2; center.x = window.xMax + icon.width / 2;
} }
   
} }
// If we are not along the top or bottom of the screen... // If we are not along the top or bottom of the screen...
else else
{ {
// By default, center the icon above the window // By default, center the icon above the window
center.y = window.yMin - icon.height / 2; center.y = window.yMin - icon.height / 2;
center.x = window.center.x; center.x = window.center.x;
   
// If we are along a side... // If we are along a side...
if (window.xMax > Screen.width - icon.width || if (window.xMax > Screen.width - icon.width ||
window.xMin < icon.width window.xMin < icon.width
) )
{ {
// UNDONE: I'm not sure I like the feel of this part. // UNDONE: I'm not sure I like the feel of this part.
// If we are along a side towards the bottom, put the icon below the window // If we are along a side towards the bottom, put the icon below the window
if (window.center.y > Screen.height / 2) if (window.center.y > Screen.height / 2)
{ {
center.y = window.yMax + icon.height / 2; center.y = window.yMax + icon.height / 2;
} }
   
// Along the left side, align the left edge of the icon with the left edge of the window. // Along the left side, align the left edge of the icon with the left edge of the window.
if (window.xMax > Screen.width - icon.width) if (window.xMax > Screen.width - icon.width)
{ {
center.x = window.xMax - icon.width / 2; center.x = window.xMax - icon.width / 2;
} }
// Along the right side, align the right edge of the icon with the right edge of the window. // Along the right side, align the right edge of the icon with the right edge of the window.
else if (window.xMin < icon.width) else if (window.xMin < icon.width)
{ {
center.x = window.xMin + icon.width / 2; center.x = window.xMin + icon.width / 2;
} }
} }
} }
   
// Assign the vector to the center of the rect. // Assign the vector to the center of the rect.
icon.center = center; icon.center = center;
   
// Return the icon's position. // Return the icon's position.
return icon; return icon;
} }
   
private static ScreenMessage debugmsg = new ScreenMessage("", 2f, ScreenMessageStyle.UPPER_RIGHT); private static ScreenMessage debugmsg = new ScreenMessage("", 2f, ScreenMessageStyle.UPPER_RIGHT);
   
[System.Diagnostics.Conditional("DEBUG")] [System.Diagnostics.Conditional("DEBUG")]
public static void PostDebugMessage(string Msg) public static void PostDebugMessage(string Msg)
{ {
if (HighLogic.LoadedScene > GameScenes.SPACECENTER) if (HighLogic.LoadedScene > GameScenes.SPACECENTER)
{ {
debugmsg.message = Msg; debugmsg.message = Msg;
ScreenMessages.PostScreenMessage(debugmsg, true); ScreenMessages.PostScreenMessage(debugmsg, true);
} }
   
KSPLog.print(Msg); KSPLog.print(Msg);
} }
} }
} }
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>10.0.0</ProductVersion> <ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{45ACC1CC-942C-4A66-BFC7-8BE375938B18}</ProjectGuid> <ProjectGuid>{45ACC1CC-942C-4A66-BFC7-8BE375938B18}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>VOID</RootNamespace> <RootNamespace>VOID</RootNamespace>
<AssemblyName>VOID</AssemblyName> <AssemblyName>VOID</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath> <OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG; TRACE</DefineConstants> <DefineConstants>DEBUG; TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="/usr/bin/cp -fv ${ProjectDir}/bin/Debug/VOID.dll /mnt/games/ssd/KSP_linux/GameData/VOID/Plugins/" /> <Command type="AfterBuild" command="xcopy /Y ${ProjectDir}\bin\Debug\*.dll ..\..\..\Games\KSP_win\GameData\VOID\Plugins\" workingdir="${ProjectDir}" externalConsole="True" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath> <OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="/usr/bin/cp -fv ${ProjectDir}/bin/Release/VOID.dll /mnt/games/ssd/KSP_linux/GameData/VOID/Plugins/" /> <Command type="AfterBuild" command="xcopy /Y ${ProjectDir}\bin\Release\*.dll ..\..\..\Games\KSP_win\GameData\VOID\Plugins\" workingdir="${ProjectDir}" externalConsole="True" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
<Compile Include="Tools.cs" /> <Compile Include="Tools.cs" />
<Compile Include="IVOID_Module.cs" /> <Compile Include="IVOID_Module.cs" />
<Compile Include="VOIDFlightMaster.cs" /> <Compile Include="VOIDFlightMaster.cs" />
<Compile Include="VOID_Core.cs" /> <Compile Include="VOID_Core.cs" />
<Compile Include="VOID_Module.cs" /> <Compile Include="VOID_Module.cs" />
<Compile Include="VOID_HUD.cs" /> <Compile Include="VOID_HUD.cs" />
<Compile Include="VOID_SaveValue.cs" /> <Compile Include="VOID_SaveValue.cs" />
<Compile Include="VOID_Orbital.cs" /> <Compile Include="VOID_Orbital.cs" />
<Compile Include="VOID_SurfAtmo.cs" /> <Compile Include="VOID_SurfAtmo.cs" />
<Compile Include="VOID_VesselInfo.cs" /> <Compile Include="VOID_VesselInfo.cs" />
<Compile Include="VOID_Transfer.cs" /> <Compile Include="VOID_Transfer.cs" />
<Compile Include="VOID_CBInfoBrowser.cs" /> <Compile Include="VOID_CBInfoBrowser.cs" />
<Compile Include="VOID_Rendezvous.cs" /> <Compile Include="VOID_Rendezvous.cs" />
<Compile Include="VOID_VesselRegister.cs" /> <Compile Include="VOID_VesselRegister.cs" />
<Compile Include="VOID_DataLogger.cs" /> <Compile Include="VOID_DataLogger.cs" />
<Compile Include="VOID_EditorCore.cs" /> <Compile Include="VOID_EditorCore.cs" />
<Compile Include="VOID_EditorHUD.cs" /> <Compile Include="VOID_EditorHUD.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\..\..\..\..\mnt\games-ssd\KSP_linux\KSP_Data\Managed\Assembly-CSharp.dll</HintPath> <HintPath>..\..\..\Games\KSP_win\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="UnityEngine"> <Reference Include="UnityEngine">
<HintPath>..\..\..\..\..\mnt\games-ssd\KSP_linux\KSP_Data\Managed\UnityEngine.dll</HintPath> <HintPath>..\..\..\Games\KSP_win\KSP_Data\Managed\UnityEngine.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="System"> <Reference Include="System">
<HintPath>..\..\..\..\..\mnt\games-ssd\KSP_linux\KSP_Data\Managed\System.dll</HintPath> <HintPath>..\..\..\Games\KSP_win\KSP_Data\Managed\System.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Engineer.Extensions\Engineer.Extensions.csproj"> <ProjectReference Include="..\Engineer.Extensions\Engineer.Extensions.csproj">
<Project>{2FCF882B-0771-4649-8D04-81D7AA76A486}</Project> <Project>{2FCF882B-0771-4649-8D04-81D7AA76A486}</Project>
<Name>Engineer.Extensions</Name> <Name>Engineer.Extensions</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\VesselSimulator\VesselSimulator.csproj"> <ProjectReference Include="..\VesselSimulator\VesselSimulator.csproj">
<Project>{30FD6C0B-D36E-462F-B0FF-F0FAC9C666CF}</Project> <Project>{30FD6C0B-D36E-462F-B0FF-F0FAC9C666CF}</Project>
<Name>VesselSimulator</Name> <Name>VesselSimulator</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ProjectExtensions> <ProjectExtensions>
<MonoDevelop> <MonoDevelop>
<Properties> <Properties>
<Policies> <Policies>
<StandardHeader Text=" &#xA; ${FileName}&#xA; &#xA; Author:&#xA; ${AuthorName} &lt;${AuthorEmail}&gt;&#xA;&#xA; Copyright (c) ${Year} ${CopyrightHolder}&#xA;&#xA; This program is free software: you can redistribute it and/or modify&#xA; it under the terms of the GNU General Public License as published by&#xA; the Free Software Foundation, either version 3 of the License, or&#xA; (at your option) any later version.&#xA;&#xA; This program is distributed in the hope that it will be useful,&#xA; but WITHOUT ANY WARRANTY; without even the implied warranty of&#xA; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#xA; GNU General Public License for more details.&#xA;&#xA; You should have received a copy of the GNU General Public License&#xA; along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;." IncludeInNewFiles="True" /> <StandardHeader Text=" &#xA; ${FileName}&#xA; &#xA; Author:&#xA; ${AuthorName} &lt;${AuthorEmail}&gt;&#xA;&#xA; Copyright (c) ${Year} ${CopyrightHolder}&#xA;&#xA; This program is free software: you can redistribute it and/or modify&#xA; it under the terms of the GNU General Public License as published by&#xA; the Free Software Foundation, either version 3 of the License, or&#xA; (at your option) any later version.&#xA;&#xA; This program is distributed in the hope that it will be useful,&#xA; but WITHOUT ANY WARRANTY; without even the implied warranty of&#xA; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#xA; GNU General Public License for more details.&#xA;&#xA; You should have received a copy of the GNU General Public License&#xA; along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;." IncludeInNewFiles="True" />
</Policies> </Policies>
</Properties> </Properties>
</MonoDevelop> </MonoDevelop>
</ProjectExtensions> </ProjectExtensions>
</Project> </Project>