public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = timeSelector.ComputeManeuverTime(o, universalTime, target);

            if (!target.NormalTargetExists)
            {
                throw new OperationException("must select a target to match planes with.");
            }
            else if (o.referenceBody != target.TargetOrbit.referenceBody)
            {
                throw new OperationException("can only match planes with an object in the same sphere of influence.");
            }
            else if (timeSelector.timeReference == TimeReference.REL_ASCENDING)
            {
                if (!o.AscendingNodeExists(target.TargetOrbit))
                {
                    throw new OperationException("ascending node with target doesn't exist.");
                }
            }
            else
            {
                if (!o.DescendingNodeExists(target.TargetOrbit))
                {
                    throw new OperationException("descending node with target doesn't exist.");
                }
            }

            Vector3d dV = (timeSelector.timeReference == TimeReference.REL_ASCENDING) ?
                OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, target.TargetOrbit, UT, out UT):
                OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, target.TargetOrbit, UT, out UT);

            return new ManeuverParameters(dV, UT);
        }
Exemple #2
0
        public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = timeSelector.ComputeManeuverTime(o, universalTime, target);

            if (!target.NormalTargetExists)
            {
                throw new Exception("must select a target to match planes with.");
            }
            else if (o.referenceBody != target.TargetOrbit.referenceBody)
            {
                throw new Exception("can only match planes with an object in the same sphere of influence.");
            }
            else if (timeSelector.timeReference == TimeReference.REL_ASCENDING)
            {
                if (!o.AscendingNodeExists(target.TargetOrbit))
                {
                    throw new Exception("ascending node with target doesn't exist.");
                }
            }
            else
            {
                if (!o.DescendingNodeExists(target.TargetOrbit))
                {
                    throw new Exception("descending node with target doesn't exist.");
                }
            }

            Vector3d dV = (timeSelector.timeReference == TimeReference.REL_ASCENDING) ?
                          OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, target.TargetOrbit, UT, out UT):
                          OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, target.TargetOrbit, UT, out UT);

            return(new ManeuverParameters(dV, UT));
        }
Exemple #3
0
        public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = timeSelector.ComputeManeuverTime(o, universalTime, target);

            if (!target.NormalTargetExists)
            {
                throw new OperationException(Localizer.Format("#MechJeb_match_planes_Exception1"));//must select a target to match planes with.
            }
            else if (o.referenceBody != target.TargetOrbit.referenceBody)
            {
                throw new OperationException(Localizer.Format("#MechJeb_match_planes_Exception2"));//can only match planes with an object in the same sphere of influence.
            }

            var      anExists = o.AscendingNodeExists(target.TargetOrbit);
            var      dnExists = o.DescendingNodeExists(target.TargetOrbit);
            double   anTime   = 0;
            double   dnTime   = 0;
            var      anDeltaV = anExists ? OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, target.TargetOrbit, UT, out anTime) : Vector3d.zero;
            var      dnDeltaV = anExists ? OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, target.TargetOrbit, UT, out dnTime) : Vector3d.zero;
            Vector3d dV;

            if (timeSelector.timeReference == TimeReference.REL_ASCENDING)
            {
                if (!anExists)
                {
                    throw new OperationException(Localizer.Format("#MechJeb_match_planes_Exception3"));//ascending node with target doesn't exist.
                }
                UT = anTime;
                dV = anDeltaV;
            }
            else if (timeSelector.timeReference == TimeReference.REL_DESCENDING)
            {
                if (!dnExists)
                {
                    throw new OperationException(Localizer.Format("#MechJeb_match_planes_Exception4"));//descending node with target doesn't exist.
                }
                UT = dnTime;
                dV = dnDeltaV;
            }
            else if (timeSelector.timeReference == TimeReference.REL_NEAREST_AD)
            {
                if (!anExists && !dnExists)
                {
                    throw new OperationException(Localizer.Format("#MechJeb_match_planes_Exception5"));//neither ascending nor descending node with target exists.
                }
                if (!dnExists || anTime <= dnTime)
                {
                    UT = anTime;
                    dV = anDeltaV;
                }
                else
                {
                    UT = dnTime;
                    dV = dnDeltaV;
                }
            }
            else if (timeSelector.timeReference == TimeReference.REL_HIGHEST_AD)
            {
                if (!anExists && !dnExists)
                {
                    throw new OperationException(Localizer.Format("#MechJeb_match_planes_Exception5"));//neither ascending nor descending node with target exists.
                }
                if (!dnExists || anDeltaV.magnitude <= dnDeltaV.magnitude)
                {
                    UT = anTime;
                    dV = anDeltaV;
                }
                else
                {
                    UT = dnTime;
                    dV = dnDeltaV;
                }
            }
            else
            {
                throw new OperationException(Localizer.Format("#MechJeb_match_planes_Exception6"));//wrong time reference.
            }

            return(new ManeuverParameters(dV, UT));
        }
Exemple #4
0
        protected override void WindowGUI(int windowID)
        {
            if (vessel.patchedConicSolver.maneuverNodes.Count == 0)
            {
                GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label1"));//"No maneuver nodes to edit."
                RelativityModeSelectUI();
                base.WindowGUI(windowID);
                return;
            }

            GUILayout.BeginVertical();

            ManeuverNode oldNode = node;

            if (vessel.patchedConicSolver.maneuverNodes.Count == 1)
            {
                node = vessel.patchedConicSolver.maneuverNodes[0];
            }
            else
            {
                if (!vessel.patchedConicSolver.maneuverNodes.Contains(node))
                {
                    node = vessel.patchedConicSolver.maneuverNodes[0];
                }

                int nodeIndex = vessel.patchedConicSolver.maneuverNodes.IndexOf(node);
                int numNodes  = vessel.patchedConicSolver.maneuverNodes.Count;

                nodeIndex = GuiUtils.ArrowSelector(nodeIndex, numNodes, "Maneuver node #" + (nodeIndex + 1));

                node = vessel.patchedConicSolver.maneuverNodes[nodeIndex];
                if (nodeIndex < (numNodes - 1) && GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button1")))
                {
                    MergeNext(nodeIndex);                                                                                           //"Merge next node"
                }
            }

            if (node != oldNode)
            {
                prograde   = node.DeltaV.z;
                radialPlus = node.DeltaV.x;
                normalPlus = node.DeltaV.y;
            }

            if (gizmo != node.attachedGizmo)
            {
                if (gizmo != null)
                {
                    gizmo.OnGizmoUpdated -= GizmoUpdateHandler;
                }
                gizmo = node.attachedGizmo;
                if (gizmo != null)
                {
                    gizmo.OnGizmoUpdated += GizmoUpdateHandler;
                }
            }


            GUILayout.BeginHorizontal();
            GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label2"), prograde, "m/s", 60);//"Prograde:"
            if (LimitedRepeatButtoon("-"))
            {
                prograde -= progradeDelta;
                node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50));
            if (LimitedRepeatButtoon("+"))
            {
                prograde += progradeDelta;
                node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label3"), radialPlus, "m/s", 60);//"Radial+:"
            if (LimitedRepeatButtoon("-"))
            {
                radialPlus -= radialPlusDelta;
                node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50));
            if (LimitedRepeatButtoon("+"))
            {
                radialPlus += radialPlusDelta;
                node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_NodeEd_Label4"), normalPlus, "m/s", 60);//"Normal+:"
            if (LimitedRepeatButtoon("-"))
            {
                normalPlus -= normalPlusDelta;
                node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50));
            if (LimitedRepeatButtoon("+"))
            {
                normalPlus += normalPlusDelta;
                node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label5"), GUILayout.ExpandWidth(true));//"Set delta to:"
            if (GUILayout.Button("0.01", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 0.01;
            }
            if (GUILayout.Button("0.1", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 0.1;
            }
            if (GUILayout.Button("1", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 1;
            }
            if (GUILayout.Button("10", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 10;
            }
            if (GUILayout.Button("100", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 100;
            }
            GUILayout.EndHorizontal();

            if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button2")))
            {
                node.UpdateNode(new Vector3d(radialPlus, normalPlus, prograde), node.UT);                                                               //"Update"
            }
            GUILayout.BeginHorizontal();
            GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label6"), GUILayout.ExpandWidth(true));//"Shift time"
            if (GUILayout.Button("-o", GUILayout.ExpandWidth(false)))
            {
                node.UpdateNode(node.DeltaV, node.UT - node.patch.period);
            }
            if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
            {
                node.UpdateNode(node.DeltaV, node.UT - timeOffset);
            }
            timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100));
            if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
            {
                node.UpdateNode(node.DeltaV, node.UT + timeOffset);
            }
            if (GUILayout.Button("+o", GUILayout.ExpandWidth(false)))
            {
                node.UpdateNode(node.DeltaV, node.UT + node.patch.period);
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button3"), GUILayout.ExpandWidth(true)))//"Snap node to"
            {
                Orbit  o  = node.patch;
                double UT = node.UT;
                switch (snap)
                {
                case Snap.PERIAPSIS:
                    UT = o.NextPeriapsisTime(o.eccentricity < 1 ? UT - o.period / 2 : UT);
                    break;

                case Snap.APOAPSIS:
                    if (o.eccentricity < 1)
                    {
                        UT = o.NextApoapsisTime(UT - o.period / 2);
                    }
                    break;

                case Snap.EQ_ASCENDING:
                    if (o.AscendingNodeEquatorialExists())
                    {
                        UT = o.TimeOfAscendingNodeEquatorial(UT - o.period / 2);
                    }
                    break;

                case Snap.EQ_DESCENDING:
                    if (o.DescendingNodeEquatorialExists())
                    {
                        UT = o.TimeOfDescendingNodeEquatorial(UT - o.period / 2);
                    }
                    break;

                case Snap.REL_ASCENDING:
                    if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody)
                    {
                        if (o.AscendingNodeExists(core.target.TargetOrbit))
                        {
                            UT = o.TimeOfAscendingNode(core.target.TargetOrbit, UT - o.period / 2);
                        }
                    }
                    break;

                case Snap.REL_DESCENDING:
                    if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody)
                    {
                        if (o.DescendingNodeExists(core.target.TargetOrbit))
                        {
                            UT = o.TimeOfDescendingNode(core.target.TargetOrbit, UT - o.period / 2);
                        }
                    }
                    break;
                }
                node.UpdateNode(node.DeltaV, UT);
            }

            snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]);

            GUILayout.EndHorizontal();

            RelativityModeSelectUI();


            if (core.node != null)
            {
                if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && !core.node.enabled)
                {
                    if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button4")))//"Execute next node"
                    {
                        core.node.ExecuteOneNode(this);
                    }

                    if (MechJebModuleGuidanceController.isLoadedPrincipia && GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button7")))//Execute next Principia node
                    {
                        core.node.ExecuteOnePNode(this);
                    }

                    if (vessel.patchedConicSolver.maneuverNodes.Count > 1)
                    {
                        if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button5")))//"Execute all nodes"
                        {
                            core.node.ExecuteAllNodes(this);
                        }
                    }
                }
                else if (core.node.enabled)
                {
                    if (GUILayout.Button(Localizer.Format("#MechJeb_NodeEd_button6")))//"Abort node execution"
                    {
                        core.node.Abort();
                    }
                }

                GUILayout.BeginHorizontal();
                core.node.autowarp = GUILayout.Toggle(core.node.autowarp, Localizer.Format("#MechJeb_NodeEd_checkbox1"), GUILayout.ExpandWidth(true)); //"Auto-warp"
                GUILayout.Label(Localizer.Format("#MechJeb_NodeEd_Label7"), GUILayout.ExpandWidth(false));                                             //"Tolerance:"
                core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false));
                GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();
            }

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
Exemple #5
0
        public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = 0;

            if (!target.NormalTargetExists)
            {
                throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception1"));//must select a target for the bi-impulsive transfer.
            }
            else if (o.referenceBody != target.TargetOrbit.referenceBody)
            {
                throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception2"));//target for bi-impulsive transfer must be in the same sphere of influence.
            }

            Vector3d dV;

            Orbit targetOrbit = target.TargetOrbit;

            if (periodOffset != 0)
            {
                targetOrbit = target.TargetOrbit.Clone();
                targetOrbit.MutatedOrbit(periodOffset: periodOffset);
            }

            if (simpleTransfer)
            {
                dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, targetOrbit, universalTime, out UT);
            }
            else
            {
                if (timeSelector.timeReference == TimeReference.COMPUTED)
                {
                    dV = OrbitalManeuverCalculator.DeltaVAndTimeForBiImpulsiveAnnealed(o, targetOrbit, universalTime, out UT, intercept_only: intercept_only);
                }
                else
                {
                    var    anExists = o.AscendingNodeExists(target.TargetOrbit);
                    var    dnExists = o.DescendingNodeExists(target.TargetOrbit);
                    double anTime   = o.TimeOfAscendingNode(target.TargetOrbit, universalTime);
                    double dnTime   = o.TimeOfDescendingNode(target.TargetOrbit, universalTime);

                    if (timeSelector.timeReference == TimeReference.REL_ASCENDING)
                    {
                        if (!anExists)
                        {
                            throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception3"));//ascending node with target doesn't exist.
                        }
                        UT = anTime;
                    }
                    else if (timeSelector.timeReference == TimeReference.REL_DESCENDING)
                    {
                        if (!dnExists)
                        {
                            throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception4"));//descending node with target doesn't exist.
                        }
                        UT = dnTime;
                    }
                    else if (timeSelector.timeReference == TimeReference.REL_NEAREST_AD)
                    {
                        if (!anExists && !dnExists)
                        {
                            throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception5"));//neither ascending nor descending node with target exists.
                        }
                        if (!dnExists || anTime <= dnTime)
                        {
                            UT = anTime;
                        }
                        else
                        {
                            UT = dnTime;
                        }
                    }

                    UT = timeSelector.ComputeManeuverTime(o, universalTime, target);
                    dV = OrbitalManeuverCalculator.DeltaVAndTimeForBiImpulsiveAnnealed(o, targetOrbit, UT, out UT, intercept_only: intercept_only, fixed_ut: true);
                }
            }

            return(new ManeuverParameters(dV, UT));
        }
        protected override void WindowGUI(int windowID)
        {
            if (vessel.patchedConicSolver.maneuverNodes.Count == 0)
            {
                GUILayout.Label("No maneuver nodes to edit.");
                RelativityModeSelectUI();
                base.WindowGUI(windowID);
                return;
            }

            GUILayout.BeginVertical();

            ManeuverNode oldNode = node;

            if (vessel.patchedConicSolver.maneuverNodes.Count == 1)
            {
                node = vessel.patchedConicSolver.maneuverNodes[0];
            }
            else
            {
                if (!vessel.patchedConicSolver.maneuverNodes.Contains(node))
                {
                    node = vessel.patchedConicSolver.maneuverNodes[0];
                }

                int nodeIndex = vessel.patchedConicSolver.maneuverNodes.IndexOf(node);
                int numNodes  = vessel.patchedConicSolver.maneuverNodes.Count;

                nodeIndex = GuiUtils.ArrowSelector(nodeIndex, numNodes, "Maneuver node #" + (nodeIndex + 1));

                node = vessel.patchedConicSolver.maneuverNodes[nodeIndex];
            }

            if (node != oldNode)
            {
                prograde   = node.DeltaV.z;
                radialPlus = node.DeltaV.x;
                normalPlus = node.DeltaV.y;
            }

            if (gizmo != node.attachedGizmo)
            {
                if (gizmo != null)
                {
                    gizmo.OnGizmoUpdated -= GizmoUpdateHandler;
                }
                gizmo = node.attachedGizmo;
                if (gizmo != null)
                {
                    gizmo.OnGizmoUpdated += GizmoUpdateHandler;
                }
            }


            GUILayout.BeginHorizontal();
            GuiUtils.SimpleTextBox("Prograde:", prograde, "m/s", 60);
            if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
            {
                prograde -= progradeDelta;
                node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            progradeDelta.text = GUILayout.TextField(progradeDelta.text, GUILayout.Width(50));
            if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
            {
                prograde += progradeDelta;
                node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GuiUtils.SimpleTextBox("Radial+:", radialPlus, "m/s", 60);
            if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
            {
                radialPlus -= radialPlusDelta;
                node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            radialPlusDelta.text = GUILayout.TextField(radialPlusDelta.text, GUILayout.Width(50));
            if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
            {
                radialPlus += radialPlusDelta;
                node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GuiUtils.SimpleTextBox("Normal+:", normalPlus, "m/s", 60);
            if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
            {
                normalPlus -= normalPlusDelta;
                node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            normalPlusDelta.text = GUILayout.TextField(normalPlusDelta.text, GUILayout.Width(50));
            if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
            {
                normalPlus += normalPlusDelta;
                node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }
            GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Set delta to:", GUILayout.ExpandWidth(true));
            if (GUILayout.Button("0.01", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 0.01;
            }
            if (GUILayout.Button("0.1", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 0.1;
            }
            if (GUILayout.Button("1", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 1;
            }
            if (GUILayout.Button("10", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 10;
            }
            if (GUILayout.Button("100", GUILayout.ExpandWidth(true)))
            {
                progradeDelta = radialPlusDelta = normalPlusDelta = 100;
            }
            GUILayout.EndHorizontal();

            if (GUILayout.Button("Update"))
            {
                node.OnGizmoUpdated(new Vector3d(radialPlus, normalPlus, prograde), node.UT);
            }

            GUILayout.BeginHorizontal();
            GUILayout.Label("Shift time", GUILayout.ExpandWidth(true));
            if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
            {
                node.OnGizmoUpdated(node.DeltaV, node.UT - timeOffset);
            }
            timeOffset.text = GUILayout.TextField(timeOffset.text, GUILayout.Width(100));
            if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
            {
                node.OnGizmoUpdated(node.DeltaV, node.UT + timeOffset);
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Snap node to", GUILayout.ExpandWidth(true)))
            {
                Orbit  o  = node.patch;
                double UT = node.UT;
                switch (snap)
                {
                case Snap.PERIAPSIS:
                    UT = o.NextPeriapsisTime(UT - o.period / 2);     //period is who-knows-what for e > 1, but this should still work
                    break;

                case Snap.APOAPSIS:
                    if (o.eccentricity < 1)
                    {
                        UT = o.NextApoapsisTime(UT - o.period / 2);
                    }
                    break;

                case Snap.EQ_ASCENDING:
                    if (o.AscendingNodeEquatorialExists())
                    {
                        UT = o.TimeOfAscendingNodeEquatorial(UT - o.period / 2);
                    }
                    break;

                case Snap.EQ_DESCENDING:
                    if (o.DescendingNodeEquatorialExists())
                    {
                        UT = o.TimeOfDescendingNodeEquatorial(UT - o.period / 2);
                    }
                    break;

                case Snap.REL_ASCENDING:
                    if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody)
                    {
                        if (o.AscendingNodeExists(core.target.TargetOrbit))
                        {
                            UT = o.TimeOfAscendingNode(core.target.TargetOrbit, UT - o.period / 2);
                        }
                    }
                    break;

                case Snap.REL_DESCENDING:
                    if (core.target.NormalTargetExists && core.target.TargetOrbit.referenceBody == o.referenceBody)
                    {
                        if (o.DescendingNodeExists(core.target.TargetOrbit))
                        {
                            UT = o.TimeOfDescendingNode(core.target.TargetOrbit, UT - o.period / 2);
                        }
                    }
                    break;
                }
                node.OnGizmoUpdated(node.DeltaV, UT);
            }

            snap = (Snap)GuiUtils.ArrowSelector((int)snap, numSnaps, snapStrings[(int)snap]);

            GUILayout.EndHorizontal();

            RelativityModeSelectUI();


            if (core.node != null)
            {
                if (vessel.patchedConicSolver.maneuverNodes.Count > 0 && !core.node.enabled)
                {
                    if (GUILayout.Button("Execute next node"))
                    {
                        core.node.ExecuteOneNode(this);
                    }

                    if (vessel.patchedConicSolver.maneuverNodes.Count > 1)
                    {
                        if (GUILayout.Button("Execute all nodes"))
                        {
                            core.node.ExecuteAllNodes(this);
                        }
                    }
                }
                else if (core.node.enabled)
                {
                    if (GUILayout.Button("Abort node execution"))
                    {
                        core.node.Abort();
                    }
                }

                GUILayout.BeginHorizontal();
                core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp", GUILayout.ExpandWidth(true));
                GUILayout.Label("Tolerance:", GUILayout.ExpandWidth(false));
                core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false));
                GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();
            }

            GUILayout.EndVertical();

            base.WindowGUI(windowID);
        }
Exemple #7
0
        bool CheckPreconditions(Orbit o, double UT)
        {
            errorMessage = "";
            bool error = false;

            string burnAltitude = MuUtils.ToSI(o.Radius(UT) - o.referenceBody.Radius) + "m";

            switch (operation)
            {
            case Operation.CIRCULARIZE:
                break;

            case Operation.ELLIPTICIZE:
                if (o.referenceBody.Radius + newPeA > o.Radius(UT))
                {
                    error        = true;
                    errorMessage = "new periapsis cannot be higher than the altitude of the burn (" + burnAltitude + ")";
                }
                else if (o.referenceBody.Radius + newApA < o.Radius(UT))
                {
                    error        = true;
                    errorMessage = "new apoapsis cannot be lower than the altitude of the burn (" + burnAltitude + ")";
                }
                else if (newPeA < -o.referenceBody.Radius)
                {
                    error        = true;
                    errorMessage = "new periapsis cannot be lower than minus the radius of " + o.referenceBody.theName + "(-" + MuUtils.ToSI(o.referenceBody.Radius, 3) + "m)";
                }
                break;

            case Operation.PERIAPSIS:
                if (o.referenceBody.Radius + newPeA > o.Radius(UT))
                {
                    error        = true;
                    errorMessage = "new periapsis cannot be higher than the altitude of the burn (" + burnAltitude + ")";
                }
                else if (newPeA < -o.referenceBody.Radius)
                {
                    error        = true;
                    errorMessage = "new periapsis cannot be lower than minus the radius of " + o.referenceBody.theName + "(-" + MuUtils.ToSI(o.referenceBody.Radius, 3) + "m)";
                }
                break;

            case Operation.APOAPSIS:
                if (o.referenceBody.Radius + newApA < o.Radius(UT))
                {
                    error        = true;
                    errorMessage = "new apoapsis cannot be lower than the altitude of the burn (" + burnAltitude + ")";
                }
                break;

            case Operation.INCLINATION:
                break;

            case Operation.PLANE:
                if (!core.target.NormalTargetExists)
                {
                    error        = true;
                    errorMessage = "must select a target to match planes with.";
                }
                else if (o.referenceBody != core.target.Orbit.referenceBody)
                {
                    error        = true;
                    errorMessage = "can only match planes with an object in the same sphere of influence.";
                }
                else if (timeReference == TimeReference.REL_ASCENDING)
                {
                    if (!o.AscendingNodeExists(core.target.Orbit))
                    {
                        error        = true;
                        errorMessage = "ascending node with target doesn't exist.";
                    }
                }
                else
                {
                    if (!o.DescendingNodeExists(core.target.Orbit))
                    {
                        error        = true;
                        errorMessage = "descending node with target doesn't exist.";
                    }
                }
                break;

            case Operation.TRANSFER:
                if (!core.target.NormalTargetExists)
                {
                    error        = true;
                    errorMessage = "must select a target for the Hohmann transfer.";
                }
                else if (o.referenceBody != core.target.Orbit.referenceBody)
                {
                    error        = true;
                    errorMessage = "target for Hohmann transfer must be in the same sphere of influence.";
                }
                else if (o.eccentricity > 1)
                {
                    error        = true;
                    errorMessage = "starting orbit for Hohmann transfer must not be hyperbolic.";
                }
                else if (core.target.Orbit.eccentricity > 1)
                {
                    error        = true;
                    errorMessage = "target orbit for Hohmann transfer must not be hyperbolic.";
                }
                else if (o.RelativeInclination(core.target.Orbit) > 30 && o.RelativeInclination(core.target.Orbit) < 150)
                {
                    errorMessage = "Warning: target's orbital plane is at a " + o.RelativeInclination(core.target.Orbit).ToString("F0") + "º angle to starting orbit's plane (recommend at most 30º). Planned transfer may not intercept target properly.";
                }
                else if (o.eccentricity > 0.2)
                {
                    errorMessage = "Warning: Recommend starting Hohmann transfers from a near-circular orbit (eccentricity < 0.2). Planned transfer is starting from an orbit with eccentricity " + o.eccentricity.ToString("F2") + " and so may not intercept target properly.";
                }
                break;

            case Operation.COURSE_CORRECTION:
                if (!core.target.NormalTargetExists)
                {
                    error        = true;
                    errorMessage = "must select a target for the course correction.";
                }
                else if (o.referenceBody != core.target.Orbit.referenceBody)
                {
                    error        = true;
                    errorMessage = "target for course correction must be in the same sphere of influence";
                }
                else if (o.NextClosestApproachTime(core.target.Orbit, UT) < UT + 1 ||
                         o.NextClosestApproachDistance(core.target.Orbit, UT) > core.target.Orbit.semiMajorAxis * 0.2)
                {
                    errorMessage = "Warning: orbit before course correction doesn't seem to approach target very closely. Planned course correction may be extreme. Recommend plotting an approximate intercept orbit and then plotting a course correction.";
                }
                break;

            case Operation.INTERPLANETARY_TRANSFER:
                if (!core.target.NormalTargetExists)
                {
                    error        = true;
                    errorMessage = "must select a target for the interplanetary transfer.";
                }
                else if (o.referenceBody.referenceBody == null)
                {
                    error        = true;
                    errorMessage = "doesn't make sense to plot an interplanetary transfer from an orbit around " + o.referenceBody.theName + ".";
                }
                else if (o.referenceBody.referenceBody != core.target.Orbit.referenceBody)
                {
                    error = true;
                    if (o.referenceBody == core.target.Orbit.referenceBody)
                    {
                        errorMessage = "use regular Hohmann transfer function to intercept another body orbiting " + o.referenceBody.theName + ".";
                    }
                    else
                    {
                        errorMessage = "an interplanetary transfer from within " + o.referenceBody.theName + "'s sphere of influence must target a body that orbits " + o.referenceBody.theName + "'s parent, " + o.referenceBody.referenceBody.theName + ".";
                    }
                }
                else if (o.referenceBody.orbit.RelativeInclination(core.target.Orbit) > 30)
                {
                    errorMessage = "Warning: target's orbital plane is at a " + o.RelativeInclination(core.target.Orbit).ToString("F0") + "º angle to " + o.referenceBody.theName + "'s orbital plane (recommend at most 30º). Planned interplanetary transfer may not intercept target properly.";
                }
                else
                {
                    double relativeInclination = Vector3d.Angle(o.SwappedOrbitNormal(), o.referenceBody.orbit.SwappedOrbitNormal());
                    if (relativeInclination > 10)
                    {
                        errorMessage = "Warning: Recommend starting interplanetary transfers from " + o.referenceBody.theName + " from an orbit in the same plane as " + o.referenceBody.theName + "'s orbit around " + o.referenceBody.referenceBody.theName + ". Starting orbit around " + o.referenceBody.theName + " is inclined " + relativeInclination.ToString("F1") + "º with respect to " + o.referenceBody.theName + "'s orbit around " + o.referenceBody.referenceBody.theName + " (recommend < 10º). Planned transfer may not intercept target properly.";
                    }
                    else if (o.eccentricity > 0.2)
                    {
                        errorMessage = "Warning: Recommend starting interplanetary transfers from a near-circular orbit (eccentricity < 0.2). Planned transfer is starting from an orbit with eccentricity " + o.eccentricity.ToString("F2") + " and so may not intercept target properly.";
                    }
                }
                break;

            case Operation.MOON_RETURN:
                if (o.referenceBody.referenceBody == null)
                {
                    error        = true;
                    errorMessage = o.referenceBody.theName + " is not orbiting another body you could return to.";
                }
                else if (o.eccentricity > 0.2)
                {
                    errorMessage = "Warning: Recommend starting moon returns from a near-circular orbit (eccentricity < 0.2). Planned return is starting from an orbit with eccentricity " + o.eccentricity.ToString("F2") + " and so may not be accurate.";
                }
                break;

            case Operation.LAMBERT:
                if (!core.target.NormalTargetExists)
                {
                    error        = true;
                    errorMessage = "must select a target to intercept.";
                }
                else if (o.referenceBody != core.target.Orbit.referenceBody)
                {
                    error        = true;
                    errorMessage = "target must be in the same sphere of influence.";
                }
                break;

            case Operation.KILL_RELVEL:
                if (!core.target.NormalTargetExists)
                {
                    error        = true;
                    errorMessage = "must select a target to match velocities with.";
                }
                else if (o.referenceBody != core.target.Orbit.referenceBody)
                {
                    error        = true;
                    errorMessage = "target must be in the same sphere of influence.";
                }
                break;
            }

            if (error)
            {
                errorMessage = "Couldn't plot maneuver: " + errorMessage;
            }

            return(!error);
        }
        bool CheckPreconditions(Orbit o, double UT)
        {
            errorMessage = "";
            bool error = false;

            string burnAltitude = MuUtils.ToSI(o.Radius(UT) - o.referenceBody.Radius) + "m";

            switch (operation)
            {
                case Operation.CIRCULARIZE:
                    break;

                case Operation.ELLIPTICIZE:
                    if (o.referenceBody.Radius + newPeA > o.Radius(UT))
                    {
                        error = true;
                        errorMessage = "new periapsis cannot be higher than the altitude of the burn (" + burnAltitude + ")";
                    }
                    else if (o.referenceBody.Radius + newApA < o.Radius(UT))
                    {
                        error = true;
                        errorMessage = "new apoapsis cannot be lower than the altitude of the burn (" + burnAltitude + ")";
                    }
                    else if (newPeA < -o.referenceBody.Radius)
                    {
                        error = true;
                        errorMessage = "new periapsis cannot be lower than minus the radius of " + o.referenceBody.theName + "(-" + MuUtils.ToSI(o.referenceBody.Radius, 3) + "m)";
                    }
                    break;

                case Operation.PERIAPSIS:
                    if (o.referenceBody.Radius + newPeA > o.Radius(UT))
                    {
                        error = true;
                        errorMessage = "new periapsis cannot be higher than the altitude of the burn (" + burnAltitude + ")";
                    }
                    else if (newPeA < -o.referenceBody.Radius)
                    {
                        error = true;
                        errorMessage = "new periapsis cannot be lower than minus the radius of " + o.referenceBody.theName + "(-" + MuUtils.ToSI(o.referenceBody.Radius, 3) + "m)";
                    }
                    break;

                case Operation.APOAPSIS:
                    if (o.referenceBody.Radius + newApA < o.Radius(UT))
                    {
                        error = true;
                        errorMessage = "new apoapsis cannot be lower than the altitude of the burn (" + burnAltitude + ")";
                    }
                    break;

                case Operation.INCLINATION:
                    break;

                case Operation.PLANE:
                    if (!core.target.NormalTargetExists)
                    {
                        error = true;
                        errorMessage = "must select a target to match planes with.";
                    }
                    else if (o.referenceBody != core.target.Orbit.referenceBody)
                    {
                        error = true;
                        errorMessage = "can only match planes with an object in the same sphere of influence.";
                    }
                    else if (timeReference == TimeReference.REL_ASCENDING)
                    {
                        if (!o.AscendingNodeExists(core.target.Orbit))
                        {
                            error = true;
                            errorMessage = "ascending node with target doesn't exist.";
                        }
                    }
                    else
                    {
                        if (!o.DescendingNodeExists(core.target.Orbit))
                        {
                            error = true;
                            errorMessage = "descending node with target doesn't exist.";
                        }
                    }
                    break;

                case Operation.TRANSFER:
                    if (!core.target.NormalTargetExists)
                    {
                        error = true;
                        errorMessage = "must select a target for the Hohmann transfer.";
                    }
                    else if (o.referenceBody != core.target.Orbit.referenceBody)
                    {
                        error = true;
                        errorMessage = "target for Hohmann transfer must be in the same sphere of influence.";
                    }
                    else if (o.eccentricity > 1)
                    {
                        error = true;
                        errorMessage = "starting orbit for Hohmann transfer must not be hyperbolic.";
                    }
                    else if (core.target.Orbit.eccentricity > 1)
                    {
                        error = true;
                        errorMessage = "target orbit for Hohmann transfer must not be hyperbolic.";
                    }
                    else if (o.RelativeInclination(core.target.Orbit) > 30 && o.RelativeInclination(core.target.Orbit) < 150)
                    {
                        errorMessage = "Warning: target's orbital plane is at a " + o.RelativeInclination(core.target.Orbit).ToString("F0") + "º angle to starting orbit's plane (recommend at most 30º). Planned transfer may not intercept target properly.";
                    }
                    else if (o.eccentricity > 0.2)
                    {
                        errorMessage = "Warning: Recommend starting Hohmann transfers from a near-circular orbit (eccentricity < 0.2). Planned transfer is starting from an orbit with eccentricity " + o.eccentricity.ToString("F2") + " and so may not intercept target properly.";
                    }
                    break;

                case Operation.COURSE_CORRECTION:
                    if (!core.target.NormalTargetExists)
                    {
                        error = true;
                        errorMessage = "must select a target for the course correction.";
                    }
                    else if (o.referenceBody != core.target.Orbit.referenceBody)
                    {
                        error = true;
                        errorMessage = "target for course correction must be in the same sphere of influence";
                    }
                    else if (o.NextClosestApproachTime(core.target.Orbit, UT) < UT + 1 ||
                        o.NextClosestApproachDistance(core.target.Orbit, UT) > core.target.Orbit.semiMajorAxis * 0.2)
                    {
                        errorMessage = "Warning: orbit before course correction doesn't seem to approach target very closely. Planned course correction may be extreme. Recommend plotting an approximate intercept orbit and then plotting a course correction.";
                    }
                    break;

                case Operation.INTERPLANETARY_TRANSFER:
                    if (!core.target.NormalTargetExists)
                    {
                        error = true;
                        errorMessage = "must select a target for the interplanetary transfer.";
                    }
                    else if (o.referenceBody.referenceBody == null)
                    {
                        error = true;
                        errorMessage = "doesn't make sense to plot an interplanetary transfer from an orbit around " + o.referenceBody.theName + ".";
                    }
                    else if (o.referenceBody.referenceBody != core.target.Orbit.referenceBody)
                    {
                        error = true;
                        if (o.referenceBody == core.target.Orbit.referenceBody) errorMessage = "use regular Hohmann transfer function to intercept another body orbiting " + o.referenceBody.theName + ".";
                        else errorMessage = "an interplanetary transfer from within " + o.referenceBody.theName + "'s sphere of influence must target a body that orbits " + o.referenceBody.theName + "'s parent, " + o.referenceBody.referenceBody.theName + ".";
                    }
                    else if (o.referenceBody.orbit.RelativeInclination(core.target.Orbit) > 30)
                    {
                        errorMessage = "Warning: target's orbital plane is at a " + o.RelativeInclination(core.target.Orbit).ToString("F0") + "º angle to " + o.referenceBody.theName + "'s orbital plane (recommend at most 30º). Planned interplanetary transfer may not intercept target properly.";
                    }
                    else
                    {
                        double relativeInclination = Vector3d.Angle(o.SwappedOrbitNormal(), o.referenceBody.orbit.SwappedOrbitNormal());
                        if (relativeInclination > 10)
                        {
                            errorMessage = "Warning: Recommend starting interplanetary transfers from " + o.referenceBody.theName + " from an orbit in the same plane as " + o.referenceBody.theName + "'s orbit around " + o.referenceBody.referenceBody.theName + ". Starting orbit around " + o.referenceBody.theName + " is inclined " + relativeInclination.ToString("F1") + "º with respect to " + o.referenceBody.theName + "'s orbit around " + o.referenceBody.referenceBody.theName + " (recommend < 10º). Planned transfer may not intercept target properly.";
                        }
                        else if (o.eccentricity > 0.2)
                        {
                            errorMessage = "Warning: Recommend starting interplanetary transfers from a near-circular orbit (eccentricity < 0.2). Planned transfer is starting from an orbit with eccentricity " + o.eccentricity.ToString("F2") + " and so may not intercept target properly.";
                        }
                    }
                    break;

                case Operation.MOON_RETURN:
                    if (o.referenceBody.referenceBody == null)
                    {
                        error = true;
                        errorMessage = o.referenceBody.theName + " is not orbiting another body you could return to.";
                    }
                    else if (o.eccentricity > 0.2)
                    {
                        errorMessage = "Warning: Recommend starting moon returns from a near-circular orbit (eccentricity < 0.2). Planned return is starting from an orbit with eccentricity " + o.eccentricity.ToString("F2") + " and so may not be accurate.";
                    }
                    break;

                case Operation.LAMBERT:
                    if (!core.target.NormalTargetExists)
                    {
                        error = true;
                        errorMessage = "must select a target to intercept.";
                    }
                    else if (o.referenceBody != core.target.Orbit.referenceBody)
                    {
                        error = true;
                        errorMessage = "target must be in the same sphere of influence.";
                    }
                    break;

                case Operation.KILL_RELVEL:
                    if (!core.target.NormalTargetExists)
                    {
                        error = true;
                        errorMessage = "must select a target to match velocities with.";
                    }
                    else if (o.referenceBody != core.target.Orbit.referenceBody)
                    {
                        error = true;
                        errorMessage = "target must be in the same sphere of influence.";
                    }
                    break;
            }

            if (error) errorMessage = "Couldn't plot maneuver: " + errorMessage;

            return !error;
        }
Exemple #9
0
        public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = 0;

            if (!target.NormalTargetExists)
            {
                throw new OperationException("must select a target for the bi-impulsive transfer.");
            }
            else if (o.referenceBody != target.TargetOrbit.referenceBody)
            {
                throw new OperationException("target for bi-impulsive transfer must be in the same sphere of influence.");
            }

            var    anExists = o.AscendingNodeExists(target.TargetOrbit);
            var    dnExists = o.DescendingNodeExists(target.TargetOrbit);
            double anTime   = o.TimeOfAscendingNode(target.TargetOrbit, universalTime);
            double dnTime   = o.TimeOfDescendingNode(target.TargetOrbit, universalTime);

            if (timeSelector.timeReference == TimeReference.REL_ASCENDING)
            {
                if (!anExists)
                {
                    throw new OperationException("ascending node with target doesn't exist.");
                }
                UT = anTime;
            }
            else if (timeSelector.timeReference == TimeReference.REL_DESCENDING)
            {
                if (!dnExists)
                {
                    throw new OperationException("descending node with target doesn't exist.");
                }
                UT = dnTime;
            }
            else if (timeSelector.timeReference == TimeReference.REL_NEAREST_AD)
            {
                if (!anExists && !dnExists)
                {
                    throw new OperationException("neither ascending nor descending node with target exists.");
                }
                if (!dnExists || anTime <= dnTime)
                {
                    UT = anTime;
                }
                else
                {
                    UT = dnTime;
                }
            }
            else if (timeSelector.timeReference != TimeReference.COMPUTED)
            {
                UT = timeSelector.ComputeManeuverTime(o, universalTime, target);
            }

            Vector3d dV;

            if (timeSelector.timeReference == TimeReference.COMPUTED)
            {
                dV = OrbitalManeuverCalculator.DeltaVAndTimeForBiImpulsiveAnnealed(o, target.TargetOrbit, universalTime, out UT, intercept_only: intercept_only);
            }
            else
            {
                dV = OrbitalManeuverCalculator.DeltaVAndTimeForBiImpulsiveAnnealed(o, target.TargetOrbit, UT, out UT, intercept_only: intercept_only, fixed_ut: true);
            }

            return(new ManeuverParameters(dV, UT));
        }
        public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = timeSelector.ComputeManeuverTime(o, universalTime, target);

            if (!target.NormalTargetExists)
            {
                throw new OperationException("must select a target to match planes with.");
            }
            else if (o.referenceBody != target.TargetOrbit.referenceBody)
            {
                throw new OperationException("can only match planes with an object in the same sphere of influence.");
            }

            var anExists = o.AscendingNodeExists(target.TargetOrbit);
            var dnExists = o.DescendingNodeExists(target.TargetOrbit);
            double anTime = 0;
            double dnTime = 0;
            var anDeltaV = anExists ? OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, target.TargetOrbit, UT, out anTime) : Vector3d.zero;
            var dnDeltaV = anExists ? OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, target.TargetOrbit, UT, out dnTime) : Vector3d.zero;
            Vector3d dV;

            if(timeSelector.timeReference == TimeReference.REL_ASCENDING)
            {
                if(!anExists)
                {
                    throw new OperationException("ascending node with target doesn't exist.");
                }
                UT = anTime;
                dV = anDeltaV;
            }
            else if(timeSelector.timeReference == TimeReference.REL_DESCENDING)
            {
                if(!dnExists)
                {
                    throw new OperationException("descending node with target doesn't exist.");
                }
                UT = dnTime;
                dV = dnDeltaV;
            }
            else if(timeSelector.timeReference == TimeReference.REL_NEAREST_AD)
            {
                if(!anExists && !dnExists)
                {
                    throw new OperationException("neither ascending nor descending node with target exists.");
                }
                if(!dnExists || anTime <= dnTime)
                {
                    UT = anTime;
                    dV = anDeltaV;
                }
                else
                {
                    UT = dnTime;
                    dV = dnDeltaV;
                }
            }
            else if(timeSelector.timeReference == TimeReference.REL_HIGHEST_AD)
            {
                if(!anExists && !dnExists)
                {
                    throw new OperationException("neither ascending nor descending node with target exists.");
                }
                if(!dnExists || anDeltaV.magnitude <= dnDeltaV.magnitude)
                {
                    UT = anTime;
                    dV = anDeltaV;
                }
                else
                {
                    UT = dnTime;
                    dV = dnDeltaV;
                }
            }
            else
            {
                throw new OperationException("wrong time reference.");
            }

            return new ManeuverParameters(dV, UT);
        }