protected override void Overrides() { Fields["displayChance"].guiName = "Chance of Control Surface Failure"; Fields["safetyRating"].guiName = "Control Surface Safety Rating"; failureType = "Stuck Control Surface"; //Part is mechanical so can be repaired remotely. remoteRepairable = true; controlSurface = part.FindModuleImplementing <ModuleControlSurface>(); }
internal ControlSurface(Part part) { Part = part; controlSurface = part.InternalPart.Module <ModuleControlSurface> (); if (controlSurface == null) { throw new ArgumentException("Part does not have a ModuleControlSurface PartModule"); } }
protected void Init(ModuleControlSurface surface, SimulatedPart part) { base.Init(surface, part); this.deflectionLiftCoeff = surface.deflectionLiftCoeff * surface.ctrlSurfaceArea; this.authorityLimiter = surface.authorityLimiter; this.ctrlSurfaceRange = surface.ctrlSurfaceRange; // TODO: Incorporate transformName if required. this.rotationAxis = surface.transform.rotation * Vector3.right; this.ignorePitch = surface.ignorePitch; this.maxAuthority = 150f; // surface.maxAuthority is private. Hopefully its value never changes. }
public override void OnStart(StartState state) { try { base.OnStart(state); ControlSurfaceModule = part.FindModuleImplementing <ModuleControlSurface>(); ctrlSurfaceRange = ControlSurfaceModule.ctrlSurfaceRange; ControlSurfaceModule.ctrlSurfaceRange = ctrlSurfaceRange * vacuumRange; } catch (Exception ex) { Debug.LogError("PROBLEM.\n" + ex.Message + "\n" + ex.StackTrace); } }
public void FixedUpdate() { ControlSurfaceModule = part.FindModuleImplementing <ModuleControlSurface>(); if (null == ControlSurfaceModule) { return; } if (plusEnabled) { ControlSurfaceModule.actuatorSpeed = actuatorSpeed; } }
public void FixedUpdate() { ControlSurfaceModule = part.FindModuleImplementing<ModuleControlSurface>(); if (null == ControlSurfaceModule) { return; } if (plusEnabled) { ControlSurfaceModule.actuatorSpeed = actuatorSpeed; } }
public override void OnStart(StartState state) { base.OnStart(state); _surfaceModule = part.FindModuleImplementing <ModuleControlSurface>(); if (_surfaceModule == null) { part.RemoveModule(this); Destroy(this); } else { _ready = true; } }
public override void OnUpgrade(ConfigNode node, LoadContext loadContext, ConfigNode parentNode) { ConfigNode[] nodes = node.GetNodes("MODULE"); int num = nodes.Length; while (num-- > 0) { string value = nodes[num].GetValue("name"); if (value == "ModuleControlSurface") { ModuleControlSurface baseModule = GetBaseModule(node, loadContext); ConvertControlAuthority(nodes[num], baseModule); ConvertControlAuthorityAxisGroup(nodes[num]); } } }
//control surface will stick and not respond to input public override void FailPart() { controlSurface = part.FindModuleImplementing <ModuleControlSurface>(); controlSurface.ignorePitch = true; controlSurface.ignoreRoll = true; controlSurface.ignoreYaw = true; if (OhScrap.highlight) { OhScrap.SetFailedHighlight(); } if (hasFailed) { return; } Debug.Log("[OhScrap]: " + SYP.ID + " has suffered a control surface failure"); }
public void setup() { //Set up atmoshpere change listener //Debug.Log("setup called"); cs = GetComponent <ModuleControlSurface>(); //get the parts control surface module if (toggles == null) //if necessary, initialize static list { toggles = new List <ModuleCSToggle>(); } toggles.Add(this); removeNullToggles(); // Clean up elements from previous iterations of the list csFields = new List <BaseField>(); if (cs.authorityLimiter != 0) //We don't want to override authority if the surface is disabled { authority = cs.authorityLimiter; } if (!controlActive) //Needed to disable the appropriate gui event buttons { disableCS(); } else { enableCS(); } //bool inAtmo = FlightGlobals.ActiveVessel.atmDensity != 0; //if (inAtmo && !wasInAtmo) { //If we changed atmosphere state while vessel was not loaded, enable / disable control surface // enableCS(); //} //if (!inAtmo && wasInAtmo) { // disableCS(); //} GameEvents.onVesselSituationChange.Add(UpdateCurrentAtmosphereState); setupCalled = true; //Setup done }
public override void OnStart(StartState state) { base.OnStart(state); deployModule = part.Modules[DeployModuleIndex] as IScalarModule; surfaces = part.FindModulesImplementing <ModuleLiftingSurface>().ToArray(); for (int i = 0; i < surfaces.Length; i++) { lifts.Add(surfaces[i].deflectionLiftCoeff); if (surfaces[i].GetType() == typeof(ModuleControlSurface) | surfaces[i].GetType() == typeof(ModuleAeroSurface)) { ModuleControlSurface srf = surfaces[i] as ModuleControlSurface; ranges.Add(srf.ctrlSurfaceRange); } } deployModule.OnStop.Add(UpdateSurfaces); UpdateSurfaces(deployModule.GetScalar); }
//control surface will stick and not respond to input protected override void FailPart() { controlSurface = part.FindModuleImplementing <ModuleControlSurface>(); controlSurface.ignorePitch = true; controlSurface.ignoreRoll = true; controlSurface.ignoreYaw = true; if (OhScrap.highlight) { OhScrap.SetFailedHighlight(); } if (message) { return; } if (vessel.vesselType != VesselType.Debris) { ScreenMessages.PostScreenMessage("Control Surface Failure!"); } Debug.Log("[OhScrap]: " + SYP.ID + " has suffered a control surface failure"); message = true; }
private void AnalyzeControlSurfaces() { torqueControlSurface.Reset(); foreach (var pair in controlSurfaces) { Part p = pair.Key; List <ModuleControlSurface> mlist = p.Modules.GetModules <ModuleControlSurface>(); for (int m = 0; m < mlist.Count; m++) { Vector3 pos; Vector3 neg; ModuleControlSurface cs = mlist[m]; cs.GetPotentialTorque(out pos, out neg); torqueReactionWheel.Add(pos); torqueReactionWheel.Add(-neg); } } }
public override void OnStart(StartState state) { Debug.Log(moduleName + ".Start(): v01.07"); base.OnStart(state); ControlSurfaceModule = part.FindModuleImplementing<ModuleControlSurface>(); if (null == ControlSurfaceModule) { Debug.LogWarning(moduleName + ".Start(): Did not find Control Surface Module."); return; } ControlSurfaceModule.Fields["deploy"].guiActive = true; ControlSurfaceModule.Fields["deploy"].guiActiveEditor = true; ControlSurfaceModule.Fields["deployInvert"].guiActive = true; ControlSurfaceModule.Fields["deployInvert"].guiActiveEditor = true; SetupStockPlus(); }
protected override void FailPart() { if (part.vessel.atmDensity == 0) { return; } controlSurface = part.FindModuleImplementing <ModuleControlSurface>(); controlSurface.ignorePitch = true; controlSurface.ignoreRoll = true; controlSurface.ignoreYaw = true; if (UPFM.highlight) { UPFM.SetFailedHighlight(); } if (message) { return; } ScreenMessages.PostScreenMessage("Control Surface Failure!"); Debug.Log("[UPFM]: " + SYP.ID + " has suffered a control surface failure"); message = true; }
public override void OnStart(StartState state) { Debug.Log(moduleName + ".Start(): v01.04"); base.OnStart(state); ControlSurfaceModule = part.FindModuleImplementing <ModuleControlSurface>(); if (null == ControlSurfaceModule) { Debug.LogWarning(moduleName + ".Start(): Did not find Control Surface Module."); return; } ControlSurfaceModule.Fields["deploy"].guiActive = true; ControlSurfaceModule.Fields["deploy"].guiActiveEditor = true; ControlSurfaceModule.Fields["deployInvert"].guiActive = true; ControlSurfaceModule.Fields["deployInvert"].guiActiveEditor = true; SetupStockPlus(); }
public void FixedUpdate() { ControlSurfaceModule = part.FindModuleImplementing <ModuleControlSurface>(); if (null == ControlSurfaceModule) { return; } if (true == plusEnabled) { if (FlightGlobals.getStaticPressure(part.transform.position) < 0.001f) { if (vacuumRange > 0.01f) { vacuumRange -= 0.05f; } else { vacuumRange = 0.01f; } } else { if (vacuumRange < 1.0f) { vacuumRange += 0.05f; } else { vacuumRange = 1.0f; } } ControlSurfaceModule.ctrlSurfaceRange = ctrlSurfaceRange * Authority * vacuumRange * Mathf.Sign(ControlSurfaceModule.ctrlSurfaceRange); } }
private float vacuumRange = 1.0f; // disables flight controls when in vacuum #endregion Fields #region Methods public void FixedUpdate() { ControlSurfaceModule = part.FindModuleImplementing<ModuleControlSurface>(); if (null == ControlSurfaceModule) { return; } if (true == plusEnabled) { if (FlightGlobals.getStaticPressure(part.transform.position) < 0.001f) { if (vacuumRange > 0.01f) { vacuumRange -= 0.05f; } else { vacuumRange = 0.01f; } } else { if (vacuumRange < 1.0f) { vacuumRange += 0.05f; } else { vacuumRange = 1.0f; } } ControlSurfaceModule.ctrlSurfaceRange = ctrlSurfaceRange * Authority * vacuumRange * Mathf.Sign(ControlSurfaceModule.ctrlSurfaceRange); } }
public override void OnFixedUpdate() { base.OnFixedUpdate(); if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready) { if (boostFlap) { if (!bfCheck) { bfCheck = true; bfPart = ControlSurface(); bfPart.ignorePitch = true; bfPart.ignoreRoll = true; bfPart.ignoreYaw = true; } if (!manualDeploy) { if (!this.vessel.Landed) { if (!deployed) { deployed = true; bfPart.actuatorSpeed = actuatorSpeed; if (toggleDeploy) { bfPart.deploy = false; } else { bfPart.deploy = true; } } } else { deployed = false; if (toggleDeploy) { bfPart.deploy = true; } else { bfPart.deploy = false; } } } else { if (!deployed) { deployed = true; if (toggleDeploy) { bfPart.deploy = false; } else { bfPart.deploy = true; } } } } else { if (bfCheck) { bfCheck = false; } } } }
private ModuleControlSurface ControlSurface() { ModuleControlSurface Control = part.FindModuleImplementing <ModuleControlSurface>(); return(Control); }
// This method calculates part values such as mass, lift, drag and connection forces, as well as all intermediates. public void CalculateAerodynamicValues(bool doInteraction = true) { // Calculate intemediate values //print(part.name + ": Calc Aero values"); b_2 = (double)tipPosition.z - (double)Root.localPosition.z + 1.0; MAC = ((double)tipScale.x + (double)rootScale.x + 2.0) * (double)modelChordLenght / 2.0; midChordSweep = (MathD.Rad2Deg * Math.Atan(((double)Root.localPosition.x - (double)tipPosition.x) / b_2)); taperRatio = ((double)tipScale.x + 1.0) / ((double)rootScale.x + 1.0); surfaceArea = MAC * b_2; aspectRatio = 2.0 * b_2 / MAC; ArSweepScale = Math.Pow(aspectRatio / MathD.Cos(MathD.Deg2Rad * midChordSweep), 2.0) + 4.0; ArSweepScale = 2.0 + Math.Sqrt(ArSweepScale); ArSweepScale = (2.0 * MathD.PI) / ArSweepScale * aspectRatio; wingMass = MathD.Clamp((double)massFudgeNumber * surfaceArea * ((ArSweepScale * 2.0) / (3.0 + ArSweepScale)) * ((1.0 + taperRatio) / 2), 0.01, double.MaxValue); Cd = (double)dragBaseValue / ArSweepScale * (double)dragMultiplier; Cl = (double)liftFudgeNumber * surfaceArea * ArSweepScale; //print("Gather Children"); GatherChildrenCl(); connectionForce = MathD.Round(MathD.Clamp(MathD.Sqrt(Cl + ChildrenCl) * (double)connectionFactor, (double)connectionMinimum, double.MaxValue)); // Values always set if (isWing) { wingCost = (float)wingMass * (1f + (float)ArSweepScale / 4f) * costDensity; wingCost = Mathf.Round(wingCost / 5f) * 5f; } else if (isCtrlSrf) { wingCost = (float)wingMass * (1f + (float)ArSweepScale / 4f) * costDensity * (1f - modelControlSurfaceFraction); wingCost += (float)wingMass * (1f + (float)ArSweepScale / 4f) * costDensityControl * modelControlSurfaceFraction; wingCost = Mathf.Round(wingCost / 5f) * 5f; } part.breakingForce = Mathf.Round((float)connectionForce); part.breakingTorque = Mathf.Round((float)connectionForce); // Stock-only values if (!FARactive) { // numbers for lift from: http://forum.kerbalspaceprogram.com/threads/118839-Updating-Parts-to-1-0?p=1896409&viewfull=1#post1896409 float stockLiftCoefficient = (float)(surfaceArea / 3.52); // CoL/P matches CoM unless otherwise specified part.CoMOffset = new Vector3(Vector3.Dot(Tip.position - Root.position, part.transform.right) / 2, Vector3.Dot(Tip.position - Root.position, part.transform.up) / 2, 0); if (isWing && !isCtrlSrf) { part.Modules.GetModules <ModuleLiftingSurface>().FirstOrDefault().deflectionLiftCoeff = stockLiftCoefficient; part.mass = stockLiftCoefficient * 0.1f; } else { ModuleControlSurface mCtrlSrf = part.Modules.OfType <ModuleControlSurface>().FirstOrDefault(); if (mCtrlSrf != null) { mCtrlSrf.deflectionLiftCoeff = stockLiftCoefficient; mCtrlSrf.ctrlSurfaceArea = modelControlSurfaceFraction; part.mass = stockLiftCoefficient * (1 + modelControlSurfaceFraction) * 0.1f; } } } // FAR values // With reflection stuff from r4m0n if (FARactive) { if (part.Modules.Contains("FARControllableSurface")) { PartModule FARmodule = part.Modules["FARControllableSurface"]; Type FARtype = FARmodule.GetType(); FARtype.GetField("b_2").SetValue(FARmodule, b_2); FARtype.GetField("b_2_actual").SetValue(FARmodule, b_2); FARtype.GetField("MAC").SetValue(FARmodule, MAC); FARtype.GetField("MAC_actual").SetValue(FARmodule, MAC); FARtype.GetField("S").SetValue(FARmodule, surfaceArea); FARtype.GetField("MidChordSweep").SetValue(FARmodule, midChordSweep); FARtype.GetField("TaperRatio").SetValue(FARmodule, taperRatio); FARtype.GetField("ctrlSurfFrac").SetValue(FARmodule, modelControlSurfaceFraction); //print("Set fields"); } else if (part.Modules.Contains("FARWingAerodynamicModel")) { PartModule FARmodule = part.Modules["FARWingAerodynamicModel"]; Type FARtype = FARmodule.GetType(); FARtype.GetField("b_2").SetValue(FARmodule, b_2); FARtype.GetField("b_2_actual").SetValue(FARmodule, b_2); FARtype.GetField("MAC").SetValue(FARmodule, MAC); FARtype.GetField("MAC_actual").SetValue(FARmodule, MAC); FARtype.GetField("S").SetValue(FARmodule, surfaceArea); FARtype.GetField("MidChordSweep").SetValue(FARmodule, midChordSweep); FARtype.GetField("TaperRatio").SetValue(FARmodule, taperRatio); } if (!triggerUpdate && doInteraction) { TriggerUpdateAllWings(); } if (doInteraction) { triggerUpdate = false; } } //print("FAR Done"); // Update GUI values if (!FARactive) { guiCd = Mathf.Round((float)Cd * 100f) / 100f; guiCl = Mathf.Round((float)Cl * 100f) / 100f; guiWingMass = part.mass; } guiMAC = (float)MAC; guiB_2 = (float)b_2; guiMidChordSweep = (float)midChordSweep; guiTaperRatio = (float)taperRatio; guiSurfaceArea = (float)surfaceArea; guiAspectRatio = (float)aspectRatio; StartCoroutine(updateAeroDelayed()); }
//============================================================================================================================================ public void EngageAero() { //FAR Compatibility =) //Skip this if FAR isn't being used if (assemblyFARUsed == true) { foreach (Part EnabledPart in EnabledPartList) { if (EnabledPart.Modules.Contains ("FARControllableSurface")) { AeroFARModuleReference = EnabledPart.Modules ["FARControllableSurface"]; if (AeroFARModuleReference.Fields.GetValue ("isSpoiler").ToString() == "True") { RoboBrakes_AeroEnabledCount++; BaseActionList BAL = new BaseActionList (EnabledPart, AeroFARModuleReference); foreach (BaseAction BA in BAL) { if ((RoboBrakes_AUTOMATICBRAKE_ACTIVE == true && RoboBrakes_AEROAUTO == true) | (RoboBrakes_OVERRIDEBRAKE_ACTIVE == true && RoboBrakes_AEROOVERRIDE == true)) { if (BA.guiName == "Activate Spoiler") { KSPActionParam AP = new KSPActionParam (KSPActionGroup.None, KSPActionType.Activate); BA.Invoke (AP); } } else { if (BA.guiName == "Activate Spoiler") { KSPActionParam AP = new KSPActionParam (KSPActionGroup.None, KSPActionType.Deactivate); BA.Invoke (AP); } } } } } } } foreach (Part EnabledPart in EnabledPartList) { //--------------------------------------------------------------------------------------------------------------------- //Control Surface Module if (EnabledPart.Modules.Contains ("ModuleControlSurface")) { ModuleControlSurface MCS = new ModuleControlSurface (); MCS = EnabledPart.FindModuleImplementing<ModuleControlSurface> (); RoboBrakes_AeroEnabledCount++; BaseActionList BAL = new BaseActionList (EnabledPart, MCS); foreach (BaseAction BA in BAL) { if ((RoboBrakes_AUTOMATICBRAKE_ACTIVE == true && RoboBrakes_AEROAUTO == true) | (RoboBrakes_OVERRIDEBRAKE_ACTIVE == true && RoboBrakes_AEROOVERRIDE == true)) { if (BA.guiName == "Extend") { KSPActionParam AP = new KSPActionParam (KSPActionGroup.None, KSPActionType.Activate); BA.Invoke (AP); } } else { if (BA.guiName == "Retract") { KSPActionParam AP = new KSPActionParam (KSPActionGroup.None, KSPActionType.Activate); BA.Invoke (AP); } } } } //--------------------------------------------------------------------------------------------------------------------- //Module Aero Surface if (EnabledPart.Modules.Contains ("ModuleAeroSurface")) { ModuleAeroSurface MAS = new ModuleAeroSurface (); MAS = EnabledPart.FindModuleImplementing<ModuleAeroSurface> (); RoboBrakes_AeroEnabledCount++; BaseActionList BAL = new BaseActionList (EnabledPart, MAS); foreach (BaseAction BA in BAL) { if ((RoboBrakes_AUTOMATICBRAKE_ACTIVE == true && RoboBrakes_AEROAUTO == true) | (RoboBrakes_OVERRIDEBRAKE_ACTIVE == true && RoboBrakes_AEROOVERRIDE == true)) { if (BA.guiName == "Extend") { KSPActionParam AP = new KSPActionParam (KSPActionGroup.None, KSPActionType.Activate); BA.Invoke (AP); } } else { if (BA.guiName == "Retract") { KSPActionParam AP = new KSPActionParam (KSPActionGroup.None, KSPActionType.Activate); BA.Invoke (AP); } } } } } }
public StockModule(ModuleControlSurface module) { controlSurface = module; }
/// <summary> /// Import from MechJeb2 /// https://github.com/MuMech/MechJeb2/blob/dev/MechJeb2/VesselState.cs /// </summary> public static void AnalyzeParts(Vessel vessel) { torqueAvailable = Vector3d.zero; Vector6 torqueReactionSpeed6 = new Vector6(); torqueReactionWheel.Reset(); torqueControlSurface.Reset(); torqueGimbal.Reset(); torqueOthers.Reset(); UpdateRCSThrustAndTorque(vessel); for (int i = 0; i < vessel.parts.Count; i++) { Part p = vessel.parts[i]; for (int m = 0; m < p.Modules.Count; m++) { PartModule pm = p.Modules[m]; if (!pm.isEnabled) { continue; } ModuleReactionWheel rw = pm as ModuleReactionWheel; if (rw != null) { Vector3 pos; Vector3 neg; rw.GetPotentialTorque(out pos, out neg); // GetPotentialTorque reports the same value for pos & neg on ModuleReactionWheel torqueReactionWheel.Add(pos); torqueReactionWheel.Add(-neg); } else if (pm is ModuleControlSurface) // also does ModuleAeroSurface { ModuleControlSurface cs = (pm as ModuleControlSurface); Vector3 ctrlTorquePos; Vector3 ctrlTorqueNeg; cs.GetPotentialTorque(out ctrlTorquePos, out ctrlTorqueNeg); torqueControlSurface.Add(ctrlTorquePos); torqueControlSurface.Add(ctrlTorqueNeg); torqueReactionSpeed6.Add(Mathf.Abs(cs.ctrlSurfaceRange) / cs.actuatorSpeed * Vector3d.Max(ctrlTorquePos.Abs(), ctrlTorqueNeg.Abs())); } else if (pm is ModuleGimbal) { ModuleGimbal g = (pm as ModuleGimbal); Vector3 pos; Vector3 neg; g.GetPotentialTorque(out pos, out neg); // GetPotentialTorque reports the same value for pos & neg on ModuleGimbal torqueGimbal.Add(pos); torqueGimbal.Add(-neg); if (g.useGimbalResponseSpeed) { torqueReactionSpeed6.Add((Mathf.Abs(g.gimbalRange) / g.gimbalResponseSpeed) * Vector3d.Max(pos.Abs(), neg.Abs())); } } else if (pm is ModuleRCS) { // Handled separately } else if (pm is ITorqueProvider) { ITorqueProvider tp = pm as ITorqueProvider; Vector3 pos; Vector3 neg; tp.GetPotentialTorque(out pos, out neg); torqueOthers.Add(pos); torqueOthers.Add(neg); } } } torqueAvailable += Vector3d.Max(torqueReactionWheel.positive, torqueReactionWheel.negative); torqueAvailable += Vector3d.Max(rcsTorqueAvailable.positive, rcsTorqueAvailable.negative); torqueAvailable += Vector3d.Max(torqueControlSurface.positive, torqueControlSurface.negative); torqueAvailable += Vector3d.Max(torqueGimbal.positive, torqueGimbal.negative); torqueAvailable += Vector3d.Max(torqueOthers.positive, torqueOthers.negative); if (torqueAvailable.sqrMagnitude > 0) { torqueReactionSpeed = Vector3d.Max(torqueReactionSpeed6.positive, torqueReactionSpeed6.negative); torqueReactionSpeed.Scale(torqueAvailable.InvertNoNaN()); } else { torqueReactionSpeed = Vector3d.zero; } }
public override void OnStart(PartModule.StartState state) { debug.debugMode = debugMode; FARActive = AssemblyLoader.loadedAssemblies.Any(a => a.assembly.GetName().Name.Equals("FerramAerospaceResearch", StringComparison.InvariantCultureIgnoreCase)); // This line breaks the plugin :( if (FARActive) { foreach (BaseField f in Fields) { f.guiActive = false; } foreach (BaseEvent e in Events) { e.active = false; e.guiActive = false; e.guiActiveEditor = false; } foreach (BaseAction a in Actions) { a.active = false; } this.enabled = false; return; } //debug.debugMessage("FSwing OnStart: " + part.name); #region fligth mode if (HighLogic.LoadedSceneIsFlight) { findTransforms(true); // Check if a stock wing module is present, if not, manipulate FSliftSurface stuff instead. if (affectStockWingModule) { //Debug.Log("FSwing: getting stock wing module"); stockWingModule = part.FindModuleImplementing <ModuleControlSurface>(); if (stockWingModule != null) { //Debug.Log("FSwing: success"); } else { debug.debugMessage("FSwing: did not Find stock wing module"); affectStockWingModule = false; } } // get the main lift surface for the leading edge to manipulate if (affectStockWingModule) { useCtrlSrf = false; } else { FSliftSurface[] surfaces = part.GetComponents <FSliftSurface>(); foreach (FSliftSurface surface in surfaces) { if (surface.liftTransformName == leadingEdgeLiftSurface) { mainLift = surface; mainLiftAreaDefault = surface.wingArea; //Debug.Log("FSwing: Slat assigned main lift to: " + surface.liftTransformName); break; } } if (mainLift == null) { debug.debugMessage("FSwing: leading edge missing main FSliftSurface: " + leadingEdgeLiftSurface); } } } #endregion #region help popup helpPopup = new Firespitter.info.HelpPopup("Wing setup help", helpTextInternal); /*helpSection = new PopupSection(); * PopupElement helpText = new PopupElement(helpTextnternal, true); * helpSection.AddElement(helpText, 300f); * if (windowID == 0) * windowID = FSGUIwindowID.getNextID(); * helpPopup = new FSGUIPopup(part, "FSwing", 0, windowID, windowRect, "Wing setup help"); * helpPopup.sections.Add(helpSection); * helpPopup.useInEditor = true; * helpPopup.useInFlight = true;*/ #endregion originalCtrlSurfaceRange = ctrlSurfaceRange; if (affectStockWingModule || !showTweakables) { Fields["pitchResponse"].guiActive = false; Fields["pitchResponse"].guiActiveEditor = false; Fields["rollResponse"].guiActive = false; Fields["rollResponse"].guiActiveEditor = false; Fields["yawResponse"].guiActive = false; Fields["yawResponse"].guiActiveEditor = false; Fields["flapResponse"].guiActive = false; Fields["flapResponse"].guiActiveEditor = false; } ApplyDamage(partHealth); }
private void CountSurfaces() { print("Counting wings for " + vessel.GetName()); liftingSurfaces = new List <ModuleLiftingSurface>(); controlSurfaces = new List <ModuleControlSurface>(); liftingInitLift = new List <float>(); controlInitLift = new List <float>(); inRange = true; groundPlane = new Plane(); // This will be calculated later wingSpan = 42 / 42; foreach (Part part in vessel.Parts) { ModuleControlSurface thingThatLiftsPartsAndMoves = null; ModuleLiftingSurface thingThatLiftsParts = null; // Look through the list of part modules to find anything that inherits ModuleLiftingSurface foreach (PartModule module in part.Modules) { if (typeof(ModuleLiftingSurface).IsAssignableFrom(module.GetType())) { //thingThatLiftsParts = (ModuleLiftingSurface)(module); //initialLift = thingThatLiftsParts.deflectionLiftCoeff; thingThatLiftsParts = (ModuleLiftingSurface)(module); if (module is ModuleControlSurface) { thingThatLiftsPartsAndMoves = (ModuleControlSurface)(module); } } } if (thingThatLiftsParts != null) { if (thingThatLiftsPartsAndMoves != null) { // It's a control surface, add to control surface arrays controlSurfaces.Add(thingThatLiftsPartsAndMoves); controlInitLift.Add(thingThatLiftsPartsAndMoves.ctrlSurfaceArea); } else { // It's just a lifting surface, add to lifting surface arrays liftingSurfaces.Add(thingThatLiftsParts); liftingInitLift.Add(thingThatLiftsParts.deflectionLiftCoeff); } } //thingThatLiftsPartsAndMoves.OnCenterOfLiftQuery(); } print("LiftingSurfaces counted for " + vessel.GetName() + ": " + liftingSurfaces.Count); print("ControlSurfaces counted for " + vessel.GetName() + ": " + controlSurfaces.Count); }
public static Vector3 get_part_torque(CenterOfLiftQuery qry, Part p, Vector3 CoM, ref float lift, ref float drag) { if (p == null || (p.Rigidbody != p.rb) && !PhysicsGlobals.ApplyDragToNonPhysicsParts) { return(Vector3.zero); } Vector3 lift_pos = Vector3.zero; Vector3 drag_pos = Vector3.zero; if (!p.ShieldedFromAirstream) { var providers = p.FindModulesImplementing <ModuleLiftingSurface>(); if ((providers != null) && providers.Count > 0) { p.hasLiftModule = true; } Vector3 res = Vector3.zero; if (p.hasLiftModule && providers[0] is ModuleControlSurface) { p.DragCubes.SetCubeWeight("neutral", 1.5f); p.DragCubes.SetCubeWeight("fullDeflectionPos", 0.0f); p.DragCubes.SetCubeWeight("fullDeflectionNeg", 0.0f); } // drag from drag-cubes if (!p.DragCubes.None) { Vector3 drag_force = Vector3.zero; p.dragVector = qry.refVector; p.dragVectorSqrMag = p.dragVector.sqrMagnitude; p.dragVectorMag = Mathf.Sqrt(p.dragVectorSqrMag); p.dragVectorDir = p.dragVector / p.dragVectorMag; p.dragVectorDirLocal = -p.partTransform.InverseTransformDirection(p.dragVectorDir); p.dynamicPressurekPa = qry.refAirDensity * 0.0005 * p.dragVectorSqrMag; if (p.rb != p.Rigidbody && PhysicsGlobals.ApplyDragToNonPhysicsPartsAtParentCoM) { drag_pos = p.Rigidbody.worldCenterOfMass; lift_pos = drag_pos; } else { lift_pos = p.partTransform.TransformPoint(p.CoLOffset); drag_pos = p.partTransform.TransformPoint(p.CoPOffset); } p.DragCubes.SetDrag(p.dragVectorDirLocal, mach); float pseudoreynolds = (float)(density * Mathf.Abs(speed)); float pseudoredragmult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate(pseudoreynolds); float drag_k = p.DragCubes.AreaDrag * PhysicsGlobals.DragCubeMultiplier * pseudoredragmult; p.dragScalar = (float)(p.dynamicPressurekPa * drag_k * PhysicsGlobals.DragMultiplier); drag_force = p.dragScalar * -p.dragVectorDir; res += Vector3.Cross(drag_force, drag_pos - CoM); Vector3 sum_force = drag_force; drag += Vector3.Dot(sum_force, -p.dragVectorDir); } if (!p.hasLiftModule) { // stock aero lift if (!p.DragCubes.None) { p.bodyLiftScalar = (float)(p.dynamicPressurekPa * p.bodyLiftMultiplier * PhysicsGlobals.BodyLiftMultiplier * CorrectCoL.CoLMarkerFull.lift_curves.liftMachCurve.Evaluate(mach)); Vector3 lift_force = p.partTransform.rotation * (p.bodyLiftScalar * p.DragCubes.LiftForce); lift_force = Vector3.ProjectOnPlane(lift_force, -p.dragVectorDir); res += Vector3.Cross(lift_force, lift_pos - CoM); Vector3 sum_force = lift_force; lift += Vector3.Dot(sum_force, Vector3.Cross(p.dragVectorDir, EditorLogic.RootPart.transform.right).normalized); } return(res); } else { double q = 0.5 * qry.refAirDensity * qry.refVector.sqrMagnitude; for (int i = 0; i < providers.Count; i++) { Vector3 dragvect; Vector3 liftvect; Vector3 lift_force = Vector3.zero; Vector3 drag_force = Vector3.zero; float abs; ModuleLiftingSurface lsurf = providers[i]; ModuleControlSurface csurf = lsurf as ModuleControlSurface; lsurf.SetupCoefficients(qry.refVector, out dragvect, out liftvect, out lsurf.liftDot, out abs); lift_pos = p.partTransform.TransformPoint(p.CoLOffset); drag_pos = p.partTransform.TransformPoint(p.CoPOffset); lift_force = lsurf.GetLiftVector(liftvect, lsurf.liftDot, abs, q, mach); if (lsurf.useInternalDragModel) { drag_force = lsurf.GetDragVector(dragvect, abs, q); } if (csurf != null) { float deflection = (float)deflection_field.GetValue(csurf); Quaternion incidence = Quaternion.AngleAxis(csurf.ctrlSurfaceRange * deflection, p.partTransform.rotation * Vector3.right); liftvect = incidence * liftvect; lsurf.liftDot = Vector3.Dot(dragvect, liftvect); abs = Mathf.Abs(lsurf.liftDot); lift_force = lift_force * (1.0f - csurf.ctrlSurfaceArea); lift_force += lsurf.GetLiftVector(liftvect, lsurf.liftDot, abs, q, mach) * csurf.ctrlSurfaceArea; if (csurf.useInternalDragModel) { drag_force = drag_force * (1.0f - csurf.ctrlSurfaceArea); drag_force += csurf.GetDragVector(dragvect, abs, q) * csurf.ctrlSurfaceArea; } } res += Vector3.Cross(lift_force, lift_pos - CoM); res += Vector3.Cross(drag_force, drag_pos - CoM); Vector3 result_force = lift_force + drag_force; lift += Vector3.Dot(result_force, Vector3.Cross(qry.refVector, EditorLogic.RootPart.transform.right).normalized); drag += Vector3.Dot(result_force, -qry.refVector.normalized); } return(res); } } return(Vector3.zero); }
public void Update(Vessel vessel) { if (vessel.rigidbody == null) { return; //if we try to update before rigidbodies exist we spam the console with NullPointerExceptions. } //if (vessel.packed) return; // To investigate some strange error if ((vessel.mainBody == null || (object)(vessel.mainBody) == null) && counter == 0) { if ((object)(vessel.mainBody) == null) { MechJebCore.print("vessel.mainBody is proper null"); } else { MechJebCore.print("vessel.mainBody is Unity null"); } counter = counter++ % 100; } time = Planetarium.GetUniversalTime(); deltaT = TimeWarp.fixedDeltaTime; CoM = vessel.findWorldCenterOfMass(); up = (CoM - vessel.mainBody.position).normalized; Rigidbody rigidBody = vessel.rootPart.rigidbody; if (rigidBody != null) { rootPartPos = rigidBody.position; } north = Vector3d.Exclude(up, (vessel.mainBody.position + vessel.mainBody.transform.up * (float)vessel.mainBody.Radius) - CoM).normalized; east = vessel.mainBody.getRFrmVel(CoM).normalized; forward = vessel.GetTransform().up; rotationSurface = Quaternion.LookRotation(north, up); rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.GetTransform().rotation) * rotationSurface); // velocityVesselOrbit = vessel.orbit.GetVel(); // velocityVesselOrbitUnit = velocityVesselOrbit.normalized; // velocityVesselSurface = velocityVesselOrbit - vessel.mainBody.getRFrmVel(CoM); // velocityVesselSurfaceUnit = velocityVesselSurface.normalized; velocityMainBodySurface = rotationSurface * vessel.srf_velocity; horizontalOrbit = Vector3d.Exclude(up, vessel.obt_velocity).normalized; horizontalSurface = Vector3d.Exclude(up, vessel.srf_velocity).normalized; angularVelocity = Quaternion.Inverse(vessel.GetTransform().rotation) * vessel.rigidbody.angularVelocity; radialPlusSurface = Vector3d.Exclude(vessel.srf_velocity, up).normalized; radialPlus = Vector3d.Exclude(vessel.obt_velocity, up).normalized; normalPlusSurface = -Vector3d.Cross(radialPlusSurface, vessel.srf_velocity.normalized); normalPlus = -Vector3d.Cross(radialPlus, vessel.obt_velocity.normalized); gravityForce = FlightGlobals.getGeeForceAtPosition(CoM); localg = gravityForce.magnitude; speedOrbital.value = vessel.obt_velocity.magnitude; speedSurface.value = vessel.srf_velocity.magnitude; speedVertical.value = Vector3d.Dot(vessel.srf_velocity, up); speedSurfaceHorizontal.value = Vector3d.Exclude(up, vessel.srf_velocity).magnitude; //(velocityVesselSurface - (speedVertical * up)).magnitude; speedOrbitHorizontal = (vessel.obt_velocity - (speedVertical * up)).magnitude; vesselHeading.value = rotationVesselSurface.eulerAngles.y; vesselPitch.value = (rotationVesselSurface.eulerAngles.x > 180) ? (360.0 - rotationVesselSurface.eulerAngles.x) : -rotationVesselSurface.eulerAngles.x; vesselRoll.value = (rotationVesselSurface.eulerAngles.z > 180) ? (rotationVesselSurface.eulerAngles.z - 360.0) : rotationVesselSurface.eulerAngles.z; altitudeASL.value = vessel.mainBody.GetAltitude(CoM); //RaycastHit sfc; //if (Physics.Raycast(CoM, -up, out sfc, (float)altitudeASL + 10000.0F, 1 << 15)) //{ // altitudeTrue.value = sfc.distance; //} //else if (vessel.mainBody.pqsController != null) //{ // // from here: http://kerbalspaceprogram.com/forum/index.php?topic=10324.msg161923#msg161923 // altitudeTrue.value = vessel.mainBody.GetAltitude(CoM) - (vessel.mainBody.pqsController.GetSurfaceHeight(QuaternionD.AngleAxis(vessel.mainBody.GetLongitude(CoM), Vector3d.down) * QuaternionD.AngleAxis(vessel.mainBody.GetLatitude(CoM), Vector3d.forward) * Vector3d.right) - vessel.mainBody.pqsController.radius); //} //else //{ // altitudeTrue.value = vessel.mainBody.GetAltitude(CoM); //} //double surfaceAltitudeASL = altitudeASL - altitudeTrue; double surfaceAltitudeASL = vessel.mainBody.pqsController != null ? vessel.pqsAltitude : 0d; altitudeTrue.value = altitudeASL - surfaceAltitudeASL; altitudeBottom = altitudeTrue; foreach (Part p in vessel.parts) { if (p.collider != null) { Vector3d bottomPoint = p.collider.ClosestPointOnBounds(vessel.mainBody.position); double partBottomAlt = vessel.mainBody.GetAltitude(bottomPoint) - surfaceAltitudeASL; altitudeBottom = Math.Max(0, Math.Min(altitudeBottom, partBottomAlt)); } } double atmosphericPressure = FlightGlobals.getStaticPressure(altitudeASL, vessel.mainBody); if (atmosphericPressure < vessel.mainBody.atmosphereMultiplier * 1e-6) { atmosphericPressure = 0; } atmosphericDensity = FlightGlobals.getAtmDensity(atmosphericPressure); atmosphericDensityGrams = atmosphericDensity * 1000; orbitApA.value = vessel.orbit.ApA; orbitPeA.value = vessel.orbit.PeA; orbitPeriod.value = vessel.orbit.period; orbitTimeToAp.value = vessel.orbit.timeToAp; if (vessel.orbit.eccentricity < 1) { orbitTimeToPe.value = vessel.orbit.timeToPe; } else { orbitTimeToPe.value = -vessel.orbit.meanAnomaly / (2 * Math.PI / vessel.orbit.period); } orbitLAN.value = vessel.orbit.LAN; orbitArgumentOfPeriapsis.value = vessel.orbit.argumentOfPeriapsis; orbitInclination.value = vessel.orbit.inclination; orbitEccentricity.value = vessel.orbit.eccentricity; orbitSemiMajorAxis.value = vessel.orbit.semiMajorAxis; latitude.value = vessel.mainBody.GetLatitude(CoM); longitude.value = MuUtils.ClampDegrees180(vessel.mainBody.GetLongitude(CoM)); if (vessel.mainBody != Planetarium.fetch.Sun) { Vector3d delta = vessel.mainBody.getPositionAtUT(Planetarium.GetUniversalTime() + 1) - vessel.mainBody.getPositionAtUT(Planetarium.GetUniversalTime() - 1); Vector3d plUp = Vector3d.Cross(vessel.mainBody.getPositionAtUT(Planetarium.GetUniversalTime()) - vessel.mainBody.referenceBody.getPositionAtUT(Planetarium.GetUniversalTime()), vessel.mainBody.getPositionAtUT(Planetarium.GetUniversalTime() + vessel.mainBody.orbit.period / 4) - vessel.mainBody.referenceBody.getPositionAtUT(Planetarium.GetUniversalTime() + vessel.mainBody.orbit.period / 4)).normalized; angleToPrograde = MuUtils.ClampDegrees360((((vessel.orbit.inclination > 90) || (vessel.orbit.inclination < -90)) ? 1 : -1) * ((Vector3)up).AngleInPlane(plUp, delta)); } else { angleToPrograde = 0; } mainBody = vessel.mainBody; radius = (CoM - vessel.mainBody.position).magnitude; mass = massDrag = torqueThrustPYAvailable = 0; thrustVectorLastFrame = new Vector3d(); thrustVectorMaxThrottle = new Vector3d(); thrustVectorMinThrottle = new Vector3d(); torqueAvailable = new Vector3d(); rcsThrustAvailable = new Vector6(); rcsTorqueAvailable = new Vector6(); ctrlTorqueAvailable = new Vector6(); EngineInfo einfo = new EngineInfo(CoM); IntakeInfo iinfo = new IntakeInfo(); parachutes = new List <ModuleParachute>(); var rcsbal = vessel.GetMasterMechJeb().rcsbal; if (vessel.ActionGroups[KSPActionGroup.RCS] && rcsbal.enabled) { Vector3d rot = Vector3d.zero; foreach (Vector6.Direction dir6 in Enum.GetValues(typeof(Vector6.Direction))) { Vector3d dir = Vector6.directions[dir6]; double[] throttles; List <RCSSolver.Thruster> thrusters; rcsbal.GetThrottles(dir, out throttles, out thrusters); if (throttles != null) { for (int i = 0; i < throttles.Length; i++) { if (throttles[i] > 0) { Vector3d force = thrusters[i].GetThrust(dir, rot); rcsThrustAvailable.Add(vessel.GetTransform().InverseTransformDirection(dir * Vector3d.Dot(force * throttles[i], dir))); } } } } } hasMFE = false; foreach (Part p in vessel.parts) { if (p.IsPhysicallySignificant()) { double partMass = p.TotalMass(); mass += partMass; massDrag += partMass * p.maximum_drag; } if (vessel.ActionGroups[KSPActionGroup.RCS] && !rcsbal.enabled) { foreach (ModuleRCS pm in p.Modules.OfType <ModuleRCS>()) { double maxT = pm.thrusterPower; Vector3d partPosition = p.Rigidbody.worldCenterOfMass - CoM; if ((pm.isEnabled) && (!pm.isJustForShow)) { foreach (Transform t in pm.thrusterTransforms) { Vector3d thrusterThrust = vessel.GetTransform().InverseTransformDirection(-t.up.normalized) * pm.thrusterPower; rcsThrustAvailable.Add(thrusterThrust); Vector3d thrusterTorque = Vector3.Cross(vessel.GetTransform().InverseTransformDirection(partPosition), thrusterThrust); rcsTorqueAvailable.Add(thrusterTorque); } } } } if (p is ControlSurface) { Vector3d partPosition = p.Rigidbody.worldCenterOfMass - CoM; ControlSurface cs = (p as ControlSurface); Vector3d airSpeed = vessel.srf_velocity + Vector3.Cross(cs.Rigidbody.angularVelocity, cs.transform.position - cs.Rigidbody.position); // Air Speed is velocityVesselSurface // AddForceAtPosition seems to need the airspeed vector rotated with the flap rotation x its surface Quaternion airSpeedRot = Quaternion.AngleAxis(cs.ctrlSurfaceRange * cs.ctrlSurfaceArea, cs.transform.rotation * cs.pivotAxis); Vector3 ctrlTroquePos = vessel.GetTransform().InverseTransformDirection(Vector3.Cross(partPosition, cs.getLiftVector(airSpeedRot * airSpeed))); Vector3 ctrlTroqueNeg = vessel.GetTransform().InverseTransformDirection(Vector3.Cross(partPosition, cs.getLiftVector(Quaternion.Inverse(airSpeedRot) * airSpeed))); ctrlTorqueAvailable.Add(ctrlTroquePos); ctrlTorqueAvailable.Add(ctrlTroqueNeg); } if (p is CommandPod) { torqueAvailable += Vector3d.one * Math.Abs(((CommandPod)p).rotPower); } foreach (VesselStatePartExtension vspe in vesselStatePartExtensions) { vspe(p); } foreach (PartModule pm in p.Modules) { if (!pm.isEnabled) { continue; } if (pm is ModuleReactionWheel) { ModuleReactionWheel rw = (ModuleReactionWheel)pm; // I had to remove the test for active in .23 since the new ressource system reply to the RW that // there is no energy available when the RW do tiny adjustement. // I replaceed it with a test that check if there is electricity anywhere on the ship. // Let's hope we don't get reaction wheel that use something else //if (rw.wheelState == ModuleReactionWheel.WheelState.Active && !rw.stateString.Contains("Not enough")) if (rw.wheelState == ModuleReactionWheel.WheelState.Active && vessel.HasElectricCharge()) { torqueAvailable += new Vector3d(rw.PitchTorque, rw.RollTorque, rw.YawTorque); } } else if (pm is ModuleEngines) { einfo.AddNewEngine(pm as ModuleEngines); } else if (pm is ModuleEnginesFX) { einfo.AddNewEngine(pm as ModuleEnginesFX); } else if (pm is ModuleResourceIntake) { iinfo.addIntake(pm as ModuleResourceIntake); } else if (pm is ModuleParachute) { parachutes.Add(pm as ModuleParachute); } else if (pm is ModuleControlSurface) { // TODO : Tweakable for ignorePitch / ignoreYaw / ignoreRoll ModuleControlSurface cs = (pm as ModuleControlSurface); Vector3d partPosition = p.Rigidbody.worldCenterOfMass - CoM; Vector3d airSpeed = vessel.srf_velocity + Vector3.Cross(cs.part.Rigidbody.angularVelocity, cs.transform.position - cs.part.Rigidbody.position); Quaternion airSpeedRot = Quaternion.AngleAxis(cs.ctrlSurfaceRange * cs.ctrlSurfaceArea, cs.transform.rotation * Vector3.right); Vector3 ctrlTroquePos = vessel.GetTransform().InverseTransformDirection(Vector3.Cross(partPosition, cs.getLiftVector(airSpeedRot * airSpeed))); Vector3 ctrlTroqueNeg = vessel.GetTransform().InverseTransformDirection(Vector3.Cross(partPosition, cs.getLiftVector(Quaternion.Inverse(airSpeedRot) * airSpeed))); ctrlTorqueAvailable.Add(ctrlTroquePos); ctrlTorqueAvailable.Add(ctrlTroqueNeg); } if (pm.ClassName == "ModuleEngineConfigs" || pm.ClassName == "ModuleHybridEngine" || pm.ClassName == "ModuleHybridEngines") { hasMFE = true; } foreach (VesselStatePartModuleExtension vspme in vesselStatePartModuleExtensions) { vspme(pm); } } } // Consider all the parachutes { bool tempParachuteDeployed = false; foreach (ModuleParachute p in parachutes) { if (p.deploymentState == ModuleParachute.deploymentStates.DEPLOYED || p.deploymentState == ModuleParachute.deploymentStates.SEMIDEPLOYED) { tempParachuteDeployed = true; break; } } this.parachuteDeployed = tempParachuteDeployed; } torqueAvailable += Vector3d.Max(rcsTorqueAvailable.positive, rcsTorqueAvailable.negative); // Should we use Max or Min ? torqueAvailable += Vector3d.Max(ctrlTorqueAvailable.positive, ctrlTorqueAvailable.negative); // Should we use Max or Min ? thrustVectorMaxThrottle += einfo.thrustMax; thrustVectorMinThrottle += einfo.thrustMin; thrustVectorLastFrame += einfo.thrustCurrent; torqueThrustPYAvailable += einfo.torqueThrustPYAvailable; if (thrustVectorMaxThrottle.magnitude == 0 && vessel.ActionGroups[KSPActionGroup.RCS]) { rcsThrust = true; thrustVectorMaxThrottle += (Vector3d)(vessel.transform.up) * rcsThrustAvailable.down; } else { rcsThrust = false; } // Convert the resource information from the einfo and iinfo format // to the more useful ResourceInfo format. resources = new Dictionary <int, ResourceInfo>(); foreach (var info in einfo.resourceRequired) { int id = info.Key; var req = info.Value; resources[id] = new ResourceInfo( PartResourceLibrary.Instance.GetDefinition(id), req.requiredLastFrame, req.requiredAtMaxThrottle, iinfo.getIntakes(id)); } int intakeAirId = PartResourceLibrary.Instance.GetDefinition("IntakeAir").id; intakeAir = 0; intakeAirNeeded = 0; intakeAirAtMax = 0; intakeAirAllIntakes = 0; if (resources.ContainsKey(intakeAirId)) { intakeAir = resources[intakeAirId].intakeProvided; intakeAirAllIntakes = resources[intakeAirId].intakeAvailable; intakeAirNeeded = resources[intakeAirId].required; intakeAirAtMax = resources[intakeAirId].requiredAtMaxThrottle; } angularMomentum = new Vector3d(angularVelocity.x * MoI.x, angularVelocity.y * MoI.y, angularVelocity.z * MoI.z); inertiaTensor = new Matrix3x3(); foreach (Part p in vessel.parts) { if (p.Rigidbody == null) { continue; } //Compute the contributions to the vessel inertia tensor due to the part inertia tensor Vector3d principalMoments = p.Rigidbody.inertiaTensor; Quaternion princAxesRot = Quaternion.Inverse(vessel.GetTransform().rotation) * p.transform.rotation * p.Rigidbody.inertiaTensorRotation; Quaternion invPrincAxesRot = Quaternion.Inverse(princAxesRot); for (int i = 0; i < 3; i++) { Vector3d iHat = Vector3d.zero; iHat[i] = 1; for (int j = 0; j < 3; j++) { Vector3d jHat = Vector3d.zero; jHat[j] = 1; inertiaTensor[i, j] += Vector3d.Dot(iHat, princAxesRot * Vector3d.Scale(principalMoments, invPrincAxesRot * jHat)); } } //Compute the contributions to the vessel inertia tensor due to the part mass and position double partMass = p.TotalMass(); Vector3 partPosition = vessel.GetTransform().InverseTransformDirection(p.Rigidbody.worldCenterOfMass - CoM); for (int i = 0; i < 3; i++) { inertiaTensor[i, i] += partMass * partPosition.sqrMagnitude; for (int j = 0; j < 3; j++) { inertiaTensor[i, j] += -partMass * partPosition[i] * partPosition[j]; } } } MoI = new Vector3d(inertiaTensor[0, 0], inertiaTensor[1, 1], inertiaTensor[2, 2]); angularMomentum = inertiaTensor * angularVelocity; }
protected override void DI_Start(StartState state) { if (HighLogic.LoadedSceneIsFlight) { this.controlSurface = this.part.Modules.OfType<ModuleControlSurface>().Single(); } }