From: Andy Wilkinson Date: Tue, 27 May 2014 05:23:09 +0000 Subject: VOID_Tools: New CelestialBody tools. X-Git-Tag: 0.13 X-Git-Url: http://git.toad.homelinux.net/projects/VOID.git/commitdiff/cef6a3f --- VOID_Tools: New CelestialBody tools. --- --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -29,6 +29,7 @@ using System.Runtime.CompilerServices; [assembly: KSPAssemblyDependency("ToadicusTools", 0, 0)] +[assembly: KSPAssemblyDependency("VesselSimulator", 0, 0)] // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. --- a/VOID.csproj +++ b/VOID.csproj @@ -93,6 +93,7 @@ + --- a/VOID_CBInfoBrowser.cs +++ b/VOID_CBInfoBrowser.cs @@ -274,14 +274,14 @@ GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - GUILayout.Label(((Math.Pow((body.Radius), 2) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); + GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); // divide by 1000 to convert m to km - GUILayout.Label((((4d / 3) * Math.PI * Math.Pow(body.Radius, 3)) / 1000).ToString("0.00e+00") + "km³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); + GUILayout.Label((((4d / 3) * Math.PI * (body.Radius * body.Radius * body.Radius)) / 1000).ToString("0.00e+00") + "km³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - double p = body.Mass / (Math.Pow(body.Radius, 3) * (4d / 3) * Math.PI); + double p = body.Mass / ((body.Radius * body.Radius * body.Radius) * (4d / 3) * Math.PI); GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); @@ -299,7 +299,7 @@ GUILayout.Label(num_art_sats.ToString(), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - double g_ASL = (VOID_Core.Constant_G * body.Mass) / Math.Pow(body.Radius, 2); + double g_ASL = (VOID_Core.Constant_G * body.Mass) / (body.Radius * body.Radius); GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); --- a/VOID_Core.cs +++ b/VOID_Core.cs @@ -480,8 +480,9 @@ if (this.vessel != null && this.vesselSimActive) { + double radius = VOID_Core.Instance.vessel.Radius(); SimManager.Gravity = VOID_Core.Instance.vessel.mainBody.gravParameter / - Math.Pow(VOID_Core.Instance.vessel.Radius(), 2); + (radius * radius); SimManager.TryStartSimulation(); } else if (!this.vesselSimActive) @@ -1033,7 +1034,7 @@ { get { - return core.Kerbin.gravParameter / Math.Pow(core.Kerbin.Radius, 2); + return core.Kerbin.gravParameter / (core.Kerbin.Radius * core.Kerbin.Radius); } } } --- a/VOID_DataLogger.cs +++ b/VOID_DataLogger.cs @@ -234,7 +234,7 @@ line += vessel.flightIntegrator.getExternalTemperature().ToString("F2") + ";"; //gravity double r_vessel = vessel.mainBody.Radius + vessel.mainBody.GetAltitude(vessel.findWorldCenterOfMass()); - double g_vessel = (VOID_Core.Constant_G * vessel.mainBody.Mass) / Math.Pow(r_vessel, 2); + double g_vessel = (VOID_Core.Constant_G * vessel.mainBody.Mass) / (r_vessel * r_vessel); line += g_vessel.ToString("F3") + ";"; //atm density line += (vessel.atmDensity * 1000).ToString("F3") + ";"; --- a/VOID_DataValue.cs +++ b/VOID_DataValue.cs @@ -103,7 +103,7 @@ return (T)this.cache; } - public string ValueUnitString() { + public virtual string ValueUnitString() { return this.Value.ToString() + this.Units; } @@ -145,7 +145,6 @@ { return v.ToSingle(); } - protected IFormatProvider formatProvider; @@ -325,6 +324,26 @@ { public VOID_StrValue(string Label, Func ValueFunc) : base(Label, ValueFunc, "") {} } + + public class VOID_Vector3dValue : VOID_DataValue + { + public VOID_Vector3dValue(string Label, Func ValueFunc, string Units) + : base(Label, ValueFunc, Units) + {} + + public string ToString(string format) + { + return string.Format("{0}: {1}{2}", + this.Label, + this.Value.ToString(format), + this.Units + ); + } + + public string ValueUnitString(string format) { + return this.Value.ToString(format) + this.Units; + } + } } --- a/VOID_HUD.cs +++ b/VOID_HUD.cs @@ -269,62 +269,6 @@ () => core.vessel.getSurfacePitch(), "°" ); - - public static readonly VOID_DoubleValue stageMassFlow = new VOID_DoubleValue( - "Stage Mass Flow", - delegate() - { - if (SimManager.LastStage == null) - { - return double.NaN; - } - - double stageIsp = SimManager.LastStage.isp; - double stageThrust = SimManager.LastStage.actualThrust; - - return stageThrust / (stageIsp * KerbinGee); - }, - "Mg/s" - ); - - public static readonly VOID_DoubleValue burnTimeCompleteAtNode = new VOID_DoubleValue( - "Full burn time to complete at node", - delegate() - { - if (SimManager.LastStage == null) - { - return double.NaN; - } - - double nextManeuverDV = core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude; - double stageThrust = SimManager.LastStage.actualThrust; - - return burnTime(nextManeuverDV, totalMass, stageMassFlow, stageThrust); - }, - "s" - ); - - public static readonly VOID_DoubleValue burnTimeHalfDoneAtNode = new VOID_DoubleValue( - "Full burn time to be half done at node", - delegate() - { - if (SimManager.LastStage == null) - { - return double.NaN; - } - - double nextManeuverDV = core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude / 2d; - double stageThrust = SimManager.LastStage.actualThrust; - - return burnTime(nextManeuverDV, totalMass, stageMassFlow, stageThrust); - }, - "s" - ); - - private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust) - { - return initialMass / massFlow * (Math.Exp(deltaV * massFlow / thrust) - 1d); - } } } --- /dev/null +++ b/VOID_HUDAdvanced.cs @@ -1,1 +1,663 @@ - +// VOID +// +// VOID_HUD.cs +// +// Copyright © 2014, toadicus +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using Engineer.VesselSimulator; +using KSP; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ToadicusTools; +using UnityEngine; + +namespace VOID +{ + public class VOID_HUDAdvanced : VOID_Module, IVOID_Module + { + /* + * Fields + * */ + protected VOID_HUD primaryHUD; + + protected Rect leftHUDdefaultPos; + protected Rect rightHUDdefaultPos; + + [AVOID_SaveValue("leftHUDPos")] + protected VOID_SaveValue leftHUDPos; + [AVOID_SaveValue("rightHUDPos")] + protected VOID_SaveValue rightHUDPos; + + [AVOID_SaveValue("positionsLocked")] + protected VOID_SaveValue positionsLocked; + + /* + * Properties + * */ + public int ColorIndex + { + get + { + if (this.primaryHUD == null) + { + return 0; + } + + return this.primaryHUD.ColorIndex; + } + } + + /* + * Methods + * */ + public VOID_HUDAdvanced() : base() + { + this._Name = "Advanced Heads-Up Display"; + + this._Active.value = true; + + this.leftHUDdefaultPos = new Rect( + Screen.width * .5f - (float)GameSettings.UI_SIZE * .25f - 300f, + Screen.height - 200f, + 300f, 90f + ); + this.leftHUDPos = new Rect(this.leftHUDdefaultPos); + + this.rightHUDdefaultPos = new Rect( + Screen.width * .5f + (float)GameSettings.UI_SIZE * .25f, + Screen.height - 200f, + 300f, 90f + ); + this.rightHUDPos = new Rect(this.rightHUDdefaultPos); + + this.positionsLocked = true; + + Tools.PostDebugMessage (this, "Constructed."); + } + + protected void leftHUDWindow(int id) + { + StringBuilder leftHUD; + + leftHUD = new StringBuilder(); + + VOID_Core.Instance.LabelStyles["hud"].alignment = TextAnchor.UpperRight; + + if (VOID_Core.Instance.powerAvailable) + { + leftHUD.AppendFormat( + string.Intern("Mass: {0}\n"), + VOID_Data.totalMass.ToSIString(2) + ); + + if (VOID_Data.vesselCrewCapacity > 0) + { + leftHUD.AppendFormat( + string.Intern("Crew: {0} / {1}\n"), + VOID_Data.vesselCrewCount.Value, + VOID_Data.vesselCrewCapacity.Value + ); + } + + leftHUD.AppendFormat( + string.Intern("Acc: {0} T:W: {1}\n"), + VOID_Data.vesselAccel.ToSIString(2), + VOID_Data.currThrustWeight.Value.ToString("f2") + ); + + leftHUD.AppendFormat( + string.Intern("Ang Vel: {0}\n"), + VOID_Data.vesselAngularVelocity.ToSIString(2) + ); + + if (VOID_Data.stageNominalThrust != 0d) + { + leftHUD.AppendFormat( + string.Intern("Thrust Offset: {0}\n"), + VOID_Data.vesselThrustOffset.Value.ToString("F1") + ); + } + } + else + { + VOID_Core.Instance.LabelStyles["hud"].normal.textColor = Color.red; + leftHUD.Append(string.Intern("-- POWER LOST --")); + } + + GUILayout.Label(leftHUD.ToString(), VOID_Core.Instance.LabelStyles["hud"], GUILayout.ExpandWidth(true)); + + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); + } + + protected void rightHUDWindow(int id) + { + StringBuilder rightHUD; + + rightHUD = new StringBuilder(); + + VOID_Core.Instance.LabelStyles["hud"].alignment = TextAnchor.UpperLeft; + + if (VOID_Core.Instance.powerAvailable) + { + rightHUD.AppendFormat( + "Burn Δv (Rem/Tot): {0} / {1}\n", + VOID_Data.currManeuverDVRemaining.ValueUnitString("f2"), + VOID_Data.currManeuverDeltaV.ValueUnitString("f2") + ); + + if (VOID_Data.upcomingManeuverNodes > 1) + { + rightHUD.AppendFormat("Next Burn Δv: {0}\n", + VOID_Data.nextManeuverDeltaV.ValueUnitString("f2") + ); + } + + rightHUD.AppendFormat("Burn Time (Rem/Total): {0} / {1}\n", + VOID_Tools.ConvertInterval(VOID_Data.currentNodeBurnRemaining.Value), + VOID_Tools.ConvertInterval(VOID_Data.currentNodeBurnDuration.Value) + ); + + if (VOID_Data.burnTimeDoneAtNode.Value != string.Empty) + { + rightHUD.AppendFormat("{0} (done @ node)\n", + VOID_Data.burnTimeDoneAtNode.Value + ); + + rightHUD.AppendFormat("{0} (½ done @ node)", + VOID_Data.burnTimeHalfDoneAtNode.Value + ); + } + else + { + rightHUD.Append("Node is past"); + } + } + else + { + VOID_Core.Instance.LabelStyles["hud"].normal.textColor = Color.red; + rightHUD.Append(string.Intern("-- POWER LOST --")); + } + + GUILayout.Label(rightHUD.ToString(), VOID_Core.Instance.LabelStyles["hud"], GUILayout.ExpandWidth(true)); + + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); + } + + public override void DrawGUI() + { + if (this.primaryHUD == null) + { + foreach (IVOID_Module module in VOID_Core.Instance.Modules) + { + if (module is VOID_HUD) + { + this.primaryHUD = module as VOID_HUD; + } + } + } + else + { + if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)) + { + SimManager.RequestSimulation(); + } + + this.leftHUDPos.value = GUI.Window( + VOID_Core.Instance.windowID, + this.leftHUDPos, + VOID_Tools.GetWindowHandler(this.leftHUDWindow), + GUIContent.none, + GUIStyle.none + ); + + if (VOID_Data.upcomingManeuverNodes > 0) + { + this.rightHUDPos.value = GUI.Window( + VOID_Core.Instance.windowID, + this.rightHUDPos, + VOID_Tools.GetWindowHandler(this.leftHUDWindow), + GUIContent.none, + GUIStyle.none + ); + } + } + } + + public override void DrawConfigurables() + { + this.positionsLocked = GUILayout.Toggle(this.positionsLocked, + string.Intern("Lock Advanced HUD Positions"), + GUILayout.ExpandWidth(false)); + } + } + + public static partial class VOID_Data + { + public static int upcomingManeuverNodes + { + get + { + if (core.vessel == null || + core.vessel.patchedConicSolver == null || + core.vessel.patchedConicSolver.maneuverNodes == null + ) + { + return 0; + } + + return core.vessel.patchedConicSolver.maneuverNodes.Count; + } + } + + public static readonly VOID_Vector3dValue vesselThrustOffset = new VOID_Vector3dValue( + "Thrust Offset", + delegate() + { + if (core.vessel == null) + { + return Vector3d.zero; + } + + List engineModules = core.vessel.getModulesOfType(); + + Vector3d thrustPos = Vector3d.zero; + Vector3d thrustDir = Vector3d.zero; + float thrust = 0; + + foreach (PartModule engine in engineModules) + { + float moduleThrust = 0; + + switch (engine.moduleName) + { + case "ModuleEngines": + case "ModuleEnginesFX": + break; + default: + continue; + } + + if (!engine.isEnabled) + { + continue; + } + + CenterOfThrustQuery cotQuery = new CenterOfThrustQuery(); + + if (engine is ModuleEngines) + { + ModuleEngines engineModule = engine as ModuleEngines; + + moduleThrust = engineModule.finalThrust; + + engineModule.OnCenterOfThrustQuery(cotQuery); + } + else // engine is ModuleEnginesFX + { + ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX; + + moduleThrust = engineFXModule.finalThrust; + + engineFXModule.OnCenterOfThrustQuery(cotQuery); + } + + if (moduleThrust != 0d) + { + cotQuery.thrust = moduleThrust; + } + + thrustPos += cotQuery.pos * cotQuery.thrust; + thrustDir += cotQuery.dir * cotQuery.thrust; + thrust += cotQuery.thrust; + } + + if (thrust != 0) + { + thrustPos /= thrust; + thrustDir /= thrust; + } + + Transform vesselTransform = core.vessel.transform; + + thrustPos = vesselTransform.InverseTransformPoint(thrustPos); + thrustDir = vesselTransform.InverseTransformDirection(thrustDir); + + Vector3d thrustOffset = VectorTools.PointDistanceToLine( + thrustPos, thrustDir.normalized, core.vessel.findLocalCenterOfMass()); + + Tools.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" + + "\tthrustPos: {0}\n" + + "\tthrustDir: {1}\n" + + "\tthrustOffset: {2}\n" + + "\tvessel.CoM: {3}", + thrustPos, + thrustDir.normalized, + thrustOffset, + core.vessel.findWorldCenterOfMass() + ); + + return thrustOffset; + }, + "m" + ); + + public static readonly VOID_DoubleValue vesselAccel = new VOID_DoubleValue( + "Acceleration", + () => geeForce * KerbinGee, + "m/s" + ); + + public static readonly VOID_IntValue vesselCrewCount = new VOID_IntValue( + "Crew Onboard", + delegate() + { + if (core.vessel != null) + { + return core.vessel.GetCrewCount(); + } + else + { + return 0; + } + }, + "" + ); + + public static readonly VOID_IntValue vesselCrewCapacity = new VOID_IntValue( + "Crew Capacity", + delegate() + { + if (core.vessel != null) + { + return core.vessel.GetCrewCapacity(); + } + else + { + return 0; + } + }, + "" + ); + + public static readonly VOID_DoubleValue vesselAngularVelocity = new VOID_DoubleValue( + "Angular Velocity", + delegate() + { + if (core.vessel != null) + { + return core.vessel.angularVelocity.magnitude; + } + else + { + return double.NaN; + } + }, + "rad/s" + ); + + public static readonly VOID_DoubleValue stageNominalThrust = new VOID_DoubleValue( + "Nominal Stage Thrust", + delegate() + { + if (SimManager.LastStage == null) + { + return double.NaN; + } + + if (SimManager.LastStage.actualThrust == 0d) + { + return SimManager.LastStage.thrust; + } + else + { + return SimManager.LastStage.actualThrust; + } + }, + "kN" + ); + + public static readonly VOID_DoubleValue stageMassFlow = new VOID_DoubleValue( + "Stage Mass Flow", + delegate() + { + if (SimManager.LastStage == null) + { + return double.NaN; + } + + double stageIsp = SimManager.LastStage.isp; + double stageThrust = stageNominalThrust; + + Tools.PostDebugMessage(typeof(VOID_Data), "calculating stageMassFlow from:\n" + + "\tstageIsp: {0}\n" + + "\tstageThrust: {1}\n" + + "\tKerbinGee: {2}\n", + stageIsp, + stageThrust, + KerbinGee + ); + + return stageThrust / (stageIsp * KerbinGee); + }, + "Mg/s" + ); + + public static readonly VOID_DoubleValue currManeuverDeltaV = new VOID_DoubleValue( + "Current Maneuver Delta-V", + delegate() + { + if (upcomingManeuverNodes > 0) + { + return core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude; + } + else + { + return double.NaN; + } + }, + "m/s" + ); + + public static readonly VOID_DoubleValue currManeuverDVRemaining = new VOID_DoubleValue( + "Remaining Maneuver Delta-V", + delegate() + { + if (upcomingManeuverNodes > 0) + { + return core.vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(core.vessel.orbit).magnitude; + } + else + { + return double.NaN; + } + }, + "m/s" + ); + + public static readonly VOID_DoubleValue nextManeuverDeltaV = new VOID_DoubleValue( + "Current Maneuver Delta-V", + delegate() + { + if (upcomingManeuverNodes > 1) + { + return core.vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude; + } + else + { + return double.NaN; + } + }, + "m/s" + ); + + public static readonly VOID_DoubleValue currentNodeBurnDuration = new VOID_DoubleValue( + "Total Burn Time", + delegate() + { + if (SimManager.LastStage == null || currManeuverDeltaV.Value == double.NaN) + { + return double.NaN; + } + + double stageThrust = stageNominalThrust; + + return burnTime(currManeuverDeltaV.Value, totalMass, stageMassFlow, stageThrust); + }, + "s" + ); + + public static readonly VOID_DoubleValue currentNodeBurnRemaining = new VOID_DoubleValue( + "Burn Time Remaining", + delegate() + { + if (SimManager.LastStage == null || currManeuverDVRemaining == double.NaN) + { + return double.NaN; + } + + double stageThrust = stageNominalThrust; + + return burnTime(currManeuverDVRemaining, totalMass, stageMassFlow, stageThrust); + }, + "s" + ); + + public static readonly VOID_DoubleValue currentNodeHalfBurnDuration = new VOID_DoubleValue( + "Half Burn Time", + delegate() + { + if (SimManager.LastStage == null || currManeuverDeltaV.Value == double.NaN) + { + return double.NaN; + } + + double stageThrust = stageNominalThrust; + + return burnTime(currManeuverDeltaV.Value / 2d, totalMass, stageMassFlow, stageThrust); + }, + "s" + ); + + public static readonly VOID_StrValue burnTimeDoneAtNode = new VOID_StrValue( + "Full burn time to be half done at node", + delegate() + { + if (SimManager.LastStage == null && upcomingManeuverNodes < 1) + { + return "N/A"; + } + + ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0]; + + if ((node.UT - Planetarium.GetUniversalTime()) < 0) + { + return string.Empty; + } + + double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime(); + + int sign = Math.Sign(interval); + interval = Math.Abs(interval); + + string format; + + if (sign >= 0) + { + format = string.Intern("T - {0}"); + } + else + { + format = string.Intern("T + {0}"); + } + + return string.Format(format, VOID_Tools.ConvertInterval(interval)); + } + ); + + public static readonly VOID_StrValue burnTimeHalfDoneAtNode = new VOID_StrValue( + "Full burn time to be half done at node", + delegate() + { + if (SimManager.LastStage == null && upcomingManeuverNodes < 1) + { + return "N/A"; + } + + ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0]; + + if ((node.UT - Planetarium.GetUniversalTime()) < 0) + { + return string.Empty; + } + + double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime(); + + int sign = Math.Sign(interval); + interval = Math.Abs(interval); + + string format; + + if (sign >= 0) + { + format = string.Intern("T - {0}"); + } + else + { + format = string.Intern("T + {0}"); + } + + return string.Format(format, VOID_Tools.ConvertInterval(interval)); + } + ); + + private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust) + { + Tools.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" + + "\tdeltaV: {0}\n" + + "\tinitialMass: {1}\n" + + "\tmassFlow: {2}\n" + + "\tthrust: {3}\n", + deltaV, + initialMass, + massFlow, + thrust + ); + return initialMass / massFlow * (Math.Exp(deltaV * massFlow / thrust) - 1d); + } + } +} + --- a/VOID_Module.cs +++ b/VOID_Module.cs @@ -51,6 +51,14 @@ /* * Properties * */ + protected virtual VOID_Core core + { + get + { + return VOID_Core.Instance; + } + } + public virtual bool toggleActive { get @@ -206,42 +214,7 @@ protected float defWidth = 250f; protected float defHeight = 50f; - public virtual void ModuleWindow(int _) - { -// if (VOID_Core.Instance.updateTimer - this.lastUpdate > VOID_Core.Instance.updatePeriod) { -// foreach (var fieldinfo in this.GetType().GetFields( -// BindingFlags.Instance | -// BindingFlags.NonPublic | -// BindingFlags.Public | -// BindingFlags.FlattenHierarchy -// )) -// { -// object field = null; -// -// try -// { -// field = fieldinfo.GetValue (this); -// } -// catch (NullReferenceException) { -// Tools.PostDebugMessage(string.Format( -// "{0}: caught NullReferenceException, could not get value for field {1}.", -// this.GetType().Name, -// fieldinfo.Name -// )); -// } -// -// if (field == null) { -// continue; -// } -// -// if (typeof(IVOID_DataValue).IsAssignableFrom (field.GetType ())) { -// (field as IVOID_DataValue).Refresh (); -// } -// } -// -// this.lastUpdate = VOID_Core.Instance.updateTimer; -// } - } + public abstract void ModuleWindow(int _); public override void DrawGUI() { --- a/VOID_Orbital.cs +++ b/VOID_Orbital.cs @@ -52,8 +52,6 @@ public override void ModuleWindow(int _) { - base.ModuleWindow (_); - int idx = 0; GUILayout.BeginVertical(); @@ -186,7 +184,7 @@ double orbitRadius = VOID_Core.Instance.vessel.mainBody.Radius + VOID_Core.Instance.vessel.mainBody.GetAltitude(VOID_Core.Instance.vessel.findWorldCenterOfMass()); return (VOID_Core.Constant_G * VOID_Core.Instance.vessel.mainBody.Mass) / - Math.Pow(orbitRadius, 2); + (orbitRadius * orbitRadius); }, "m/s²" ); --- a/VOID_Rendezvous.cs +++ b/VOID_Rendezvous.cs @@ -193,7 +193,13 @@ GUILayout.Label(Tools.MuMech_ToSI((vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); - //target_vessel_extended_orbital_info = GUILayout.Toggle(target_vessel_extended_orbital_info, "Extended info"); + // Toadicus edit: added local sidereal longitude. + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Local Sidereal Longitude:"); + GUILayout.Label(LSL.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"]); + GUILayout.EndHorizontal(); + + toggleExtendedOrbital.value = GUILayout.Toggle(toggleExtendedOrbital, "Extended info"); if (toggleExtendedOrbital) { @@ -237,12 +243,6 @@ GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Arg. of periapsis:"); GUILayout.Label(v.orbit.argumentOfPeriapsis.ToString("F3") + "°", GUILayout.ExpandWidth(false)); - GUILayout.EndHorizontal(); - - // Toadicus edit: added local sidereal longitude. - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Local Sidereal Longitude:"); - GUILayout.Label(LSL.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"]); GUILayout.EndHorizontal(); } } --- a/VOID_SurfAtmo.cs +++ b/VOID_SurfAtmo.cs @@ -49,8 +49,6 @@ public override void ModuleWindow(int _) { - base.ModuleWindow (_); - int idx = 0; GUILayout.BeginVertical(); --- a/VOID_Tools.cs +++ b/VOID_Tools.cs @@ -28,12 +28,71 @@ using KSP; using System; +using System.Collections.Generic; using UnityEngine; namespace VOID { public static partial class VOID_Tools { + #region CelestialBody Utilities + public static bool hasAncestor(this CelestialBody bodyA, CelestialBody bodyB) + { + if (bodyA == null || bodyB == null) + { + return false; + } + + while (bodyA.orbitDriver != null) + { + if (bodyA.orbit.referenceBody == bodyB) + { + return true; + } + + bodyA = bodyA.orbit.referenceBody; + } + + return false; + } + + public static bool NearestRelatedParents(ref CelestialBody bodyA, ref CelestialBody bodyB) + { + if (bodyA == null || bodyB == null || bodyA.orbitDriver == null || bodyB.orbitDriver == null) + { + throw new ArgumentException(string.Concat( + "CelestialBody::FindRelatedParents: ", + "Neither body may be null, and both bodies must have orbits." + )); + } + + CelestialBody a, b; + + a = bodyA; + + while (bodyA.orbitDriver != null) + { + b = bodyB; + + while (b.orbitDriver != null) + { + if (a.orbit.referenceBody == b.orbit.referenceBody) + { + bodyA = a; + bodyB = b; + return true; + } + + b = b.orbit.referenceBody; + } + + a = a.orbit.referenceBody; + } + + return false; + } + #endregion + #region VESSEL_EXTENSIONS_SCIENCE public static CBAttributeMap.MapAttribute GetBiome(this Vessel vessel) { @@ -256,6 +315,39 @@ } #endregion + private static Dictionary functionCache; + public static UnityEngine.GUI.WindowFunction GetWindowHandler(Action func) + { + if (functionCache == null) + { + functionCache = new Dictionary(); + } + + int hashCode = func.GetHashCode(); + + if (!functionCache.ContainsKey(hashCode)) + { + functionCache[hashCode] = delegate (int id) + { + try + { + func(id); + } + catch (ArgumentException ex) + { + Debug.LogWarning( + string.Format("[{0}]: ArgumentException caught during window call.", func.Target.GetType().Name) + ); + #if DEBUG + Debug.LogException(ex); + #endif + } + }; + } + + return functionCache[hashCode]; + } + /// /// Converts the interval given in seconds to a human-friendly /// time period in [years], [days], hours, minutes, and seconds. @@ -303,9 +395,11 @@ seconds %= SecondsPerMinute; - string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:00.0}s"; - string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:00.0}s"; - string format_3 = "{0:D2}h {1:D2}m {2:00.0}s"; + string format_1 = string.Intern("{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:00.0}s"); + string format_2 = string.Intern("{0:D1}d {1:D2}h {2:D2}m {3:00.0}s"); + string format_3 = string.Intern("{0:D2}h {1:D2}m {2:00.0}s"); + string format_4 = string.Intern("{0:D2}m {1:00.0}s"); + string format_5 = string.Intern("{0:00.0}s"); if (years > 0) { @@ -315,9 +409,17 @@ { return string.Format(format_2, days, hours, minutes, seconds); } + else if (hours > 0) + { + return string.Format(format_3, hours, minutes, seconds); + } + else if (minutes > 0) + { + return string.Format(format_4, minutes, seconds); + } else { - return string.Format(format_3, hours, minutes, seconds); + return string.Format(format_5, seconds); } } @@ -335,8 +437,14 @@ //transfer angles 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_transfer = (2 * Math.PI) * Math.Sqrt(Math.Pow((((r_target / 1000) + (r_current / 1000)) / 2), 3) / (grav_param / 1000000000)); + r_target /= 1000; + r_current /= 1000; + grav_param /= 1000000000; + + double midpoint = (r_target + r_current) / 2; + + double T_target = (2 * Math.PI) * Math.Sqrt((r_target * r_target * r_target) / grav_param); + double T_transfer = (2 * Math.PI) * Math.Sqrt((midpoint * midpoint * midpoint) / grav_param); return 360 * (0.5 - (T_transfer / (2 * T_target))); } @@ -375,7 +483,7 @@ r = r1*r2 return math.sqrt(bar / r) */ - double foo = r2 * Math.Pow(v, 2) - 2 * mu; + double foo = r2 * (v * v) - 2 * mu; double bar = r1 * foo + (2 * r2 * mu); double r = r1 * r2; return Math.Sqrt(bar / r); @@ -397,9 +505,9 @@ return 180 - degrees */ double epsilon, h, ee, theta, degrees; - epsilon = (Math.Pow(v, 2) / 2) - (mu / r); + epsilon = ((v * v) / 2) - (mu / r); 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 * (h * h)) / (mu * mu))); theta = Math.Acos(1.0 / ee); degrees = theta * (180.0 / Math.PI); return 180 - degrees; --- a/VOID_VesselInfo.cs +++ b/VOID_VesselInfo.cs @@ -48,8 +48,6 @@ public override void ModuleWindow(int _) { - base.ModuleWindow (_); - if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)) { SimManager.RequestSimulation(); @@ -127,7 +125,7 @@ return double.NaN; } - return SimManager.LastStage.totalBaseMass; + return SimManager.LastStage.totalMass - SimManager.LastStage.totalBaseMass; }, "tons" ); @@ -178,6 +176,34 @@ } ); + public static readonly VOID_DoubleValue currThrustWeight = new VOID_DoubleValue( + "T:W Ratio", + delegate() + { + if (SimManager.LastStage == null) + { + return double.NaN; + } + + return SimManager.LastStage.actualThrustToWeight; + }, + "" + ); + + public static readonly VOID_DoubleValue maxThrustWeight = new VOID_DoubleValue( + "T:W Ratio", + delegate() + { + if (SimManager.LastStage == null) + { + return double.NaN; + } + + return SimManager.LastStage.maxThrustToWeight; + }, + "" + ); + public static readonly VOID_StrValue currmaxThrustWeight = new VOID_StrValue( "T:W (curr/max)", delegate() @@ -185,20 +211,10 @@ if (SimManager.Stages == null || SimManager.LastStage == null) return "N/A"; - double currThrust = SimManager.LastStage.actualThrust; - double maxThrust = SimManager.LastStage.thrust; - double mass = SimManager.LastStage.totalMass; - double gravity = VOID_Core.Instance.vessel.mainBody.gravParameter / - Math.Pow( - VOID_Core.Instance.vessel.mainBody.Radius + VOID_Core.Instance.vessel.altitude, - 2 - ); - double weight = mass * gravity; - return string.Format( "{0} / {1}", - (currThrust / weight).ToString("F2"), - (maxThrust / weight).ToString("F2") + (VOID_Data.currThrustWeight.Value).ToString("F2"), + (VOID_Data.maxThrustWeight.Value).ToString("F2") ); } ); @@ -213,7 +229,7 @@ double maxThrust = SimManager.LastStage.thrust; double mass = SimManager.LastStage.totalMass; double gravity = (VOID_Core.Constant_G * VOID_Core.Instance.vessel.mainBody.Mass) / - Math.Pow(VOID_Core.Instance.vessel.mainBody.Radius, 2); + (VOID_Core.Instance.vessel.mainBody.Radius * VOID_Core.Instance.vessel.mainBody.Radius); double weight = mass * gravity; return maxThrust / weight;