Exemple #1
0
        public static void ResetEditor()
        {
            Color crossSection = GUIColors.GetColor(3);

            crossSection.a = 0.8f;

            Color crossSectionDeriv = GUIColors.GetColor(2);

            crossSectionDeriv.a = 0.8f;
            instance._areaRulingOverlay.RestartOverlay();
            //instance._areaRulingOverlay = new EditorAreaRulingOverlay(new Color(0.05f, 0.05f, 0.05f, 0.7f), crossSection, crossSectionDeriv, 10, 5);
            RequestUpdateVoxel();
        }
        void Start()
        {
            if (CompatibilityChecker.IsAllCompatible() && instance == null)
            {
                instance = this;
            }
            else
            {
                GameObject.Destroy(this);
                return;
            }

            _vehicleAero = new VehicleAerodynamics();

            guiRect = new Rect(Screen.width / 4, Screen.height / 6, 10, 10);

            _instantSim = new InstantConditionSim();
            GUIDropDown <int>           flapSettingDropDown   = new GUIDropDown <int>(new string[] { "0 (up)", "1 (init climb)", "2 (takeoff)", "3 (landing)" }, new int[] { 0, 1, 2, 3 }, 0);
            GUIDropDown <CelestialBody> celestialBodyDropdown = CreateBodyDropdown();

            modeDropdown = new GUIDropDown <FAREditorMode>(FAReditorMode_str, new FAREditorMode[] { FAREditorMode.STATIC, FAREditorMode.STABILITY, FAREditorMode.SIMULATION, FAREditorMode.AREA_RULING });

            _simManager = new EditorSimManager(_instantSim);

            _editorGraph     = new StaticAnalysisGraphGUI(_simManager, flapSettingDropDown, celestialBodyDropdown);
            _stabDeriv       = new StabilityDerivGUI(_simManager, flapSettingDropDown, celestialBodyDropdown);
            _stabDerivLinSim = new StabilityDerivSimulationGUI(_simManager);

            Color crossSection = GUIColors.GetColor(3);

            crossSection.a = 0.8f;

            Color crossSectionDeriv = GUIColors.GetColor(2);

            crossSectionDeriv.a = 0.8f;

            _areaRulingOverlay = new EditorAreaRulingOverlay(new Color(0.05f, 0.05f, 0.05f, 0.7f), crossSection, crossSectionDeriv, 10, 5);
            guiRect.height     = 500;
            guiRect.width      = 650;

            GameEvents.onEditorPartEvent.Add(UpdateGeometryEvent);
            GameEvents.onEditorUndo.Add(ResetEditorEvent);
            GameEvents.onEditorRedo.Add(ResetEditorEvent);
            GameEvents.onEditorShipModified.Add(ResetEditorEvent);
            GameEvents.onEditorLoad.Add(ResetEditorEvent);

            GameEvents.onGUIEngineersReportReady.Add(AddDesignConcerns);
            GameEvents.onGUIEngineersReportDestroy.Add(RemoveDesignConcerns);

            RequestUpdateVoxel();
        }
        public GraphData MachNumberSweep(
            double aoAdegrees,
            double pitch,
            double lowerBound,
            double upperBound,
            int numPoints,
            int flapSetting,
            bool spoilers,
            CelestialBody body
            )
        {
            FARAeroUtil.UpdateCurrentActiveBody(body);

            FARAeroUtil.ResetEditorParts();

            var ClValues    = new double[numPoints];
            var CdValues    = new double[numPoints];
            var CmValues    = new double[numPoints];
            var LDValues    = new double[numPoints];
            var AlphaValues = new double[numPoints];

            var input = new InstantConditionSimInput(aoAdegrees, 0, 0, 0, 0, 0, 0, pitch, flapSetting, spoilers);

            for (int i = 0; i < numPoints; i++)
            {
                input.machNumber = i / (double)numPoints * (upperBound - lowerBound) + lowerBound;

                if (input.machNumber.NearlyEqual(0))
                {
                    input.machNumber = 0.001;
                }

                _instantCondition.GetClCdCmSteady(input, out InstantConditionSimOutput output, i == 0);
                AlphaValues[i] = input.machNumber;
                ClValues[i]    = output.Cl;
                CdValues[i]    = output.Cd;
                CmValues[i]    = output.Cm;
                LDValues[i]    = output.Cl * 0.1 / output.Cd;
            }

            var data = new GraphData {
                xValues = AlphaValues
            };

            data.AddData(ClValues, GUIColors.GetColor(0), Localizer.Format("FARAbbrevCl"), true);
            data.AddData(CdValues, GUIColors.GetColor(1), Localizer.Format("FARAbbrevCd"), true);
            data.AddData(CmValues, GUIColors.GetColor(2), Localizer.Format("FARAbbrevCm"), true);
            data.AddData(LDValues, GUIColors.GetColor(3), Localizer.Format("FARAbbrevL_D"), true);

            return(data);
        }
        public GraphData MachNumberSweep(double aoAdegrees, double pitch, double lowerBound, double upperBound, int numPoints, int flapSetting, bool spoilers, CelestialBody body)
        {
            FARAeroUtil.UpdateCurrentActiveBody(body);

            FARAeroUtil.ResetEditorParts();

            double[] ClValues    = new double[(int)numPoints];
            double[] CdValues    = new double[(int)numPoints];
            double[] CmValues    = new double[(int)numPoints];
            double[] LDValues    = new double[(int)numPoints];
            double[] AlphaValues = new double[(int)numPoints];

            InstantConditionSimInput input = new InstantConditionSimInput(aoAdegrees, 0, 0, 0, 0, 0, FlightEnv.NewDefaultVal(body), pitch, flapSetting, spoilers);

            for (int i = 0; i < numPoints; i++)
            {
                input.fltenv.MachNumber = lowerBound + (upperBound - lowerBound) * (i == 0? 0 : i / (numPoints - 1.0));

                if (input.fltenv.MachNumber < 1E-3)
                {
                    input.fltenv.MachNumber = 1E-3;
                }

                InstantConditionSimOutput output;

                _instantCondition.GetClCdCmSteady(input, out output, i == 0, false);
                AlphaValues[i] = input.fltenv.MachNumber;
                ClValues[i]    = output.Cl;
                CdValues[i]    = output.Cd;
                CmValues[i]    = output.Cm;
                LDValues[i]    = output.Cl * 0.1 / output.Cd;
            }

            GraphData data = new GraphData();

            data.xValues = AlphaValues;
            data.AddData(ClValues, GUIColors.GetColor(0), Localizer.Format("FARAbbrevCl"), true);
            data.AddData(CdValues, GUIColors.GetColor(1), Localizer.Format("FARAbbrevCd"), true);
            data.AddData(CmValues, GUIColors.GetColor(2), Localizer.Format("FARAbbrevCm"), true);
            data.AddData(LDValues, GUIColors.GetColor(3), Localizer.Format("FARAbbrevL_D"), true);

            data.exportdata.AddSizeVariables(_instantCondition, pitch, flapSetting, spoilers);
            data.exportdata.AddMachSweepXVariable(aoAdegrees, AlphaValues);
            data.exportdata.AddYVariables(data);

            return(data);
        }
Exemple #5
0
        public GraphData MachNumberSweep(double aoAdegrees, double pitch, double lowerBound, double upperBound, int numPoints, int flapSetting, bool spoilers, CelestialBody body)
        {
            FARAeroUtil.UpdateCurrentActiveBody(body);

            FARAeroUtil.ResetEditorParts();

            double[] ClValues    = new double[(int)numPoints];
            double[] CdValues    = new double[(int)numPoints];
            double[] CmValues    = new double[(int)numPoints];
            double[] LDValues    = new double[(int)numPoints];
            double[] AlphaValues = new double[(int)numPoints];

            InstantConditionSimInput input = new InstantConditionSimInput(aoAdegrees, 0, 0, 0, 0, 0, 0, pitch, flapSetting, spoilers);

            for (int i = 0; i < numPoints; i++)
            {
                input.machNumber = i / (double)numPoints * (upperBound - lowerBound) + lowerBound;

                if (input.machNumber == 0)
                {
                    input.machNumber = 0.001;
                }

                InstantConditionSimOutput output;

                _instantCondition.GetClCdCmSteady(input, out output, i == 0);
                AlphaValues[i] = input.machNumber;
                ClValues[i]    = output.Cl;
                CdValues[i]    = output.Cd;
                CmValues[i]    = output.Cm;
                LDValues[i]    = output.Cl * 0.1 / output.Cd;
            }

            GraphData data = new GraphData();

            data.xValues = AlphaValues;
            data.AddData(ClValues, GUIColors.GetColor(0), "Cl", true);
            data.AddData(CdValues, GUIColors.GetColor(1), "Cd", true);
            data.AddData(CmValues, GUIColors.GetColor(2), "Cm", true);
            data.AddData(LDValues, GUIColors.GetColor(3), "L/D", true);

            return(data);
        }
Exemple #6
0
        public GraphData RunTransientSimLateral(StabilityDerivOutput vehicleData, double endTime, double initDt, double[] InitCond)
        {
            SimMatrix A = new SimMatrix(4, 4);

            A.PrintToConsole();

            int i   = 0;
            int j   = 0;
            int num = 0;

            double[] Derivs = new double[27];

            vehicleData.stabDerivs.CopyTo(Derivs, 0);

            Derivs[15] = Derivs[15] / vehicleData.nominalVelocity;
            Derivs[18] = Derivs[18] / vehicleData.nominalVelocity;
            Derivs[21] = Derivs[21] / vehicleData.nominalVelocity - 1;

            double Lb = Derivs[16] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));
            double Nb = Derivs[17] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));

            double Lp = Derivs[19] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));
            double Np = Derivs[20] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));

            double Lr = Derivs[22] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));
            double Nr = Derivs[23] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));

            Derivs[16] = Lb + Derivs[26] / Derivs[0] * Nb;
            Derivs[17] = Nb + Derivs[26] / Derivs[2] * Lb;

            Derivs[19] = Lp + Derivs[26] / Derivs[0] * Np;
            Derivs[20] = Np + Derivs[26] / Derivs[2] * Lp;

            Derivs[22] = Lr + Derivs[26] / Derivs[0] * Nr;
            Derivs[23] = Nr + Derivs[26] / Derivs[2] * Lr;

            for (int k = 0; k < Derivs.Length; k++)
            {
                double f = Derivs[k];
                if (num < 15)
                {
                    num++;              //Avoid Ix, Iy, Iz and long derivs
                    continue;
                }
                else
                {
                    num++;
                }
                FARLogger.Info("" + i + "," + j);
                if (i <= 2)
                {
                    A.Add(f, i, j);
                }

                if (j < 2)
                {
                    j++;
                }
                else
                {
                    j = 0;
                    i++;
                }
            }
            A.Add(_instantCondition.CalculateAccelerationDueToGravity(vehicleData.body, vehicleData.altitude) * Math.Cos(vehicleData.stableAoA * Math.PI / 180) / vehicleData.nominalVelocity, 3, 0);
            A.Add(1, 1, 3);


            A.PrintToConsole();                //We should have an array that looks like this:

            /*             i --------------->
             *       j  [ Yb / u0 , Yp / u0 , -(1 - Yr/ u0) ,  g Cos(θ0) / u0 ]
             *       |  [   Lb    ,    Lp   ,      Lr       ,          0          ]
             *       |  [   Nb    ,    Np   ,      Nr       ,          0          ]
             *      \ / [    0    ,    1    ,      0        ,          0          ]
             *       V                              //And one that looks like this:
             *
             *          [ Z e ]
             *          [ X e ]
             *          [ M e ]
             *          [  0  ]
             *
             *
             */
            RungeKutta4 transSolve = new RungeKutta4(endTime, initDt, A, InitCond);

            transSolve.Solve();

            GraphData lines = new GraphData();

            lines.xValues = transSolve.time;

            double[] yVal = transSolve.GetSolution(0);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(3), "β", true);

            yVal = transSolve.GetSolution(1);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(2), "p", true);

            yVal = transSolve.GetSolution(2);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(1), "r", true);

            yVal = transSolve.GetSolution(3);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(0), "φ", true);

            /*graph.SetBoundaries(0, endTime, -10, 10);
             * graph.SetGridScaleUsingValues(1, 5);
             * graph.horizontalLabel = "time";
             * graph.verticalLabel = "value";
             * graph.Update();*/

            return(lines);
        }
Exemple #7
0
        public GraphData RunTransientSimLongitudinal(StabilityDerivOutput vehicleData, double endTime, double initDt, double[] InitCond)
        {
            SimMatrix A = new SimMatrix(4, 4);
            SimMatrix B = new SimMatrix(1, 4);

            A.PrintToConsole();

            int i   = 0;
            int j   = 0;
            int num = 0;

            double[] Derivs = new double[27];

            for (int k = 0; k < vehicleData.stabDerivs.Length; k++)
            {
                double f = vehicleData.stabDerivs[k];
                if (num < 3 || num >= 15)
                {
                    num++;              //Avoid Ix, Iy, Iz
                    continue;
                }
                else
                {
                    num++;
                }
                FARLogger.Info(i + "," + j);
                if (i <= 2)
                {
                    if (num == 10)
                    {
                        A.Add(f + vehicleData.nominalVelocity, i, j);
                    }
                    else
                    {
                        A.Add(f, i, j);
                    }
                }
                else
                {
                    B.Add(f, 0, j);
                }
                if (j < 2)
                {
                    j++;
                }
                else
                {
                    j = 0;
                    i++;
                }
            }
            A.Add(-_instantCondition.CalculateAccelerationDueToGravity(vehicleData.body, vehicleData.altitude), 3, 1);
            A.Add(1, 2, 3);


            A.PrintToConsole();                //We should have an array that looks like this:

            /*             i --------------->
             *       j  [ Z w , Z u , Z q  + u,  0 ]
             *       |  [ X w , X u , X q     , -g ]
             *       |  [ M w , M u , M q     ,  0 ]
             *      \ / [  0  ,  0  ,  1      ,  0 ]
             *       V                              //And one that looks like this:
             *
             *          [ Z e ]
             *          [ X e ]
             *          [ M e ]
             *          [  0  ]
             *
             *
             */

            RungeKutta4 transSolve = new RungeKutta4(endTime, initDt, A, InitCond);

            transSolve.Solve();

            GraphData lines = new GraphData();

            lines.xValues = transSolve.time;

            double[] yVal = transSolve.GetSolution(0);
            ScaleAndClampValues(yVal, 1, 50);
            lines.AddData(yVal, GUIColors.GetColor(3), "w", true);

            yVal = transSolve.GetSolution(1);
            ScaleAndClampValues(yVal, 1, 50);
            lines.AddData(yVal, GUIColors.GetColor(2), "u", true);

            yVal = transSolve.GetSolution(2);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(1), "q", true);

            yVal = transSolve.GetSolution(3);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(0), "θ", true);

            /*graph.SetBoundaries(0, endTime, -10, 10);
             * graph.SetGridScaleUsingValues(1, 5);
             * graph.horizontalLabel = "time";
             * graph.verticalLabel = "value";
             * graph.Update();*/

            return(lines);
        }
Exemple #8
0
        public GraphData AngleOfAttackSweep(double machNumber, double pitch, double lowerBound, double upperBound, int numPoints, int flapSetting, bool spoilers, CelestialBody body)
        {
            if (machNumber == 0)
            {
                machNumber = 0.001;
            }

            InstantConditionSimInput input = new InstantConditionSimInput(0, 0, 0, 0, 0, 0, machNumber, pitch, flapSetting, spoilers);

            FARAeroUtil.UpdateCurrentActiveBody(body);

            FARAeroUtil.ResetEditorParts();


            double[] ClValues    = new double[(int)numPoints];
            double[] CdValues    = new double[(int)numPoints];
            double[] CmValues    = new double[(int)numPoints];
            double[] LDValues    = new double[(int)numPoints];
            double[] AlphaValues = new double[(int)numPoints];
            double[] ClValues2   = new double[(int)numPoints];
            double[] CdValues2   = new double[(int)numPoints];
            double[] CmValues2   = new double[(int)numPoints];
            double[] LDValues2   = new double[(int)numPoints];

            for (int i = 0; i < 2 * numPoints; i++)
            {
                double angle = 0;
                if (i < numPoints)
                {
                    angle = i / (double)numPoints * (upperBound - lowerBound) + lowerBound;
                }
                else
                {
                    angle = (i - (double)numPoints + 1) / (double)numPoints * (lowerBound - upperBound) + upperBound;
                }

                input.alpha = angle;

                InstantConditionSimOutput output;

                _instantCondition.GetClCdCmSteady(input, out output, i == 0);

                //                MonoBehaviour.print("Cl: " + Cl + " Cd: " + Cd);
                if (i < numPoints)
                {
                    AlphaValues[i] = angle;
                    ClValues[i]    = output.Cl;
                    CdValues[i]    = output.Cd;
                    CmValues[i]    = output.Cm;
                    LDValues[i]    = output.Cl * 0.1 / output.Cd;
                }
                else
                {
                    ClValues2[numPoints * 2 - 1 - i] = output.Cl;
                    CdValues2[numPoints * 2 - 1 - i] = output.Cd;
                    CmValues2[numPoints * 2 - 1 - i] = output.Cm;
                    LDValues2[numPoints * 2 - 1 - i] = output.Cl * 0.1 / output.Cd;
                }
            }

            GraphData data = new GraphData();

            data.xValues = AlphaValues;
            data.AddData(ClValues2, GUIColors.GetColor(0) * 0.5f, "Cl2", false);
            data.AddData(ClValues, GUIColors.GetColor(0), "Cl", true);

            data.AddData(CdValues2, GUIColors.GetColor(1) * 0.5f, "Cd2", false);
            data.AddData(CdValues, GUIColors.GetColor(1), "Cd", true);

            data.AddData(CmValues2, GUIColors.GetColor(2) * 0.5f, "Cm2", false);
            data.AddData(CmValues, GUIColors.GetColor(2), "Cm", true);

            data.AddData(LDValues2, GUIColors.GetColor(3) * 0.5f, "L/D2", false);
            data.AddData(LDValues, GUIColors.GetColor(3), "L/D", true);


            return(data);
        }
Exemple #9
0
        private void UpdateAeroDisplay()
        {
            Vector3 worldDragArrow = Vector3.zero;
            Vector3 worldLiftArrow = Vector3.zero;

            if ((PhysicsGlobals.AeroForceDisplay || PhysicsGlobals.AeroDataDisplay) && !part.ShieldedFromAirstream)
            {
                Vector3 worldVelNorm = partTransform.localToWorldMatrix.MultiplyVector(partLocalVelNorm);
                worldDragArrow = Vector3.Dot(worldSpaceAeroForce, worldVelNorm) * worldVelNorm;
                worldLiftArrow = worldSpaceAeroForce - worldDragArrow;
            }

            if (PhysicsGlobals.AeroForceDisplay && !part.ShieldedFromAirstream)
            {
                if (liftArrow == null)
                {
                    liftArrow = ArrowPointer.Create(partTransform,
                                                    Vector3.zero,
                                                    worldLiftArrow,
                                                    worldLiftArrow.magnitude *
                                                    FARKSPAddonFlightScene.FARAeroForceDisplayScale,
                                                    GUIColors.GetColor(0),
                                                    true);
                }
                else
                {
                    liftArrow.Direction = worldLiftArrow;
                    liftArrow.Length    = worldLiftArrow.magnitude * FARKSPAddonFlightScene.FARAeroForceDisplayScale;
                }

                if (dragArrow == null)
                {
                    dragArrow = ArrowPointer.Create(partTransform,
                                                    Vector3.zero,
                                                    worldDragArrow,
                                                    worldDragArrow.magnitude *
                                                    FARKSPAddonFlightScene.FARAeroForceDisplayScale,
                                                    GUIColors.GetColor(1),
                                                    true);
                }
                else
                {
                    dragArrow.Direction = worldDragArrow;
                    dragArrow.Length    = worldDragArrow.magnitude * FARKSPAddonFlightScene.FARAeroForceDisplayScale;
                }

                if (FARDebugValues.showMomentArrows)
                {
                    if (momentArrow == null)
                    {
                        momentArrow = ArrowPointer.Create(partTransform,
                                                          Vector3.zero,
                                                          worldSpaceTorque,
                                                          worldSpaceTorque.magnitude *
                                                          FARKSPAddonFlightScene.FARAeroForceDisplayScale,
                                                          GUIColors.GetColor(2),
                                                          true);
                    }
                    else
                    {
                        momentArrow.Direction = -worldSpaceTorque;
                        momentArrow.Length    =
                            worldSpaceTorque.magnitude * FARKSPAddonFlightScene.FARAeroForceDisplayScale;
                    }
                }
            }
            else
            {
                if (!(liftArrow is null))
                {
                    Destroy(liftArrow);
                    liftArrow = null;
                }

                if (!(dragArrow is null))
                {
                    Destroy(dragArrow);
                    dragArrow = null;
                }

                if (!(momentArrow is null))
                {
                    Destroy(momentArrow);
                    momentArrow = null;
                }
            }

            if (PhysicsGlobals.AeroDataDisplay && !part.ShieldedFromAirstream)
            {
                if (!fieldsVisible)
                {
                    Fields["dragForce"].guiActive = true;
                    Fields["liftForce"].guiActive = true;
                    fieldsVisible = true;
                }

                dragForce = worldDragArrow.magnitude;
                liftForce = worldLiftArrow.magnitude;
            }
            else if (fieldsVisible)
            {
                Fields["dragForce"].guiActive = false;
                Fields["liftForce"].guiActive = false;
                fieldsVisible = false;
            }
        }
Exemple #10
0
        public static GraphData RunTransientSimLongitudinal(
            StabilityDerivOutput vehicleData,
            double endTime,
            double initDt,
            double[] InitCond
            )
        {
            var A = new SimMatrix(4, 4);
            var B = new SimMatrix(1, 4);

            A.PrintToConsole();

            int i   = 0;
            int j   = 0;
            int num = 0;

            foreach (double f in vehicleData.stabDerivs)
            {
                if (num < 3 || num >= 15)
                {
                    num++; //Avoid Ix, Iy, Iz
                    continue;
                }

                num++;
                FARLogger.Info(i + "," + j);
                if (i <= 2)
                {
                    if (num == 10)
                    {
                        A.Add(f + vehicleData.nominalVelocity, i, j);
                    }
                    else
                    {
                        A.Add(f, i, j);
                    }
                }
                else
                {
                    B.Add(f, 0, j);
                }
                if (j < 2)
                {
                    j++;
                }
                else
                {
                    j = 0;
                    i++;
                }
            }

            A.Add(-InstantConditionSim.CalculateAccelerationDueToGravity(vehicleData.body, vehicleData.altitude), 3, 1);
            A.Add(1, 2, 3);


            A.PrintToConsole(); //We should have an array that looks like this:

            /*             i --------------->
             *       j  [ Z w , Z u , Z q  + u,  0 ]
             *       |  [ X w , X u , X q     , -g ]
             *       |  [ M w , M u , M q     ,  0 ]
             *      \ / [  0  ,  0  ,  1      ,  0 ]
             *       V                              //And one that looks like this:
             *
             *          [ Z e ]
             *          [ X e ]
             *          [ M e ]
             *          [  0  ]
             *
             *
             */

            var transSolve = new RungeKutta4(endTime, initDt, A, InitCond);

            transSolve.Solve();

            var lines = new GraphData {
                xValues = transSolve.time
            };

            double[] yVal = transSolve.GetSolution(0);
            ScaleAndClampValues(yVal, 1, 50);
            lines.AddData(yVal, GUIColors.GetColor(3), "w", true);

            yVal = transSolve.GetSolution(1);
            ScaleAndClampValues(yVal, 1, 50);
            lines.AddData(yVal, GUIColors.GetColor(2), "u", true);

            yVal = transSolve.GetSolution(2);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(1), "q", true);

            yVal = transSolve.GetSolution(3);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(0), "θ", true);

            return(lines);
        }
        public GraphData AngleOfAttackSweep(
            double machNumber,
            double pitch,
            double lowerBound,
            double upperBound,
            int numPoints,
            int flapSetting,
            bool spoilers,
            CelestialBody body
            )
        {
            if (machNumber.NearlyEqual(0))
            {
                machNumber = 0.001;
            }

            var input = new InstantConditionSimInput(0, 0, 0, 0, 0, 0, machNumber, pitch, flapSetting, spoilers);

            FARAeroUtil.UpdateCurrentActiveBody(body);

            FARAeroUtil.ResetEditorParts();


            var ClValues    = new double[numPoints];
            var CdValues    = new double[numPoints];
            var CmValues    = new double[numPoints];
            var LDValues    = new double[numPoints];
            var AlphaValues = new double[numPoints];
            var ClValues2   = new double[numPoints];
            var CdValues2   = new double[numPoints];
            var CmValues2   = new double[numPoints];
            var LDValues2   = new double[numPoints];

            for (int i = 0; i < 2 * numPoints; i++)
            {
                double angle;
                if (i < numPoints)
                {
                    angle = i / (double)numPoints * (upperBound - lowerBound) + lowerBound;
                }
                else
                {
                    angle = (i - (double)numPoints + 1) / numPoints * (lowerBound - upperBound) + upperBound;
                }

                input.alpha = angle;

                _instantCondition.GetClCdCmSteady(input, out InstantConditionSimOutput output, i == 0);

                if (i < numPoints)
                {
                    AlphaValues[i] = angle;
                    ClValues[i]    = output.Cl;
                    CdValues[i]    = output.Cd;
                    CmValues[i]    = output.Cm;
                    LDValues[i]    = output.Cl * 0.1 / output.Cd;
                }
                else
                {
                    ClValues2[numPoints * 2 - 1 - i] = output.Cl;
                    CdValues2[numPoints * 2 - 1 - i] = output.Cd;
                    CmValues2[numPoints * 2 - 1 - i] = output.Cm;
                    LDValues2[numPoints * 2 - 1 - i] = output.Cl * 0.1 / output.Cd;
                }
            }

            var data = new GraphData {
                xValues = AlphaValues
            };

            data.AddData(ClValues2, GUIColors.GetColor(0) * 0.5f, "Cl2", false);
            data.AddData(ClValues, GUIColors.GetColor(0), Localizer.Format("FARAbbrevCl"), true);

            data.AddData(CdValues2, GUIColors.GetColor(1) * 0.5f, "Cd2", false);
            data.AddData(CdValues, GUIColors.GetColor(1), Localizer.Format("FARAbbrevCd"), true);

            data.AddData(CmValues2, GUIColors.GetColor(2) * 0.5f, "Cm2", false);
            data.AddData(CmValues, GUIColors.GetColor(2), Localizer.Format("FARAbbrevCm"), true);

            data.AddData(LDValues2, GUIColors.GetColor(3) * 0.5f, "L/D2", false);
            data.AddData(LDValues, GUIColors.GetColor(3), Localizer.Format("FARAbbrevL_D"), true);


            return(data);
        }
        private void Start()
        {
            if (CompatibilityChecker.IsAllCompatible() && Instance == null)
            {
                Instance = this;
            }
            else
            {
                Destroy(this);
                return;
            }

            showGUI = false;
            if (FARDebugAndSettings.FARDebugButtonStock)
            {
                FARDebugAndSettings.FARDebugButtonStock.SetFalse(false);
            }

            _vehicleAero = new VehicleAerodynamics();

            // ReSharper disable PossibleLossOfFraction
            guiRect = new Rect(Screen.width / 4, Screen.height / 6, 10, 10);
            // ReSharper restore PossibleLossOfFraction

            _instantSim = new InstantConditionSim();
            var flapSettingDropDown =
                new GUIDropDown <int>(new[]
            {
                Localizer.Format("FARFlapSetting0"),
                Localizer.Format("FARFlapSetting1"),
                Localizer.Format("FARFlapSetting2"),
                Localizer.Format("FARFlapSetting3")
            },
                                      new[] { 0, 1, 2, 3 });
            GUIDropDown <CelestialBody> celestialBodyDropdown = CreateBodyDropdown();

            modeDropdown = new GUIDropDown <FAREditorMode>(FAReditorMode_str,
                                                           new[]
            {
                FAREditorMode.STATIC,
                FAREditorMode.STABILITY,
                FAREditorMode.SIMULATION,
                FAREditorMode.AREA_RULING
            });

            _simManager = new EditorSimManager(_instantSim);

            _editorGraph     = new StaticAnalysisGraphGUI(_simManager, flapSettingDropDown, celestialBodyDropdown);
            _stabDeriv       = new StabilityDerivGUI(_simManager, flapSettingDropDown, celestialBodyDropdown);
            _stabDerivLinSim = new StabilityDerivSimulationGUI(_simManager);

            Color crossSection = GUIColors.GetColor(3);

            crossSection.a = 0.8f;

            Color crossSectionDeriv = GUIColors.GetColor(2);

            crossSectionDeriv.a = 0.8f;

            _areaRulingOverlay =
                EditorAreaRulingOverlay.CreateNewAreaRulingOverlay(new Color(0.05f, 0.05f, 0.05f, 0.7f),
                                                                   crossSection,
                                                                   crossSectionDeriv,
                                                                   10,
                                                                   5);
            guiRect.height = 500;
            guiRect.width  = 650;


            GameEvents.onEditorVariantApplied.Add(UpdateGeometryEvent);
            GameEvents.onEditorPartEvent.Add(UpdateGeometryEvent);
            GameEvents.onEditorUndo.Add(ResetEditorEvent);
            GameEvents.onEditorRedo.Add(ResetEditorEvent);
            GameEvents.onEditorShipModified.Add(ResetEditorEvent);
            GameEvents.onEditorLoad.Add(ResetEditorEvent);

            GameEvents.onGUIEngineersReportReady.Add(AddDesignConcerns);
            GameEvents.onGUIEngineersReportDestroy.Add(RemoveDesignConcerns);

            RequestUpdateVoxel();
        }
        public GraphData AngleOfAttackSweep(double machNumber, double pitch, double lowerBound, double upperBound, int numPoints, int flapSetting, bool spoilers, CelestialBody body)
        {
            if (machNumber < 1E-3)
            {
                machNumber = 1E-3;
            }

            FARAeroUtil.UpdateCurrentActiveBody(body);

            FARAeroUtil.ResetEditorParts();

            double[] ClValues    = new double[(int)numPoints];
            double[] CdValues    = new double[(int)numPoints];
            double[] CmValues    = new double[(int)numPoints];
            double[] LDValues    = new double[(int)numPoints];
            double[] AlphaValues = new double[(int)numPoints];
            double[] ClValues2   = new double[(int)numPoints];
            double[] CdValues2   = new double[(int)numPoints];
            double[] CmValues2   = new double[(int)numPoints];
            double[] LDValues2   = new double[(int)numPoints];

            InstantConditionSimInput input = new InstantConditionSimInput(0, 0, 0, 0, 0, 0, FlightEnv.NewDefaultVal(body), pitch, flapSetting, spoilers);

            input.fltenv.MachNumber = machNumber;

            for (int i = 0; i < 2 * numPoints; i++)
            {
                double angle = 0;
                if (i < numPoints)
                {
                    angle = lowerBound + (upperBound - lowerBound) * (i == 0? 0 : i / (numPoints - 1.0));
                }
                else
                {
                    angle = upperBound + (lowerBound - upperBound) * (i == numPoints ? 0 : (i - numPoints) / (numPoints - 1.0));
                }
                input.alpha = angle;

                InstantConditionSimOutput output;

                _instantCondition.GetClCdCmSteady(input, out output, i == 0, false);

                if (i < numPoints)
                {
                    AlphaValues[i] = angle;
                    ClValues[i]    = output.Cl;
                    CdValues[i]    = output.Cd;
                    CmValues[i]    = output.Cm;
                    LDValues[i]    = output.Cl * 0.1 / output.Cd;
                }
                else
                {
                    ClValues2[numPoints * 2 - 1 - i] = output.Cl;
                    CdValues2[numPoints * 2 - 1 - i] = output.Cd;
                    CmValues2[numPoints * 2 - 1 - i] = output.Cm;
                    LDValues2[numPoints * 2 - 1 - i] = output.Cl * 0.1 / output.Cd;
                }
            }

            GraphData data = new GraphData();

            data.xValues = AlphaValues;
            data.AddData(ClValues2, GUIColors.GetColor(0) * 0.5f, "Cl2", false);
            data.AddData(ClValues, GUIColors.GetColor(0), Localizer.Format("FARAbbrevCl"), true);
            data.AddData(CdValues2, GUIColors.GetColor(1) * 0.5f, "Cd2", false);
            data.AddData(CdValues, GUIColors.GetColor(1), Localizer.Format("FARAbbrevCd"), true);
            data.AddData(CmValues2, GUIColors.GetColor(2) * 0.5f, "Cm2", false);
            data.AddData(CmValues, GUIColors.GetColor(2), Localizer.Format("FARAbbrevCm"), true);
            data.AddData(LDValues2, GUIColors.GetColor(3) * 0.5f, "L/D2", false);
            data.AddData(LDValues, GUIColors.GetColor(3), Localizer.Format("FARAbbrevL_D"), true);

            data.exportdata.AddSizeVariables(_instantCondition, pitch, flapSetting, spoilers);
            data.exportdata.AddAoASweepXVariable(machNumber, AlphaValues);
            data.exportdata.AddYVariables(data);

            return(data);
        }
        public GraphData RunTransientSimLateral(StabilityDerivOutput vehicleData, double endTime, double initDt, double[] InitCond)
        {
            SimMatrix A = new SimMatrix(4, 4);

            int i = 0;
            int j = 0;

            double[] Derivs = new double[27];

            vehicleData.stabDerivs.CopyTo(Derivs, 0);

            double u0           = vehicleData.nominalVelocity;
            double b2u          = vehicleData.b / (2 * u0);
            double effg         = _instantCondition.CalculateEffectiveGravity(vehicleData.body, vehicleData.altitude, u0) * Math.Cos(vehicleData.stableCondition.stableAoA * Math.PI / 180);
            double factor_xz_x  = Derivs[26] / Derivs[0];
            double factor_xz_z  = Derivs[26] / Derivs[2];
            double factor_invxz = 1 / (1 - factor_xz_x * factor_xz_z);

            FARLogger.Info("u0= " + u0);
            FARLogger.Info("b/(2u)= " + b2u + " IGNORED!");
            FARLogger.Info("effg= " + effg + ", after multiplication with cos(AoA).");
            FARLogger.Info("Ixz/Ix= " + factor_xz_x + ", used to add yaw to roll-deriv.");
            FARLogger.Info("Ixz/Iz= " + factor_xz_z + ", used to add roll to yaw-deriv.");
            FARLogger.Info("(1 - Ixz^2/(IxIz))^-1= " + factor_invxz);

            // Rodhern: For possible backward compability the rotation (moment) derivatives can be
            //  scaled by "b/(2u)" (for pitch rate "mac/(2u)").
            //for (int h = 18; h <= 23; h++)
            //    Derivs[h] = Derivs[h] * b2u;

            Derivs[15] = Derivs[15] / u0;
            Derivs[18] = Derivs[18] / u0;
            Derivs[21] = Derivs[21] / u0 - 1;

            double Lb = Derivs[16] * factor_invxz;
            double Nb = Derivs[17] * factor_invxz;

            double Lp = Derivs[19] * factor_invxz;
            double Np = Derivs[20] * factor_invxz;

            double Lr = Derivs[22] * factor_invxz;
            double Nr = Derivs[23] * factor_invxz;

            Derivs[16] = Lb + factor_xz_x * Nb;
            Derivs[17] = Nb + factor_xz_z * Lb;

            Derivs[19] = Lp + factor_xz_x * Np;
            Derivs[20] = Np + factor_xz_z * Lp;

            Derivs[22] = Lr + factor_xz_x * Nr;
            Derivs[23] = Nr + factor_xz_z * Lr;

            for (int k = 15; k < Derivs.Length; k++)
            {
                double f = Derivs[k];

                if (i <= 2)
                {
                    FARLogger.Info("A[" + i + "," + j + "]= f_" + k + " = " + f + ", after manipulation.");
                    A.Add(f, i, j);
                }

                if (j < 2)
                {
                    j++;
                }
                else
                {
                    j = 0;
                    i++;
                }
            }
            A.Add(effg / u0, 3, 0);
            A.Add(1, 1, 3);

            A.PrintToConsole();                //We should have an array that looks like this:

            /*             i --------------->
             *       j  [ Yb / u0 , Yp / u0 , -(1 - Yr/ u0) ,  g Cos(θ0) / u0 ]
             *       |  [   Lb    ,    Lp   ,      Lr       ,          0          ]
             *       |  [   Nb    ,    Np   ,      Nr       ,          0          ]
             *      \ / [    0    ,    1    ,      0        ,          0          ]
             *       V
             */

            RungeKutta4 transSolve = new RungeKutta4(endTime, initDt, A, InitCond);

            transSolve.Solve();

            GraphData lines = new GraphData();

            lines.xValues = transSolve.time;

            double[] yVal = transSolve.GetSolution(0);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(3), "β", true);

            yVal = transSolve.GetSolution(1);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(2), "p", true);

            yVal = transSolve.GetSolution(2);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(1), "r", true);

            yVal = transSolve.GetSolution(3);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(0), "φ", true);

            /*graph.SetBoundaries(0, endTime, -10, 10);
             * graph.SetGridScaleUsingValues(1, 5);
             * graph.horizontalLabel = "time";
             * graph.verticalLabel = "value";
             * graph.Update();*/

            return(lines);
        }
        public GraphData RunTransientSimLongitudinal(StabilityDerivOutput vehicleData, double endTime, double initDt, double[] InitCond)
        {
            SimMatrix A = new SimMatrix(4, 4);

            int i = 0;
            int j = 0;

            double[] Derivs = new double[27];

            vehicleData.stabDerivs.CopyTo(Derivs, 0);

            double MAC2u = vehicleData.MAC / (2 * vehicleData.nominalVelocity);
            double effg  = _instantCondition.CalculateEffectiveGravity(vehicleData.body, vehicleData.altitude, vehicleData.nominalVelocity);

            FARLogger.Info("MAC/(2u)= " + MAC2u + " IGNORED!");
            FARLogger.Info("effg= " + effg);

            // Rodhern: For possible backward compability the rotation (moment) derivatives can be
            //  scaled by "mac/(2u)" (pitch) and "b/(2u)" (roll and yaw).
            //for (int h = 9; h <= 11; h++)
            //    Derivs[h] = Derivs[h] * MAC2u;

            Derivs[9] = Derivs[9] + vehicleData.nominalVelocity;

            for (int k = 3; k < 15 && k < Derivs.Length; k++)
            {
                double f = Derivs[k];

                if (i <= 2)
                {
                    FARLogger.Info("A[" + i + "," + j + "]= f_" + k + " = " + f);
                    A.Add(f, i, j);
                }
                else
                {
                    FARLogger.Debug("Ignore B[0," + j + "]= " + f);
                }

                if (j < 2)
                {
                    j++;
                }
                else
                {
                    j = 0;
                    i++;
                }
            }
            A.Add(-effg, 3, 1);
            A.Add(1, 2, 3);

            A.PrintToConsole();                //We should have an array that looks like this:

            /*            i --------------->
             *       j  [ Z w , Z u , Z q  + u,  0 ]
             *       |  [ X w , X u , X q     , -g ]
             *       |  [ M w , M u , M q     ,  0 ]
             *      \ / [  0  ,  0  ,  1      ,  0 ]
             *       V
             */
            //And one that looks like this: (Unused)

            /*
             *          [ Z e ]
             *          [ X e ]
             *          [ M e ]
             *          [  0  ]
             *
             */

            RungeKutta4 transSolve = new RungeKutta4(endTime, initDt, A, InitCond);

            transSolve.Solve();

            GraphData lines = new GraphData();

            lines.xValues = transSolve.time;

            double[] yVal = transSolve.GetSolution(0);
            ScaleAndClampValues(yVal, 1, 50);
            lines.AddData(yVal, GUIColors.GetColor(3), "w", true);

            yVal = transSolve.GetSolution(1);
            ScaleAndClampValues(yVal, 1, 50);
            lines.AddData(yVal, GUIColors.GetColor(2), "u", true);

            yVal = transSolve.GetSolution(2);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(1), "q", true);

            yVal = transSolve.GetSolution(3);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, GUIColors.GetColor(0), "θ", true);

            /*graph.SetBoundaries(0, endTime, -10, 10);
             * graph.SetGridScaleUsingValues(1, 5);
             * graph.horizontalLabel = "time";
             * graph.verticalLabel = "value";
             * graph.Update();*/

            return(lines);
        }