Esempio n. 1
0
        public static void CopyDragCubesList(DragCubeList source, DragCubeList dest)
        {
            dest.ClearCubes();

            dest.None       = source.None;
            dest.Procedural = source.Procedural;

            for (int i = 0; i < source.Cubes.Count; i++)
            {
                DragCube c = new DragCube();
                CopyDragCube(source.Cubes[i], c);
                dest.Cubes.Add(c);
            }

            dest.SetDragWeights();

            for (int i = 0; i < 6; i++)
            {
                dest.WeightedArea[i]  = source.WeightedArea[i];
                dest.WeightedDrag[i]  = source.WeightedDrag[i];
                dest.AreaOccluded[i]  = source.AreaOccluded[i];
                dest.WeightedDepth[i] = source.WeightedDepth[i];
            }

            dest.SetDragWeights();

            // We are missing PostOcclusionArea but it seems to be used in Thermal only
        }
Esempio n. 2
0
        //TODO : rewrite the cube calls to only store and update the minimum needed data ( AreaOccluded + WeightedDrag ?)

        protected static void CopyDragCubesList(DragCubeList source, DragCubeList dest)
        {
            dest.ClearCubes();

            dest.None = source.None;

            // Procedural need access to part so things gets bad quick.
            dest.Procedural = false;

            for (int i = 0; i < source.Cubes.Count; i++)
            {
                DragCube c = DragCubePool.Instance.Borrow();
                CopyDragCube(source.Cubes[i], c);
                dest.Cubes.Add(c);
            }

            dest.SetDragWeights();

            for (int i = 0; i < 6; i++)
            {
                dest.WeightedArea[i]  = source.WeightedArea[i];
                dest.WeightedDrag[i]  = source.WeightedDrag[i];
                dest.AreaOccluded[i]  = source.AreaOccluded[i];
                dest.WeightedDepth[i] = source.WeightedDepth[i];
            }

            dest.SetDragWeights();

            // We are missing PostOcclusionArea but it seems to be used in Thermal only
        }
Esempio n. 3
0
        protected void CopyDragCubesList(DragCubeList source, DragCubeList dest)
        {
            source.ForceUpdate(true, true);
            source.SetDragWeights();
            source.SetPartOcclusion();

            dest.ClearCubes();

            dest.SetPart(source.Part);

            dest.None = source.None;

            // Procedural need access to part so things gets bad quick.
            dest.Procedural = false;

            for (int i = 0; i < source.Cubes.Count; i++)
            {
                DragCube c;
                lock (DragCubePool.Instance)
                    c = DragCubePool.Instance.Borrow();
                CopyDragCube(source.Cubes[i], c);
                dest.Cubes.Add(c);
            }

            dest.SetDragWeights();

            for (int i = 0; i < 6; i++)
            {
                dest.WeightedArea[i]  = source.WeightedArea[i];
                dest.WeightedDrag[i]  = source.WeightedDrag[i];
                dest.AreaOccluded[i]  = source.AreaOccluded[i];
                dest.WeightedDepth[i] = source.WeightedDepth[i];
            }

            dest.SetDragWeights();

            dest.BodyLiftCurve = new PhysicsGlobals.LiftingSurfaceCurve();
            dest.SurfaceCurves = new PhysicsGlobals.SurfaceCurvesList();

            dest.DragCurveCd         = simCurves.DragCurveCd.Clone();
            dest.DragCurveCdPower    = simCurves.DragCurveCdPower.Clone();
            dest.DragCurveMultiplier = simCurves.DragCurveMultiplier.Clone();

            dest.BodyLiftCurve.liftCurve     = simCurves.LiftCurve.Clone();
            dest.BodyLiftCurve.dragCurve     = simCurves.DragCurve.Clone();
            dest.BodyLiftCurve.dragMachCurve = simCurves.DragMachCurve.Clone();
            dest.BodyLiftCurve.liftMachCurve = simCurves.LiftMachCurve.Clone();

            dest.SurfaceCurves.dragCurveMultiplier = simCurves.DragCurveMultiplier.Clone();
            dest.SurfaceCurves.dragCurveSurface    = simCurves.DragCurveSurface.Clone();
            dest.SurfaceCurves.dragCurveTail       = simCurves.DragCurveTail.Clone();
            dest.SurfaceCurves.dragCurveTip        = simCurves.DragCurveTip.Clone();

            dest.SetPartOcclusion();
        }
Esempio n. 4
0
        protected void SetCubeWeight(string name, float newWeight)
        {
            int count = cubes.Cubes.Count;

            if (count == 0)
            {
                return;
            }

            bool noChange = true;

            for (int i = count - 1; i >= 0; i--)
            {
                if (cubes.Cubes[i].Name == name && cubes.Cubes[i].Weight != newWeight)
                {
                    cubes.Cubes[i].Weight = newWeight;
                    noChange = false;
                }
            }

            if (noChange)
            {
                return;
            }

            cubes.SetDragWeights();
        }
Esempio n. 5
0
        protected void CopyDragCubesList(DragCubeList source, DragCubeList dest)
        {
            dest.ClearCubes();

            dest.SetPart(source.Part);

            dest.None = source.None;

            // Procedural need access to part so things gets bad quick.
            dest.Procedural = false;

            for (int i = 0; i < source.Cubes.Count; i++)
            {
                DragCube c = DragCubePool.Instance.Borrow();
                CopyDragCube(source.Cubes[i], c);
                dest.Cubes.Add(c);
            }

            dest.SetDragWeights();

            for (int i = 0; i < 6; i++)
            {
                dest.WeightedArea[i]  = source.WeightedArea[i];
                dest.WeightedDrag[i]  = source.WeightedDrag[i];
                dest.AreaOccluded[i]  = source.AreaOccluded[i];
                dest.WeightedDepth[i] = source.WeightedDepth[i];
            }

            dest.SetDragWeights();

            dest.DragCurveCd         = simCurves.DragCurveCd;
            dest.DragCurveCdPower    = simCurves.DragCurveCdPower;
            dest.DragCurveMultiplier = simCurves.DragCurveMultiplier;

            dest.BodyLiftCurve.liftCurve     = simCurves.LiftCurve;
            dest.BodyLiftCurve.dragCurve     = simCurves.DragCurve;
            dest.BodyLiftCurve.dragMachCurve = simCurves.DragMachCurve;
            dest.BodyLiftCurve.liftMachCurve = simCurves.LiftMachCurve;

            dest.SurfaceCurves.dragCurveMultiplier = simCurves.DragCurveMultiplier;
            dest.SurfaceCurves.dragCurveSurface    = simCurves.DragCurveSurface;
            dest.SurfaceCurves.dragCurveTail       = simCurves.DragCurveTail;
            dest.SurfaceCurves.dragCurveTip        = simCurves.DragCurveTip;
        }
Esempio n. 6
0
        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);
        }
Esempio n. 7
0
        //TODO : rewrite the cube calls to only store and update the minimum needed data ( AreaOccluded + WeightedDrag ?)

        protected static void CopyDragCubesList(DragCubeList source, DragCubeList dest)
        {
            dest.ClearCubes();

            dest.None = source.None;

            // Procedural need access to part so things gets bad quick.
            dest.Procedural = false;

            for (int i = 0; i < source.Cubes.Count; i++)
            {
                DragCube c = new DragCube();
                CopyDragCube(source.Cubes[i], c);
                dest.Cubes.Add(c);
            }

            dest.SetDragWeights();

            for (int i=0; i<6; i++)
            {
                dest.WeightedArea[i] = source.WeightedArea[i];
                dest.WeightedDrag[i] = source.WeightedDrag[i];
                dest.AreaOccluded[i] = source.AreaOccluded[i];
                dest.WeightedDepth[i] = source.WeightedDepth[i];
            }

            dest.SetDragWeights();

            // We are missing PostOcclusionArea but it seems to be used in Thermal only
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        //*******************************************************
        public static Vector3 SimAeroForce(CelestialBody body, IShipconstruct vessel, Vector3 v_wrld_vel, double altitude, double latitude = 0.0, bool verbose = false)
        {
            //Profiler.Start("SimAeroForce");
            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
                Vector3d part_force = Vector3d.zero;
#endif

                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;

                float pseudoreynolds   = (float)(rho * v_wrld_vel.magnitude);
                float pseudoredragmult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate(pseudoreynolds);

                //Profiler.Start("SimAeroForce#Body");
                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.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.SetDragWeights();
                            cubes.SetPartOcclusion();
                            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));
                        }

#if DEBUG
                        if (verbose && i == 0)
                        {
                            Debug.Log(p.name);
                            Debug.Log(string.Format("{0}, {1}, {2}, {3}, {4}, {5}",
                                                    p.DragCubes.AreaOccluded[0], p.DragCubes.AreaOccluded[1], p.DragCubes.AreaOccluded[2], p.DragCubes.AreaOccluded[3], p.DragCubes.AreaOccluded[4], p.DragCubes.AreaOccluded[5]));
                            Debug.Log(string.Format("{0}, {1}, {2}, {3}, {4}, {5}",
                                                    p.DragCubes.WeightedDrag[0], p.DragCubes.WeightedDrag[1], p.DragCubes.WeightedDrag[2], p.DragCubes.WeightedDrag[3], p.DragCubes.WeightedDrag[4], p.DragCubes.WeightedDrag[5]));
                            Debug.Log(p_drag_data.area);
                            Debug.Log(p_drag_data.exposedArea);
                        }
#endif

                        drag = p_drag_data.areaDrag * PhysicsGlobals.DragCubeMultiplier;

                        liftForce = p_drag_data.liftForce;
                    }

                    dragForce = -(Vector3d)sim_dragVectorDir * drag;

                    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;
                }
                dragForce *= dyn_pressure * pseudoredragmult * PhysicsGlobals.DragMultiplier;

                total_drag += dragForce;
#if DEBUG
                part_force += dragForce;
#endif

                // 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
#if DEBUG
                    part_force += bodyLift;
#endif
                    total_lift += bodyLift;
                }
                //Profiler.Stop("SimAeroForce#Body");

                // Find ModuleLifingSurface for wings and liftforce.
                // Should catch control surface as it is a subclass
                //Profiler.Start("SimAeroForce#LiftModule");
                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;
#if DEBUG
                        part_force += local_drag + local_lift;
#endif
                    }
                }
                //Profiler.Stop("SimAeroForce#LiftModule");

#if DEBUG
                if (verbose)
                {
                    Debug.Log(p.name + ": " + part_force);
                }
#endif
            }
            // RETURN STUFF
            Vector3 force = total_lift + total_drag;
            //Profiler.Stop("SimAeroForce");
            return(force);
        }
Esempio n. 10
0
        //*******************************************************
        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);
        }
Esempio n. 11
0
        //*******************************************************
        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));
        }
Esempio n. 13
0
                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));
                }