Exemplo n.º 1
0
        void Start()
        {
            //Get primary celestial body (i.e. Kerbin)
            kerbin = Util.getbody();
            //Check to see if weather is enabled
            wx_enabled = Util.getWindBool();
            Util.Log("Wx Enabled, " + wx_enabled.ToString());
            Util.CacheKWPLocalization();
            //Initialize wind vector
            kwind.x = 0.0f;
            kwind.y = 0.0f;
            kwind.z = 0.0f;

            //Initialize variable lists
            for (int i = 0; i < 6; i++)
            {
                vel_list.Add(0);
            }
            for (int i = 0; i < nvars + 1; i++)
            {
                wx_list3d.Add(0);
            }
            for (int i = 0; i < nsvars; i++)
            {
                wx_list2d.Add(0);
            }
            //Get wind direction specificity
            wstr = HighLogic.CurrentGame.Parameters.CustomParams <KerbalWxCustomParams_Sec3>().windstrs;

            //Get variable units
            wind_unit   = HighLogic.CurrentGame.Parameters.CustomParams <KerbalWxCustomParams_Sec3>().windunit;
            temp_unit   = HighLogic.CurrentGame.Parameters.CustomParams <KerbalWxCustomParams_Sec3>().tempunit;
            pres_unit   = HighLogic.CurrentGame.Parameters.CustomParams <KerbalWxCustomParams_Sec3>().presunit;
            precip_unit = HighLogic.CurrentGame.Parameters.CustomParams <KerbalWxCustomParams_Sec3>().precipunit;
            vel_unit    = HighLogic.CurrentGame.Parameters.CustomParams <KerbalWxCustomParams_Sec3>().velunit;

            //Get Wx Type (Climatology or Point forecast)
            use_climo = Util.useCLIM();
            use_point = Util.useWX();

            //Initialize class instance based on Wx type

            _kwx_climo = (KerbalWxClimo)FindObjectOfType(typeof(KerbalWxClimo));
            _kwx_point = (KerbalWxPoint)FindObjectOfType(typeof(KerbalWxPoint));

            //Add to toolbar
            AddToolbarButton();
            Util.Log("Instantiate Toolbar and KWP");
        }
        void Start()
        {
            //Check if KWP is enabled by default
            wx_enabled = HighLogic.CurrentGame.Parameters.CustomParams <KerbalWxCustomParams>().WxEnabled;
            //Util.Log("MFI: wx_enabled: " + wx_enabled);
            //Determine MPAS data set
            use_climo = Util.useCLIM();
            use_point = Util.useWX();
            aero      = Util.allowAero();
            thermo    = Util.allowThermo();

            //Check if FAR is available
            haveFAR = RegisterWithFAR();
            //Get instance of climate api
            _clim_api = new climate_api();
            _wx_api   = new weather_api();

            _clim_wx  = new KerbalWxClimo();
            _point_wx = new KerbalWxPoint();

            if (!haveFAR)
            {
                Vessel v = FlightGlobals.ActiveVessel;

                //Override KSP's FlightIntegrator using the ModularFlightIntegrator
                Util.Log("Register Modular FlightIntegrator");
                if (aero)
                {
                    ModularFI.ModularFlightIntegrator.RegisterUpdateAerodynamicsOverride(UpdateAerodynamics);
                }
                if (thermo)
                {
                    ModularFI.ModularFlightIntegrator.RegisterUpdateThermodynamicsPre(UpdateThermodynamicsPre);
                }

                if ((aero) || (thermo))
                {
                    //Util.Log("MFI On");
                    Util.setMFI(true);
                }
            }
            GameObject.Destroy(this);
        }
        //Update aerodynamics
        //Adapted from KSP Trajectories, Kerbal Wind Tunnel, FAR, and AeroGUI
        void UpdateAerodynamics(ModularFI.ModularFlightIntegrator fi, Part part)
        {
            Vessel v = FlightGlobals.ActiveVessel;

            wx_enabled = Util.getWindBool(); //Is weather enabled?
            use_climo  = Util.useCLIM();     //Are we using the climatology
            use_point  = Util.useWX();       //Are we using MPAS point time-series

            //Get main vessel and get reference to Kerbin (i.e. celestial body)
            kerbin = Util.getbody();

            //Get wind vector (initialize to zero)
            Vector3d windVec = Vector3d.zero;

            if (use_climo)
            {
                //Retrieve wind vector from climatology
                windVec = KerbalWxClimo.getWSWind(); // .GetWind(FlightGlobals.currentMainBody, part, rb.position);
            }
            else if (use_point)
            {
                //Retrieve wind vector from point forecast
                windVec = KerbalWxPoint.getWSWind(); // .GetWind(FlightGlobals.currentMainBody, part, rb.position);
            }
            //Check to see if root part is in list. If not do not perform aero update.
            //This avoids updating aerodynamics of parts that have been decoupled and are no longer part of the active vessel.
            bool hasPart = false;

            for (int i = 0; i < fi.PartThermalDataCount; i++)
            {
                PartThermalData pttd  = fi.partThermalDataList[i];
                Part            ppart = pttd.part;
                if (ppart == v.rootPart)
                {
                    hasPart = true;
                }
            }

            if (!hasPart)
            {
                return;
            }

            //Get position of current vessel
            double vheight = v.altitude;
            double vlat    = v.latitude;
            double vlng    = v.longitude;

            double air_pressure; double air_density; double soundSpeed;
            //Define gamma (i.e. ratio between specific heat of dry air at constant pressure and specific heat of dry air at constant volume: cp/cv).
            double gamma = 1.4;
            //Util.Log("MFI wx_enabled: " + wx_enabled+", use_point: "+use_point+", use_climo: "+use_climo);
            bool inatmos = false;

            if ((FlightGlobals.ActiveVessel.mainBody == kerbin) && (v.altitude <= 70000) && (wx_enabled))
            {
                if (use_climo)
                {
                    //Retrieve air pressure/density at vessel location
                    climate_api.wx_aero ptd = _clim_api.getPTD(vlat, vlng, vheight);
                    air_density  = ptd.density;
                    air_pressure = ptd.pressure;
                }
                else
                {
                    //Retrieve air pressure/density at vessel location
                    weather_api.wx_aero ptd = _wx_api.getPTD(vheight);
                    air_density  = ptd.density;
                    air_pressure = ptd.pressure;
                }
                //Compute speed of sound based on air pressure and air density.
                soundSpeed = Math.Sqrt(gamma * (air_pressure / air_density));
                inatmos    = true;
            }
            else
            {
                soundSpeed = v.speedOfSound;
            }
            //Get height from surface
            double hsfc = v.heightFromTerrain;
            //Determine if vessel is grounded (i.e. on the ground)
            bool isgrounded = true;

            if (hsfc >= 10)
            {
                isgrounded = false;
            }

            //If FAR is present FAR will handle aerodynamic updates or if we're not on Kerbin (i.e. in a different atmosphere)
            if (part.Modules.Contains <ModuleAeroSurface>() || (part.Modules.Contains("MissileLauncher") && part.vessel.rootPart == part) || (haveFAR) || (v.mainBody != kerbin) || (!inatmos))
            {
                fi.BaseFIUpdateAerodynamics(part);

                if (((!part.DragCubes.None) && (!part.hasLiftModule)) || (part.name.Contains("kerbalEVA")))
                {
                    double drag  = part.DragCubes.AreaDrag * PhysicsGlobals.DragCubeMultiplier * fi.pseudoReDragMult;
                    float  pscal = (float)(part.dynamicPressurekPa * drag * PhysicsGlobals.DragMultiplier);

                    //Estimate lift force from body lift
                    Vector3 lforce = part.transform.rotation * (part.bodyLiftScalar * part.DragCubes.LiftForce);
                    lforce = Vector3.ProjectOnPlane(lforce, -part.dragVectorDir);
                }
                return;
            }
            else
            {
                fi.BaseFIUpdateAerodynamics(part); //Run base aerodynamic update first (fix bug where parachutes experience multiplicative acceleration)

                // Get rigid body
                Rigidbody rb = part.rb;
                if (rb)
                {
                    if (part == v.rootPart)
                    {
                        v.mach = 0;
                    }
                    //Retrieve wind vector at vessel location
                    //Vector3d windVec = KWPWind.GetWind(FlightGlobals.currentMainBody, part, rb.position);
                    //Util.Log("MFI windVec: " + windVec + ", use_point: " + use_point + ", use_climo: " + use_climo);
                    //Retrieve world velocity without wind vector
                    Vector3 velocity_nowind = rb.velocity + Krakensbane.GetFrameVelocity();
                    //Compute mach number
                    double mach_nowind = velocity_nowind.magnitude / soundSpeed;

                    Vector3 drag_sum = Vector3.zero;
                    Vector3 lift_sum = Vector3.zero;

                    if (((!part.DragCubes.None) && (!part.hasLiftModule)) || (part.name.Contains("kerbalEVA")))
                    {
                        //Estimate Drag force
                        double pseudoreynolds   = part.atmDensity * Math.Abs(velocity_nowind.magnitude);
                        double pseudoReDragMult = PhysicsGlobals.DragCurvePseudoReynolds.Evaluate((float)pseudoreynolds);
                        double drag             = part.DragCubes.AreaDrag * PhysicsGlobals.DragCubeMultiplier * pseudoReDragMult;
                        float  pscal            = (float)(part.dynamicPressurekPa * drag * PhysicsGlobals.DragMultiplier);
                        drag_sum += -part.dragVectorDir * pscal;

                        //Estimate lift force from body lift
                        float   pbodyLiftScalar = (float)(part.dynamicPressurekPa * part.bodyLiftMultiplier * PhysicsGlobals.BodyLiftMultiplier) * PhysicsGlobals.GetLiftingSurfaceCurve("BodyLift").liftMachCurve.Evaluate((float)part.machNumber);
                        Vector3 lforce2         = part.transform.rotation * (pbodyLiftScalar * part.DragCubes.LiftForce);
                        lforce2   = Vector3.ProjectOnPlane(lforce2, -part.dragVectorDir);
                        lift_sum += lforce2;
                    }

                    //Util.Log("BodyLift Default: " + part.bodyLiftScalar + ", Lift Force: " + lift_force);
                    //Loop through each part module to look for lifting surfaces
                    for (int j = 0; j < part.Modules.Count; ++j)
                    {
                        var m = part.Modules[j];
                        if (m is ModuleLiftingSurface)
                        {
                            //Initialize force vectors
                            Vector3 lforce = Vector3.zero;
                            Vector3 dforce = Vector3.zero;
                            //Convert kPa to Pa
                            double liftQ = part.dynamicPressurekPa * 1000;
                            ModuleLiftingSurface wing = (ModuleLiftingSurface)m;

                            //Get wing coefficients
                            Vector3 nVel       = Vector3.zero;
                            Vector3 liftVector = Vector3.zero;
                            float   liftdot;
                            float   absdot;
                            wing.SetupCoefficients(velocity_nowind, out nVel, out liftVector, out liftdot, out absdot);

                            //Get Lift/drag force
                            lforce = wing.GetLiftVector(liftVector, liftdot, absdot, liftQ, (float)part.machNumber);
                            dforce = wing.GetDragVector(nVel, absdot, liftQ);

                            if (part.name.Contains("kerbalEVA"))
                            {
                                continue;
                            }
                            drag_sum += dforce;
                            //lift_sum += lforce;
                            if (isgrounded)
                            {
                                lift_sum += lforce;
                            }
                        }
                    }

                    //Retrieve world velocity and subtract off wind vector
                    Vector3 velocity_wind = rb.velocity + Krakensbane.GetFrameVelocity() - windVec;
                    //Compute mach number
                    double mach_wind = velocity_wind.magnitude / soundSpeed;
                    //Set mach number
                    part.machNumber = mach_wind; // *mdiv;
                    if (part == v.rootPart)
                    {
                        fi.mach = mach_wind;
                    }
                    //Get drag and lift forces with wind
                    List <Vector3> total_forces = GetDragLiftForce(fi, part, velocity_wind, windVec, part.machNumber, isgrounded);

                    //Compute difference in drag/lift with and without wind.
                    Vector3 total_drag = total_forces[0] - drag_sum;
                    Vector3 total_lift = total_forces[1] - lift_sum;

                    //Calculate force due to wind
                    Vector3 force = total_lift + total_drag;

                    if (double.IsNaN(force.sqrMagnitude) || (((float)force.magnitude).NearlyEqual(0.0f)))
                    {
                        force = Vector3d.zero;
                    }
                    else
                    {
                        //Adapted from FAR - apply numerical control factor
                        float numericalControlFactor = (float)(part.rb.mass * velocity_wind.magnitude * 0.67 / (force.magnitude * TimeWarp.fixedDeltaTime));
                        force *= Math.Min(numericalControlFactor, 1);
                        part.AddForce(force);
                    }
                    v.mach = fi.mach;
                }
            }
        }