public static Operation[] getAvailableOperations()
        {
            // Use reflection to discover all classes that inherit from Operation and have a defalt constructor
            if (operations.Count == 0)
            {
                foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
                {
                    try
                    {
                        addTypes(assembly.GetTypes());
                    }
                    catch (ReflectionTypeLoadException e)
                    {
                        addTypes(e.Types);
                    }
                    catch (InvalidOperationException)
                    {
                        // Silently drop exception generated by users who manage to put assembly that
                        // can't load for reasons (missing deps most of the time)
                    }
                }
                Log.info("ManeuverPlanner initialization: found {0} maneuvers", operations.Count);
            }

            var res = operations.ConvertAll(t => (Operation)t.GetConstructor(Type.EmptyTypes).Invoke(null));

            res.Sort((x, y) => x.getName().CompareTo(y.getName()));
            return(res.ToArray());
        }
 public static void CreateDispatcher()
 {
     if (_instanceExists)
     {
         return;
     }
     Log.info("Starting the Dispatcher");
     new GameObject(typeof(Dispatcher).Name).AddComponent <Dispatcher>();
 }
        IEnumerator Start()
        {
            // We do this in MainMenu because something is going on in that scene that kills anything loaded with a bundle
            if (diffuseAmbient)
            {
                Log.info("Shaders already loaded");
            }

            Log.info("Loading Shaders Bundles");

            // Load the font asset bundle
            AssetBundleCreateRequest bundleLoadRequest = AssetBundle.LoadFromFileAsync(shaderPath);

            yield return(bundleLoadRequest);

            AssetBundle assetBundle = bundleLoadRequest.assetBundle;

            if (assetBundle == null)
            {
                Log.err("Failed to load AssetBundle {0}", shaderPath);
                yield break;
            }

            AssetBundleRequest assetLoadRequest = assetBundle.LoadAssetAsync <Shader>(diffuseAmbientName);

            yield return(assetLoadRequest);

            diffuseAmbient = assetLoadRequest.asset as Shader;

            assetLoadRequest = assetBundle.LoadAssetAsync <Shader>(diffuseAmbientIgnoreZName);
            yield return(assetLoadRequest);

            diffuseAmbientIgnoreZ = assetLoadRequest.asset as Shader;

            assetBundle.Unload(false);
            Log.info("Loaded Shaders Bundles");

            comboBoxBackground          = new Texture2D(16, 16, TextureFormat.RGBA32, false);
            comboBoxBackground.wrapMode = TextureWrapMode.Clamp;

            for (int x = 0; x < comboBoxBackground.width; x++)
            {
                for (int y = 0; y < comboBoxBackground.height; y++)
                {
                    if (x == 0 || x == comboBoxBackground.width - 1 || y == 0 || y == comboBoxBackground.height - 1)
                    {
                        comboBoxBackground.SetPixel(x, y, new Color(0, 0, 0, 1));
                    }
                    else
                    {
                        comboBoxBackground.SetPixel(x, y, new Color(0.05f, 0.05f, 0.05f, 0.95f));
                    }
                }
            }

            comboBoxBackground.Apply();
        }
        private PontryaginLaunch NewPontryaginForLaunch(double inc, double sma)
        {
            lambdaDot = Vector3d.zero;
            double   desiredHeading       = OrbitalManeuverCalculator.HeadingForInclination(inc, vesselState.latitude);
            Vector3d desiredHeadingVector = Math.Sin(desiredHeading * UtilMath.Deg2Rad) * vesselState.east + Math.Cos(desiredHeading * UtilMath.Deg2Rad) * vesselState.north;
            Vector3d desiredThrustVector  = Math.Cos(45 * UtilMath.Deg2Rad) * desiredHeadingVector + Math.Sin(45 * UtilMath.Deg2Rad) * vesselState.up; /* 45 pitch guess */

            lambda = desiredThrustVector;
            Log.info("sma = {0}; deltaV guess = {1}", sma, approximateDeltaV(sma));
            return(new PontryaginLaunch(core: core, mu: mainBody.gravParameter, r0: vesselState.orbitalPosition, v0: vesselState.orbitalVelocity, pv0: lambda, dV: approximateDeltaV(sma)));
        }
        override public void activateAction()
        {
            base.activateAction();
            writeModuleConfiguration();

            /*
             * if (this.launchingToRendezvous)
             * {
             *  this.autopilot.StartCountdown(this.scriptModule.vesselState.time +
             *          LaunchTiming.TimeToPhaseAngle(this.autopilot.launchPhaseAngle,
             *              mainBody, this.scriptModule.vesselState.longitude, targetOrbit));
             * }
             */
            autopilot.users.Add(this);
            Log.info("Autopilot should be engaged!");
        }
Exemple #6
0
        // From FAR with ferram4 authorisation
        public static MechJebModuleDockingAutopilot.Box3d GetBoundingBox(this Vessel vessel, bool debug = false)
        {
            Vector3 minBounds = new Vector3();
            Vector3 maxBounds = new Vector3();

            Log.dbg("[GetBoundingBox] Start {0}", vessel.vesselName);

            for (int i = 0; i < vessel.parts.Count; i++)
            {
                Part p = vessel.parts[i];
                PartExtensions.Vector3Pair partBox = p.GetBoundingBox();

                Log.dbg("[GetBoundingBox] {0} {1:0.000}", p.name, (partBox.p1 - partBox.p2).magnitude);

                maxBounds.x = Mathf.Max(maxBounds.x, partBox.p1.x);
                minBounds.x = Mathf.Min(minBounds.x, partBox.p2.x);
                maxBounds.y = Mathf.Max(maxBounds.y, partBox.p1.y);
                minBounds.y = Mathf.Min(minBounds.y, partBox.p2.y);
                maxBounds.z = Mathf.Max(maxBounds.z, partBox.p1.z);
                minBounds.z = Mathf.Min(minBounds.z, partBox.p2.z);

                //foreach (var sympart in p.symmetryCounterparts)
                //{
                //    partBox = sympart.GetBoundingBox();

                //    maxBounds.x = Mathf.Max(maxBounds.x, partBox.p1.x);
                //    minBounds.x = Mathf.Min(minBounds.x, partBox.p2.x);
                //    maxBounds.y = Mathf.Max(maxBounds.y, partBox.p1.y);
                //    minBounds.y = Mathf.Min(minBounds.y, partBox.p2.y);
                //    maxBounds.z = Mathf.Max(maxBounds.z, partBox.p1.z);
                //    minBounds.z = Mathf.Min(minBounds.z, partBox.p2.z);
                //}
            }

            if (debug)
            {
                Log.info("[GetBoundingBox] End {0}", vessel.vesselName);
            }

            MechJebModuleDockingAutopilot.Box3d box = new MechJebModuleDockingAutopilot.Box3d();

            box.center = new Vector3d((maxBounds.x + minBounds.x) / 2, (maxBounds.y + minBounds.y) / 2, (maxBounds.z + minBounds.z) / 2);
            box.size   = new Vector3d(Math.Abs(box.center.x - maxBounds.x), Math.Abs(box.center.y - maxBounds.y), Math.Abs(box.center.z - maxBounds.z));

            return(box);
        }
        private void CheckForResult()
        {
            lock (readyResults)
            {
                while (readyResults.Count > 0)
                {
                    ReentrySimulation.Result newResult = readyResults.Dequeue();

                    // If running the simulation resulted in an error then just ignore it.
                    if (newResult.outcome != ReentrySimulation.Outcome.ERROR)
                    {
                        if (newResult.body != null)
                        {
                            newResult.endASL = newResult.body.TerrainAltitude(newResult.endPosition.latitude, newResult.endPosition.longitude);
                        }

                        if (newResult.multiplierHasError)
                        {
                            if (errorResult != null)
                            {
                                errorResult.Release();
                            }
                            errorResult = newResult;
                        }
                        else
                        {
                            if (result != null)
                            {
                                result.Release();
                            }
                            result = newResult;
                        }
                    }
                    else
                    {
                        if (newResult.exception != null)
                        {
                            Log.info("Exception in the last simulation\n{0}\n{1}", newResult.exception.Message, newResult.exception.StackTrace);
                        }
                        newResult.Release();
                    }
                }
            }
        }
Exemple #8
0
        void DrivePrelaunch(FlightCtrlState s)
        {
            if (vessel.LiftedOff() && !vessel.Landed)
            {
                status = Localizer.Format("#MechJeb_Ascent_status4");//"Vessel is not landed, skipping pre-launch"
                mode   = AscentMode.ASCEND;
                return;
            }

            if (autoThrottle)
            {
                Log.info("prelaunch killing throttle");
                core.thrust.ThrustOff();
            }

            core.attitude.AxisControl(false, false, false);

            if (timedLaunch && tMinus > 10.0)
            {
                status = "Pre Launch";
                return;
            }

            if (autodeploySolarPanels && mainBody.atmosphere)
            {
                core.solarpanel.RetractAll();
                if (core.solarpanel.AllRetracted())
                {
                    Log.dbg("Prelaunch -> Ascend");
                    mode = AscentMode.ASCEND;
                }
                else
                {
                    status = Localizer.Format("#MechJeb_Ascent_status5");//"Retracting solar panels"
                }
            }
            else
            {
                mode = AscentMode.ASCEND;
            }
        }
        // sma is only used for the initial guess but it is the responsibility of the caller
        public void flightangle4constraintMAXE(double rTm, double gamma, double inc, double LAN, int numStages, double sma, bool omitCoast, bool currentInc)
        {
            if (status == PVGStatus.ENABLED)
            {
                return;
            }

            bool doupdate = false;

            if (rTm != old_rTm || gamma != old_gamma || numStages != old_numStages || LAN != old_LAN)
            {
                doupdate = true;
            }

            // avoid slight drift in the current inclination from resetting guidance constantly
            if (inc != old_inc && !currentInc)
            {
                doupdate = true;
            }

            if (p == null || doupdate)
            {
                if (p != null)
                {
                    Log.dbg("killing a thread if its there to kill");
                    p.KillThread();
                }

                Log.info("MechJebModuleGuidanceController: setting up flightangle3constraintMAXE");
                PontryaginLaunch solver = NewPontryaginForLaunch(inc, sma);
                solver.omitCoast = omitCoast;
                solver.flightangle4constraintMAXE(rTm, gamma * UtilMath.Deg2Rad, inc * UtilMath.Deg2Rad, LAN * UtilMath.Deg2Rad, numStages);
                p = solver;
            }

            old_rTm       = rTm;
            old_gamma     = gamma;
            old_LAN       = LAN;
            old_numStages = numStages;
            old_inc       = inc;
        }
        // sma is only used for the initial guess but it is the responsibility of the caller
        public void flightangle5constraint(double rT, double vT, double inc, double gamma, double LAN, double sma, bool omitCoast, bool currentInc)
        {
            if (status == PVGStatus.ENABLED)
            {
                return;
            }

            bool doupdate = false;

            if (rT != old_rT || vT != old_vT || gamma != old_gamma || LAN != old_LAN)
            {
                doupdate = true;
            }

            // avoid slight drift in the current inclination from resetting guidance constantly
            if (inc != old_inc && !currentInc)
            {
                doupdate = true;
            }

            if (p == null || doupdate)
            {
                if (p != null)
                {
                    p.KillThread();
                }

                Log.info("MechJebModuleGuidanceController: setting up flightangle5constraint, rT: {0}; vT: {1}; inc: {2}; gamma: {3}; LAN: {4}; sma: {5}", rT, vT, inc, gamma, LAN, sma);
                PontryaginLaunch solver = NewPontryaginForLaunch(inc, sma);
                solver.omitCoast = omitCoast;
                solver.flightangle5constraint(rT, vT, gamma * UtilMath.Deg2Rad, inc * UtilMath.Deg2Rad, LAN * UtilMath.Deg2Rad);
                p = solver;
            }

            old_rT    = rT;
            old_vT    = vT;
            old_inc   = inc;
            old_gamma = gamma;
            old_LAN   = LAN;
        }
        public void keplerian5constraint(double sma, double ecc, double inc, double LAN, double ArgP, bool omitCoast, bool currentInc)
        {
            if (status == PVGStatus.ENABLED)
            {
                return;
            }

            bool doupdate = false;

            if (sma != old_sma || ecc != old_ecc || inc != old_inc || LAN != old_LAN || ArgP != old_ArgP)
            {
                doupdate = true;
            }

            // avoid slight drift in the current inclination from resetting guidance constantly
            if (inc != old_inc && !currentInc)
            {
                doupdate = true;
            }

            if (p == null || doupdate)
            {
                if (p != null)
                {
                    p.KillThread();
                }

                Log.info("MechJebModuleGuidanceController: setting up keplerian5constraint");
                PontryaginLaunch solver = NewPontryaginForLaunch(inc, sma);
                solver.omitCoast = omitCoast;
                solver.keplerian5constraint(sma, ecc, inc * UtilMath.Deg2Rad, LAN * UtilMath.Deg2Rad, ArgP * UtilMath.Deg2Rad);
                p = solver;
            }

            old_sma  = sma;
            old_ecc  = ecc;
            old_inc  = inc;
            old_LAN  = LAN;
            old_ArgP = ArgP;
        }
Exemple #12
0
        public override void Drive(FlightCtrlState s)
        {
            float threshold = 0.1F;
            bool  _userCommandingRotation = !(Mathfx.Approx(s.pitch, s.pitchTrim, threshold) &&
                                              Mathfx.Approx(s.yaw, s.yawTrim, threshold) &&
                                              Mathfx.Approx(s.roll, s.rollTrim, threshold));
            bool _userCommandingTranslation = !(Math.Abs(s.X) < threshold &&
                                                Math.Abs(s.Y) < threshold &&
                                                Math.Abs(s.Z) < threshold);

            if (_userCommandingRotation && !_userCommandingTranslation)
            {
                userCommandingRotationSmoothed = 2;
            }
            else if (userCommandingRotationSmoothed > 0)
            {
                userCommandingRotationSmoothed--;
            }

            if (core.GetComputerModule <MechJebModuleThrustWindow>().hidden&& core.GetComputerModule <MechJebModuleAscentGuidance>().hidden)
            {
                return;
            }

            if ((tmode != TMode.OFF) && (vesselState.thrustAvailable > 0))
            {
                double spd = 0;

                switch (tmode)
                {
                case TMode.KEEP_ORBITAL:
                    spd = vesselState.speedOrbital;
                    break;

                case TMode.KEEP_SURFACE:
                    spd = vesselState.speedSurface;
                    break;

                case TMode.KEEP_VERTICAL:
                    spd = vesselState.speedVertical;
                    Vector3d rot = Vector3d.up;
                    if (trans_kill_h)
                    {
                        Vector3 hsdir = Vector3.ProjectOnPlane(vesselState.surfaceVelocity, vesselState.up);
                        Vector3 dir   = -hsdir + vesselState.up * Math.Max(Math.Abs(spd), 20 * mainBody.GeeASL);
                        if ((Math.Min(vesselState.altitudeASL, vesselState.altitudeTrue) > 5000) && (hsdir.magnitude > Math.Max(Math.Abs(spd), 100 * mainBody.GeeASL) * 2))
                        {
                            tmode         = TMode.DIRECT;
                            trans_spd_act = 100;
                            rot           = -hsdir;
                        }
                        else
                        {
                            rot = dir.normalized;
                        }
                        core.attitude.attitudeTo(rot, AttitudeReference.INERTIAL, null);
                    }
                    break;
                }

                double t_err = (trans_spd_act - spd) / vesselState.maxThrustAccel;
                if ((tmode == TMode.KEEP_ORBITAL && Vector3d.Dot(vesselState.forward, vesselState.orbitalVelocity) < 0) ||
                    (tmode == TMode.KEEP_SURFACE && Vector3d.Dot(vesselState.forward, vesselState.surfaceVelocity) < 0))
                {
                    //allow thrust to declerate
                    t_err *= -1;
                }

                double t_act = pid.Compute(t_err);

                if ((tmode != TMode.KEEP_VERTICAL) ||
                    !trans_kill_h ||
                    (core.attitude.attitudeError < 2) ||
                    ((Math.Min(vesselState.altitudeASL, vesselState.altitudeTrue) < 1000) && (core.attitude.attitudeError < 90)))
                {
                    if (tmode == TMode.DIRECT)
                    {
                        trans_prev_thrust = targetThrottle = trans_spd_act / 100.0F;
                    }
                    else
                    {
                        trans_prev_thrust = targetThrottle = Mathf.Clamp01(trans_prev_thrust + (float)t_act);
                    }
                }
                else
                {
                    bool useGimbal = (vesselState.torqueGimbal.positive.x > vesselState.torqueAvailable.x * 10) ||
                                     (vesselState.torqueGimbal.positive.z > vesselState.torqueAvailable.z * 10);

                    bool useDiffThrottle = (vesselState.torqueDiffThrottle.x > vesselState.torqueAvailable.x * 10) ||
                                           (vesselState.torqueDiffThrottle.z > vesselState.torqueAvailable.z * 10);

                    if ((core.attitude.attitudeError >= 2) && (useGimbal || (useDiffThrottle && core.thrust.differentialThrottle)))
                    {
                        trans_prev_thrust = targetThrottle = 0.1F;
                        Log.detail(" targetThrottle = 0.1F");
                    }
                    else
                    {
                        trans_prev_thrust = targetThrottle = 0;
                    }
                }
            }

            // Only set throttle if a module need it. Otherwise let the user or other mods set it
            // There is always at least 1 user : the module itself (why ?)
            if (users.Count > 1)
            {
                s.mainThrottle = targetThrottle;
            }

            throttleLimit      = 1;
            throttleFixedLimit = 1;

            limiter = LimitMode.None;

            if (limitThrottle)
            {
                if (maxThrottle < throttleLimit)
                {
                    setFixedLimit((float)maxThrottle, LimitMode.Throttle);
                }
            }

            if (limitToTerminalVelocity)
            {
                float limit = TerminalVelocityThrottle();
                if (limit < throttleLimit)
                {
                    setFixedLimit(limit, LimitMode.TerminalVelocity);
                }
            }

            if (limitDynamicPressure)
            {
                float limit = MaximumDynamicPressureThrottle();
                if (limit < throttleLimit)
                {
                    setFixedLimit(limit, LimitMode.DynamicPressure);
                }
            }

            if (limitToPreventOverheats)
            {
                float limit = (float)TemperatureSafetyThrottle();
                if (limit < throttleLimit)
                {
                    setFixedLimit(limit, LimitMode.Temperature);
                }
            }

            if (limitAcceleration)
            {
                float limit = AccelerationLimitedThrottle();
                if (limit < throttleLimit)
                {
                    setFixedLimit(limit, LimitMode.Acceleration);
                }
            }

            if (electricThrottle && ElectricEngineRunning())
            {
                float limit = ElectricThrottle();
                if (limit < throttleLimit)
                {
                    setFixedLimit(limit, LimitMode.Electric);
                }
            }

            if (limitToPreventFlameout)
            {
                // This clause benefits being last: if we don't need much air
                // due to prior limits, we can close some intakes.
                float limit = FlameoutSafetyThrottle();
                if (limit < throttleLimit)
                {
                    setFixedLimit(limit, LimitMode.Flameout);
                }
            }

            // Any limiters which can limit to non-zero values must come before this, any
            // limiters (like ullage) which enforce zero throttle should come after.  The
            // minThrottle setting has authority over any other limiter that sets non-zero throttle.
            if (limiterMinThrottle && limiter != LimitMode.None)
            {
                if (minThrottle > throttleFixedLimit)
                {
                    setFixedLimit((float)minThrottle, LimitMode.MinThrottle);
                }
                if (minThrottle > throttleLimit)
                {
                    setTempLimit((float)minThrottle, LimitMode.MinThrottle);
                }
            }

            /* auto-RCS ullaging up to very stable */
            if (autoRCSUllaging && s.mainThrottle > 0.0F && throttleLimit > 0.0F)
            {
                if (vesselState.lowestUllage < VesselState.UllageState.VeryStable)
                {
                    Log.info("RCS auto-ullaging: found state below very stable: {0}", vesselState.lowestUllage);
                    if (vessel.hasEnabledRCSModules())
                    {
                        if (!vessel.ActionGroups[KSPActionGroup.RCS])
                        {
                            Log.info("RCS auto-ullaging: enabling RCS action group for automatic ullaging");
                            vessel.ActionGroups.SetGroup(KSPActionGroup.RCS, true);
                        }
                        Log.info("RCS auto-ullaging: firing RCS to stabilize ulllage");
                        setTempLimit(0.0F, LimitMode.UnstableIgnition);
                        s.Z = -1.0F;
                    }
                    else
                    {
                        Log.info("RCS auto-ullaging: vessel has no enabled/staged RCS modules");
                    }
                }
            }

            /* prevent unstable ignitions */
            if (limitToPreventUnstableIgnition && s.mainThrottle > 0.0F && throttleLimit > 0.0F)
            {
                if (vesselState.lowestUllage < VesselState.UllageState.Stable)
                {
                    ScreenMessages.PostScreenMessage(preventingUnstableIgnitionsMessage);
                    Log.info("Unstable Ignitions: preventing ignition in state: {0}", vesselState.lowestUllage);
                    setTempLimit(0.0F, LimitMode.UnstableIgnition);
                }
            }

            // we have to force the throttle here so that rssMode can work, otherwise we don't get our last throttle command
            // back on the next tick after disabling.  we save this before applying the throttle limits so that we preserve
            // the requested throttle, and not the limited throttle.
            if (core.rssMode)
            {
                SetFlightGlobals(s.mainThrottle);
            }

            if (double.IsNaN(throttleLimit))
            {
                throttleLimit = 1.0F;
            }
            throttleLimit = Mathf.Clamp01(throttleLimit);

            /* we do not _apply_ the "fixed" limit, the actual throttleLimit should always be the more limited and lower one */
            /* the purpose of the "fixed" limit is for external consumers like the node executor to consume */
            if (double.IsNaN(throttleFixedLimit))
            {
                throttleFixedLimit = 1.0F;
            }
            throttleFixedLimit = Mathf.Clamp01(throttleFixedLimit);

            vesselState.throttleLimit      = throttleLimit;
            vesselState.throttleFixedLimit = throttleFixedLimit;

            if (s.mainThrottle < throttleLimit)
            {
                limiter = LimitMode.None;
            }

            s.mainThrottle = Mathf.Min(s.mainThrottle, throttleLimit);

            if (smoothThrottle)
            {
                s.mainThrottle = SmoothThrottle(s.mainThrottle);
            }

            if (double.IsNaN(s.mainThrottle))
            {
                s.mainThrottle = 0;
            }

            s.mainThrottle = Mathf.Clamp01(s.mainThrottle);


            if (s.Z == 0 && core.rcs.rcsThrottle && vesselState.rcsThrust)
            {
                s.Z = -s.mainThrottle;
            }

            lastThrottle = s.mainThrottle;

            if (!core.attitude.enabled)
            {
                Vector3d act = new Vector3d(s.pitch, s.yaw, s.roll);
                differentialThrottleDemandedTorque = -Vector3d.Scale(act.xzy, vesselState.torqueDiffThrottle * s.mainThrottle * 0.5f);
            }
        }
        void LoadComputerModules()
        {
            if (moduleRegistry == null)
            {
                moduleRegistry = new List <Type>();
                foreach (var ass in AppDomain.CurrentDomain.GetAssemblies())
                {
                    try
                    {
                        foreach (var module in (from t in ass.GetTypes() where t.IsSubclassOf(typeof(ComputerModule)) && !t.IsAbstract select t).ToList())
                        {
                            moduleRegistry.Add(module);
                        }
                    }
                    catch (Exception e)
                    {
                        Log.err(e, "moduleRegistry creation threw an exception in LoadComputerModules loading {0}: {1}", ass.FullName, e);
                    }
                }
            }

            Assembly        assembly        = Assembly.GetExecutingAssembly();
            FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);

            // Mono compiler is stupid and use AssemblyVersion for the AssemblyFileVersion
            // So we use an other field to store the dev build number ...
            Attribute[] attributes  = Attribute.GetCustomAttributes(assembly, typeof(AssemblyInformationalVersionAttribute));
            string      dev_version = "";

            if (attributes.Length > 0)
            {
                dev_version = ((AssemblyInformationalVersionAttribute)attributes[0]).InformationalVersion;
            }

            if (dev_version == "")
            {
                version = string.Format("{0}.{1}.{2}", fileVersionInfo.FileMajorPart, fileVersionInfo.FileMinorPart, fileVersionInfo.FileBuildPart);
            }
            else
            {
                version = dev_version;
            }

            if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight)
            {
                Log.info("Loading Mechjeb {0}", version);
            }

            try
            {
                foreach (Type t in moduleRegistry)
                {
                    if ((t != typeof(ComputerModule)) && (t != typeof(DisplayModule) && (t != typeof(MechJebModuleCustomInfoWindow))) &&
                        (t != typeof(AutopilotModule)) &&
                        !blacklist.Contains(t.Name) && (GetComputerModule(t.Name) == null))
                    {
                        ConstructorInfo constructorInfo = t.GetConstructor(new[] { typeof(MechJebCore) });
                        if (constructorInfo != null)
                        {
                            AddComputerModule((ComputerModule)(constructorInfo.Invoke(new object[] { this })));
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.err(e, "moduleRegistry loading threw an exception in LoadComputerModules: {0}", e);
            }

            attitude       = GetComputerModule <MechJebModuleAttitudeController>();
            staging        = GetComputerModule <MechJebModuleStagingController>();
            thrust         = GetComputerModule <MechJebModuleThrustController>();
            target         = GetComputerModule <MechJebModuleTargetController>();
            warp           = GetComputerModule <MechJebModuleWarpController>();
            rcs            = GetComputerModule <MechJebModuleRCSController>();
            rcsbal         = GetComputerModule <MechJebModuleRCSBalancer>();
            rover          = GetComputerModule <MechJebModuleRoverController>();
            node           = GetComputerModule <MechJebModuleNodeExecutor>();
            solarpanel     = GetComputerModule <MechJebModuleSolarPanelController>();
            antennaControl = GetComputerModule <MechJebModuleDeployableAntennaController>();
            landing        = GetComputerModule <MechJebModuleLandingAutopilot>();
            settings       = GetComputerModule <MechJebModuleSettings>();
            airplane       = GetComputerModule <MechJebModuleAirplaneAutopilot>();
            guidance       = GetComputerModule <MechJebModuleGuidanceController>();
            stageStats     = GetComputerModule <MechJebModuleStageStats>();
            stageTracking  = GetComputerModule <MechJebModuleLogicalStageTracking>();
        }
        public void FixedUpdate()
        {
            if (!FlightGlobals.ready)
            {
                return;
            }

            LoadDelayedModules();

            CheckControlledVessel(); //make sure our onFlyByWire callback is registered with the right vessel

            if (this != vessel.GetMasterMechJeb() || (HighLogic.LoadedSceneIsFlight && !vessel.isActiveVessel))
            {
                wasMasterAndFocus = false;
            }

            if (this != vessel.GetMasterMechJeb())
            {
                return;
            }
            Profiler.BeginSample("MechJebCore.FixedUpdate");

            if (!wasMasterAndFocus && (HighLogic.LoadedSceneIsEditor || vessel.isActiveVessel))
            {
                if (HighLogic.LoadedSceneIsFlight && (lastFocus != null) && lastFocus.loaded && (lastFocus.GetMasterMechJeb() != null))
                {
                    Log.info("Focus changed! Forcing {0} to save", lastFocus.vesselName);
                    lastFocus.GetMasterMechJeb().OnSave(null);
                }

                // Clear the modules cache
                ClearModulesCache();

                OnLoad(null); // Force Global reload

                wasMasterAndFocus = true;
                lastFocus         = vessel;
            }

            if (vessel == null)
            {
                Profiler.EndSample();
                return; //don't run ComputerModules' OnFixedUpdate in editor
            }

            Profiler.BeginSample("vesselState");
            ready = vesselState.Update(vessel);
            Profiler.EndSample();

            foreach (ComputerModule module in GetComputerModules <ComputerModule>())
            {
                Profiler.BeginSample(module.profilerName);
                try
                {
                    if (module.enabled)
                    {
                        module.OnFixedUpdate();
                    }
                }
                catch (Exception e)
                {
                    Log.err(e, "module {0} threw an exception in OnFixedUpdate: {1}", module.GetType().Name, e);
                }
                Profiler.EndSample();
            }
            Profiler.EndSample();
        }
Exemple #15
0
        public void SetupToolBarButtons()
        {
            if (!ToolbarManager.ToolbarAvailable)
            {
                return;
            }

            SetupMainToolbarButton();

            foreach (DisplayModule module in core.GetDisplayModules(DisplayOrder.instance).Where(m => !m.hidden))
            {
                Button button;
                if (!toolbarButtons.ContainsKey(module))
                {
                    Log.detail("Create button for module {0}", module.GetName());

                    String name = GetCleanName(module.GetName());

                    String TexturePath       = "MechJeb2/Icons/" + name;
                    String TexturePathActive = TexturePath + "_active";

                    button        = new Button();
                    button.button = ToolbarManager.Instance.add("MechJeb2", name);

                    if (GameDatabase.Instance.GetTexture(TexturePath, false) == null)
                    {
                        button.texturePath = Qmark;
                        Log.info("No icon for {0}", name);
                    }
                    else
                    {
                        button.texturePath = TexturePath;
                    }

                    if (GameDatabase.Instance.GetTexture(TexturePathActive, false) == null)
                    {
                        button.texturePathActive = TexturePath;
                        Log.dbg("No icon for {0}_active", name);
                    }
                    else
                    {
                        button.texturePathActive = TexturePathActive;
                    }

                    toolbarButtons[module] = button;

                    button.button.ToolTip  = "MechJeb " + module.GetName();
                    button.button.OnClick += (b) =>
                    {
                        DisplayModule mod = FlightGlobals.ActiveVessel.GetMasterMechJeb().GetDisplayModules(DisplayOrder.instance).FirstOrDefault(m => m == module);
                        if (mod != null)
                        {
                            mod.enabled = !mod.enabled;
                        }
                    };
                }
                else
                {
                    button = toolbarButtons[module];
                }

                button.button.Visible     = module.showInCurrentScene;
                button.button.TexturePath = module.isActive() ? button.texturePathActive : button.texturePath;
            }

            // create toolbar buttons for features
            if (featureButtons.Count == 0)
            {
                var maneuverPlannerModule = core.GetComputerModule <MechJebModuleManeuverPlanner>();
                if (!HighLogic.LoadedSceneIsEditor && maneuverPlannerModule != null && !maneuverPlannerModule.hidden)
                {
                    CreateFeatureButton(maneuverPlannerModule, "Exec_Node", "MechJeb Execute Next Node", (b) =>
                    {
                        if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && core.node != null)
                        {
                            if (core.node.enabled)
                            {
                                core.node.Abort();
                            }
                            else
                            {
                                if (vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude > 0.0001)
                                {
                                    core.node.ExecuteOneNode(maneuverPlannerModule);
                                }
                                else
                                {
                                    ScreenMessages.PostScreenMessage("Maneuver burn vector not set", 3f);
                                }
                            }
                        }
                        else
                        {
                            ScreenMessages.PostScreenMessage("No maneuver nodes", 2f);
                        }
                    }, () => vessel.patchedConicSolver.maneuverNodes.Count > 0 && core.node != null && core.node.enabled);

                    CreateFeatureButton(maneuverPlannerModule, "Autostage_Once", "MechJeb Autostage Once", (b) =>
                    {
                        var w = core.GetComputerModule <MechJebModuleThrustWindow>();

                        if (core.staging.enabled && core.staging.autostagingOnce)
                        {
                            if (core.staging.users.Contains(w))
                            {
                                core.staging.users.Remove(w);
                                w.autostageSavedState = false;
                            }
                        }
                        else
                        {
                            core.staging.AutostageOnce(w);
                        }
                    }, () => core.staging.enabled && core.staging.autostagingOnce);

                    CreateFeatureButton(maneuverPlannerModule, "Auto_Warp", "MechJeb Auto-warp", (b) =>
                    {
                        core.node.autowarp = !core.node.autowarp;
                    }, () => core.node.autowarp);
                }
            }
        }
        public ManeuverParameters OptimizeEjection(double UT_transfer, Orbit initial_orbit, Orbit target, CelestialBody target_body, double UT_arrival, double earliest_UT)
        {
            int N = 0;

            while (true)
            {
                alglib.minlmstate  state;
                alglib.minlmreport rep;

                double[] x     = new double[5];
                double[] scale = new double[5];

                Vector3d exitDV, captureDV;
                CalcLambertDVs(UT_transfer, UT_arrival - UT_transfer, out exitDV, out captureDV);

                var maneuver = ComputeEjectionManeuver(exitDV, origin, UT_transfer);

                x[0] = maneuver.dV.x;
                x[1] = maneuver.dV.y;
                x[2] = maneuver.dV.z;
                x[3] = maneuver.UT + N * initial_orbit.period;

                scale[0] = scale[1] = scale[2] = maneuver.dV.magnitude;
                scale[3] = initial_orbit.period;

                OptimizerData data = new OptimizerData();
                data.initial_orbit = initial_orbit;
                data.target_orbit  = target;
                data.target_body   = target_body;
                data.UT_arrival    = UT_arrival;
                data.failed        = true;

                alglib.minlmcreatev(4, 3, x, 0.001, out state);
                alglib.minlmsetcond(state, 0, 0);
                alglib.minlmsetscale(state, scale);
                alglib.minlmoptimize(state, DistanceToTarget, null, data);
                alglib.minlmresults(state, out x, out rep);

                Log.info("Transfer calculator: termination type = {0}", rep.terminationtype);
                Log.info("Transfer calculator: iteration count = {0}", rep.iterationscount);

                // try again if we failed to intersect the target orbit
                if (data.failed)
                {
                    Log.info("Failed to intersect target orbit");
                    N++;
                }
                // try again in one orbit if the maneuver node is in the past
                else if (x[3] < earliest_UT || data.failed)
                {
                    Log.info("Transfer calculator: maneuver is {0} s too early, trying again in {1} s", (earliest_UT - x[3]), initial_orbit.period);
                    N++;
                }
                else
                {
                    Log.info("from optimizer DV = {0} t = {1} original arrival = {2}", new Vector3d(x[0], x[1], x[2]), x[3], UT_arrival);
                    return(new ManeuverParameters(new Vector3d(x[0], x[1], x[2]), x[3]));
                }
                if (N > 10)
                {
                    throw new OperationException("Ejection Optimization failed; try manual selection");
                }
            }
        }
        // sma is positive for elliptical, negative for hyperbolic and is the radius of periapsis for parabolic
        public static void Test(double sma, double ecc)
        {
            double        k     = Math.Sqrt(Math.Abs(1 / (sma * sma * sma)));
            List <double> Elist = new List <double>(); // eccentric anomaly
            List <double> tlist = new List <double>(); // time of flight
            List <double> rlist = new List <double>(); // magnitude of r
            List <double> vlist = new List <double>(); // mangitude of v
            List <double> flist = new List <double>(); // true anomaly
            List <double> dlist = new List <double>(); // list of diffs

            for (double E = 0.0; E < 2 * Math.PI; E += Math.PI / 180.0)
            {
                Elist.Add(E);
                double tof = 0;
                if (ecc < 1)
                {
                    tof = (E - ecc * Math.Sin(E)) / k;
                }
                else if (ecc == 1)
                {
                    tof = Math.Sqrt(2) * (E + E * E * E / 3.0) / k;
                }
                else
                {
                    tof = (ecc * Math.Sinh(E) - E) / k;
                }

                tlist.Add(tof);

                double smp = 0;
                if (ecc == 1)
                {
                    smp = 2 * sma;
                }
                else
                {
                    smp = sma * (1.0 - ecc * ecc);
                }

                double energy = 0;
                if (ecc != 1)
                {
                    energy = -1.0 / (2.0 * sma);
                }

                double f = 0;
                if (ecc < 1)
                {
                    f = 2.0 * Math.Atan(Math.Sqrt((1 + ecc) / (1 - ecc)) * Math.Tan(E / 2.0));
                }
                else if (ecc == 1)
                {
                    f = 2 * Math.Atan(E);
                }
                else
                {
                    f = 2.0 * Math.Atan(Math.Sqrt((ecc + 1) / (ecc - 1)) * Math.Tanh(E / 2.0));
                }

                double r = smp / (1.0 + ecc * Math.Cos(f));

                double v = Math.Sqrt(2 * (energy + 1.0 / r));
                if (f < 0)
                {
                    f += 2 * Math.PI;
                }

                rlist.Add(r);
                vlist.Add(v);
                flist.Add(f);
            }

            double diffmax = 0.0;
            int    maxn1   = 0;
            int    maxn2   = 0;

            for (int n1 = 0; n1 < Elist.Count; n1++)
            {
                for (int n2 = n1 + 1; n2 < Elist.Count; n2++)
                {
                    double VR11, VT11, VR12, VT12;
                    double VR21, VT21, VR22, VT22;
                    int    n;

                    VLAMB(1.0, rlist[n1], rlist[n2], flist[n2] - flist[n1], tlist[n2] - tlist[n1], out n, out VR11, out VT11, out VR12, out VT12, out VR21, out VT21, out VR22, out VT22);
                    double Vi    = Math.Sqrt(VR11 * VR11 + VT11 * VT11);
                    double Vf    = Math.Sqrt(VR12 * VR12 + VT12 * VT12);
                    double diff1 = vlist[n1] - Vi;
                    double diff2 = vlist[n2] - Vf;
                    double diff  = Math.Sqrt(diff1 * diff1 + diff2 * diff2);
                    dlist.Add(diff);
                    if (diff > diffmax)
                    {
                        diffmax = diff;
                        maxn1   = n1;
                        maxn2   = n2;
                    }
                }
            }
            DebugLogList(dlist);

            Log.info("diffmax = {0}; n1 = {1}; n2 = ", diffmax, maxn1, maxn2);
        }
Exemple #18
0
        public override void OnUpdate()
        {
            //Commenting this because now we support autostaging on non active vessels
            //if (!vessel.isActiveVessel)
            //    return;

            //if autostage enabled, and if we've already staged at least once, and if there are stages left,
            //and if we are allowed to continue staging, and if we didn't just fire the previous stage
            if (waitingForFirstStaging || vessel.currentStage <= 0 || vessel.currentStage <= autostageLimit || vessel.currentStage <= autostageLimitInternal ||
                vesselState.time - lastStageTime < autostagePostDelay)
            {
                return;
            }

            //don't decouple active or idle engines or tanks
            UpdateActiveModuleEngines();
            UpdateBurnedResources();
            if (InverseStageDecouplesActiveOrIdleEngineOrTank(vessel.currentStage - 1, vessel, burnedResources, activeModuleEngines))
            {
                return;
            }

            // prevent staging when the current stage has active engines and the next stage has any engines (but not decouplers or clamps)
            if (hotStaging && InverseStageHasActiveEngines(vessel.currentStage, vessel) && InverseStageHasEngines(vessel.currentStage - 1, vessel) && !InverseStageFiresDecoupler(vessel.currentStage - 1, vessel) && !InverseStageReleasesClamps(vessel.currentStage - 1, vessel) && LastNonZeroDVStageBurnTime() > hotStagingLeadTime)
            {
                return;
            }

            //Don't fire a stage that will activate a parachute, unless that parachute gets decoupled:
            if (HasStayingChutes(vessel.currentStage - 1, vessel))
            {
                return;
            }

            //Always drop deactivated engines or tanks
            if (!InverseStageDecouplesDeactivatedEngineOrTank(vessel.currentStage - 1, vessel))
            {
                //only decouple fairings if the dynamic pressure, altitude, and aerothermal flux conditions are respected
                if ((core.vesselState.dynamicPressure > fairingMaxDynamicPressure || core.vesselState.altitudeASL < fairingMinAltitude || core.vesselState.freeMolecularAerothermalFlux > fairingMaxAerothermalFlux) &&
                    HasFairing(vessel.currentStage - 1, vessel))
                {
                    return;
                }

                //only release launch clamps if we're at nearly full thrust
                if (vesselState.thrustCurrent / vesselState.thrustAvailable < clampAutoStageThrustPct &&
                    InverseStageReleasesClamps(vessel.currentStage - 1, vessel))
                {
                    return;
                }
            }

            //When we find that we're allowed to stage, start a countdown (with a
            //length given by autostagePreDelay) and only stage once that countdown finishes,
            if (countingDown)
            {
                if (vesselState.time - stageCountdownStart > autostagePreDelay)
                {
                    if (InverseStageFiresDecoupler(vessel.currentStage - 1, vessel))
                    {
                        //if we decouple things, delay the next stage a bit to avoid exploding the debris
                        lastStageTime = vesselState.time;
                    }

                    if (!this.vessel.isActiveVessel)
                    {
                        this.currentActiveVessel = FlightGlobals.ActiveVessel;
                        Log.info($"Mechjeb Autostage: Switching from {0} to vessel {1} to stage", FlightGlobals.ActiveVessel.name, this.vessel.name);

                        this.remoteStagingStatus = RemoteStagingState.WaitingFocus;
                        FlightGlobals.ForceSetActiveVessel(this.vessel);
                    }
                    else
                    {
                        Log.info("Mechjeb Autostage: Executing next stage on {0}", FlightGlobals.ActiveVessel.name);

                        if (remoteStagingStatus == RemoteStagingState.Disabled)
                        {
                            StageManager.ActivateNextStage();
                        }
                        else if (remoteStagingStatus == RemoteStagingState.FocusFinished)
                        {
                            StageManager.ActivateNextStage();
                            FlightGlobals.ForceSetActiveVessel(currentActiveVessel);
                            Log.info("Mechjeb Autostage: Has switching back to {0} ", FlightGlobals.ActiveVessel.name);
                            this.remoteStagingStatus = RemoteStagingState.Disabled;
                        }
                    }
                    countingDown = false;

                    if (autostagingOnce)
                    {
                        users.Clear();
                    }
                }
            }
            else
            {
                countingDown        = true;
                stageCountdownStart = vesselState.time;
            }
        }
Exemple #19
0
        private void InitLandingSitesList()
        {
            landingSites = new List <LandingSite>();

            // Import landing sites from users createded .cfg
            foreach (var mjConf in GameDatabase.Instance.GetConfigs("MechJeb2Landing"))
            {
                foreach (ConfigNode site in mjConf.config.GetNode("LandingSites").GetNodes("Site"))
                {
                    Log.info("site {0}", site);
                    string launchSiteName = site.GetValue("name");
                    string lat            = site.GetValue("latitude");
                    string lon            = site.GetValue("longitude");

                    if (launchSiteName == null || lat == null || lon == null)
                    {
                        Log.info("Ignore langing site with null value");
                        continue;
                    }

                    double latitude, longitude;
                    double.TryParse(lat, out latitude);
                    double.TryParse(lon, out longitude);

                    string        bodyName = site.GetValue("body");
                    CelestialBody body     = bodyName != null?FlightGlobals.Bodies.Find(b => b.bodyName == bodyName) : Planetarium.fetch.Home;

                    if (!landingSites.Any(p => p.name == launchSiteName))
                    {
                        Log.info("Adding {0}", launchSiteName);
                        landingSites.Add(new LandingSite()
                        {
                            name      = launchSiteName,
                            latitude  = latitude,
                            longitude = longitude,
                            body      = body
                        });
                    }
                }
            }

            // Import KerbTown/Kerbal-Konstructs launch site
            foreach (var config in GameDatabase.Instance.GetConfigs("STATIC"))
            {
                foreach (ConfigNode instances in config.config.GetNodes("Instances"))
                {
                    string bodyName       = instances.GetValue("CelestialBody");
                    string radialPos      = instances.GetValue("RadialPosition");
                    string launchSiteName = instances.GetValue("LaunchSiteName");
                    string launchSiteType = instances.GetValue("LaunchSiteType");

                    if (bodyName == null || radialPos == null || launchSiteName == null || launchSiteType == null ||
                        launchSiteType != "VAB")
                    {
                        continue;
                    }

                    Vector3d      pos  = ConfigNode.ParseVector3D(radialPos).normalized;
                    CelestialBody body = FlightGlobals.Bodies.Find(b => b.bodyName == bodyName);

                    double latitude  = Math.Asin(pos.y) * UtilMath.Rad2Deg;
                    double longitude = Math.Atan2(pos.z, pos.x) * UtilMath.Rad2Deg;

                    if (body != null && !landingSites.Any(p => p.name == launchSiteName))
                    {
                        landingSites.Add(new LandingSite()
                        {
                            name      = launchSiteName,
                            latitude  = !double.IsNaN(latitude) ? latitude : 0,
                            longitude = !double.IsNaN(longitude) ? longitude : 0,
                            body      = body
                        });
                    }
                }
            }

            // Import RSS Launch sites
            UrlDir.UrlConfig rssSites = GameDatabase.Instance.GetConfigs("KSCSWITCHER").FirstOrDefault();
            if (rssSites != null)
            {
                ConfigNode launchSites = rssSites.config.GetNode("LaunchSites");
                if (launchSites != null)
                {
                    foreach (ConfigNode site in launchSites.GetNodes("Site"))
                    {
                        string     launchSiteName = site.GetValue("displayName");
                        ConfigNode pqsCity        = site.GetNode("PQSCity");
                        if (pqsCity == null)
                        {
                            continue;
                        }

                        string lat = pqsCity.GetValue("latitude");
                        string lon = pqsCity.GetValue("longitude");

                        if (launchSiteName == null || lat == null || lon == null)
                        {
                            continue;
                        }

                        double latitude, longitude;
                        double.TryParse(lat, out latitude);
                        double.TryParse(lon, out longitude);

                        if (!landingSites.Any(p => p.name == launchSiteName))
                        {
                            landingSites.Add(new LandingSite()
                            {
                                name      = launchSiteName,
                                latitude  = latitude,
                                longitude = longitude,
                                body      = Planetarium.fetch.Home
                            });
                        }
                    }
                }
            }

            if (landingSiteIdx > landingSites.Count)
            {
                landingSiteIdx = 0;
            }
        }
        public override void Bootstrap(double t0)
        {
            int stageCount = numStages > 0 ? numStages : stages.Count;

            // build arcs off of ksp stages, with coasts
            List <Arc> arcs = new List <Arc>();

            for (int i = 0; i < stageCount; i++)
            {
                arcs.Add(new Arc(this, stage: stages[i], t0: t0));
            }

            // bootstrap with infinite ISP upper stage
            arcs[arcs.Count - 1].infinite = true;

            // allocate y0
            y0 = new double[arcIndex(arcs, arcs.Count)];

            // update initial position and guess for first arc
            double ve = g0 * stages[0].isp;

            tgo     = ve * stages[0].startMass / stages[0].startThrust * (1 - Math.Exp(-dV / ve));
            tgo_bar = tgo / t_scale;

            // initialize overall burn time
            y0[0] = tgo_bar;

            UpdateY0(arcs);

            // seed continuity initial conditions
            yf = new double[arcs.Count * 13];
            multipleIntegrate(y0, yf, arcs, initialize: true);


            if (!runOptimizer(arcs))
            {
                Fatal("Target is unreachable even with infinite ISP");
                return;
            }

            Solution new_sol = new Solution(t_scale, v_scale, r_scale, t0);

            multipleIntegrate(y0, new_sol, arcs, 10);

            for (int i = arcs.Count - 1; i >= 0; i--)
            {
                if (new_sol.tgo(new_sol.t0, i) < 1)
                {
                    // burn is less than one second, delete it
                    RemoveArc(arcs, i, new_sol);
                }
            }

            bool insertedCoast = false;

            if (arcs.Count > 1 && !omitCoast)
            {
                InsertCoast(arcs, arcs.Count - 1, new_sol);
                insertedCoast = true;
            }
            arcs[arcs.Count - 1].infinite = false;

            // now that we're done with the infinite burn make sure the total burn time of the guess doesn't exceed the rocket.
            double tot_bt_bar = 0.0;

            for (int i = 0; i < arcs.Count; i++)
            {
                if (!arcs[i].coast)
                {
                    tot_bt_bar += arcs[i].max_bt_bar;
                }
            }

            y0[0] = Math.Min(tot_bt_bar, y0[0]);

            if (!runOptimizer(arcs))
            {
                if (insertedCoast)
                {
                    Log.info("failed to converge with a coast, removing from the solution");

                    RemoveArc(arcs, arcs.Count - 2, new_sol);
                    insertedCoast = false;

                    if (!runOptimizer(arcs))
                    {
                        Fatal("Target is unreachable");
                        y0 = null;
                        return;
                    }
                }
                else
                {
                    Fatal("Target is unreachable");
                    y0 = null;
                    return;
                }
            }

            if (insertedCoast)
            {
                new_sol = new Solution(t_scale, v_scale, r_scale, t0);
                multipleIntegrate(y0, new_sol, arcs, 10);

                double coastlen = new_sol.tgo(new_sol.t0, arcs.Count - 2); // human seconds

                if (coastlen < 1)
                {
                    Log.info("optimum coast of {0} seconds was removed from the solution", coastlen);

                    RemoveArc(arcs, arcs.Count - 2, new_sol);

                    if (!runOptimizer(arcs))
                    {
                        Fatal("failed to converge after removing negative length coast after jettison");
                        return;
                    }
                }
            }

            new_sol = new Solution(t_scale, v_scale, r_scale, t0);
            multipleIntegrate(y0, new_sol, arcs, 10);

            this.solution = new_sol;

            yf = new double[arcs.Count * 13];
            multipleIntegrate(y0, yf, arcs);
        }