public Vector3 GetAero(Vector3 velocityVect, float mach, float pseudoReDragMult, out Vector3 torque, Vector3 torquePoint) { torque = Vector3.zero; if (shieldedFromAirstream || noDrag) { return(Vector3.zero); } Vector3 dragVectorDirLocal = -(vesselToPart * velocityVect); Vector3 drag = -velocityVect; Vector3 liftV = Vector3.zero; switch (dragModel) { case Part.DragModel.SPHERICAL: drag *= maximum_drag; break; case Part.DragModel.CYLINDRICAL: drag *= Mathf.Lerp(minimum_drag, maximum_drag, Math.Abs(Vector3.Dot(dragReferenceVector, velocityVect))); break; case Part.DragModel.CONIC: drag *= Mathf.Lerp(minimum_drag, maximum_drag, Vector3.Angle(dragReferenceVector, velocityVect) / 180f); break; case Part.DragModel.DEFAULT: case Part.DragModel.CUBE: if (cubesNone) { drag *= maximum_drag; } else { lock (this.cubes) { cubes.SetDrag(dragVectorDirLocal, mach); drag *= cubes.AreaDrag * PhysicsGlobals.DragCubeMultiplier; if (!hasLiftModule) { // direction of the lift in a vessel centric reference liftV = partToVessel * (cubes.LiftForce * bodyLiftMultiplier); liftV = Vector3.ProjectOnPlane(liftV, velocityVect) * PhysicsGlobals.BodyLiftMultiplier * cubes.BodyLiftCurve.liftMachCurve.Evaluate(mach); } } } break; default: drag = Vector3.zero; break; } drag *= PhysicsGlobals.DragMultiplier * pseudoReDragMult; //Debug.Log(name + ": " + drag.magnitude / pseudoReDragMult); torque = Vector3.Cross(liftV, CoL - torquePoint) + Vector3.Cross(drag, CoP - torquePoint); return(drag + liftV); }
public virtual Vector3d Drag(Vector3d vesselVelocity, double dragFactor, float mach) { if (shieldedFromAirstream || noDrag) { return(Vector3d.zero); } Vector3d dragVectorDirLocal = -(vesselToPart * vesselVelocity).normalized; cubes.SetDrag(dragVectorDirLocal, mach); Vector3d drag = -vesselVelocity.normalized * cubes.AreaDrag * dragFactor; return(drag); }
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 virtual Vector3d Drag(Vector3d vesselVelocity, double dragFactor, float mach) { if (shieldedFromAirstream || noDrag) { return(Vector3d.zero); } Vector3d dragVectorDirLocal = -(vesselToPart * vesselVelocity).normalized; cubes.SetDrag(dragVectorDirLocal, mach); Vector3d drag = -vesselVelocity.normalized * cubes.AreaDrag * dragFactor; //bool delta = false; //string msg = oPart.name; //if (vesselVelocity.sqrMagnitude > 1 && dynamicPressurekPa - oPart.dynamicPressurekPa > oPart.dynamicPressurekPa * 0.1) //{ // msg += " dynamicPressurekPa " + dynamicPressurekPa.ToString("f4") + " vs " + oPart.dynamicPressurekPa.ToString("f4"); // delta = true; //} // ////if (vesselVelocity.sqrMagnitude > 1 && cubes.AreaDrag - oPart.DragCubes.AreaDrag > oPart.DragCubes.AreaDrag * 0.1) //if (vesselVelocity.sqrMagnitude > 1) //{ // msg += "\n AreaDrag " + cubes.AreaDrag.ToString("f4") + " vs " + oPart.DragCubes.AreaDrag.ToString("f4"); // //msg += "\n mach " + mach.ToString("f4") + " vs " + oPart.machNumber.ToString("f4"); // // msg += "\n dragDir " + MuUtils.PrettyPrint(dragDir) + " vs " + MuUtils.PrettyPrint(oPart.dragVectorDirLocal) + " " + Vector3.Angle(dragDir, oPart.dragVectorDirLocal).ToString("F3") + "°"; // //msg += "\n dragVel " + MuUtils.PrettyPrint(vesselVelocity.normalized) + " vs " + MuUtils.PrettyPrint(oPart.dragVector.normalized) + " " + Vector3.Angle(vesselVelocity.normalized, oPart.dragVector).ToString("F3") + "°"; // // msg += "\n Real° " + MuUtils.PrettyPrint(oPart.dragVectorDirLocal) + " " + Vector3.Angle(oPart.dragVectorDirLocal, Vector3.down).ToString("F3") + "°"; // msg += "\n Sim° " + MuUtils.PrettyPrint(dragDir) + " " + Vector3.Angle(dragDir, Vector3.down).ToString("F3") + "°"; // // msg += "\n toUp " + MuUtils.PrettyPrint(vesselToPart * Vector3.up) + Vector3.Angle(vesselToPart * Vector3.up, Vector3.up).ToString("F3") + "°"; // // // Vector3 quatUp = vesselToPart * Vector3.up; // Vector3 shipUp = oPart.vessel.transform.InverseTransformDirection(oPart.transform.up); // // msg += "\n Ups " + MuUtils.PrettyPrint(quatUp) + " vs " + MuUtils.PrettyPrint(shipUp) + " " + Vector3.Angle(quatUp, shipUp).ToString("F3") + "°"; // // // // //msg += "\n AreaOccluded "; // //for (int i = 0; i < 6; i++) // //{ // // msg += cubes.AreaOccluded[i].ToString("F3") + "/" + oPart.DragCubes.AreaOccluded[i].ToString("F3") + " "; // //} // //msg += "\n WeightedDrag "; // //for (int i = 0; i < 6; i++) // //{ // // msg += cubes.WeightedDrag[i].ToString("F3") + "/" + oPart.DragCubes.WeightedDrag[i].ToString("F3") + " "; // //} // // msg += "\n vesselToPart " + MuUtils.PrettyPrint(vesselToPart.eulerAngles); // delta = true; //} // //if (delta) // MechJebCore.print(msg); return(drag); }
public static double GetChuteArea(List <Part> parts) { double RCParameter = 0; bool realChuteInUse = false; try { foreach (Part p in parts) { //Make a list of all the Module Names for easy checking later. This can be avoided, but is convenient. List <string> ModuleNames = new List <string>(); foreach (PartModule pm in p.Modules) { ModuleNames.Add(pm.moduleName); } if (ModuleNames.Contains("RealChuteModule")) { if (!realChuteInUse) { RCParameter = 0; } //First off, get the PPMS since we'll need that PartModule realChute = p.Modules["RealChuteModule"]; //Assuming that's not somehow null, then we continue if (realChute != null) //Some of this was adopted from DebRefund, as Vendan's method of handling multiple parachutes is better than what I had. { //We make a list of ConfigNodes containing the parachutes (usually 1, but now there can be any number of them) //We get that from the PPMS ConfigNode rcNode = new ConfigNode(); realChute.Save(rcNode); //It's existence means that RealChute is installed and in use on the craft (you could have it installed and use stock chutes, so we only check if it's on the craft) realChuteInUse = true; RCParameter += ProcessRealchute(rcNode); } } else if (ModuleNames.Contains("RealChuteFAR")) //RealChute Lite for FAR { if (!realChuteInUse) { RCParameter = 0; } PartModule realChute = p.Modules["RealChuteFAR"]; float diameter = 0.0F; //realChute.moduleValues.GetValue("deployedDiameter") if (realChute != null) { try { diameter = realChute.Fields.GetValue <float>("deployedDiameter"); Log.Info($"[SR] Diameter is {diameter}."); } catch (Exception e) { Debug.LogError("[SR] Exception while finding deployedDiameter for RealChuteFAR module on module."); Debug.LogException(e); } } else { Log.Info("[SR] moduleRef is null, attempting workaround to find diameter."); object dDefault = p.partInfo.partPrefab.Modules["RealChuteFAR"]?.Fields?.GetValue("deployedDiameter"); //requires C# 6 if (dDefault != null) { diameter = Convert.ToSingle(dDefault); Log.Info($"[SR] Workaround gave a diameter of {diameter}."); } else { Log.Info("[SR] Couldn't get default value, setting to 0 and calling it a day."); diameter = 0.0F; } } float dragC = 1.0f; //float.Parse(realChute.moduleValues.GetValue("staticCd")); RCParameter += (dragC * Mathf.Pow(diameter, 2) * Math.PI / 4.0); realChuteInUse = true; } else if (!realChuteInUse && ModuleNames.Contains("ModuleParachute")) { //Credit to m4v and RCSBuildAid: https://github.com/m4v/RCSBuildAid/blob/master/Plugin/CoDMarker.cs Part part = p ?? p.partInfo.partPrefab; //the part, or the part prefab DragCubeList dragCubes = part.DragCubes; dragCubes.SetCubeWeight("DEPLOYED", 1); dragCubes.SetCubeWeight("SEMIDEPLOYED", 0); dragCubes.SetCubeWeight("PACKED", 0); dragCubes.SetOcclusionMultiplier(0); Quaternion rotation = Quaternion.LookRotation(Vector3d.up); try { rotation = Quaternion.LookRotation(part.partTransform?.InverseTransformDirection(Vector3d.up) ?? Vector3d.up); } catch (Exception e) { Debug.LogException(e); } dragCubes.SetDragVectorRotation(rotation); } if (!realChuteInUse) { Part part = p ?? p.partInfo.partPrefab; //the part reference, or the part prefab DragCubeList dragCubes = part.DragCubes; dragCubes.ForceUpdate(false, true); dragCubes.SetDragWeights(); dragCubes.SetPartOcclusion(); Vector3 dir = Vector3d.up; try { dir = -part.partTransform?.InverseTransformDirection(Vector3d.down) ?? Vector3d.up; } catch (Exception e) { //Debug.LogException(e); Log.Info("[SR] The expected excpetion is still present. " + e.Message); } dragCubes.SetDrag(dir, 0.03f); //mach 0.03, or about 10m/s double dragCoeff = dragCubes.AreaDrag * PhysicsGlobals.DragCubeMultiplier; RCParameter += (dragCoeff * PhysicsGlobals.DragMultiplier); } } } catch (Exception e) { Debug.LogError("[SR] Error occured while trying to determine total chute area."); Debug.LogException(e); } return(RCParameter); }
//******************************************************* 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); }
//******************************************************* 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)); }