protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); if ((part.vessel.mainBody != Planetarium.fetch.Sun) && (part.vessel.mainBody.referenceBody != null) && (part.vessel.mainBody.referenceBody.orbitingBodies.Count > 0)) { foreach (CelestialBody sibling in part.vessel.mainBody.referenceBody.orbitingBodies) { if (sibling != part.vessel.mainBody) { GUILayout.BeginHorizontal(); GUILayout.Label(sibling.name, GUILayout.ExpandWidth(true)); GUILayout.Label(ARUtils.clampDegrees((sibling.orbit.trueAnomaly + sibling.orbit.argumentOfPeriapsis + sibling.orbit.LAN) - (part.vessel.mainBody.orbit.trueAnomaly + part.vessel.mainBody.orbit.argumentOfPeriapsis + part.vessel.mainBody.orbit.LAN)).ToString("F6") + "°"); GUILayout.EndHorizontal(); } } } GUILayout.Label("Click for a calculator\nhttp://ksp.olex.biz/"); if ((Event.current.type == EventType.repaint) && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition) && Input.GetMouseButtonDown(0)) { Application.OpenURL("http://ksp.olex.biz/"); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
void aimVelocityVector(double desiredFpa, double desiredHeading) { //horizontal control double velocityHeading = 180 / Math.PI * Math.Atan2(Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.east), Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.north)); double headingTurn = Mathf.Clamp((float)ARUtils.clampDegrees(desiredHeading - velocityHeading), -maxYaw, maxYaw); double noseHeading = velocityHeading + headingTurn; double noseRoll = (maxRoll / maxYaw) * headingTurn; //vertical control double nosePitch = desiredFpa + stableAoA + pitchCorrection; core.attitudeTo(noseHeading, nosePitch, noseRoll, this); double flightPathAngle = 180 / Math.PI * Math.Atan2(vesselState.speedVertical, vesselState.speedHorizontal); double AoA = vesselState.vesselPitch - flightPathAngle; stableAoA = (AoAtimeConstant * stableAoA + vesselState.deltaT * AoA) / (AoAtimeConstant + vesselState.deltaT); //a sort of integral error pitchCorrection = (pitchCorrectionTimeConstant * pitchCorrection + vesselState.deltaT * (nosePitch - vesselState.vesselPitch)) / (pitchCorrectionTimeConstant + vesselState.deltaT); pitchCorrection = Mathf.Clamp((float)pitchCorrection, -maxPitchCorrection, maxPitchCorrection); }
public void Update(Vessel vessel) { time = Planetarium.GetUniversalTime(); deltaT = TimeWarp.fixedDeltaTime; //Only update if (time - _updateTime < 0.25) { return; } _updateTime = time; CoM = vessel.findWorldCenterOfMass(); up = (CoM - vessel.mainBody.position).normalized; 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 * velocityVesselSurface; angularVelocity = Quaternion.Inverse(vessel.GetTransform().rotation) * vessel.rigidbody.angularVelocity; upNormalToVelSurface = Vector3d.Exclude(velocityVesselSurfaceUnit, up).normalized; upNormalToVelOrbit = Vector3d.Exclude(velocityVesselOrbit, up).normalized; leftSurface = -Vector3d.Cross(upNormalToVelSurface, velocityVesselSurfaceUnit); leftOrbit = -Vector3d.Cross(upNormalToVelOrbit, velocityVesselOrbitUnit);; gravityForce = FlightGlobals.getGeeForceAtPosition(CoM); localg = gravityForce.magnitude; speedOrbital.value = velocityVesselOrbit.magnitude; speedSurface.value = velocityVesselSurface.magnitude; speedVertical.value = Vector3d.Dot(velocityVesselSurface, up); speedHorizontal.value = (velocityVesselSurface - (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; 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)); } } atmosphericDensity = FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(altitudeASL, vessel.mainBody)); 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); //orbit.timeToPe is bugged for ecc > 1 and timewarp > 2x } 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 = ARUtils.clampDegrees(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 = ARUtils.clampDegrees360((((vessel.orbit.inclination > 90) || (vessel.orbit.inclination < -90)) ? 1 : -1) * ((Vector3)up).AngleInPlane(plUp, delta)); } else { angleToPrograde = 0; } radius = (CoM - vessel.mainBody.position).magnitude; cost = mass = thrustAvailable = thrustMinimum = massDrag = torqueRAvailable = torquePYAvailable = torqueThrustPYAvailable = 0; MoI = vessel.findLocalMOI(CoM); foreach (Part p in vessel.parts) { cost += p.partInfo.cost; if (p.physicalSignificance != Part.PhysicalSignificance.NONE) { double partMass = p.totalMass(); mass += partMass; massDrag += partMass * p.maximum_drag; } MoI += p.Rigidbody.inertiaTensor; if ((p.State == PartStates.ACTIVE) || ((Staging.CurrentStage > Staging.lastStage) && (p.inverseStage == Staging.lastStage))) { if (p is LiquidEngine && ARUtils.engineHasFuel(p)) { double usableFraction = Vector3d.Dot((p.transform.rotation * ((LiquidEngine)p).thrustVector).normalized, forward); thrustAvailable += ((LiquidEngine)p).maxThrust * usableFraction; thrustMinimum += ((LiquidEngine)p).minThrust * usableFraction; if (((LiquidEngine)p).thrustVectoringCapable) { torqueThrustPYAvailable += Math.Sin(Math.Abs(((LiquidEngine)p).gimbalRange) * Math.PI / 180) * ((LiquidEngine)p).maxThrust * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } } else if (p is LiquidFuelEngine && ARUtils.engineHasFuel(p)) { double usableFraction = Vector3d.Dot((p.transform.rotation * ((LiquidFuelEngine)p).thrustVector).normalized, forward); thrustAvailable += ((LiquidFuelEngine)p).maxThrust * usableFraction; thrustMinimum += ((LiquidFuelEngine)p).minThrust * usableFraction; if (((LiquidFuelEngine)p).thrustVectoringCapable) { torqueThrustPYAvailable += Math.Sin(Math.Abs(((LiquidFuelEngine)p).gimbalRange) * Math.PI / 180) * ((LiquidFuelEngine)p).maxThrust * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } } else if (p is SolidRocket && !p.ActivatesEvenIfDisconnected) { double usableFraction = Vector3d.Dot((p.transform.rotation * ((SolidRocket)p).thrustVector).normalized, forward); thrustAvailable += ((SolidRocket)p).thrust * usableFraction; thrustMinimum += ((SolidRocket)p).thrust * usableFraction; } else if (p is AtmosphericEngine && ARUtils.engineHasFuel(p)) { double usableFraction = Vector3d.Dot((p.transform.rotation * ((AtmosphericEngine)p).thrustVector).normalized, forward); thrustAvailable += ((AtmosphericEngine)p).maximumEnginePower * ((AtmosphericEngine)p).totalEfficiency * usableFraction; if (((AtmosphericEngine)p).thrustVectoringCapable) { torqueThrustPYAvailable += Math.Sin(Math.Abs(((AtmosphericEngine)p).gimbalRange) * Math.PI / 180) * ((AtmosphericEngine)p).maximumEnginePower * ((AtmosphericEngine)p).totalEfficiency * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } } else if (p.Modules.Contains("ModuleEngines")) { foreach (PartModule pm in p.Modules) { if ((pm is ModuleEngines) && (pm.isEnabled) && ARUtils.engineHasFuel(p) && ((ModuleEngines)p.Modules["ModuleEngines"]).getIgnitionState) { ModuleEngines e = (ModuleEngines)pm; double usableFraction = 1; // Vector3d.Dot((p.transform.rotation * e.thrustTransform.forward).normalized, forward); // TODO: Fix usableFraction thrustAvailable += e.maxThrust * usableFraction; if (e.throttleLocked) { thrustMinimum += e.maxThrust * usableFraction; } else { thrustMinimum += e.minThrust * usableFraction; } if (p.Modules.OfType <ModuleGimbal>().Count() > 0) { torqueThrustPYAvailable += Math.Sin(Math.Abs(p.Modules.OfType <ModuleGimbal>().First().gimbalRange) * Math.PI / 180) * e.maxThrust * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; // TODO: close enough? } } } } else { foreach (PartModule pm in p.Modules) { CenterOfThrustQuery ctq = new CenterOfThrustQuery(); pm.BroadcastMessage("OnCenterOfThrustQuery", ctq, SendMessageOptions.DontRequireReceiver); if (ctq.thrust > 0) { double usableFraction = 1; // Vector3d.Dot((p.transform.rotation * e.thrustTransform.forward).normalized, forward); // TODO: Fix usableFraction thrustAvailable += ctq.thrust * usableFraction; } } } } if (vessel.ActionGroups[KSPActionGroup.RCS]) { if (p is RCSModule) { double maxT = 0; for (int i = 0; i < 6; i++) { if (((RCSModule)p).thrustVectors[i] != Vector3.zero) { maxT = Math.Max(maxT, ((RCSModule)p).thrusterPowers[i]); } } torqueRAvailable += maxT; torquePYAvailable += maxT * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } if (p.Modules.Contains("ModuleRCS")) { foreach (ModuleRCS pm in p.Modules.OfType <ModuleRCS>()) { double maxT = pm.thrustForces.Max(); if ((pm.isEnabled) && (!pm.isJustForShow)) { torqueRAvailable += maxT; torquePYAvailable += maxT * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } } } } if (p is CommandPod) { torqueRAvailable += Math.Abs(((CommandPod)p).rotPower); torquePYAvailable += Math.Abs(((CommandPod)p).rotPower); } } angularMomentum = new Vector3d(angularVelocity.x * MoI.x, angularVelocity.y * MoI.y, angularVelocity.z * MoI.z); maxThrustAccel = thrustAvailable / mass; minThrustAccel = thrustMinimum / mass; double throttle = vessel.ctrlState.mainThrottle; thrust = ((1.0 - throttle) * thrustMinimum + throttle * thrustAvailable); //Update the acceleration (1 is one 1Hz update, 0.1 is 10Hz) if (time - _lastUpdate > 0.5) { double mag = vessel.srf_velocity.magnitude; //Don't update on first pass if (_lastUpdate > 0) { double new_accel = (mag - _lastVel) / (time - _lastUpdate); surface_accel_delta = new_accel - surface_accel; surface_accel = new_accel; if (surface_accel < 0 && _lastAltitude > altitudeTrue.value) { stop_distance = -(mag * mag) / (2.0 * surface_accel); } else { stop_distance = 0; } //How long will we burn to stop stop_time = 2.0 * stop_distance / mag; } //Calc how much fuel we are using fuelAmount = 0; fuelConsumption = 0; fuelTotalAmount = 0; foreach (Part p in vessel.GetActiveParts()) { foreach (ModuleEngines engine in p.Modules.OfType <ModuleEngines>()) { if (!engine.isEnabled || !engine.EngineIgnited || engine.engineShutdown) { continue; } double thr = engine.finalThrust; double Isp = engine.realIsp; double massFlowRate = thr / (Isp * 9.81); double sumRatioTimesDensity = 0; foreach (ModuleEngines.Propellant propellant in engine.propellants) { sumRatioTimesDensity += propellant.ratio * PartResourceLibrary.Instance.GetDefinition(propellant.id).density; } foreach (ModuleEngines.Propellant propellant in engine.propellants) { if (propellant.name != "ElectricCharge") { fuelConsumption += propellant.ratio * massFlowRate / sumRatioTimesDensity; fuelAmount += propellant.currentAmount; } } } //Total amount fuelTotalAmount = 0; foreach (PartResource r in p.Resources) { if (r.resourceName != "ElectricCharge") { fuelTotalAmount += r.maxAmount; } } } //Update my info _lastAltitude = altitudeTrue.value; _lastUpdate = time; _lastVel = mag; } }
public void Update(Vessel vessel) { time = Planetarium.GetUniversalTime(); deltaT = TimeWarp.fixedDeltaTime; CoM = vessel.findWorldCenterOfMass(); up = (CoM - vessel.mainBody.position).normalized; 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.transform.up; rotationSurface = Quaternion.LookRotation(north, up); rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.transform.rotation) * rotationSurface); velocityVesselOrbit = vessel.orbit.GetVel(); velocityVesselOrbitUnit = velocityVesselOrbit.normalized; velocityVesselSurface = velocityVesselOrbit - vessel.mainBody.getRFrmVel(CoM); velocityVesselSurfaceUnit = velocityVesselSurface.normalized; velocityMainBodySurface = rotationSurface * velocityVesselSurface; angularVelocity = Quaternion.Inverse(vessel.transform.rotation) * vessel.rigidbody.angularVelocity; upNormalToVelSurface = Vector3d.Exclude(velocityVesselSurfaceUnit, up).normalized; upNormalToVelOrbit = Vector3d.Exclude(velocityVesselOrbit, up).normalized; leftSurface = -Vector3d.Cross(upNormalToVelSurface, velocityVesselSurfaceUnit); leftOrbit = -Vector3d.Cross(upNormalToVelOrbit, velocityVesselOrbitUnit);; gravityForce = FlightGlobals.getGeeForceAtPosition(CoM); localg = gravityForce.magnitude; speedOrbital.value = velocityVesselOrbit.magnitude; speedSurface.value = velocityVesselSurface.magnitude; speedVertical.value = Vector3d.Dot(velocityVesselSurface, up); speedHorizontal.value = (velocityVesselSurface - (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; 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)); } } atmosphericDensity = FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(altitudeASL, vessel.mainBody)); 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); //orbit.timeToPe is bugged for ecc > 1 and timewarp > 2x } 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 = ARUtils.clampDegrees(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 = ARUtils.clampDegrees360((((vessel.orbit.inclination > 90) || (vessel.orbit.inclination < -90)) ? 1 : -1) * ((Vector3)up).AngleInPlane(plUp, delta)); } else { angleToPrograde = 0; } radius = (CoM - vessel.mainBody.position).magnitude; mass = thrustAvailable = thrustMinimum = massDrag = torqueRAvailable = torquePYAvailable = torqueThrustPYAvailable = 0; MoI = vessel.findLocalMOI(CoM); foreach (Part p in vessel.parts) { if (p.physicalSignificance != Part.PhysicalSignificance.NONE) { mass += p.mass; massDrag += p.mass * p.maximum_drag; } MoI += p.Rigidbody.inertiaTensor; if (((p.State == PartStates.ACTIVE) || ((Staging.CurrentStage > Staging.lastStage) && (p.inverseStage == Staging.lastStage))) && ((p is LiquidEngine) || (p is LiquidFuelEngine) || (p is SolidRocket) || (p is AtmosphericEngine))) { if (p is LiquidEngine && ARUtils.engineHasFuel(p)) { double usableFraction = Vector3d.Dot((p.transform.rotation * ((LiquidEngine)p).thrustVector).normalized, forward); thrustAvailable += ((LiquidEngine)p).maxThrust * usableFraction; thrustMinimum += ((LiquidEngine)p).minThrust * usableFraction; if (((LiquidEngine)p).thrustVectoringCapable) { torqueThrustPYAvailable += Math.Sin(Math.Abs(((LiquidEngine)p).gimbalRange) * Math.PI / 180) * ((LiquidEngine)p).maxThrust * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } } else if (p is LiquidFuelEngine && ARUtils.engineHasFuel(p)) { double usableFraction = Vector3d.Dot((p.transform.rotation * ((LiquidFuelEngine)p).thrustVector).normalized, forward); thrustAvailable += ((LiquidFuelEngine)p).maxThrust * usableFraction; thrustMinimum += ((LiquidFuelEngine)p).minThrust * usableFraction; if (((LiquidFuelEngine)p).thrustVectoringCapable) { torqueThrustPYAvailable += Math.Sin(Math.Abs(((LiquidFuelEngine)p).gimbalRange) * Math.PI / 180) * ((LiquidFuelEngine)p).maxThrust * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } } else if (p is SolidRocket && !p.ActivatesEvenIfDisconnected) { double usableFraction = Vector3d.Dot((p.transform.rotation * ((SolidRocket)p).thrustVector).normalized, forward); thrustAvailable += ((SolidRocket)p).thrust * usableFraction; thrustMinimum += ((SolidRocket)p).thrust * usableFraction; } else if (p is AtmosphericEngine && ARUtils.engineHasFuel(p)) { double usableFraction = Vector3d.Dot((p.transform.rotation * ((AtmosphericEngine)p).thrustVector).normalized, forward); thrustAvailable += ((AtmosphericEngine)p).maximumEnginePower * ((AtmosphericEngine)p).totalEfficiency * usableFraction; if (((AtmosphericEngine)p).thrustVectoringCapable) { torqueThrustPYAvailable += Math.Sin(Math.Abs(((AtmosphericEngine)p).gimbalRange) * Math.PI / 180) * ((AtmosphericEngine)p).maximumEnginePower * ((AtmosphericEngine)p).totalEfficiency * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } } } if ((!FlightInputHandler.RCSLock) && (p is RCSModule)) { double maxT = 0; for (int i = 0; i < 6; i++) { if (((RCSModule)p).thrustVectors[i] != Vector3.zero) { maxT = Math.Max(maxT, ((RCSModule)p).thrusterPowers[i]); } } // torqueRAvailable += maxT; torquePYAvailable += maxT * (p.Rigidbody.worldCenterOfMass - CoM).magnitude; } if (p is CommandPod) { torqueRAvailable += Math.Abs(((CommandPod)p).rotPower); torquePYAvailable += Math.Abs(((CommandPod)p).rotPower); } } angularMomentum = new Vector3d(angularVelocity.x * MoI.x, angularVelocity.y * MoI.y, angularVelocity.z * MoI.z); maxThrustAccel = thrustAvailable / mass; minThrustAccel = thrustMinimum / mass; }