//******************************************************* public static Vector3 SimAeroForce(Vessel _vessel, Vector3 v_wrld_vel, double altitude, double latitude = 0) { CelestialBody body = _vessel.mainBody; double pressure = body.GetPressure(altitude); // Lift and drag for force accumulation. Vector3d total_lift = Vector3d.zero; Vector3d total_drag = Vector3d.zero; // dynamic pressure for standard drag equation double rho = GetDensity(altitude, body); double dyn_pressure = 0.0005 * rho * v_wrld_vel.sqrMagnitude; if (rho <= 0) { return(Vector3.zero); } double soundSpeed = body.GetSpeedOfSound(pressure, rho); double mach = v_wrld_vel.magnitude / soundSpeed; if (mach > 25.0) { mach = 25.0; } // Loop through all parts, accumulating drag and lift. for (int i = 0; i < _vessel.Parts.Count; ++i) { // need checks on shielded components Part p = _vessel.Parts[i]; if (p.ShieldedFromAirstream || p.Rigidbody == null) { continue; } // Get Drag Vector3 sim_dragVectorDir = v_wrld_vel.normalized; Vector3 sim_dragVectorDirLocal = -(p.transform.InverseTransformDirection(sim_dragVectorDir)); Vector3 liftForce = new Vector3(0, 0, 0); Vector3d dragForce; switch (p.dragModel) { case Part.DragModel.DEFAULT: case Part.DragModel.CUBE: DragCubeList cubes = p.DragCubes; DragCubeList.CubeData p_drag_data = new DragCubeList.CubeData(); float drag; if (cubes.None) // since 1.0.5, some parts don't have drag cubes (for example fuel lines and struts) { drag = p.maximum_drag; } else { try { cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach, ref p_drag_data); } catch (Exception) { cubes.SetDrag(sim_dragVectorDirLocal, (float)mach); cubes.ForceUpdate(true, true); cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach, ref p_drag_data); //Debug.Log(String.Format("Trajectories: Caught NRE on Drag Initialization. Should be fixed now. {0}", e)); } float pseudoreynolds = (float)(rho * Mathf.Abs(v_wrld_vel.magnitude)); float pseudoredragmult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate(pseudoreynolds); drag = p_drag_data.areaDrag * PhysicsGlobals.DragCubeMultiplier * pseudoredragmult; liftForce = p_drag_data.liftForce; } double sim_dragScalar = dyn_pressure * (double)drag * PhysicsGlobals.DragMultiplier; dragForce = -(Vector3d)sim_dragVectorDir * sim_dragScalar; break; case Part.DragModel.SPHERICAL: dragForce = -(Vector3d)sim_dragVectorDir * (double)p.maximum_drag; break; case Part.DragModel.CYLINDRICAL: dragForce = -(Vector3d)sim_dragVectorDir * (double)Mathf.Lerp(p.minimum_drag, p.maximum_drag, Mathf.Abs(Vector3.Dot(p.partTransform.TransformDirection(p.dragReferenceVector), sim_dragVectorDir))); break; case Part.DragModel.CONIC: dragForce = -(Vector3d)sim_dragVectorDir * (double)Mathf.Lerp(p.minimum_drag, p.maximum_drag, Vector3.Angle(p.partTransform.TransformDirection(p.dragReferenceVector), sim_dragVectorDir) / 180f); break; default: // no drag to apply dragForce = new Vector3d(); break; } total_drag += dragForce; // If it isn't a wing or lifter, get body lift. if (!p.hasLiftModule) { float simbodyLiftScalar = p.bodyLiftMultiplier * PhysicsGlobals.BodyLiftMultiplier * (float)dyn_pressure; simbodyLiftScalar *= PhysicsGlobals.GetLiftingSurfaceCurve("BodyLift").liftMachCurve.Evaluate((float)mach); Vector3 bodyLift = p.transform.rotation * (simbodyLiftScalar * liftForce); bodyLift = Vector3.ProjectOnPlane(bodyLift, sim_dragVectorDir); // Only accumulate forces for non-LiftModules //Debug.Log("[Trajectories] bodyLift=" + bodyLift); total_lift += bodyLift; } // Find ModuleLifingSurface for wings and liftforce. // Should catch control surface as it is a subclass for (int j = 0; j < p.Modules.Count; ++j) { var m = p.Modules[j]; float mcs_mod; if (m is ModuleLiftingSurface) { mcs_mod = 1.0f; double liftQ = dyn_pressure * 1000; ModuleLiftingSurface wing = (ModuleLiftingSurface)m; Vector3 nVel = Vector3.zero; Vector3 liftVector = Vector3.zero; float liftdot; float absdot; wing.SetupCoefficients(v_wrld_vel, out nVel, out liftVector, out liftdot, out absdot); double prevMach = p.machNumber; p.machNumber = mach; Vector3 local_lift = mcs_mod * wing.GetLiftVector(liftVector, liftdot, absdot, liftQ, (float)mach); Vector3 local_drag = mcs_mod * wing.GetDragVector(nVel, absdot, liftQ); p.machNumber = prevMach; total_lift += local_lift; total_drag += local_drag; } } } // RETURN STUFF //Debug.Log("[Trajectories] total_lift" + total_lift + " total_drag=" + total_drag); Vector3 force = total_lift + total_drag; return(force); }
private void Init(IShipconstruct v) { totalMass = 0; dryMass = 0; CoM = Vector3.zero; CoM_dry = Vector3.zero; relativeWingArea = 0; stage = 0; List <Part> oParts = v.Parts; List <SimulatedPart> variableDragParts_ctrls = new List <SimulatedPart>(); count = oParts.Count; if (HighLogic.LoadedSceneIsEditor) { for (int i = 0; i < v.Parts.Count; i++) { Part p = v.Parts[i]; if (p.dragModel == Part.DragModel.CUBE && !p.DragCubes.None) { DragCubeList cubes = p.DragCubes; lock (cubes) { DragCubeList.CubeData p_drag_data = new DragCubeList.CubeData(); try { cubes.SetDragWeights(); cubes.SetPartOcclusion(); cubes.AddSurfaceDragDirection(-Vector3.forward, 0, ref p_drag_data); } catch (Exception) { cubes.SetDrag(Vector3.forward, 0); cubes.ForceUpdate(true, true); cubes.SetDragWeights(); cubes.SetPartOcclusion(); cubes.AddSurfaceDragDirection(-Vector3.forward, 0, ref p_drag_data); //Debug.Log(String.Format("Trajectories: Caught NRE on Drag Initialization. Should be fixed now. {0}", e)); } } } } } bool lgWarning = false; for (int i = 0; i < count; i++) { if (!lgWarning) { ModuleWheels.ModuleWheelDeployment gear = oParts[i].FindModuleImplementing <ModuleWheels.ModuleWheelDeployment>(); bool forcedRetract = !oParts[i].ShieldedFromAirstream && gear != null && gear.Position > 0; if (forcedRetract) { lgWarning = true; } } } // Recursively add all parts to collections // What a crazy change to make just to accomodate rotating parts! partCollection = PartCollection.Borrow(this, oParts[0]); CoM /= totalMass; CoM_dry /= dryMass; partCollection.origin = CoM; if (relativeWingArea == 0) { // I'm not sure what effect calling ScreenMessages from a background thread will be. // Fortunately, anyone using this mod probably has at least one wing. ScreenMessages.PostScreenMessage("No wings found, using a reference area of 1.", 5, ScreenMessageStyle.UPPER_CENTER); relativeWingArea = 1; } //if (lgWarning) //ScreenMessages.PostScreenMessage("Landing gear deployed, results may not be accurate.", 5, ScreenMessageStyle.UPPER_CENTER); }
//******************************************************* public static Vector3d SimAeroForce(Vessel vessel, Vector3d v_wrld_vel, double altitude, double latitude = 0.0) { Profiler.Start("SimAeroForce"); CelestialBody body = vessel.mainBody; double pressure = body.GetPressure(altitude); // Lift and drag for force accumulation. Vector3d total_lift = Vector3d.zero; Vector3d total_drag = Vector3d.zero; // dynamic pressure for standard drag equation double rho = GetDensity(altitude, body); double dyn_pressure = 0.0005 * rho * v_wrld_vel.sqrMagnitude; if (rho <= 0) { return(Vector3.zero); } double soundSpeed = body.GetSpeedOfSound(pressure, rho); double mach = v_wrld_vel.magnitude / soundSpeed; if (mach > 25.0) { mach = 25.0; } // Loop through all parts, accumulating drag and lift. for (int i = 0; i < vessel.Parts.Count; ++i) { // need checks on shielded components Part p = vessel.Parts[i]; #if DEBUG TrajectoriesDebug partDebug = VesselAerodynamicModel.DebugParts ? p.FindModuleImplementing <TrajectoriesDebug>() : null; if (partDebug != null) { partDebug.Drag = 0; partDebug.Lift = 0; } #endif if (p.ShieldedFromAirstream || p.Rigidbody == null) { continue; } // Get Drag Vector3d sim_dragVectorDir = v_wrld_vel.normalized; Vector3d sim_dragVectorDirLocal = -(p.transform.InverseTransformDirection(sim_dragVectorDir)); Vector3d liftForce = Vector3d.zero; Vector3d dragForce; Profiler.Start("SimAeroForce#drag"); switch (p.dragModel) { case Part.DragModel.DEFAULT: case Part.DragModel.CUBE: DragCubeList cubes = p.DragCubes; DragCubeList.CubeData p_drag_data = new DragCubeList.CubeData(); double drag; if (cubes.None) // since 1.0.5, some parts don't have drag cubes (for example fuel lines and struts) { drag = p.maximum_drag; } else { try { cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach, ref p_drag_data); } catch (Exception e) { cubes.SetDrag(sim_dragVectorDirLocal, (float)mach); cubes.ForceUpdate(true, true); cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach, ref p_drag_data); Util.DebugLogError("Exception {0} on drag initialization", e); } double pseudoreynolds = rho * Math.Abs(v_wrld_vel.magnitude); double pseudoredragmult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate((float)pseudoreynolds); drag = p_drag_data.areaDrag * PhysicsGlobals.DragCubeMultiplier * pseudoredragmult; liftForce = p_drag_data.liftForce; } double sim_dragScalar = dyn_pressure * drag * PhysicsGlobals.DragMultiplier; dragForce = -sim_dragVectorDir * sim_dragScalar; break; case Part.DragModel.SPHERICAL: dragForce = -sim_dragVectorDir * p.maximum_drag; break; case Part.DragModel.CYLINDRICAL: dragForce = -sim_dragVectorDir *Mathf.Lerp(p.minimum_drag, p.maximum_drag, Mathf.Abs(Vector3.Dot(p.partTransform.TransformDirection(p.dragReferenceVector), sim_dragVectorDir))); break; case Part.DragModel.CONIC: dragForce = -sim_dragVectorDir *Mathf.Lerp(p.minimum_drag, p.maximum_drag, Vector3.Angle(p.partTransform.TransformDirection(p.dragReferenceVector), sim_dragVectorDir) / 180f); break; default: // no drag to apply dragForce = Vector3d.zero; break; } Profiler.Stop("SimAeroForce#drag"); #if DEBUG if (partDebug != null) { partDebug.Drag += (float)dragForce.magnitude; } #endif total_drag += dragForce; // If it isn't a wing or lifter, get body lift. if (!p.hasLiftModule) { Profiler.Start("SimAeroForce#BodyLift"); float simbodyLiftScalar = p.bodyLiftMultiplier * PhysicsGlobals.BodyLiftMultiplier * (float)dyn_pressure; simbodyLiftScalar *= PhysicsGlobals.GetLiftingSurfaceCurve("BodyLift").liftMachCurve.Evaluate((float)mach); Vector3 bodyLift = p.transform.rotation * (simbodyLiftScalar * liftForce); bodyLift = Vector3.ProjectOnPlane(bodyLift, sim_dragVectorDir); // Only accumulate forces for non-LiftModules total_lift += bodyLift; Profiler.Stop("SimAeroForce#BodyLift"); } Profiler.Start("SimAeroForce#LiftingSurface"); // Find ModuleLifingSurface for wings and liftforce. // Should catch control surface as it is a subclass for (int j = 0; j < p.Modules.Count; ++j) { var m = p.Modules[j]; if (m is ModuleLiftingSurface wing) { const float mcs_mod = 1.0f; double liftQ = dyn_pressure * 1000; wing.SetupCoefficients(v_wrld_vel, out var nVel, out var liftVector, out var liftdot, out var absdot); double prevMach = p.machNumber; p.machNumber = mach; Vector3 local_lift = mcs_mod * wing.GetLiftVector(liftVector, liftdot, absdot, liftQ, (float)mach); Vector3 local_drag = mcs_mod * wing.GetDragVector(nVel, absdot, liftQ); p.machNumber = prevMach; total_lift += local_lift; total_drag += local_drag; #if DEBUG if (partDebug != null) { partDebug.Lift += local_lift.magnitude; partDebug.Drag += local_drag.magnitude; } #endif } } Profiler.Stop("SimAeroForce#LiftingSurface"); } // RETURN STUFF Vector3 force = total_lift + total_drag; Profiler.Stop("SimAeroForce"); return(force); }
//******************************************************* public static Vector3 SimDragForce(CelestialBody body, IShipconstruct vessel, Vector3 v_wrld_vel, double altitude, double latitude = 0.0) { double pressure = body.GetPressure(altitude); // Lift and drag for force accumulation. Vector3d total_drag = Vector3d.zero; // dynamic pressure for standard drag equation double rho = GetDensity(altitude, body); double dyn_pressure = 0.0005 * rho * v_wrld_vel.sqrMagnitude; if (rho <= 0) { return(Vector3.zero); } double soundSpeed = body.GetSpeedOfSound(pressure, rho); double mach = v_wrld_vel.magnitude / soundSpeed; if (mach > 25.0) { mach = 25.0; } // Loop through all parts, accumulating drag and lift. for (int i = vessel.Parts.Count - 1; i >= 0; i--) { // need checks on shielded components Part part = vessel.Parts[i]; if (part.ShieldedFromAirstream || part.Rigidbody == null) { continue; } // Get Drag Vector3 sim_dragVectorDir = v_wrld_vel.normalized; Vector3 sim_dragVectorDirLocal = -(part.transform.InverseTransformDirection(sim_dragVectorDir)); Vector3d dragForce; switch (part.dragModel) { case Part.DragModel.DEFAULT: case Part.DragModel.CUBE: DragCubeList cubes = part.DragCubes; DragCubeList.CubeData p_drag_data = new DragCubeList.CubeData(); float drag; if (cubes.None) // since 1.0.5, some parts don't have drag cubes (for example fuel lines and struts) { drag = part.maximum_drag; } else { try { cubes.SetDragWeights(); cubes.SetPartOcclusion(); cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach, ref p_drag_data); } catch (Exception) { cubes.SetDrag(sim_dragVectorDirLocal, (float)mach); cubes.ForceUpdate(true, true); cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach, ref p_drag_data); //Debug.Log(String.Format("Trajectories: Caught NRE on Drag Initialization. Should be fixed now. {0}", e)); } float pseudoreynolds = (float)(rho * Mathf.Abs(v_wrld_vel.magnitude)); float pseudoredragmult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate(pseudoreynolds); drag = p_drag_data.areaDrag * PhysicsGlobals.DragCubeMultiplier * pseudoredragmult; } double sim_dragScalar = dyn_pressure * (double)drag * PhysicsGlobals.DragMultiplier; dragForce = -(Vector3d)sim_dragVectorDir * sim_dragScalar; break; case Part.DragModel.SPHERICAL: dragForce = -(Vector3d)sim_dragVectorDir * (double)part.maximum_drag; break; case Part.DragModel.CYLINDRICAL: dragForce = -(Vector3d)sim_dragVectorDir * (double)Mathf.Lerp(part.minimum_drag, part.maximum_drag, Mathf.Abs(Vector3.Dot(part.partTransform.TransformDirection(part.dragReferenceVector), sim_dragVectorDir))); break; case Part.DragModel.CONIC: dragForce = -(Vector3d)sim_dragVectorDir * (double)Mathf.Lerp(part.minimum_drag, part.maximum_drag, Vector3.Angle(part.partTransform.TransformDirection(part.dragReferenceVector), sim_dragVectorDir) / 180f); break; default: // no drag to apply dragForce = new Vector3d(); break; } total_drag += dragForce; // Find ModuleLifingSurface for wings and liftforce. // Should catch control surface as it is a subclass for (int j = part.Modules.Count - 1; j >= 0; j--) { if (part.Modules[j] is ModuleLiftingSurface) { float mcs_mod = 1.0f; double liftQ = dyn_pressure * 1000; ModuleLiftingSurface wing = (ModuleLiftingSurface)part.Modules[j]; Vector3 nVel = Vector3.zero; Vector3 liftVector = Vector3.zero; float liftdot; float absdot; wing.SetupCoefficients(v_wrld_vel, out nVel, out liftVector, out liftdot, out absdot); double prevMach = part.machNumber; part.machNumber = mach; Vector3 local_drag = mcs_mod * wing.GetDragVector(nVel, absdot, liftQ); part.machNumber = prevMach; total_drag += local_drag; } } } // RETURN STUFF return(total_drag); }
//******************************************************* public static Vector3 SimLiftForce(CelestialBody body, IShipconstruct vessel, Vector3 v_wrld_vel, double altitude, double latitude = 0.0) { //Profiler.Start("SimLiftForce"); double pressure = body.GetPressure(altitude); // Lift and drag for force accumulation. Vector3d total_lift = Vector3d.zero; // dynamic pressure for standard drag equation double rho = GetDensity(altitude, body); double dyn_pressure = 0.0005 * rho * v_wrld_vel.sqrMagnitude; if (rho <= 0) { return(Vector3.zero); } double soundSpeed = body.GetSpeedOfSound(pressure, rho); double mach = v_wrld_vel.magnitude / soundSpeed; if (mach > 25.0) { mach = 25.0; } // Loop through all parts, accumulating drag and lift. for (int i = vessel.Parts.Count - 1; i >= 0; i--) { // need checks on shielded components Part part = vessel.Parts[i]; if (part.ShieldedFromAirstream || part.Rigidbody == null) { continue; } // Get Drag Vector3 sim_dragVectorDir = v_wrld_vel.normalized; Vector3 sim_dragVectorDirLocal = -(part.transform.InverseTransformDirection(sim_dragVectorDir)); Vector3 liftForce = new Vector3(0, 0, 0); //Profiler.Start("SimLiftForce#Body"); switch (part.dragModel) { case Part.DragModel.DEFAULT: case Part.DragModel.CUBE: DragCubeList cubes = part.DragCubes; DragCubeList.CubeData p_drag_data = new DragCubeList.CubeData(); if (!cubes.None) // since 1.0.5, some parts don't have drag cubes (for example fuel lines and struts) { try { cubes.SetDragWeights(); cubes.SetPartOcclusion(); cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach, ref p_drag_data); } catch (Exception) { cubes.SetDrag(sim_dragVectorDirLocal, (float)mach); cubes.ForceUpdate(true, true); cubes.AddSurfaceDragDirection(-sim_dragVectorDirLocal, (float)mach, ref p_drag_data); //Debug.Log(String.Format("Trajectories: Caught NRE on Drag Initialization. Should be fixed now. {0}", e)); } float pseudoreynolds = (float)(rho * Mathf.Abs(v_wrld_vel.magnitude)); float pseudoredragmult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate(pseudoreynolds); liftForce = p_drag_data.liftForce; } break; } // If it isn't a wing or lifter, get body lift. if (!part.hasLiftModule) { float simbodyLiftScalar = part.bodyLiftMultiplier * PhysicsGlobals.BodyLiftMultiplier * (float)dyn_pressure; simbodyLiftScalar *= PhysicsGlobals.GetLiftingSurfaceCurve("BodyLift").liftMachCurve.Evaluate((float)mach); Vector3 bodyLift = part.transform.rotation * (simbodyLiftScalar * liftForce); bodyLift = Vector3.ProjectOnPlane(bodyLift, sim_dragVectorDir); // Only accumulate forces for non-LiftModules total_lift += bodyLift; } //Profiler.Stop("SimLiftForce#Body"); // Find ModuleLifingSurface for wings and liftforce. // Should catch control surface as it is a subclass //Profiler.Start("SimLiftForce#LiftModule"); for (int j = part.Modules.Count - 1; j >= 0; j--) { if (part.Modules[j] is ModuleLiftingSurface) { float mcs_mod = 1.0f; double liftQ = dyn_pressure * 1000; ModuleLiftingSurface wing = (ModuleLiftingSurface)part.Modules[j]; Vector3 nVel = Vector3.zero; Vector3 liftVector = Vector3.zero; float liftdot; float absdot; wing.SetupCoefficients(v_wrld_vel, out nVel, out liftVector, out liftdot, out absdot); double prevMach = part.machNumber; part.machNumber = mach; Vector3 local_lift = mcs_mod * wing.GetLiftVector(liftVector, liftdot, absdot, liftQ, (float)mach); part.machNumber = prevMach; total_lift += local_lift; } } //Profiler.Stop("SimLiftForce#LiftModule"); } // RETURN STUFF //Profiler.Stop("SimLiftForce"); return(total_lift); }
private void Init(IShipconstruct v, SimCurves _simCurves) { totalMass = 0; dryMass = 0; CoM = Vector3.zero; CoM_dry = Vector3.zero; List<Part> oParts = v.Parts; List<SimulatedPart> variableDragParts_ctrls = new List<SimulatedPart>(); count = oParts.Count; if (HighLogic.LoadedSceneIsEditor) { for (int i = 0; i < v.Parts.Count; i++) { Part p = v.Parts[i]; if (p.dragModel == Part.DragModel.CUBE && !p.DragCubes.None) { DragCubeList cubes = p.DragCubes; DragCubeList.CubeData p_drag_data = new DragCubeList.CubeData(); try { cubes.SetDragWeights(); cubes.SetPartOcclusion(); cubes.AddSurfaceDragDirection(-Vector3.forward, 0, ref p_drag_data); } catch (Exception) { cubes.SetDrag(Vector3.forward, 0); cubes.ForceUpdate(true, true); cubes.SetDragWeights(); cubes.SetPartOcclusion(); cubes.AddSurfaceDragDirection(-Vector3.forward, 0, ref p_drag_data); //Debug.Log(String.Format("Trajectories: Caught NRE on Drag Initialization. Should be fixed now. {0}", e)); } } } } simCurves = _simCurves; if (parts.Capacity < count) parts.Capacity = count; bool lgWarning = false; int stage = 0; for (int i = 0; i < count; i++) { if (!lgWarning) { ModuleWheels.ModuleWheelDeployment gear = oParts[i].FindModuleImplementing<ModuleWheels.ModuleWheelDeployment>(); bool forcedRetract = !oParts[i].ShieldedFromAirstream && gear != null && gear.Position > 0; if (forcedRetract) lgWarning = true; } SimulatedPart simulatedPart = SimulatedPart.Borrow(oParts[i], this); parts.Add(simulatedPart); totalMass += simulatedPart.totalMass; dryMass += simulatedPart.dryMass; CoM += simulatedPart.totalMass * simulatedPart.CoM; CoM_dry += simulatedPart.dryMass * simulatedPart.CoM; ModuleLiftingSurface liftingSurface = oParts[i].FindModuleImplementing<ModuleLiftingSurface>(); if (liftingSurface != null) { parts[i].hasLiftModule = true; if (liftingSurface is ModuleControlSurface ctrlSurface) { ctrls.Add(SimulatedControlSurface.Borrow(ctrlSurface, simulatedPart)); variableDragParts_ctrls.Add(simulatedPart); if (ctrlSurface.ctrlSurfaceArea < 1) surfaces.Add(SimulatedLiftingSurface.Borrow(ctrlSurface, simulatedPart)); } else surfaces.Add(SimulatedLiftingSurface.Borrow(liftingSurface, simulatedPart)); } List<ITorqueProvider> torqueProviders = oParts[i].FindModulesImplementing<ITorqueProvider>(); // TODO: Add them to a list. if(oParts[i].inverseStage > stage) { SimulatedEngine.Release(engines); engines.Clear(); stage = oParts[i].inverseStage; } if (oParts[i].inverseStage >= stage) { MultiModeEngine multiMode = oParts[i].FindModuleImplementing<MultiModeEngine>(); if (multiMode != null) { engines.Add(SimulatedEngine.Borrow(oParts[i].FindModulesImplementing<ModuleEngines>().Find(engine => engine.engineID == multiMode.mode), simulatedPart)); } else { ModuleEngines engine = oParts[i].FindModulesImplementing<ModuleEngines>().FirstOrDefault(); if (engine != null) engines.Add(SimulatedEngine.Borrow(engine, simulatedPart)); } } } CoM /= totalMass; CoM_dry /= dryMass; if (lgWarning) ScreenMessages.PostScreenMessage("Landing gear deployed, results may not be accurate.", 5, ScreenMessageStyle.UPPER_CENTER); /*for (int i = 0; i < count; i++) { parts[i].CoM -= this.CoM; parts[i].CoL -= this.CoM; parts[i].CoP -= this.CoM; }*/ parts.RemoveAll(part => variableDragParts_ctrls.Contains(part)); }
public void update(double curSpeed, double curDensity) { maxSpeed = 0; breakDistance = 0; curDensity = Math.Max(curDensity, 0.2 * vesselState.mainBody.atmDensityASL); double curSpeedOfSound = Math.Max(vesselState.speedOfSound, vesselState.mainBody.GetSpeedOfSound(0.2 * vesselState.mainBody.atmPressureASL, 0.2 * vesselState.mainBody.atmDensityASL)); //create List by descending order of maxSpeed with drag and max chute reaction time SortedList <double, (float, float)> parachuteTypes = new SortedList <double, (float, float)>(Comparer <double> .Create((a, b) => Math.Sign(b - a))); foreach (var p in vesselState.parachutes) { if (p.deploymentState == ModuleParachute.deploymentStates.STOWED) { p.refDensity = curDensity; p.CalcBaseStats(); DragCubeList simParachute = new DragCubeList(); simParachute.LoadCube(p.part.DragCubes, "DEPLOYED"); simParachute.SetPart(p.part); simParachute.SetOcclusionMultiplier(0f); simParachute.ResetCubeWeights(); simParachute.SetDragWeights(); simParachute.SetPartOcclusion(); //Debug.Log(String.Format("ParachuteInfo.update Parchute {0} has up Cube area={1:F1} drag={2:F1} weight={3:F1} AreaOccluded={4:F1}", // p.part.name, simParachute.Cubes[0].Area[(int) DragCube.DragFace.YP], simParachute.Cubes[0].Drag[(int) DragCube.DragFace.YP], // simParachute.Cubes[0].Weight, simParachute.AreaOccluded[(int)DragCube.DragFace.YP])); DragCubeList.CubeData simDrag = new DragCubeList.CubeData(); simParachute.AddSurfaceDragDirection(Vector3.up, (float)(p.maxSafeSpeedAtRef / curSpeedOfSound), ref simDrag); //Debug.Log(String.Format("ParachuteInfo.update Parchute {0} has areaDrag={1:F1}, crossSectionalArea={2:F1}, exposedArea={3:F1}", // p.part.name, simDrag.areaDrag, simDrag.crossSectionalArea, simDrag.exposedArea)); if (parachuteTypes.ContainsKey(p.maxSafeSpeedAtRef)) { parachuteTypes[p.maxSafeSpeedAtRef] = (parachuteTypes[p.maxSafeSpeedAtRef].Item1 + simDrag.areaDrag, Mathf.Max(parachuteTypes[p.maxSafeSpeedAtRef].Item2, p.Anim[p.semiDeployedAnimation].length / p.semiDeploymentSpeed + p.Anim[p.fullyDeployedAnimation].length / p.deploymentSpeed)); } else { parachuteTypes.Add(p.maxSafeSpeedAtRef, (simDrag.areaDrag, p.Anim[p.semiDeployedAnimation].length / p.semiDeploymentSpeed + p.Anim[p.fullyDeployedAnimation].length / p.deploymentSpeed)); } } } float totalFriction = 0; double lastSpeed = 0; foreach (var pt in parachuteTypes) { double effSpeed = Math.Min(curSpeed, pt.Key); // base equation deceleration term + chute reaction term with deceleration taken from moving equations with netwon friction // during reaction time we hardly break, so assume float friction_const = pt.Value.Item1 * 0.0005f * (float)curDensity * PhysicsGlobals.DragMultiplier * PhysicsGlobals.DragCubeMultiplier * PhysicsGlobals.DragCurvePseudoReynolds.Evaluate((float)(effSpeed * curDensity)); if (breakDistance == 0) // first term for highest speed { breakDistance = (float)vesselState.mass / friction_const * Math.Log(effSpeed) + effSpeed * pt.Value.Item2; undeployedDistance = effSpeed * pt.Value.Item2;// - vesselState.mass / friction_const ; maxSpeed = lastSpeed = effSpeed; totalFriction = friction_const; //Debug.Log(String.Format("ParachuteInfo.update has first chute type with friction={0:F4} and effSpeed={1:F0}, delay={3:F1} results break dist={2:F0}", friction_const, effSpeed, breakDistance, pt.Value.Item2)); } else { // calculate slowdown during parachute opening using old friction effSpeed *= (float)vesselState.mass / (totalFriction * pt.Value.Item2 * effSpeed + vesselState.mass); breakDistance -= (float)vesselState.mass / (totalFriction + friction_const) * friction_const / totalFriction * Math.Log(effSpeed); undeployedDistance += pt.Value.Item2 * effSpeed;// + vesselState.mass * lastSpeed / (totalFriction * effSpeed) - vesselState.mass / (totalFriction + friction_const); lastSpeed = effSpeed; totalFriction += friction_const; //Debug.Log(String.Format("ParachuteInfo.update has next chute type with friction={0:F4} and effSpeed={1:F0}, delay={3:F1} results break dist={2:F0}", friction_const, effSpeed, breakDistance, pt.Value.Item2)); } } if (totalFriction > 0) { double terminalSpeed = Math.Sqrt((float)vesselState.mass / totalFriction * vesselState.mainBody.GeeASL * PhysicsGlobals.GravitationalAcceleration); //we are not getting slower than terminal velocity, so substract this as best guess for integration constant v breakDistance -= (float)vesselState.mass / totalFriction * Math.Log(terminalSpeed); //undeployedDistance += vesselState.mass * lastSpeed / (totalFriction * terminalSpeed); //Debug.Log(String.Format("ParachuteInfo.update has terminal velocity term with friction={0:F4} and terminalSpeed={1:F0} results break dist={2:F0}", totalFriction, terminalSpeed, breakDistance)); } Debug.Log(String.Format("ParachuteInfo.update for speed={0:F0} gives maxSpeed={1:F0} break dist={2:F0} undeployedDistance={3:F0}", curSpeed, maxSpeed, breakDistance, undeployedDistance)); }