Example #1
0
        public void UpdateTransformMatrixList(Matrix4x4 worldToVesselMatrix)
        {
            if (meshDataList != null)
            {
                _ready = false;
                //if the previous transform order hasn't been completed yet, wait here to let it
                while (_meshesToUpdate > 0)
                {
                    if (this == null)
                    {
                        return;
                    }
                }
                _ready = false;

                _meshesToUpdate = meshDataList.Count;
                for (int i = 0; i < meshDataList.Count; ++i)
                {
                    GeometryMesh mesh = meshDataList[i];
                    if (mesh.TrySetThisToVesselMatrixForTransform())
                    {
                        mesh.TransformBasis(worldToVesselMatrix);
                    }
                    else
                    {
                        FARLogger.Info("A mesh on " + part.partInfo.title + " did not exist and was removed");
                        meshDataList.RemoveAt(i);
                        --i;
                        lock (this)
                        {
                            --_meshesToUpdate;
                        }
                    }
                }
            }

            if (crossSectionAdjusters == null)
            {
                return;
            }
            foreach (ICrossSectionAdjuster adjuster in crossSectionAdjusters)
            {
                adjuster.SetThisToVesselMatrixForTransform();
                adjuster.TransformBasis(worldToVesselMatrix);
                adjuster.UpdateArea();
            }
        }
Example #2
0
 private void OnDisplayList(int id)
 {
     GUI.BringWindowToFront(id);
     scrollPos = GUILayout.BeginScrollView(scrollPos, listStyle);
     for (int i = 0; i < stringOptions.Length; i++)
     {
         // Highlight the selected item
         GUIStyle tmpStyle = (selectedOption == i) ? selectedItemStyle : dropdownItemStyle;
         if (GUILayout.Button(stringOptions[i], tmpStyle))
         {
             FARLogger.Info("Selected " + stringOptions[i]);
             selectedOption = i;
             HideList();
         }
     }
     GUILayout.EndScrollView();
 }
Example #3
0
        private void UpdateInfo()
        {
            if (_infoMessages.Count <= 0)
            {
                return;
            }
            var sB = new StringBuilder();

            foreach (string message in _infoMessages)
            {
                sB.AppendLine(message);
            }

            _infoMessages.Clear();

            FARLogger.Info("" + sB);
        }
        public void UpdateTransformMatrixList(Matrix4x4 worldToVesselMatrix)
        {
            if (meshDataList != null)
            {
                _ready = false;
                while (_meshesToUpdate > 0) //if the previous transform order hasn't been completed yet, wait here to let it
                {
                    if (this == null)
                    {
                        return;
                    }
                }
                _ready = false;

                _meshesToUpdate = meshDataList.Count;
                for (int i = 0; i < meshDataList.Count; ++i)
                {
                    GeometryMesh mesh = meshDataList[i];
                    if (mesh.TrySetThisToVesselMatrixForTransform())
                    {
                        //ThreadPool.QueueUserWorkItem(mesh.MultithreadTransformBasis, worldToVesselMatrix);
                        mesh.TransformBasis(worldToVesselMatrix);
                    }
                    else
                    {
                        FARLogger.Info("A mesh on " + part.partInfo.title + " did not exist and was removed");
                        meshDataList.RemoveAt(i);
                        --i;
                        lock (this)
                            --_meshesToUpdate;
                    }
                }
            }
            if (crossSectionAdjusters != null)
            {
                for (int i = 0; i < crossSectionAdjusters.Count; ++i)
                {
                    ICrossSectionAdjuster adjuster = crossSectionAdjusters[i];
                    adjuster.SetThisToVesselMatrixForTransform();
                    adjuster.TransformBasis(worldToVesselMatrix);
                    adjuster.UpdateArea();
                }
            }
            //overallMeshBounds = part.GetPartOverallMeshBoundsInBasis(worldToVesselMatrix);
        }
        private void DataInput(InitialConditions inits, StabilityDerivOutput vehicleData, bool longitudinal)
        {
            GUILayout.BeginHorizontal();
            for (int i = 0; i < inits.inits.Length; i++)
            {
                GUILayout.Label(Localizer.Format("FAREditorSimInit") + inits.names[i] + ": ");
                inits.inits[i] = GUILayout.TextField(inits.inits[i], GUILayout.ExpandWidth(true));
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("FAREditorSimEndTime"));
            inits.maxTime = GUILayout.TextField(inits.maxTime, GUILayout.ExpandWidth(true));
            GUILayout.Label(Localizer.Format("FAREditorSimTimestep"));
            inits.dt = GUILayout.TextField(inits.dt, GUILayout.ExpandWidth(true));
            if (GUILayout.Button(Localizer.Format("FAREditorSimRunButton"), GUILayout.Width(150.0F), GUILayout.Height(25.0F)))
            {
                for (int i = 0; i < inits.inits.Length; i++)
                {
                    inits.inits[i] = Regex.Replace(inits.inits[i], @"[^-?[0-9]*(\.[0-9]*)?]", "");
                }
                inits.maxTime = Regex.Replace(inits.maxTime, @"[^-?[0-9]*(\.[0-9]*)?]", "");
                inits.dt      = Regex.Replace(inits.dt, @"[^-?[0-9]*(\.[0-9]*)?]", "");

                double[] initCond = new double[inits.inits.Length];
                for (int i = 0; i < initCond.Length; i++)
                {
                    initCond[i] = Convert.ToDouble(inits.inits[i]) * inits.scaling[i];
                    FARLogger.Info("initCond[" + i + "]= " + initCond[i] + ", after scaling with " + inits.scaling[i] + ".");
                }

                GraphData data;
                if (longitudinal)
                {
                    data = simManager.StabDerivLinearSim.RunTransientSimLongitudinal(vehicleData, Convert.ToDouble(inits.maxTime), Convert.ToDouble(inits.dt), initCond);
                }
                else
                {
                    data = simManager.StabDerivLinearSim.RunTransientSimLateral(vehicleData, Convert.ToDouble(inits.maxTime), Convert.ToDouble(inits.dt), initCond);
                }

                UpdateGraph(data, Localizer.Format("FAREditorSimGraphTime"), Localizer.Format("FAREditorSimGraphParams"), 0, Convert.ToDouble(inits.maxTime), 50);
            }
            GUILayout.EndHorizontal();
        }
Example #6
0
        protected override void OnStart()
        {
            FARLogger.Info("FARVesselAero on " + vessel.name + " reporting startup");
            base.OnStart();

            if (!HighLogic.LoadedSceneIsFlight)
            {
                enabled = false;
                return;
            }

            _currentGeoModules = new List <GeometryPartModule>();

            foreach (Part p in vessel.parts)
            {
                p.maximum_drag = 0;
                p.minimum_drag = 0;
                p.angularDrag  = 0;

                GeometryPartModule g = p.GetComponent <GeometryPartModule>();
                if (!(g is null))
                {
                    _currentGeoModules.Add(g);
                    if (g.Ready)
                    {
                        geoModulesReady++;
                    }
                }

                if (!p.Modules.Contains <KerbalEVA>() && !p.Modules.Contains <FlagSite>())
                {
                    continue;
                }
                FARLogger.Info("Handling Stuff for KerbalEVA / Flag");
                g = (GeometryPartModule)p.AddModule("GeometryPartModule");
                g.OnStart(StartState());
                p.AddModule("FARAeroPartModule").OnStart(StartState());
                _currentGeoModules.Add(g);
            }

            RequestUpdateVoxel(false);

            enabled = true;
        }
Example #7
0
        public static void LoadConfiguration()
        {
            string[] namesTmp = Enum.GetNames(typeof(KSPActionGroup));
            string[] names    = new string[namesTmp.Length - 1];

            for (int i = 0; i < namesTmp.Length - 1; ++i)
            {
                names[i] = namesTmp[i];
            }
            KSPActionGroup[] agTypes = new KSPActionGroup[names.Length];
            actionGroupDropDown = new GUIDropDown <KSPActionGroup> [3];

            for (int i = 0; i < agTypes.Length; i++)
            {
                agTypes[i] = (KSPActionGroup)Enum.Parse(typeof(KSPActionGroup), names[i]);
            }
            // straight forward, reading the (action name, action group) tuples
            KSP.IO.PluginConfiguration config = FARDebugAndSettings.config;
            for (int i = 0; i < ACTION_COUNT; ++i)
            {
                try
                {
                    id2actionGroup[i]    = (KSPActionGroup)Enum.Parse(typeof(KSPActionGroup), config.GetValue(configKeys[i], id2actionGroup[i].ToString()));;
                    currentGuiStrings[i] = id2actionGroup[i].ToString(); // don't forget to initialize the gui
                    FARLogger.Info(String.Format("Loaded AG {0} as {1}", configKeys[i], id2actionGroup[i]));
                }
                catch (Exception e)
                {
                    FARLogger.Warning("Error reading config key '" + configKeys[i] + "' with value '" + config.GetValue(configKeys[i], "n/a") + "' gave " + e.ToString());
                }
                int initIndex = 0;
                for (int j = 0; j < agTypes.Length; j++)
                {
                    if (id2actionGroup[i] == agTypes[j])
                    {
                        initIndex = j;
                        break;
                    }
                }
                GUIDropDown <KSPActionGroup> dropDown = new GUIDropDown <KSPActionGroup>(names, agTypes, initIndex);
                actionGroupDropDown[i] = dropDown;
            }
        }
Example #8
0
        private Bounds SetBoundsFromMeshes()
        {
            if (meshDataList.Count == 0)
            {
                // If the mesh is empty, try rebuilding it. This can happen when a part was added to the editor but not
                // the ship before adding it to the ship
                RebuildAllMeshData();
            }

            Vector3 upper = Vector3.one * float.NegativeInfinity, lower = Vector3.one * float.PositiveInfinity;

            foreach (GeometryMesh geoMesh in meshDataList)
            {
                if (!geoMesh.valid)
                {
                    continue;
                }

                upper = Vector3.Max(upper, geoMesh.bounds.max);
                lower = Vector3.Min(lower, geoMesh.bounds.min);
            }

            var overallBounds = new Bounds((upper + lower) * 0.5f, upper - lower);

            float tmpTestBounds = overallBounds.center.x +
                                  overallBounds.center.y +
                                  overallBounds.center.z +
                                  overallBounds.extents.x +
                                  overallBounds.extents.y +
                                  overallBounds.extents.z;

            if (float.IsNaN(tmpTestBounds) || float.IsInfinity(tmpTestBounds))
            {
                FARLogger.Info("Overall bounds error in " + part.partInfo.title + " " + meshDataList.Count + " meshes");
                Valid = false;
            }
            else
            {
                Valid = true;
            }

            return(overallBounds);
        }
Example #9
0
        public StockProcFairingGeoUpdater(ModuleProceduralFairing fairing, GeometryPartModule geoModule)
        {
            this.fairing   = fairing;
            this.geoModule = geoModule;

            if (validParts == null)
            {
                FARLogger.Info("Fairing event setup");
                validParts = new Dictionary <Part, GeometryPartModule>();
                GameEvents.onFairingsDeployed.Add(FairingDeployGeometryUpdate);
            }

            validParts.Add(geoModule.part, geoModule);

            if (HighLogic.LoadedSceneIsEditor)
            {
                prevPanelBounds = new List <Bounds>();
            }
        }
        private void FixedUpdate()
        {
            if (EditorLogic.RootPart != null)
            {
                if (_vehicleAero.CalculationCompleted)
                {
                    _vehicleAero.UpdateSonicDragArea();
                    LEGACY_UpdateWingAeroModels(EditorLogic.SortedShipList.Count != prevPartCount || partMovement);
                    prevPartCount = EditorLogic.SortedShipList.Count;

                    voxelWatch.Stop();
                    FARLogger.Info("Voxelization Time (ms): " + voxelWatch.ElapsedMilliseconds);

                    voxelWatch.Reset();

                    _simManager.UpdateAeroData(_vehicleAero, _wingAerodynamicModel);
                    UpdateCrossSections();

                    foreach (IDesignConcern designConcern in _customDesignConcerns)
                    {
                        designConcern.Test();
                    }
                    editorReportUpdate.Invoke(EngineersReport.Instance, null);
                }

                if (_updateRateLimiter < FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate)
                {
                    _updateRateLimiter++;
                }
                else if (VoxelizationUpdateQueued)
                {
                    string shipname = EditorLogic.fetch.ship.shipName ?? "unknown ship";
                    FARLogger.Info("Updating " + shipname);
                    RecalculateVoxel();
                }
            }
            else
            {
                VoxelizationUpdateQueued = true;
                _updateRateLimiter       = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2;
            }
        }
Example #11
0
        public void Rebuild()
        {
            FARLogger.Info("Rebuilding visual voxel mesh...");
            Clear(false);
            int submeshes = m_debugVoxels.Count / MAX_VOXELS_PER_SUBMESH + 1;

            FARLogger.Info("Voxel mesh contains " + m_debugVoxels.Count + " voxels in " + submeshes + " submeshes");
            SetupSubmeshes(submeshes);
            int indexOffset = 0;

            for (int i = 0; i < submeshes; i++)
            {
                for (int j = i * MAX_VOXELS_PER_SUBMESH; j < Math.Min((i + 1) * MAX_VOXELS_PER_SUBMESH, m_debugVoxels.Count); j++)
                {
                    m_debugVoxels[j].AddToMesh(m_submeshes[i].Vertices, m_submeshes[i].Uvs, m_submeshes[i].Triangles, indexOffset);
                }
                m_submeshes[i].Rebuild();
            }
            FARLogger.Info("Finished rebuilding visual voxel mesh.");
        }
Example #12
0
        private void OnDisplayList(int id)
        {
            GUI.BringWindowToFront(id);
            scrollPos = GUILayout.BeginScrollView(scrollPos, GUIDropDownStyles.List);
            for (int i = 0; i < stringOptions.Length; i++)
            {
                // Highlight the selected item
                GUIStyle tmpStyle =
                    selectedOption == i ? GUIDropDownStyles.SelectedItem : GUIDropDownStyles.DropDownItem;
                if (!GUILayout.Button(stringOptions[i], tmpStyle))
                {
                    continue;
                }
                FARLogger.Info("Selected " + stringOptions[i]);
                selectedOption = i;
                HideList();
            }

            GUILayout.EndScrollView();
        }
Example #13
0
        public void Rebuild()
        {
            FARLogger.Info("Rebuilding visual voxel mesh...");
            Clear();
            int meshes = DebugVoxels.Count / MaxVoxelsPerSubmesh + 1;

            FARLogger.Info("Voxel mesh contains " + DebugVoxels.Count + " voxels in " + meshes + " submeshes");
            SetupSubmeshes(meshes);
            for (int i = 0; i < meshes; i++)
            {
                for (int j = i * MaxVoxelsPerSubmesh;
                     j < Math.Min((i + 1) * MaxVoxelsPerSubmesh, DebugVoxels.Count);
                     j++)
                {
                    DebugVoxels[j].AddToMesh(submeshes[i].Vertices, submeshes[i].Uvs, submeshes[i].Triangles);
                }
                submeshes[i].Rebuild();
            }

            FARLogger.Info("Finished rebuilding visual voxel mesh.");
        }
Example #14
0
        public void PrintToConsole()
        {
            StringBuilder MatrixDump = new StringBuilder();

            for (int j = 0; j < n; j++)
            {
                MatrixDump.Append("[");
                for (int i = 0; i < m; i++)
                {
                    MatrixDump.Append(matrix[i, j]);
                    if (i < m - 1)
                    {
                        MatrixDump.Append(",");
                    }
                    else
                    {
                        MatrixDump.Append("]\n\r");
                    }
                }
            }
            FARLogger.Info(MatrixDump.ToString());
        }
Example #15
0
 private void Start()
 {
     FARLogger.Info("Initiating RealChuteLite Chute Property Calculation");
     foreach (AvailablePart part in PartLoader.Instance.loadedParts)
     {
         Part prefab = part.partPrefab;
         if (prefab != null && prefab.Modules.Contains <RealChuteFAR>())
         {
             //Updates the part's GetInfo.
             RealChuteFAR module = prefab.Modules.GetModule <RealChuteFAR>();
             DragCubeSystem.Instance.LoadDragCubes(prefab);
             DragCube semi = prefab.DragCubes.Cubes.Find(c => c.Name == "SEMIDEPLOYED"), deployed = prefab.DragCubes.Cubes.Find(c => c.Name == "DEPLOYED");
             if (semi == null || deployed == null)
             {
                 FARLogger.Info("" + part.title + " cannot find drag cube for RealChuteLite");
             }
             module.preDeployedDiameter = GetApparentDiameter(semi);
             module.deployedDiameter    = GetApparentDiameter(deployed);
             part.moduleInfos.Find(m => m.moduleName == "RealChute").info = module.GetInfo();
         }
     }
 }
Example #16
0
        private Bounds SetBoundsFromMeshes()
        {
            Vector3 upper = Vector3.one * float.NegativeInfinity, lower = Vector3.one * float.PositiveInfinity;

            foreach (GeometryMesh geoMesh in meshDataList)
            {
                if (!geoMesh.valid)
                {
                    continue;
                }

                upper = Vector3.Max(upper, geoMesh.bounds.max);
                lower = Vector3.Min(lower, geoMesh.bounds.min);
            }

            var overallBounds = new Bounds((upper + lower) * 0.5f, upper - lower);

            float tmpTestBounds = overallBounds.center.x +
                                  overallBounds.center.y +
                                  overallBounds.center.z +
                                  overallBounds.extents.x +
                                  overallBounds.extents.y +
                                  overallBounds.extents.z;

            if (float.IsNaN(tmpTestBounds) || float.IsInfinity(tmpTestBounds))
            {
                FARLogger.Info("Overall bounds error in " + part.partInfo.title + " " + meshDataList.Count + " meshes");
                Valid = false;
            }
            else
            {
                Valid = true;
            }

            return(overallBounds);
        }
Example #17
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);
        }
 public void LoadAssets()
 {
     FARLogger.Info("Loading shader bundle");
     MainThread.StartCoroutine(Load);
 }
Example #19
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);
        }
Example #20
0
        public StabilityDerivOutput CalculateStabilityDerivs(
            CelestialBody body,
            double alt,
            double machNumber,
            int flapSetting,
            bool spoilers,
            double alpha,
            double beta,
            double phi
            )
        {
            GasProperties properties = FARAtmosphere.GetGasProperties(body,
                                                                      new Vector3d(0, 0, alt),
                                                                      Planetarium.GetUniversalTime());

            double pressure    = properties.Pressure;
            double temperature = properties.Temperature;
            double density     = properties.Density;
            double sspeed      = properties.SpeedOfSound;
            double u0          = sspeed * machNumber;
            double q           = u0 * u0 * density * 0.5f;

            var stabDerivOutput = new StabilityDerivOutput
            {
                nominalVelocity = u0,
                altitude        = alt,
                body            = body
            };

            Vector3d CoM  = Vector3d.zero;
            double   mass = 0;

            double MAC  = 0;
            double b    = 0;
            double area = 0;

            double Ix  = 0;
            double Iy  = 0;
            double Iz  = 0;
            double Ixy = 0;
            double Iyz = 0;
            double Ixz = 0;

            var input      = new InstantConditionSimInput(alpha, beta, phi, 0, 0, 0, machNumber, 0, flapSetting, spoilers);
            var pertOutput = new InstantConditionSimOutput();

            _instantCondition.GetClCdCmSteady(input, out InstantConditionSimOutput nominalOutput, true);

            List <Part> partsList = EditorLogic.SortedShipList;

            foreach (Part p in partsList)
            {
                if (FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass
                CoM  += partMass * (Vector3d)p.transform.TransformPoint(p.CoMOffset);
                mass += partMass;
                FARWingAerodynamicModel w = p.GetComponent <FARWingAerodynamicModel>();
                if (w == null)
                {
                    continue;
                }
                if (w.isShielded)
                {
                    continue;
                }

                area += w.S;
                MAC  += w.GetMAC() * w.S;
                b    += w.Getb_2() * w.S;
                if (w is FARControllableSurface controllableSurface)
                {
                    controllableSurface.SetControlStateEditor(CoM,
                                                              p.transform.up,
                                                              0,
                                                              0,
                                                              0,
                                                              input.flaps,
                                                              input.spoilers);
                }
            }

            if (area.NearlyEqual(0))
            {
                area = _instantCondition._maxCrossSectionFromBody;
                MAC  = _instantCondition._bodyLength;
                b    = 1;
            }

            MAC  /= area;
            b    /= area;
            CoM  /= mass;
            mass *= 1000;

            stabDerivOutput.b    = b;
            stabDerivOutput.MAC  = MAC;
            stabDerivOutput.area = area;

            foreach (Part p in partsList)
            {
                if (p == null || FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                //This section handles the parallel axis theorem
                Vector3 relPos = p.transform.TransformPoint(p.CoMOffset) - CoM;
                double  x2     = relPos.z * relPos.z;
                double  y2     = relPos.x * relPos.x;
                double  z2     = relPos.y * relPos.y;
                double  x      = relPos.z;
                double  y      = relPos.x;
                double  z      = relPos.y;

                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass

                Ix += (y2 + z2) * partMass;
                Iy += (x2 + z2) * partMass;
                Iz += (x2 + y2) * partMass;

                Ixy += -x * y * partMass;
                Iyz += -z * y * partMass;
                Ixz += -x * z * partMass;

                //And this handles the part's own moment of inertia
                Vector3    principalInertia = p.Rigidbody.inertiaTensor;
                Quaternion prncInertRot     = p.Rigidbody.inertiaTensorRotation;

                //The rows of the direction cosine matrix for a quaternion
                var Row1 =
                    new Vector3(prncInertRot.x * prncInertRot.x -
                                prncInertRot.y * prncInertRot.y -
                                prncInertRot.z * prncInertRot.z +
                                prncInertRot.w * prncInertRot.w,
                                2 * (prncInertRot.x * prncInertRot.y + prncInertRot.z * prncInertRot.w),
                                2 * (prncInertRot.x * prncInertRot.z - prncInertRot.y * prncInertRot.w));

                var Row2 = new Vector3(2 * (prncInertRot.x * prncInertRot.y - prncInertRot.z * prncInertRot.w),
                                       -prncInertRot.x * prncInertRot.x +
                                       prncInertRot.y * prncInertRot.y -
                                       prncInertRot.z * prncInertRot.z +
                                       prncInertRot.w * prncInertRot.w,
                                       2 * (prncInertRot.y * prncInertRot.z + prncInertRot.x * prncInertRot.w));

                var Row3 = new Vector3(2 * (prncInertRot.x * prncInertRot.z + prncInertRot.y * prncInertRot.w),
                                       2 * (prncInertRot.y * prncInertRot.z - prncInertRot.x * prncInertRot.w),
                                       -prncInertRot.x * prncInertRot.x -
                                       prncInertRot.y * prncInertRot.y +
                                       prncInertRot.z * prncInertRot.z +
                                       prncInertRot.w * prncInertRot.w);


                //And converting the principal moments of inertia into the coordinate system used by the system
                Ix += principalInertia.x * Row1.x * Row1.x +
                      principalInertia.y * Row1.y * Row1.y +
                      principalInertia.z * Row1.z * Row1.z;
                Iy += principalInertia.x * Row2.x * Row2.x +
                      principalInertia.y * Row2.y * Row2.y +
                      principalInertia.z * Row2.z * Row2.z;
                Iz += principalInertia.x * Row3.x * Row3.x +
                      principalInertia.y * Row3.y * Row3.y +
                      principalInertia.z * Row3.z * Row3.z;

                Ixy += principalInertia.x * Row1.x * Row2.x +
                       principalInertia.y * Row1.y * Row2.y +
                       principalInertia.z * Row1.z * Row2.z;
                Ixz += principalInertia.x * Row1.x * Row3.x +
                       principalInertia.y * Row1.y * Row3.y +
                       principalInertia.z * Row1.z * Row3.z;
                Iyz += principalInertia.x * Row2.x * Row3.x +
                       principalInertia.y * Row2.y * Row3.y +
                       principalInertia.z * Row2.z * Row3.z;
            }

            Ix *= 1000;
            Iy *= 1000;
            Iz *= 1000;

            stabDerivOutput.stabDerivs[0] = Ix;
            stabDerivOutput.stabDerivs[1] = Iy;
            stabDerivOutput.stabDerivs[2] = Iz;

            stabDerivOutput.stabDerivs[24] = Ixy;
            stabDerivOutput.stabDerivs[25] = Iyz;
            stabDerivOutput.stabDerivs[26] = Ixz;

            //This is the effect of gravity
            double effectiveG = InstantConditionSim.CalculateAccelerationDueToGravity(body, alt);

            //This is the effective reduction of gravity due to high velocity
            effectiveG -= u0 * u0 / (alt + body.Radius);
            double neededCl = mass * effectiveG / (q * area);


            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);
            //Longitudinal Mess
            _instantCondition.SetState(machNumber, neededCl, CoM, 0, input.flaps, input.spoilers);
            FARMathUtil.OptimizationResult optResult =
                FARMathUtil.Secant(_instantCondition.FunctionIterateForAlpha,
                                   0,
                                   10,
                                   1e-4,
                                   1e-4,
                                   minLimit: -90,
                                   maxLimit: 90);
            int calls = optResult.FunctionCalls;

            // if stable AoA doesn't exist, calculate derivatives at 0 incidence
            if (!optResult.Converged)
            {
                FARLogger.Info("Stable angle of attack not found, calculating derivatives at 0 incidence instead");
                alpha = 0;
                _instantCondition.FunctionIterateForAlpha(alpha);
                calls += 1;
            }
            else
            {
                alpha = optResult.Result;
            }

            input.alpha   = alpha;
            nominalOutput = _instantCondition.iterationOutput;

            input.alpha = alpha + 2;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            stabDerivOutput.stableCl       = neededCl;
            stabDerivOutput.stableCd       = nominalOutput.Cd;
            stabDerivOutput.stableAoA      = alpha;
            stabDerivOutput.stableAoAState = "";
            if (Math.Abs((nominalOutput.Cl - neededCl) / neededCl) > 0.1)
            {
                stabDerivOutput.stableAoAState = nominalOutput.Cl > neededCl ? "<" : ">";
            }

            FARLogger.Info("Cl needed: " +
                           neededCl.ToString(CultureInfo.InvariantCulture) +
                           ", AoA: " +
                           stabDerivOutput.stableAoA.ToString(CultureInfo.InvariantCulture) +
                           ", Cl: " +
                           nominalOutput.Cl.ToString(CultureInfo.InvariantCulture) +
                           ", Cd: " +
                           nominalOutput.Cd.ToString(CultureInfo.InvariantCulture) +
                           ", function calls: " +
                           calls.ToString());

            //vert vel derivs
            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cl += nominalOutput.Cd;
            pertOutput.Cd -= nominalOutput.Cl;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (Iy * u0);

            stabDerivOutput.stabDerivs[3] = pertOutput.Cl; //Zw
            stabDerivOutput.stabDerivs[4] = pertOutput.Cd; //Xw
            stabDerivOutput.stabDerivs[5] = pertOutput.Cm; //Mw

            // Rodhern: The motivation for the revised stability derivatives sign interpretations of Zq, Xq, Ze and Xe
            //  is to align the sign conventions used for Zu, Zq, Ze, Xu, Xq and Xe. Further explanation can be found
            //  here: https://forum.kerbalspaceprogram.com/index.php?/topic/109098-official-far-craft-repository/&do=findComment&comment=2425057

            input.alpha      = alpha;
            input.machNumber = machNumber + 0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);

            //fwd vel derivs
            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05 * machNumber;
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05 * machNumber;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05 * machNumber;

            pertOutput.Cl += 2 * nominalOutput.Cl;
            pertOutput.Cd += 2 * nominalOutput.Cd;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (u0 * Iy);

            stabDerivOutput.stabDerivs[6] = pertOutput.Cl; //Zu
            stabDerivOutput.stabDerivs[7] = pertOutput.Cd; //Xu
            stabDerivOutput.stabDerivs[8] = pertOutput.Cm; //Mu

            input.machNumber = machNumber;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.alphaDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);

            //pitch rate derivs
            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05;
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05;

            pertOutput.Cl *= -q * area * MAC / (2 * u0 * mass); // Rodhern: Replaced 'q' by '-q', so that formulas
            pertOutput.Cd *= -q * area * MAC / (2 * u0 * mass); //  for Zq and Xq match those for Zu and Xu.
            pertOutput.Cm *= q * area * MAC * MAC / (2 * u0 * Iy);

            stabDerivOutput.stabDerivs[9]  = pertOutput.Cl; //Zq
            stabDerivOutput.stabDerivs[10] = pertOutput.Cd; //Xq
            stabDerivOutput.stabDerivs[11] = pertOutput.Cm; //Mq

            input.alphaDot   = 0;
            input.pitchValue = 0.1;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);

            //elevator derivs
            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.1;
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.1;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.1;

            pertOutput.Cl *= -q * area / mass; // Rodhern: Replaced 'q' by '-q', so that formulas
            pertOutput.Cd *= -q * area / mass; //  for Ze and Xe match those for Zu and Xu.
            pertOutput.Cm *= q * area * MAC / Iy;

            stabDerivOutput.stabDerivs[12] = pertOutput.Cl; //Ze
            stabDerivOutput.stabDerivs[13] = pertOutput.Cd; //Xe
            stabDerivOutput.stabDerivs[14] = pertOutput.Cm; //Me

            //Lateral Mess

            input.pitchValue = 0;
            input.beta       = beta + 2;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);
            //sideslip angle derivs
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / (2 * FARMathUtil.deg2rad);
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cy     *= q * area / mass;
            pertOutput.Cn     *= q * area * b / Iz;
            pertOutput.C_roll *= q * area * b / Ix;

            stabDerivOutput.stabDerivs[15] = pertOutput.Cy;     //Yb
            stabDerivOutput.stabDerivs[17] = pertOutput.Cn;     //Nb
            stabDerivOutput.stabDerivs[16] = pertOutput.C_roll; //Lb

            input.beta = beta;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.phiDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);

            //roll rate derivs
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / 0.05;
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[18] = pertOutput.Cy;     //Yp
            stabDerivOutput.stabDerivs[20] = pertOutput.Cn;     //Np
            stabDerivOutput.stabDerivs[19] = pertOutput.C_roll; //Lp


            input.phiDot = 0;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.betaDot = -0.05;

            //yaw rate derivs
            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / 0.05f;
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05f;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05f;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[21] = pertOutput.Cy;     //Yr
            stabDerivOutput.stabDerivs[23] = pertOutput.Cn;     //Nr
            stabDerivOutput.stabDerivs[22] = pertOutput.C_roll; //Lr

            return(stabDerivOutput);
        }
Example #21
0
        private List <MeshData> CreateMeshListFromTransforms(ref List <Transform> meshTransforms)
        {
            List <MeshData>  meshList           = new List <MeshData>();
            List <Transform> validTransformList = new List <Transform>();

            if (part.Modules.Contains <KerbalEVA>() || part.Modules.Contains <FlagSite>())
            {
                FARLogger.Info("Adding vox box to Kerbal / Flag");
                meshList.Add(CreateBoxMeshForKerbalEVA());
                validTransformList.Add(part.partTransform);
                meshTransforms = validTransformList;
                return(meshList);
            }

            Bounds rendererBounds = this.part.GetPartOverallMeshBoundsInBasis(part.partTransform.worldToLocalMatrix);
            Bounds colliderBounds = this.part.GetPartColliderBoundsInBasis(part.partTransform.worldToLocalMatrix);

            bool cantUseColliders = true;
            bool isFairing        = part.Modules.Contains <ModuleProceduralFairing>() || part.Modules.Contains("ProceduralFairingSide");
            bool isDrill          = part.Modules.Contains <ModuleAsteroidDrill>() || part.Modules.Contains <ModuleResourceHarvester>();

            //Voxelize colliders
            if ((forceUseColliders || isFairing || isDrill || (rendererBounds.size.x * rendererBounds.size.z < colliderBounds.size.x * colliderBounds.size.z * 1.6f && rendererBounds.size.y < colliderBounds.size.y * 1.2f && (rendererBounds.center - colliderBounds.center).magnitude < 0.3f)) && !forceUseMeshes)
            {
                foreach (Transform t in meshTransforms)
                {
                    MeshData md = GetColliderMeshData(t);
                    if (md == null)
                    {
                        continue;
                    }

                    meshList.Add(md);
                    validTransformList.Add(t);
                    cantUseColliders = false;
                }
            }


            if (part.Modules.Contains <ModuleJettison>())
            {
                List <ModuleJettison> jettisons          = part.Modules.GetModules <ModuleJettison>();
                HashSet <Transform>   jettisonTransforms = new HashSet <Transform>();
                for (int i = 0; i < jettisons.Count; i++)
                {
                    ModuleJettison j = jettisons[i];
                    if (j.jettisonTransform == null)
                    {
                        continue;
                    }

                    jettisonTransforms.Add(j.jettisonTransform);
                    if (j.isJettisoned)
                    {
                        continue;
                    }

                    Transform t = j.jettisonTransform;
                    if (t.gameObject.activeInHierarchy == false)
                    {
                        continue;
                    }

                    MeshData md = GetVisibleMeshData(t, false);
                    if (md == null)
                    {
                        continue;
                    }

                    meshList.Add(md);
                    validTransformList.Add(t);
                }

                //Voxelize Everything
                if ((cantUseColliders || forceUseMeshes || isFairing) && !isDrill)       //in this case, voxelize _everything_
                {
                    foreach (Transform t in meshTransforms)
                    {
                        if (jettisonTransforms.Contains(t))
                        {
                            continue;
                        }
                        MeshData md = GetVisibleMeshData(t, false);
                        if (md == null)
                        {
                            continue;
                        }

                        meshList.Add(md);
                        validTransformList.Add(t);
                    }
                }
            }
            else
            {
                //Voxelize Everything
                if ((cantUseColliders || forceUseMeshes || isFairing) && !isDrill)       //in this case, voxelize _everything_
                {
                    foreach (Transform t in meshTransforms)
                    {
                        MeshData md = GetVisibleMeshData(t, false);
                        if (md == null)
                        {
                            continue;
                        }

                        meshList.Add(md);
                        validTransformList.Add(t);
                    }
                }
            }
            meshTransforms = validTransformList;
            return(meshList);
        }
        public void VesselUpdate(bool recalcGeoModules)
        {
            if (vessel == null)
            {
                vessel = gameObject.GetComponent <Vessel>();
                if (vessel == null || vessel.vesselTransform == null)
                {
                    return;
                }
            }

            if (_vehicleAero == null)
            {
                _vehicleAero         = new VehicleAerodynamics();
                _vesselIntakeRamDrag = new VesselIntakeRamDrag();
            }

            if (_updateRateLimiter < FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate)         //this has been updated recently in the past; queue an update and return
            {
                _updateQueued = true;
                return;
            }
            else                                 //last update was far enough in the past to run; reset rate limit counter and clear the queued flag
            {
                _updateRateLimiter = 0;
                _updateQueued      = false;
            }
            if (vessel.rootPart.Modules.Contains <LaunchClamp>())// || _vessel.rootPart.Modules.Contains("KerbalEVA"))
            {
                DisableModule();
                return;
            }
            if (recalcGeoModules)
            {
                _currentGeoModules.Clear();
                geoModulesReady = 0;
                for (int i = 0; i < vessel.Parts.Count; i++)
                {
                    Part p = vessel.Parts[i];
                    GeometryPartModule g = p.Modules.GetModule <GeometryPartModule>();
                    if ((object)g != null)
                    {
                        _currentGeoModules.Add(g);
                        if (g.Ready)
                        {
                            geoModulesReady++;
                        }
                    }
                }
            }
            if (_currentGeoModules.Count > geoModulesReady)
            {
                _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2;
                _updateQueued      = true;
                return;
            }

            if (_currentGeoModules.Count == 0)
            {
                DisableModule();
                FARLogger.Info("Disabling FARVesselAero on " + vessel.name + " due to no FARGeometryModules on board");
            }

            TriggerIGeometryUpdaters();
            if (FARThreading.VoxelizationThreadpool.RunInMainThread)
            {
                for (int i = _currentGeoModules.Count - 1; i >= 0; --i)
                {
                    if (!_currentGeoModules[i].Ready)
                    {
                        _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2;
                        _updateQueued      = true;
                        return;
                    }
                }
            }

            _voxelCount = VoxelCountFromType();
            if (!_vehicleAero.TryVoxelUpdate(vessel.vesselTransform.worldToLocalMatrix, vessel.vesselTransform.localToWorldMatrix, _voxelCount, vessel.Parts, _currentGeoModules, !setup))
            {
                _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2;
                _updateQueued      = true;
            }
            if (!_updateQueued)
            {
                setup = true;
            }

            FARLogger.Info("Updating vessel voxel for " + vessel.vesselName);
        }
        public StabilityDerivExportOutput CalculateStabilityDerivs(CelestialBody body, double alt, double machNumber, int flapSetting, bool spoilers, double alpha, double beta, double phi)
        {
            double pressure    = body.GetPressure(alt);
            double temperature = body.GetTemperature(alt);
            double density     = body.GetDensity(pressure, temperature);
            double sspeed      = body.GetSpeedOfSound(pressure, density);
            double u0          = sspeed * machNumber;
            double q           = u0 * u0 * density * 0.5f;

            StabilityDerivOutput          stabDerivOutput = new StabilityDerivOutput();
            StabilityDerivExportVariables stabDerivExport = new StabilityDerivExportVariables();

            stabDerivOutput.nominalVelocity = u0;
            stabDerivOutput.altitude        = alt;
            stabDerivOutput.body            = body;

            Vector3d CoM  = Vector3d.zero;
            double   mass = 0;

            double MAC  = 0;
            double b    = 0;
            double area = 0;

            double Ix  = 0;
            double Iy  = 0;
            double Iz  = 0;
            double Ixy = 0;
            double Iyz = 0;
            double Ixz = 0;

            InstantConditionSimInput  input = new InstantConditionSimInput(alpha, beta, phi, 0, 0, 0, machNumber, 0, flapSetting, spoilers);
            InstantConditionSimOutput nominalOutput;
            InstantConditionSimOutput pertOutput = new InstantConditionSimOutput();

            _instantCondition.GetClCdCmSteady(input, out nominalOutput, true);

            List <Part> partsList = EditorLogic.SortedShipList;

            for (int i = 0; i < partsList.Count; i++)
            {
                Part p = partsList[i];

                if (FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                //partMass += p.GetModuleMass(p.mass);
                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass
                CoM  += partMass * (Vector3d)p.transform.TransformPoint(p.CoMOffset);
                mass += partMass;
                FARWingAerodynamicModel w = p.GetComponent <FARWingAerodynamicModel>();
                if (w != null)
                {
                    if (w.isShielded)
                    {
                        continue;
                    }

                    area += w.S;
                    MAC  += w.GetMAC() * w.S;
                    b    += w.Getb_2() * w.S;
                    if (w is FARControllableSurface)
                    {
                        (w as FARControllableSurface).SetControlStateEditor(CoM, p.transform.up, 0, 0, 0, input.flaps, input.spoilers);
                    }
                }
            }
            if (area.NearlyEqual(0))
            {
                area = _instantCondition._maxCrossSectionFromBody;
                MAC  = _instantCondition._bodyLength;
                b    = 1;
            }
            MAC  /= area;
            b    /= area;
            CoM  /= mass;
            mass *= 1000;

            stabDerivOutput.b    = b;
            stabDerivOutput.MAC  = MAC;
            stabDerivOutput.area = area;

            for (int i = 0; i < partsList.Count; i++)
            {
                Part p = partsList[i];

                if (p == null || FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                //This section handles the parallel axis theorem
                Vector3 relPos = p.transform.TransformPoint(p.CoMOffset) - CoM;
                double  x2, y2, z2, x, y, z;
                x2 = relPos.z * relPos.z;
                y2 = relPos.x * relPos.x;
                z2 = relPos.y * relPos.y;
                x  = relPos.z;
                y  = relPos.x;
                z  = relPos.y;

                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                //partMass += p.GetModuleMass(p.mass);
                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass

                Ix += (y2 + z2) * partMass;
                Iy += (x2 + z2) * partMass;
                Iz += (x2 + y2) * partMass;

                Ixy += -x * y * partMass;
                Iyz += -z * y * partMass;
                Ixz += -x * z * partMass;

                //And this handles the part's own moment of inertia
                Vector3    principalInertia = p.Rigidbody.inertiaTensor;
                Quaternion prncInertRot     = p.Rigidbody.inertiaTensorRotation;

                //The rows of the direction cosine matrix for a quaternion
                Vector3 Row1 = new Vector3(prncInertRot.x * prncInertRot.x - prncInertRot.y * prncInertRot.y - prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w,
                                           2 * (prncInertRot.x * prncInertRot.y + prncInertRot.z * prncInertRot.w),
                                           2 * (prncInertRot.x * prncInertRot.z - prncInertRot.y * prncInertRot.w));

                Vector3 Row2 = new Vector3(2 * (prncInertRot.x * prncInertRot.y - prncInertRot.z * prncInertRot.w),
                                           -prncInertRot.x * prncInertRot.x + prncInertRot.y * prncInertRot.y - prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w,
                                           2 * (prncInertRot.y * prncInertRot.z + prncInertRot.x * prncInertRot.w));

                Vector3 Row3 = new Vector3(2 * (prncInertRot.x * prncInertRot.z + prncInertRot.y * prncInertRot.w),
                                           2 * (prncInertRot.y * prncInertRot.z - prncInertRot.x * prncInertRot.w),
                                           -prncInertRot.x * prncInertRot.x - prncInertRot.y * prncInertRot.y + prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w);


                //And converting the principal moments of inertia into the coordinate system used by the system
                Ix += principalInertia.x * Row1.x * Row1.x + principalInertia.y * Row1.y * Row1.y + principalInertia.z * Row1.z * Row1.z;
                Iy += principalInertia.x * Row2.x * Row2.x + principalInertia.y * Row2.y * Row2.y + principalInertia.z * Row2.z * Row2.z;
                Iz += principalInertia.x * Row3.x * Row3.x + principalInertia.y * Row3.y * Row3.y + principalInertia.z * Row3.z * Row3.z;

                Ixy += principalInertia.x * Row1.x * Row2.x + principalInertia.y * Row1.y * Row2.y + principalInertia.z * Row1.z * Row2.z;
                Ixz += principalInertia.x * Row1.x * Row3.x + principalInertia.y * Row1.y * Row3.y + principalInertia.z * Row1.z * Row3.z;
                Iyz += principalInertia.x * Row2.x * Row3.x + principalInertia.y * Row2.y * Row3.y + principalInertia.z * Row2.z * Row3.z;
            }
            Ix *= 1000;
            Iy *= 1000;
            Iz *= 1000;

            stabDerivOutput.stabDerivs[0] = Ix;
            stabDerivOutput.stabDerivs[1] = Iy;
            stabDerivOutput.stabDerivs[2] = Iz;

            stabDerivOutput.stabDerivs[24] = Ixy;
            stabDerivOutput.stabDerivs[25] = Iyz;
            stabDerivOutput.stabDerivs[26] = Ixz;


            double effectiveG = _instantCondition.CalculateAccelerationDueToGravity(body, alt); //This is the effect of gravity

            effectiveG -= u0 * u0 / (alt + body.Radius);                                        //This is the effective reduction of gravity due to high velocity
            double neededCl = mass * effectiveG / (q * area);


            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);
            //Longitudinal Mess
            _instantCondition.SetState(machNumber, neededCl, CoM, 0, input.flaps, input.spoilers);

            alpha         = FARMathUtil.SelectedSearchMethod(machNumber, _instantCondition.FunctionIterateForAlpha);
            input.alpha   = alpha;
            nominalOutput = _instantCondition.iterationOutput;
            //alpha_str = (alpha * Mathf.PI / 180).ToString();

            input.alpha = (alpha + 2);

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            stabDerivOutput.stableCl       = neededCl;
            stabDerivOutput.stableCd       = nominalOutput.Cd;
            stabDerivOutput.stableAoA      = alpha;
            stabDerivOutput.stableAoAState = "";
            if (Math.Abs((nominalOutput.Cl - neededCl) / neededCl) > 0.1)
            {
                stabDerivOutput.stableAoAState = ((nominalOutput.Cl > neededCl) ? "<" : ">");
            }

            FARLogger.Info("Cl needed: " + neededCl + ", AoA: " + alpha + ", Cl: " + nominalOutput.Cl + ", Cd: " + nominalOutput.Cd);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / (2 * FARMathUtil.deg2rad);                   //vert vel derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cl += nominalOutput.Cd;
            pertOutput.Cd -= nominalOutput.Cl;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (Iy * u0);

            stabDerivOutput.stabDerivs[3] = pertOutput.Cl;  //Zw
            stabDerivOutput.stabDerivs[4] = pertOutput.Cd;  //Xw
            stabDerivOutput.stabDerivs[5] = pertOutput.Cm;  //Mw

            // Rodhern: The motivation for the revised stability derivatives sign interpretations of Zq, Xq, Ze and Xe
            //  is to align the sign conventions used for Zu, Zq, Ze, Xu, Xq and Xe. Further explanation can be found
            //  here: https://forum.kerbalspaceprogram.com/index.php?/topic/109098-official-far-craft-repository/&do=findComment&comment=2425057

            input.alpha      = alpha;
            input.machNumber = machNumber + 0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05 * machNumber;                   //fwd vel derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05 * machNumber;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05 * machNumber;

            pertOutput.Cl += 2 * nominalOutput.Cl;
            pertOutput.Cd += 2 * nominalOutput.Cd;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (u0 * Iy);

            stabDerivOutput.stabDerivs[6] = pertOutput.Cl;  //Zu
            stabDerivOutput.stabDerivs[7] = pertOutput.Cd;  //Xu
            stabDerivOutput.stabDerivs[8] = pertOutput.Cm;  //Mu

            input.machNumber = machNumber;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.alphaDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05;                   //pitch rate derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05;

            pertOutput.Cl *= -q * area * MAC / (2 * u0 * mass); // Rodhern: Replaced 'q' by '-q', so that formulas
            pertOutput.Cd *= -q * area * MAC / (2 * u0 * mass); //  for Zq and Xq match those for Zu and Xu.
            pertOutput.Cm *= q * area * MAC * MAC / (2 * u0 * Iy);

            stabDerivOutput.stabDerivs[9]  = pertOutput.Cl; //Zq
            stabDerivOutput.stabDerivs[10] = pertOutput.Cd; //Xq
            stabDerivOutput.stabDerivs[11] = pertOutput.Cm; //Mq

            input.alphaDot   = 0;
            input.pitchValue = 0.1;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.1;                   //elevator derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.1;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.1;

            pertOutput.Cl *= -q * area / mass; // Rodhern: Replaced 'q' by '-q', so that formulas
            pertOutput.Cd *= -q * area / mass; //  for Ze and Xe match those for Zu and Xu.
            pertOutput.Cm *= q * area * MAC / Iy;

            stabDerivOutput.stabDerivs[12] = pertOutput.Cl; //Ze
            stabDerivOutput.stabDerivs[13] = pertOutput.Cd; //Xe
            stabDerivOutput.stabDerivs[14] = pertOutput.Cm; //Me

            //Lateral Mess

            input.pitchValue = 0;
            input.beta       = (beta + 2);

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / (2 * FARMathUtil.deg2rad);               //sideslip angle derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / (2 * FARMathUtil.deg2rad);
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cy     *= q * area / mass;
            pertOutput.Cn     *= q * area * b / Iz;
            pertOutput.C_roll *= q * area * b / Ix;

            stabDerivOutput.stabDerivs[15] = pertOutput.Cy;     //Yb
            stabDerivOutput.stabDerivs[17] = pertOutput.Cn;     //Nb
            stabDerivOutput.stabDerivs[16] = pertOutput.C_roll; //Lb

            input.beta = beta;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.phiDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / 0.05;               //roll rate derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[18] = pertOutput.Cy;     //Yp
            stabDerivOutput.stabDerivs[20] = pertOutput.Cn;     //Np
            stabDerivOutput.stabDerivs[19] = pertOutput.C_roll; //Lp


            input.phiDot = 0;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.betaDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false); pertOutput.Cy = (pertOutput.Cy - nominalOutput.Cy) / 0.05f;                   //yaw rate derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05f;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05f;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[21] = pertOutput.Cy;     //Yr
            stabDerivOutput.stabDerivs[23] = pertOutput.Cn;     //Nr
            stabDerivOutput.stabDerivs[22] = pertOutput.C_roll; //Lr

            // Assign values to export variables
            stabDerivExport.craftmass      = mass;
            stabDerivExport.envpressure    = pressure;
            stabDerivExport.envtemperature = temperature;
            stabDerivExport.envdensity     = density;
            stabDerivExport.envsoundspeed  = sspeed;
            stabDerivExport.envg           = _instantCondition.CalculateAccelerationDueToGravity(body, alt);
            stabDerivExport.sitmach        = machNumber;
            stabDerivExport.sitdynpres     = q;
            stabDerivExport.siteffg        = effectiveG;

            return(new StabilityDerivExportOutput(stabDerivOutput, stabDerivExport));
        }
        protected override void OnStart()
        {
            FARLogger.Info("FARVesselAero on " + vessel.name + " reporting startup");
            base.OnStart();

            if (!CompatibilityChecker.IsAllCompatible())
            {
                this.enabled = false;
                return;
            }
            if (!HighLogic.LoadedSceneIsFlight)
            {
                this.enabled = false;
                return;
            }

            _currentGeoModules = new List <GeometryPartModule>();

            /*if (!vessel.rootPart)
             * {
             *  this.enabled = false;
             *  return;
             * }*/

            for (int i = 0; i < vessel.parts.Count; i++)
            {
                Part p = vessel.parts[i];
                p.maximum_drag = 0;
                p.minimum_drag = 0;
                p.angularDrag  = 0;

                /*p.dragModel = Part.DragModel.NONE;
                 * p.dragReferenceVector = Vector3.zero;
                 * p.dragScalar = 0;
                 * p.dragVector = Vector3.zero;
                 * p.dragVectorDir = Vector3.zero;
                 * p.dragVectorDirLocal = Vector3.zero;
                 * p.dragVectorMag = 0;
                 * p.dragVectorSqrMag = 0;
                 *
                 * p.bodyLiftMultiplier = 0;
                 * p.bodyLiftScalar = 0;*/

                GeometryPartModule g = p.GetComponent <GeometryPartModule>();
                if ((object)g != null)
                {
                    _currentGeoModules.Add(g);
                    if (g.Ready)
                    {
                        geoModulesReady++;
                    }
                }
                if (p.Modules.Contains <KerbalEVA>() || p.Modules.Contains <FlagSite>())
                {
                    FARLogger.Info("Handling Stuff for KerbalEVA / Flag");
                    g = (GeometryPartModule)p.AddModule("GeometryPartModule");
                    g.OnStart(StartState());
                    p.AddModule("FARAeroPartModule").OnStart(StartState());
                    _currentGeoModules.Add(g);
                }
            }
            RequestUpdateVoxel(false);

            this.enabled = true;
            //GameEvents.onVesselLoaded.Add(VesselUpdateEvent);
            //GameEvents.onVesselChange.Add(VesselUpdateEvent);
            //GameEvents.onVesselLoaded.Add(VesselUpdate);
            //GameEvents.onVesselCreate.Add(VesselUpdateEvent);

            //FARLogger.Info("Starting " + _vessel.vesselName + " aero properties");
        }
        public static GraphData RunTransientSimLateral(
            StabilityDerivOutput vehicleData,
            double endTime,
            double initDt,
            double[] InitCond
            )
        {
            var A = new SimMatrix(4, 4);

            A.PrintToConsole();

            int i      = 0;
            int j      = 0;
            int num    = 0;
            var 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;

            foreach (double f in Derivs)
            {
                if (num < 15)
                {
                    num++; //Avoid Ix, Iy, Iz and long derivs
                    continue;
                }

                num++;
                FARLogger.Info("" + i + "," + j);
                if (i <= 2)
                {
                    A.Add(f, i, j);
                }

                if (j < 2)
                {
                    j++;
                }
                else
                {
                    j = 0;
                    i++;
                }
            }

            A.Add(InstantConditionSim.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  ]
             *
             *
             */
            var transSolve = new RungeKutta4(endTime, initDt, A, InitCond);

            transSolve.Solve();

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

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

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

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

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

            return(lines);
        }
        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, FARConfig.GUIColors.LdColor, "w", true);

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

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

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

            return(lines);
        }
        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 StabilityDerivOutput CalculateStabilityDerivs(double u0, double q, double machNumber, double alpha, double beta, double phi, int flapSetting, bool spoilers, CelestialBody body, double alt)
        {
            StabilityDerivOutput stabDerivOutput = new StabilityDerivOutput();

            stabDerivOutput.nominalVelocity = u0;
            stabDerivOutput.altitude        = alt;
            stabDerivOutput.body            = body;

            Vector3d CoM  = Vector3d.zero;
            double   mass = 0;

            double MAC  = 0;
            double b    = 0;
            double area = 0;

            double Ix  = 0;
            double Iy  = 0;
            double Iz  = 0;
            double Ixy = 0;
            double Iyz = 0;
            double Ixz = 0;

            InstantConditionSimInput  input = new InstantConditionSimInput(alpha, beta, phi, 0, 0, 0, machNumber, 0, flapSetting, spoilers);
            InstantConditionSimOutput nominalOutput;
            InstantConditionSimOutput pertOutput = new InstantConditionSimOutput();

            _instantCondition.GetClCdCmSteady(input, out nominalOutput, true);

            List <Part> partsList = EditorLogic.SortedShipList;

            for (int i = 0; i < partsList.Count; i++)
            {
                Part p = partsList[i];

                if (FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                //partMass += p.GetModuleMass(p.mass);
                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass
                CoM  += partMass * (Vector3d)p.transform.TransformPoint(p.CoMOffset);
                mass += partMass;
                FARWingAerodynamicModel w = p.GetComponent <FARWingAerodynamicModel>();
                if (w != null)
                {
                    if (w.isShielded)
                    {
                        continue;
                    }

                    area += w.S;
                    MAC  += w.GetMAC() * w.S;
                    b    += w.Getb_2() * w.S;
                    if (w is FARControllableSurface)
                    {
                        (w as FARControllableSurface).SetControlStateEditor(CoM, p.transform.up, 0, 0, 0, input.flaps, input.spoilers);
                    }
                }
            }
            if (area == 0)
            {
                area = _instantCondition._maxCrossSectionFromBody;
                MAC  = _instantCondition._bodyLength;
                b    = 1;
            }
            MAC  /= area;
            b    /= area;
            CoM  /= mass;
            mass *= 1000;

            stabDerivOutput.b    = b;
            stabDerivOutput.MAC  = MAC;
            stabDerivOutput.area = area;

            for (int i = 0; i < partsList.Count; i++)
            {
                Part p = partsList[i];

                if (p == null || FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                //This section handles the parallel axis theorem
                Vector3 relPos = p.transform.TransformPoint(p.CoMOffset) - CoM;
                double  x2, y2, z2, x, y, z;
                x2 = relPos.z * relPos.z;
                y2 = relPos.x * relPos.x;
                z2 = relPos.y * relPos.y;
                x  = relPos.z;
                y  = relPos.x;
                z  = relPos.y;

                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                //partMass += p.GetModuleMass(p.mass);
                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass

                Ix += (y2 + z2) * partMass;
                Iy += (x2 + z2) * partMass;
                Iz += (x2 + y2) * partMass;

                Ixy += -x * y * partMass;
                Iyz += -z * y * partMass;
                Ixz += -x * z * partMass;

                //And this handles the part's own moment of inertia
                Vector3    principalInertia = p.Rigidbody.inertiaTensor;
                Quaternion prncInertRot     = p.Rigidbody.inertiaTensorRotation;

                //The rows of the direction cosine matrix for a quaternion
                Vector3 Row1 = new Vector3(prncInertRot.x * prncInertRot.x - prncInertRot.y * prncInertRot.y - prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w,
                                           2 * (prncInertRot.x * prncInertRot.y + prncInertRot.z * prncInertRot.w),
                                           2 * (prncInertRot.x * prncInertRot.z - prncInertRot.y * prncInertRot.w));

                Vector3 Row2 = new Vector3(2 * (prncInertRot.x * prncInertRot.y - prncInertRot.z * prncInertRot.w),
                                           -prncInertRot.x * prncInertRot.x + prncInertRot.y * prncInertRot.y - prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w,
                                           2 * (prncInertRot.y * prncInertRot.z + prncInertRot.x * prncInertRot.w));

                Vector3 Row3 = new Vector3(2 * (prncInertRot.x * prncInertRot.z + prncInertRot.y * prncInertRot.w),
                                           2 * (prncInertRot.y * prncInertRot.z - prncInertRot.x * prncInertRot.w),
                                           -prncInertRot.x * prncInertRot.x - prncInertRot.y * prncInertRot.y + prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w);


                //And converting the principal moments of inertia into the coordinate system used by the system
                Ix += principalInertia.x * Row1.x * Row1.x + principalInertia.y * Row1.y * Row1.y + principalInertia.z * Row1.z * Row1.z;
                Iy += principalInertia.x * Row2.x * Row2.x + principalInertia.y * Row2.y * Row2.y + principalInertia.z * Row2.z * Row2.z;
                Iz += principalInertia.x * Row3.x * Row3.x + principalInertia.y * Row3.y * Row3.y + principalInertia.z * Row3.z * Row3.z;

                Ixy += principalInertia.x * Row1.x * Row2.x + principalInertia.y * Row1.y * Row2.y + principalInertia.z * Row1.z * Row2.z;
                Ixz += principalInertia.x * Row1.x * Row3.x + principalInertia.y * Row1.y * Row3.y + principalInertia.z * Row1.z * Row3.z;
                Iyz += principalInertia.x * Row2.x * Row3.x + principalInertia.y * Row2.y * Row3.y + principalInertia.z * Row2.z * Row3.z;
            }
            Ix *= 1000;
            Iy *= 1000;
            Iz *= 1000;

            stabDerivOutput.stabDerivs[0] = Ix;
            stabDerivOutput.stabDerivs[1] = Iy;
            stabDerivOutput.stabDerivs[2] = Iz;

            stabDerivOutput.stabDerivs[24] = Ixy;
            stabDerivOutput.stabDerivs[25] = Iyz;
            stabDerivOutput.stabDerivs[26] = Ixz;


            double effectiveG = _instantCondition.CalculateAccelerationDueToGravity(body, alt); //This is the effect of gravity

            effectiveG -= u0 * u0 / (alt + body.Radius);                                        //This is the effective reduction of gravity due to high velocity
            double neededCl = mass * effectiveG / (q * area);


            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);
            //Longitudinal Mess
            _instantCondition.SetState(machNumber, neededCl, CoM, 0, input.flaps, input.spoilers);

            alpha         = FARMathUtil.BrentsMethod(_instantCondition.FunctionIterateForAlpha, -30d, 30d, 0.001, 500);
            input.alpha   = alpha;
            nominalOutput = _instantCondition.iterationOutput;
            //alpha_str = (alpha * Mathf.PI / 180).ToString();

            input.alpha = (alpha + 2);

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            stabDerivOutput.stableCl       = neededCl;
            stabDerivOutput.stableCd       = nominalOutput.Cd;
            stabDerivOutput.stableAoA      = alpha;
            stabDerivOutput.stableAoAState = "";
            if (Math.Abs((nominalOutput.Cl - neededCl) / neededCl) > 0.1)
            {
                stabDerivOutput.stableAoAState = ((nominalOutput.Cl > neededCl) ? "<" : ">");
            }

            FARLogger.Info("Cl needed: " + neededCl + ", AoA: " + alpha + ", Cl: " + nominalOutput.Cl + ", Cd: " + nominalOutput.Cd);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / (2 * FARMathUtil.deg2rad);                   //vert vel derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cl += nominalOutput.Cd;
            pertOutput.Cd -= nominalOutput.Cl;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (Iy * u0);

            stabDerivOutput.stabDerivs[3] = pertOutput.Cl;  //Zw
            stabDerivOutput.stabDerivs[4] = pertOutput.Cd;  //Xw
            stabDerivOutput.stabDerivs[5] = pertOutput.Cm;  //Mw

            input.alpha      = alpha;
            input.machNumber = machNumber + 0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05 * machNumber;                   //fwd vel derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05 * machNumber;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05 * machNumber;

            pertOutput.Cl += 2 * nominalOutput.Cl;
            pertOutput.Cd += 2 * nominalOutput.Cd;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (u0 * Iy);

            stabDerivOutput.stabDerivs[6] = pertOutput.Cl;  //Zu
            stabDerivOutput.stabDerivs[7] = pertOutput.Cd;  //Xu
            stabDerivOutput.stabDerivs[8] = pertOutput.Cm;  //Mu

            input.machNumber = machNumber;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.alphaDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05;                   //pitch rate derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05;

            pertOutput.Cl *= q * area * MAC / (2 * u0 * mass);
            pertOutput.Cd *= q * area * MAC / (2 * u0 * mass);
            pertOutput.Cm *= q * area * MAC * MAC / (2 * u0 * Iy);

            stabDerivOutput.stabDerivs[9]  = pertOutput.Cl; //Zq
            stabDerivOutput.stabDerivs[10] = pertOutput.Cd; //Xq
            stabDerivOutput.stabDerivs[11] = pertOutput.Cm; //Mq

            input.alphaDot   = 0;
            input.pitchValue = 0.1;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.1;                   //elevator derivs
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.1;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.1;

            pertOutput.Cl *= q * area / mass;
            pertOutput.Cd *= q * area / mass;
            pertOutput.Cm *= q * area * MAC / Iy;

            stabDerivOutput.stabDerivs[12] = pertOutput.Cl; //Ze
            stabDerivOutput.stabDerivs[13] = pertOutput.Cd; //Xe
            stabDerivOutput.stabDerivs[14] = pertOutput.Cm; //Me

            //Lateral Mess

            input.pitchValue = 0;
            input.beta       = (beta + 2);

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / (2 * FARMathUtil.deg2rad);               //sideslip angle derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / (2 * FARMathUtil.deg2rad);
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cy     *= q * area / mass;
            pertOutput.Cn     *= q * area * b / Iz;
            pertOutput.C_roll *= q * area * b / Ix;

            stabDerivOutput.stabDerivs[15] = pertOutput.Cy;     //Yb
            stabDerivOutput.stabDerivs[17] = pertOutput.Cn;     //Nb
            stabDerivOutput.stabDerivs[16] = pertOutput.C_roll; //Lb

            input.beta = beta;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.phiDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false);

            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / 0.05;               //roll rate derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[18] = pertOutput.Cy;     //Yp
            stabDerivOutput.stabDerivs[20] = pertOutput.Cn;     //Np
            stabDerivOutput.stabDerivs[19] = pertOutput.C_roll; //Lp


            input.phiDot = 0;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.betaDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false); pertOutput.Cy = (pertOutput.Cy - nominalOutput.Cy) / 0.05f;                   //yaw rate derivs
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05f;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05f;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[21] = pertOutput.Cy;     //Yr
            stabDerivOutput.stabDerivs[23] = pertOutput.Cn;     //Nr
            stabDerivOutput.stabDerivs[22] = pertOutput.C_roll; //Lr

            return(stabDerivOutput);
        }
Example #29
0
        private List <MeshData> CreateMeshListFromTransforms(ref List <Transform> meshTransforms)
        {
            DebugClear();
            var meshList           = new List <MeshData>();
            var validTransformList = new List <Transform>();

            if (part.Modules.Contains <KerbalEVA>() || part.Modules.Contains <FlagSite>())
            {
                FARLogger.Info("Adding vox box to Kerbal / Flag");
                meshList.Add(CreateBoxMeshForKerbalEVA());
                validTransformList.Add(part.partTransform);
                meshTransforms = validTransformList;
                return(meshList);
            }

            Matrix4x4 worldToLocalMatrix = part.partTransform.worldToLocalMatrix;
            Bounds    rendererBounds     = part.GetPartOverallMeshBoundsInBasis(worldToLocalMatrix);
            Bounds    colliderBounds     = part.GetPartColliderBoundsInBasis(worldToLocalMatrix);

            bool cantUseColliders = true;
            bool isFairing        = part.Modules.Contains <ModuleProceduralFairing>() ||
                                    part.Modules.Contains("ProceduralFairingSide");
            bool isDrill = part.Modules.Contains <ModuleAsteroidDrill>() ||
                           part.Modules.Contains <ModuleResourceHarvester>();

            //Voxelize colliders
            if ((forceUseColliders ||
                 isFairing ||
                 isDrill ||
                 rendererBounds.size.x * rendererBounds.size.z < colliderBounds.size.x * colliderBounds.size.z * 1.6f &&
                 rendererBounds.size.y < colliderBounds.size.y * 1.2f &&
                 (rendererBounds.center - colliderBounds.center).magnitude < 0.3f) &&
                !forceUseMeshes)
            {
                foreach (Transform t in meshTransforms)
                {
                    MeshData md = GetColliderMeshData(t);
                    if (md == null)
                    {
                        continue;
                    }

                    DebugAddCollider(t);
                    meshList.Add(md);
                    validTransformList.Add(t);
                    cantUseColliders = false;
                }
            }


            if (part.Modules.Contains <ModuleJettison>())
            {
                bool variants = part.Modules.Contains <ModulePartVariants>();
                List <ModuleJettison> jettisons = part.Modules.GetModules <ModuleJettison>();
                var jettisonTransforms          = new HashSet <string>();
                foreach (ModuleJettison j in jettisons)
                {
                    if (j.jettisonTransform == null)
                    {
                        continue;
                    }

                    if (variants)
                    {
                        // with part variants, jettison name is a comma separated list of transform names
                        foreach (string transformName in j.jettisonName.Split(','))
                        {
                            jettisonTransforms.Add(transformName);
                        }
                    }
                    else
                    {
                        jettisonTransforms.Add(j.jettisonTransform.name);
                    }
                    if (j.isJettisoned)
                    {
                        continue;
                    }

                    Transform t = j.jettisonTransform;
                    if (t.gameObject.activeInHierarchy == false)
                    {
                        continue;
                    }

                    MeshData md = GetVisibleMeshData(t, ignoreIfNoRenderer, false);
                    if (md == null)
                    {
                        continue;
                    }

                    DebugAddMesh(t);
                    meshList.Add(md);
                    validTransformList.Add(t);
                }

                //Voxelize Everything
                if ((cantUseColliders || forceUseMeshes || isFairing) && !isDrill)
                {
                    foreach (Transform t in meshTransforms)
                    {
                        if (jettisonTransforms.Contains(t.name))
                        {
                            continue;
                        }
                        MeshData md = GetVisibleMeshData(t, ignoreIfNoRenderer, false);
                        if (md == null)
                        {
                            continue;
                        }

                        DebugAddMesh(t);
                        meshList.Add(md);
                        validTransformList.Add(t);
                    }
                }
            }
            else
            {
                //Voxelize Everything
                if ((cantUseColliders || forceUseMeshes || isFairing) && !isDrill)
                {
                    foreach (Transform t in meshTransforms)
                    {
                        MeshData md = GetVisibleMeshData(t, ignoreIfNoRenderer, false);
                        if (md == null)
                        {
                            continue;
                        }

                        DebugAddMesh(t);
                        meshList.Add(md);
                        validTransformList.Add(t);
                    }
                }
            }

            DebugPrint();
            meshTransforms = validTransformList;
            return(meshList);
        }
        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);
        }