private static string SelectorText(FrameType type,
                                               CelestialBody selected)
            {
                string abbreviation = Abbreviation(type, selected);

                if (abbreviation != null)
                {
                    return(abbreviation);
                }
                switch (type)
                {
                case FrameType.BODY_CENTRED_NON_ROTATING:
                    return(L10N.CacheFormat(
                               "#Principia_ReferenceFrameSelector_SelectorText_BodyCentredNonRotating"));

                case FrameType.BARYCENTRIC_ROTATING:
                    return("DEPRECATED");

                case FrameType.BODY_CENTRED_PARENT_DIRECTION:
                    return(L10N.CacheFormat(
                               "#Principia_ReferenceFrameSelector_SelectorText_BodyCentredParentDirection"));

                case FrameType.BODY_SURFACE:
                    return(L10N.CacheFormat(
                               "#Principia_ReferenceFrameSelector_SelectorText_BodySurface"));

                default:
                    throw Log.Fatal("Unexpected type " + type.ToString());
                }
            }
 private static string TargetFrameDescription(Vessel target)
 {
     return(L10N.CacheFormat(
                "#Principia_ReferenceFrameSelector_Description_Target",
                target.vesselName,
                target.orbit.referenceBody.Name()));
 }
            private static string SelectorTooltip(FrameType type,
                                                  CelestialBody selected)
            {
                string name = Name(type, selected);

                switch (type)
                {
                case FrameType.BODY_CENTRED_NON_ROTATING:
                    return(L10N.CacheFormat(
                               "#Principia_ReferenceFrameSelector_Tooltip_BodyCentredNonRotating",
                               name,
                               selected.Name()));

                case FrameType.BARYCENTRIC_ROTATING:
                    return("DEPRECATED");

                case FrameType.BODY_CENTRED_PARENT_DIRECTION:
                    return(L10N.CacheFormat(
                               "#Principia_ReferenceFrameSelector_Tooltip_BodyCentredParentDirection",
                               name,
                               selected.Name()));

                case FrameType.BODY_SURFACE:
                    return(L10N.CacheFormat(
                               "#Principia_ReferenceFrameSelector_Tooltip_BodySurface",
                               name,
                               selected.Name()));

                default:
                    throw Log.Fatal("Unexpected type " + type.ToString());
                }
            }
            protected override void RenderWindowContents(int window_id)
            {
                using (new UnityEngine.GUILayout.VerticalScope()) {
                    UnityEngine.GUILayout.Label(
                        L10N.CacheFormat(
                            "#Principia_ReferenceFrameSelector_Description_Heading",
                            Name(),
                            Abbreviation()));
                    UnityEngine.GUILayout.Label(
                        target_frame_selected ? TargetFrameDescription(target)
                                : Description(frame_type, selected_celestial),
                        Style.Multiline(UnityEngine.GUI.skin.label),
                        GUILayoutHeight(3));
                    using (new UnityEngine.GUILayout.HorizontalScope()) {
                        // Left-hand side: tree view of celestials.
                        using (new UnityEngine.GUILayout.VerticalScope(GUILayoutWidth(8))) {
                            RenderSubtree(celestial: Planetarium.fetch.Sun, depth: 0);
                        }

                        // Right-hand side: toggles for reference frame type selection.
                        using (new UnityEngine.GUILayout.VerticalScope()) {
                            RenderSubtreeToggleGrid(Planetarium.fetch.Sun);
                        }
                    }
                }
                UnityEngine.GUI.DragWindow();
            }
示例#5
0
            private void RenderOrbitGroundTrack(OrbitGroundTrack?ground_track,
                                                CelestialBody primary)
            {
                using (new UnityEngine.GUILayout.HorizontalScope()) {
                    UnityEngine.GUILayout.Label(
                        L10N.CacheFormat(
                            "#Principia_OrbitAnalyser_GroundTrack_LongitudesOfEquatorialCrossings_Prefix"),
                        UnityEngine.GUILayout.ExpandWidth(false));
                    string text = UnityEngine.GUILayout.TextField(
                        $"{ground_track_revolution_}",
                        GUILayoutWidth(2));
                    UnityEngine.GUILayout.Label(
                        L10N.CacheFormat(
                            "#Principia_OrbitAnalyser_GroundTrack_LongitudesOfEquatorialCrossings_Suffix"));
                    if (int.TryParse(text, out int revolution))
                    {
                        ground_track_revolution_ = revolution;
                    }
                }
                var equatorial_crossings = ground_track?.equatorial_crossings;

                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_GroundTrack_AscendingPass"),
                    equatorial_crossings?.longitudes_reduced_to_ascending_pass.
                    FormatEquatorialAngleInterval(primary));
                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_GroundTrack_DescendingPass"),
                    equatorial_crossings?.longitudes_reduced_to_descending_pass.
                    FormatEquatorialAngleInterval(primary));
            }
示例#6
0
            private void RenderLowestAltitude(OrbitalElements?elements,
                                              CelestialBody primary)
            {
                double?lowest_distance = elements?.radial_distance.min;

                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Elements_LowestAltitude"),
                    (lowest_distance - primary?.Radius)?.FormatAltitude());
                double?lowest_primary_distance = primary?.ocean == true
                                          ? primary.Radius
                                          : primary?.pqsController?.radiusMin;
                string altitude_warning =
                    lowest_distance < lowest_primary_distance
            ?
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Warning_Collision")
            : lowest_distance < primary?.pqsController?.radiusMax
                ? L10N.CacheFormat(
                        "#Principia_OrbitAnalyser_Warning_CollisionRisk")
                : lowest_distance < primary?.Radius + primary?.atmosphereDepth
                    ? L10N.CacheFormat(
                        "#Principia_OrbitAnalyser_Warning_Reentry")
                    : "";

                UnityEngine.GUILayout.Label(altitude_warning,
                                            Style.Warning(UnityEngine.GUI.skin.label));
            }
            private static string TargetFrameSelectorTooltip(Vessel target)
            {
                string name = TargetFrameName(target);

                return(L10N.CacheFormat(
                           "#Principia_ReferenceFrameSelector_Tooltip_Target",
                           name));
            }
示例#8
0
 protected override string ButtonText(string orbit_description)
 {
     return(orbit_description == null
    ? L10N.CacheFormat(
                "#Principia_PlannedOrbitAnalyser_ToggleButton")
    : L10N.CacheFormat(
                "#Principia_PlannedOrbitAnalyser_ToggleButtonWithDescription",
                orbit_description));
 }
 public void RenderButton()
 {
     if (UnityEngine.GUILayout.Button(
             L10N.CacheFormat("#Principia_ReferenceFrameSelector_ToggleButton",
                              name_,
                              Name())))
     {
         Toggle();
     }
 }
示例#10
0
            private static string FormatOrNull(string template, params object[] args)
            {
                // Optional translations include the language name so that they do not fall
                // back to English.
                string qualified_template = $"{template}.{UILanguage()}";

                if (!Localizer.Tags.ContainsKey(qualified_template))
                {
                    return(null);
                }
                return(L10N.CacheFormat(qualified_template, args));
            }
示例#11
0
 public BurnEditor(PrincipiaPluginAdapter adapter,
                   Vessel vessel,
                   double initial_time,
                   int index,
                   Func <int, BurnEditor> get_burn_at_index)
 {
     adapter_           = adapter;
     vessel_            = vessel;
     initial_time_      = initial_time;
     this.index         = index;
     get_burn_at_index_ = get_burn_at_index;
     Δv_tangent_        = new DifferentialSlider(
         label: L10N.CacheFormat("#Principia_BurnEditor_ΔvTangent"),
         unit: L10N.CacheFormat("#Principia_BurnEditor_SpeedUnit"),
         log10_lower_rate: log10_Δv_lower_rate,
         log10_upper_rate: log10_Δv_upper_rate,
         text_colour: Style.Tangent);
     Δv_normal_ = new DifferentialSlider(
         label: L10N.CacheFormat("#Principia_BurnEditor_ΔvNormal"),
         unit: L10N.CacheFormat("#Principia_BurnEditor_SpeedUnit"),
         log10_lower_rate: log10_Δv_lower_rate,
         log10_upper_rate: log10_Δv_upper_rate,
         text_colour: Style.Normal);
     Δv_binormal_ = new DifferentialSlider(
         label: L10N.CacheFormat("#Principia_BurnEditor_ΔvBinormal"),
         unit: L10N.CacheFormat("#Principia_BurnEditor_SpeedUnit"),
         log10_lower_rate: log10_Δv_lower_rate,
         log10_upper_rate: log10_Δv_upper_rate,
         text_colour: Style.Binormal);
     previous_coast_duration_ = new DifferentialSlider(
         label:
         L10N.CacheFormat("#Principia_BurnEditor_InitialTime"),
         unit: null,
         log10_lower_rate: log10_time_lower_rate,
         log10_upper_rate: log10_time_upper_rate,
         // We cannot have a coast of length 0, so let's make it very
         // short: that will be indistinguishable.
         zero_value: 0.001,
         min_value: 0,
         formatter: FormatPreviousCoastDuration,
         parser: TryParsePreviousCoastDuration,
         field_width: 7)
     {
         value = initial_time_ - time_base
     };
     reference_frame_selector_ = new ReferenceFrameSelector(
         adapter_,
         ReferenceFrameChanged,
         L10N.CacheFormat("#Principia_BurnEditor_ManœuvringFrame"));
     reference_frame_selector_.SetFrameParameters(
         adapter_.plotting_frame_selector_.FrameParameters());
     ComputeEngineCharacteristics();
 }
示例#12
0
            private void RenderOrbitalElements(OrbitalElements?elements,
                                               CelestialBody primary)
            {
                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Elements_SiderealPeriod"),
                    elements?.sidereal_period.FormatDuration());
                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Elements_NodalPeriod"),
                    elements?.nodal_period.FormatDuration());
                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Elements_AnomalisticPeriod"),
                    elements?.anomalistic_period.FormatDuration());
                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Elements_SemimajorAxis"),
                    elements?.mean_semimajor_axis.FormatLengthInterval());
                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Elements_Eccentricity"),
                    elements?.mean_eccentricity.FormatInterval());
                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Elements_Inclination"),
                    elements?.mean_inclination.FormatAngleInterval());
                LabeledField(
                    L10N.CacheFormat(
                        "#Principia_OrbitAnalyser_Elements_LongitudeOfAscendingNode"),
                    elements?.mean_longitude_of_ascending_nodes.FormatAngleInterval());
                LabeledField(
                    L10N.CacheFormat("#Principia_OrbitAnalyser_Elements_NodalPrecession"),
                    elements?.nodal_precession.FormatAngularFrequency());
                string periapsis = L10N.CelestialString(
                    "#Principia_OrbitAnalyser_Elements_Periapsis",
                    new[] { primary });
                string apoapsis = L10N.CelestialString(
                    "#Principia_OrbitAnalyser_Elements_Apoapsis",
                    new[] { primary });

                LabeledField(
                    L10N.CacheFormat(
                        "#Principia_OrbitAnalyser_Elements_ArgumentOfPeriapsis",
                        periapsis),
                    elements?.mean_argument_of_periapsis.FormatAngleInterval());
                LabeledField(
                    L10N.CacheFormat(
                        "#Principia_OrbitAnalyser_Elements_MeanPeriapsisAltitude",
                        periapsis),
                    elements?.mean_periapsis_distance.FormatLengthInterval(primary.Radius));
                LabeledField(
                    L10N.CacheFormat(
                        "#Principia_OrbitAnalyser_Elements_MeanApoapsisAltitude",
                        apoapsis),
                    elements?.mean_apoapsis_distance.FormatLengthInterval(primary.Radius));
            }
示例#13
0
            // Similar to |FormatAngleInterval|, but annotated with the equivalent
            // of the half-width as a distance at the equator in parentheses.
            public static string FormatEquatorialAngleInterval(this Interval interval,
                                                               CelestialBody primary)
            {
                double half_width_angle = (interval.max - interval.min) / 2;

                if (half_width_angle > Math.PI)
                {
                    return(L10N.CacheFormat("#Principia_OrbitAnalyser_Precesses"));
                }
                double half_width_distance = half_width_angle * primary.Radius;
                string formatted_distance  = half_width_distance > 1000
                                    ? $"{(half_width_distance / 1000).FormatN(1)} km"
                                    : $"{(half_width_distance).FormatN(0)} m";

                return($"{interval.FormatAngleInterval()} ({formatted_distance})");
            }
示例#14
0
            // Displays an interval of angles (given in radians) as midpoint°±half-width°,
            // or the string "(precesses)" if the half-width exceeds 180°.
            public static string FormatAngleInterval(this Interval interval)
            {
                double half_width = (interval.max - interval.min) / 2;
                double midpoint   = interval.min + half_width;

                if (half_width > Math.PI)
                {
                    return(L10N.CacheFormat("#Principia_OrbitAnalyser_Precesses"));
                }
                const double degree            = Math.PI / 180;
                int          fractional_digits =
                    Math.Max(0, 1 - (int)Math.Floor(Math.Log10(half_width / degree)));
                string formatted_midpoint   = (midpoint / degree).FormatN(fractional_digits);
                string formatted_half_width =
                    (half_width / degree).FormatN(fractional_digits);

                return($"{formatted_midpoint}°±{formatted_half_width}°");
            }
示例#15
0
            private bool RenderSelector <T>(T[] array,
                                            ref int index,
                                            string label,
                                            string format,
                                            bool enabled)
            {
                bool changed = false;

                using (new UnityEngine.GUILayout.HorizontalScope()) {
                    UnityEngine.GUILayout.Label(text: label,
                                                options: GUILayoutWidth(6));
                    if (UnityEngine.GUILayout.Button(
                            text: index == 0
                            ? L10N.CacheFormat(
                                "#Principia_DiscreteSelector_Min")
                            : "-",
                            options: GUILayoutWidth(2)) &&
                        enabled &&
                        index != 0)
                    {
                        --index;
                        changed = true;
                    }
                    UnityEngine.GUILayout.TextArea(
                        text: enabled
                        ? string.Format(Culture.culture, format, array[index])
                        : "",
                        style: Style.RightAligned(UnityEngine.GUI.skin.textArea),
                        options: GUILayoutWidth(3));
                    if (UnityEngine.GUILayout.Button(
                            text: index == array.Length - 1
                            ? L10N.CacheFormat(
                                "#Principia_DiscreteSelector_Max")
                            : "+",
                            options: GUILayoutWidth(2)) &&
                        enabled &&
                        index != array.Length - 1)
                    {
                        ++index;
                        changed = true;
                    }
                }
                return(changed);
            }
示例#16
0
            private void ComputeRCSCharacteristics()
            {
                ModuleRCS[] active_rcs = (from part in vessel_.parts
                                          select(from PartModule module in part.Modules
                                                 where module is ModuleRCS module_rcs &&
                                                 module_rcs.rcsEnabled
                                                 select module as ModuleRCS)).
                                         SelectMany(x => x).ToArray();
                Vector3d reference_direction = vessel_.ReferenceTransform.up;

                // NOTE(egg): NathanKell informs me that in >= 1.0.5, RCS has a useZaxis
                // property, that controls whether they thrust -up or -forward.  The madness
                // keeps piling up.
                double[] thrusts = (from engine in active_rcs
                                    select engine.thrusterPower *
                                    (from transform in engine.thrusterTransforms
                                     where transform.gameObject.activeInHierarchy
                                     select Math.Max(0,
                                                     Vector3d.Dot(
                                                         reference_direction,
                                                         -transform.up))).Sum()).
                                   ToArray();
                thrust_in_kilonewtons_ = thrusts.Sum();

                // This would use zip if we had 4.0 or later.  We loop for now.
                double Σ_f_over_i_sp = 0;

                for (int i = 0; i < active_rcs.Length; ++i)
                {
                    Σ_f_over_i_sp +=
                        thrusts[i] / active_rcs[i].atmosphereCurve.Evaluate(0);
                }
                specific_impulse_in_seconds_g0_ = thrust_in_kilonewtons_ / Σ_f_over_i_sp;

                // If RCS provides no thrust, model a virtually instant burn.
                if (thrust_in_kilonewtons_ == 0)
                {
                    engine_warning_ +=
                        L10N.CacheFormat("#Principia_BurnEditor_Warning_NoActiveRCS");
                    UseTheForceLuke();
                }
            }
示例#17
0
 public FlightPlanner(PrincipiaPluginAdapter adapter,
                      PredictedVessel predicted_vessel) : base(
         adapter,
         predicted_vessel)
 {
     adapter_          = adapter;
     predicted_vessel_ = predicted_vessel;
     final_time_       = new DifferentialSlider(
         label: L10N.CacheFormat("#Principia_FlightPlan_PlanLength"),
         unit: null,
         log10_lower_rate: log10_time_lower_rate,
         log10_upper_rate: log10_time_upper_rate,
         min_value: 10,
         max_value: double.PositiveInfinity,
         formatter: FormatPlanLength,
         parser: TryParsePlanLength,
         field_width: 7);
     final_trajectory_analyser_ =
         new PlannedOrbitAnalyser(adapter, predicted_vessel);
 }
示例#18
0
 private void RenderKSPFeatures()
 {
     display_patched_conics = UnityEngine.GUILayout.Toggle(
         value: display_patched_conics,
         text: L10N.CacheFormat(
             "#Principia_MainWindow_KspFeature_DisplayPatchedConics"));
     if (MapView.MapIsEnabled &&
         FlightGlobals.ActiveVessel?.orbitTargeter != null)
     {
         using (new UnityEngine.GUILayout.HorizontalScope()) {
             selecting_target_celestial_ = UnityEngine.GUILayout.Toggle(
                 selecting_target_celestial_,
                 L10N.CacheFormat("#Principia_MainWindow_TargetCelestial_Select"));
             if (selecting_target_celestial_)
             {
                 selecting_active_vessel_target = false;
             }
             CelestialBody target_celestial =
                 FlightGlobals.fetch.VesselTarget as CelestialBody;
             if (target_celestial != null)
             {
                 UnityEngine.GUILayout.Label(
                     L10N.CacheFormat("#Principia_MainWindow_TargetCelestial_Name",
                                      target_celestial.Name()),
                     UnityEngine.GUILayout.ExpandWidth(true));
                 if (UnityEngine.GUILayout.Button(
                         L10N.CacheFormat("#Principia_MainWindow_TargetCelestial_Clear"),
                         GUILayoutWidth(2)))
                 {
                     selecting_target_celestial_ = false;
                     FlightGlobals.fetch.SetVesselTarget(null);
                 }
             }
         }
     }
     else
     {
         selecting_target_celestial_ = false;
     }
 }
示例#19
0
            protected override void RenderWindow(int window_id)
            {
                // We must ensure that the GUI elements don't change between Layout and
                // Repaint.  This means that any state change must occur before Layout or
                // after Repaint.  This if statement implements the former.  It updates the
                // vessel and the editors to reflect the current state of the plugin and
                // then proceeds with the UI code.
                if (UnityEngine.Event.current.type == UnityEngine.EventType.Layout)
                {
                    UpdateVesselAndBurnEditors();
                }

                // The UI code proper, executed identically for Layout and Repaint.  We
                // can freely change the state in events like clicks (e.g., in if statements
                // for buttons) as these don't happen between Layout and Repaint.
                string vessel_guid = predicted_vessel?.id.ToString();

                if (vessel_guid == null)
                {
                    return;
                }

                if (plugin.FlightPlanExists(vessel_guid))
                {
                    RenderFlightPlan(vessel_guid);
                }
                else if (UnityEngine.GUILayout.Button(
                             L10N.CacheFormat("#Principia_FlightPlan_Create")))
                {
                    plugin.FlightPlanCreate(vessel_guid,
                                            plugin.CurrentTime() + 3600,
                                            predicted_vessel.GetTotalMass());
                    final_time_.value_if_different =
                        plugin.FlightPlanGetDesiredFinalTime(vessel_guid);
                    Shrink();
                }
                UnityEngine.GUI.DragWindow();
            }
示例#20
0
            private void ComputeEngineCharacteristics()
            {
                ModuleEngines[] active_engines =
                    (from part in vessel_.parts
                     select(from PartModule module in part.Modules
                            where (module as ModuleEngines)?.EngineIgnited == true
                            select module as ModuleEngines)).SelectMany(x => x).ToArray();
                Vector3d reference_direction = vessel_.ReferenceTransform.up;

                double[] thrusts =
                    (from engine in active_engines
                     select
                     engine.MaxThrustOutputVac(useThrustLimiter: true) *
                     (from transform in engine.thrustTransforms
                      select Math.Max(0,
                                      Vector3d.Dot(reference_direction,
                                                   -transform.forward))).Average()).
                    ToArray();
                thrust_in_kilonewtons_ = thrusts.Sum();

                // This would use zip if we had 4.0 or later.  We loop for now.
                double Σ_f_over_i_sp = 0;

                for (int i = 0; i < active_engines.Length; ++i)
                {
                    Σ_f_over_i_sp +=
                        thrusts[i] / active_engines[i].atmosphereCurve.Evaluate(0);
                }
                specific_impulse_in_seconds_g0_ = thrust_in_kilonewtons_ / Σ_f_over_i_sp;

                // If there are no engines, fall back onto RCS.
                if (thrust_in_kilonewtons_ == 0)
                {
                    engine_warning_ +=
                        L10N.CacheFormat("#Principia_BurnEditor_Warning_NoActiveEngines");
                    ComputeRCSCharacteristics();
                }
            }
            public string ReferencePlaneDescription()
            {
                if (!target_frame_selected &&
                    (frame_type == FrameType.BODY_CENTRED_NON_ROTATING ||
                     frame_type == FrameType.BODY_SURFACE))
                {
                    return(L10N.CacheFormat(
                               "#Principia_ReferenceFrameSelector_ReferencePlane_Centred",
                               selected_celestial.Name()));
                }
                string secondary =
                    target_frame_selected
            ? L10N.CacheFormat(
                        "#Principia_ReferenceFrameSelector_ReferencePlane_Secondary_Target")
            : selected_celestial.Name();
                string primary = target_frame_selected
                         ? selected_celestial.Name()
                         : selected_celestial.referenceBody.Name();

                return(L10N.CacheFormat("#Principia_ReferenceFrameSelector_ReferencePlane",
                                        secondary,
                                        primary));
            }
 private static string TargetFrameSelectorText(Vessel target)
 {
     return(TargetFrameAbbreviation(target) ?? L10N.CacheFormat(
                "#Principia_ReferenceFrameSelector_SelectorText_Target"));
 }
示例#23
0
            private string GetStatusMessage()
            {
                string vessel_guid = predicted_vessel?.id.ToString();
                string message     = "";

                if (vessel_guid != null && !status_.ok())
                {
                    int anomalous_manœuvres =
                        plugin.FlightPlanNumberOfAnomalousManoeuvres(vessel_guid);
                    int    manœuvres         = plugin.FlightPlanNumberOfManoeuvres(vessel_guid);
                    double actual_final_time =
                        plugin.FlightPlanGetActualFinalTime(vessel_guid);
                    bool timed_out = actual_final_time < final_time_.value;

                    string remedy_message =
                        L10N.CacheFormat(
                            "#Principia_FlightPlan_StatusMessage_ChangeFlightPlan"); // Preceded by "Try".
                    string status_message = L10N.CacheFormat(
                        "#Principia_FlightPlan_StatusMessage_FailedError",
                        status_.error,
                        status_.message);
                    string time_out_message =
                        timed_out ? L10N.CacheFormat(
                            "#Principia_FlightPlan_StatusMessage_TimeOut",
                            FormatPositiveTimeSpan(
                                actual_final_time -
                                plugin.FlightPlanGetInitialTime(vessel_guid)))
                    : "";
                    if (status_.is_aborted())
                    {
                        status_message = L10N.CacheFormat(
                            "#Principia_FlightPlan_StatusMessage_MaxSteps",
                            time_out_message);
                        remedy_message =
                            L10N.CacheFormat("#Principia_FlightPlan_StatusMessage_MaxSegment");
                    }
                    else if (status_.is_failed_precondition())
                    {
                        status_message = L10N.CacheFormat(
                            "#Principia_FlightPlan_StatusMessage_Singularity",
                            time_out_message);
                        remedy_message =
                            L10N.CacheFormat(
                                "#Principia_FlightPlan_StatusMessage_AvoidingCollision");
                    }
                    else if (status_.is_invalid_argument())
                    {
                        status_message = L10N.CacheFormat(
                            "#Principia_FlightPlan_StatusMessage_Infinite",
                            first_error_manœuvre_.Value + 1);
                        remedy_message = L10N.CacheFormat(
                            "#Principia_FlightPlan_StatusMessage_Adjust",
                            first_error_manœuvre_.Value + 1);
                    }
                    else if (status_.is_out_of_range())
                    {
                        if (first_error_manœuvre_.HasValue)
                        {
                            status_message = L10N.CacheFormat(
                                "#Principia_FlightPlan_StatusMessage_OutRange1",
                                first_error_manœuvre_.Value + 1,
                                first_error_manœuvre_.Value == 0
                  ? L10N.CacheFormat(
                                    "#Principia_FlightPlan_StatusMessage_OutRange2")
                  : L10N.CacheFormat(
                                    "#Principia_FlightPlan_StatusMessage_OutRange3",
                                    first_error_manœuvre_.Value),
                                manœuvres == 0 || first_error_manœuvre_.Value == manœuvres - 1
                  ? L10N.CacheFormat(
                                    "#Principia_FlightPlan_StatusMessage_OutRange4")
                  : L10N.CacheFormat(
                                    "#Principia_FlightPlan_StatusMessage_OutRange5",
                                    first_error_manœuvre_.Value + 2));
                            remedy_message = L10N.CacheFormat(
                                "#Principia_FlightPlan_StatusMessage_OutRange6",
                                manœuvres == 0 || first_error_manœuvre_.Value == manœuvres - 1
                  ? L10N.CacheFormat(
                                    "#Principia_FlightPlan_StatusMessage_OutRange7")
                  : "",
                                first_error_manœuvre_.Value + 1);
                        }
                        else
                        {
                            status_message =
                                L10N.CacheFormat("#Principia_FlightPlan_StatusMessage_TooShort");
                            remedy_message =
                                L10N.CacheFormat("#Principia_FlightPlan_StatusMessage_Increase");
                        }
                    }
                    else if (status_.is_unavailable())
                    {
                        status_message =
                            L10N.CacheFormat("#Principia_FlightPlan_StatusMessage_CantRebase");
                        remedy_message =
                            L10N.CacheFormat("#Principia_FlightPlan_StatusMessage_WaitFinish");
                    }

                    if (anomalous_manœuvres > 0)
                    {
                        message = L10N.CacheFormat(
                            "#Principia_FlightPlan_StatusMessage_Last",
                            anomalous_manœuvres,
                            status_message,
                            remedy_message,
                            (anomalous_manœuvres < manœuvres
                 ? L10N.CacheFormat("#Principia_FlightPlan_StatusMessage_Last2",
                                    manœuvres - anomalous_manœuvres)
                 : ""));
                    }
                    else
                    {
                        message =
                            L10N.CacheFormat("#Principia_FlightPlan_StatusMessage_Result",
                                             status_message,
                                             remedy_message);
                    }
                }
                message_was_displayed_ = true;
                return(message);
            }
示例#24
0
            protected override void RenderWindowContents(int window_id)
            {
                // We must ensure that the GUI elements don't change between Layout and
                // Repaint.  This means that any state change must occur before Layout or
                // after Repaint.  This if statement implements the former.  It updates the
                // vessel and the editors to reflect the current state of the plugin and
                // then proceeds with the UI code.
                if (UnityEngine.Event.current.type == UnityEngine.EventType.Layout)
                {
                    UpdateVesselAndBurnEditors();
                }

                // The UI code proper, executed identically for Layout and Repaint.  We
                // can freely change the state in events like clicks (e.g., in if statements
                // for buttons) as these don't happen between Layout and Repaint.
                string vessel_guid = predicted_vessel?.id.ToString();

                if (vessel_guid == null)
                {
                    return;
                }

                using (new UnityEngine.GUILayout.HorizontalScope()) {
                    int flight_plans         = plugin.FlightPlanCount(vessel_guid);
                    int selected_flight_plan = plugin.FlightPlanSelected(vessel_guid);
                    for (int i = 0; i < flight_plans; ++i)
                    {
                        var id = new string(L10N.CacheFormat("#Principia_AlphabeticList")[i],
                                            1);
                        if (UnityEngine.GUILayout.Toggle(i == selected_flight_plan, id,
                                                         "Button",
                                                         GUILayoutWidth(1)) &&
                            i != selected_flight_plan)
                        {
                            plugin.FlightPlanSelect(vessel_guid, i);
                            final_time_.value_if_different =
                                plugin.FlightPlanGetDesiredFinalTime(vessel_guid);
                            ClearBurnEditors();
                            UpdateVesselAndBurnEditors();
                        }
                    }
                    bool must_create_flight_plan = false;
                    if (flight_plans == 0)
                    {
                        must_create_flight_plan = UnityEngine.GUILayout.Button(
                            L10N.CacheFormat("#Principia_FlightPlan_Create"));
                    }
                    else if (flight_plans < max_flight_plans)
                    {
                        must_create_flight_plan =
                            UnityEngine.GUILayout.Button("+", GUILayoutWidth(1));
                    }
                    if (must_create_flight_plan)
                    {
                        plugin.FlightPlanCreate(vessel_guid,
                                                plugin.CurrentTime() + 3600,
                                                predicted_vessel.GetTotalMass());
                        final_time_.value_if_different =
                            plugin.FlightPlanGetDesiredFinalTime(vessel_guid);
                        ClearBurnEditors();
                        UpdateVesselAndBurnEditors();
                        return;
                    }
                }

                if (plugin.FlightPlanExists(vessel_guid))
                {
                    RenderFlightPlan(vessel_guid);
                }
                UnityEngine.GUI.DragWindow();
            }
示例#25
0
            private bool RenderCoast(int index, out double?orbital_period)
            {
                string vessel_guid    = predicted_vessel.id.ToString();
                var    coast_analysis = plugin.FlightPlanGetCoastAnalysis(
                    vessel_guid,
                    revolutions_per_cycle: null,
                    days_per_cycle: null,
                    ground_track_revolution: 0,
                    index);
                string orbit_description = null;

                orbital_period = coast_analysis.elements?.nodal_period;
                if (coast_analysis.primary_index.HasValue)
                {
                    var primary           = FlightGlobals.Bodies[coast_analysis.primary_index.Value];
                    int?nodal_revolutions = (int?)(coast_analysis.mission_duration /
                                                   coast_analysis.elements?.nodal_period);
                    orbit_description = OrbitAnalyser.OrbitDescription(
                        primary,
                        coast_analysis.elements,
                        coast_analysis.recurrence,
                        coast_analysis.ground_track,
                        nodal_revolutions);
                }
                using (new UnityEngine.GUILayout.HorizontalScope()) {
                    if (index == burn_editors_.Count)
                    {
                        final_trajectory_analyser_.index = index;
                        final_trajectory_analyser_.RenderButton();
                    }
                    else
                    {
                        double start_of_coast = index == 0
                                    ? plugin.FlightPlanGetInitialTime(
                            vessel_guid)
                                    : burn_editors_[index - 1].final_time;
                        string coast_duration =
                            (burn_editors_[index].initial_time - start_of_coast).FormatDuration(
                                show_seconds: false);
                        string coast_description = orbit_description == null
                                       ? L10N.CacheFormat(
                            "#Principia_FlightPlan_Coast",
                            coast_duration)
                                       : L10N.CacheFormat(
                            "#Principia_FlightPlan_CoastInOrbit",
                            orbit_description,
                            coast_duration);

                        UnityEngine.GUILayout.Label(coast_description);
                    }
                    if (UnityEngine.GUILayout.Button(
                            L10N.CacheFormat("#Principia_FlightPlan_AddManœuvre"),
                            GUILayoutWidth(4)))
                    {
                        double initial_time;
                        if (index == 0)
                        {
                            initial_time = plugin.CurrentTime() + 60;
                        }
                        else
                        {
                            initial_time =
                                plugin.FlightPlanGetManoeuvre(vessel_guid,
                                                              index - 1).final_time + 60;
                        }
                        var editor = new BurnEditor(adapter_,
                                                    predicted_vessel,
                                                    initial_time,
                                                    index,
                                                    get_burn_at_index: burn_editors_.
                                                    ElementAtOrDefault);
                        editor.minimized = false;
                        Burn candidate_burn = editor.Burn();
                        var  status         = plugin.FlightPlanInsert(
                            vessel_guid,
                            candidate_burn,
                            index);

                        // The previous call did not necessarily create a manœuvre.  Check if
                        // we need to add an editor.
                        int number_of_manœuvres =
                            plugin.FlightPlanNumberOfManoeuvres(vessel_guid);
                        if (number_of_manœuvres > burn_editors_.Count)
                        {
                            editor.Reset(plugin.FlightPlanGetManoeuvre(vessel_guid, index));
                            burn_editors_.Insert(index, editor);
                            UpdateBurnEditorIndices();
                            UpdateStatus(status, index);
                            Shrink();
                            return(true);
                        }
                        // TODO(phl): The error messaging here will be either confusing or
                        // wrong.  The messages should mention the new manœuvre without
                        // numbering it, since the numbering has not changed (“the new manœuvre
                        // would overlap with manœuvre #1 or manœuvre #2” or something along
                        // these lines).
                        UpdateStatus(status, index);
                    }
                }
                return(false);
            }
示例#26
0
            private void RenderUpcomingEvents()
            {
                string vessel_guid  = predicted_vessel.id.ToString();
                double current_time = plugin.CurrentTime();

                Style.HorizontalLine();
                if (first_future_manœuvre_.HasValue)
                {
                    int first_future_manœuvre    = first_future_manœuvre_.Value;
                    NavigationManoeuvre manœuvre =
                        plugin.FlightPlanGetManoeuvre(vessel_guid, first_future_manœuvre);
                    if (manœuvre.burn.initial_time > current_time)
                    {
                        using (new UnityEngine.GUILayout.HorizontalScope()) {
                            UnityEngine.GUILayout.Label(
                                L10N.CacheFormat("#Principia_FlightPlan_UpcomingManœuvre",
                                                 first_future_manœuvre + 1));
                            UnityEngine.GUILayout.Label(
                                L10N.CacheFormat("#Principia_FlightPlan_IgnitionCountdown",
                                                 FormatTimeSpan(
                                                     current_time - manœuvre.burn.initial_time)),
                                style: Style.RightAligned(UnityEngine.GUI.skin.label));
                        }
                    }
                    else
                    {
                        using (new UnityEngine.GUILayout.HorizontalScope()) {
                            UnityEngine.GUILayout.Label(
                                L10N.CacheFormat("#Principia_FlightPlan_OngoingManœuvre",
                                                 first_future_manœuvre + 1));
                            UnityEngine.GUILayout.Label(
                                L10N.CacheFormat("#Principia_FlightPlan_CutoffCountdown",
                                                 FormatTimeSpan(
                                                     current_time - manœuvre.final_time)),
                                style: Style.RightAligned(UnityEngine.GUI.skin.label));
                        }
                    }
                    // In career mode, the patched conic solver may be null.  In that case
                    // we do not offer the option of showing the manœuvre on the navball,
                    // even though the flight planner is still available to plan it.
                    // TODO(egg): We may want to consider setting the burn vector directly
                    // rather than going through the solver.
                    if (predicted_vessel.patchedConicSolver != null)
                    {
                        using (new UnityEngine.GUILayout.HorizontalScope()) {
                            show_guidance_ = UnityEngine.GUILayout.Toggle(
                                show_guidance_,
                                L10N.CacheFormat("#Principia_FlightPlan_ShowManœuvreOnNavball"));
                            if (UnityEngine.GUILayout.Button(
                                    L10N.CacheFormat("#Principia_FlightPlan_WarpToManœuvre")))
                            {
                                TimeWarp.fetch.WarpTo(manœuvre.burn.initial_time - 60);
                            }
                        }
                    }
                }
                else
                {
                    // Reserve some space to avoid the UI changing shape if we have
                    // nothing to say.
                    UnityEngine.GUILayout.Label(
                        L10N.CacheFormat(
                            "#Principia_FlightPlan_Warning_AllManœuvresInThePast"),
                        Style.Warning(UnityEngine.GUI.skin.label));
                    UnityEngine.GUILayout.Space(Width(1));
                }
            }
示例#27
0
 public void RenderButton()
 {
     RenderButton(L10N.CacheFormat("#Principia_FlightPlan_ToggleButton"),
                  GUILayoutWidth(4));
 }
示例#28
0
            private void RenderFlightPlan(string vessel_guid)
            {
                using (new UnityEngine.GUILayout.VerticalScope()) {
                    if (final_time_.Render(enabled: true))
                    {
                        var status =
                            plugin.FlightPlanSetDesiredFinalTime(
                                vessel_guid,
                                final_time_.value);
                        UpdateStatus(status, null);
                    }
                    // Always refresh the final time from C++ as it may have changed because
                    // the last burn changed.
                    final_time_.value_if_different =
                        plugin.FlightPlanGetDesiredFinalTime(vessel_guid);

                    FlightPlanAdaptiveStepParameters parameters =
                        plugin.FlightPlanGetAdaptiveStepParameters(vessel_guid);
                    length_integration_tolerance_index_ = Math.Max(
                        0,
                        Array.FindIndex(integration_tolerances_,
                                        (double tolerance) => tolerance >=
                                        parameters.
                                        length_integration_tolerance));
                    speed_integration_tolerance_index_ = Math.Max(
                        0,
                        Array.FindIndex(integration_tolerances_,
                                        (double tolerance) => tolerance >=
                                        parameters.
                                        speed_integration_tolerance));
                    max_steps_index_ = Math.Max(0,
                                                Array.FindIndex(
                                                    max_steps_,
                                                    (long step) =>
                                                    step >= parameters.max_steps));

                    using (new UnityEngine.GUILayout.HorizontalScope()) {
                        using (new UnityEngine.GUILayout.HorizontalScope()) {
                            UnityEngine.GUILayout.Label(
                                L10N.CacheFormat("#Principia_FlightPlan_MaxSteps"),
                                GUILayoutWidth(6));
                            if (max_steps_index_ == 0)
                            {
                                UnityEngine.GUILayout.Button(
                                    L10N.CacheFormat("#Principia_DiscreteSelector_Min"));
                            }
                            else if (UnityEngine.GUILayout.Button("−"))
                            {
                                --max_steps_index_;
                                UpdateAdaptiveStepParameters(ref parameters);
                                var status =
                                    plugin.FlightPlanSetAdaptiveStepParameters(
                                        vessel_guid,
                                        parameters);
                                UpdateStatus(status, null);
                            }
                            UnityEngine.GUILayout.TextArea(
                                max_steps_[max_steps_index_].ToString(),
                                GUILayoutWidth(3));
                            if (max_steps_index_ == max_steps_.Length - 1)
                            {
                                UnityEngine.GUILayout.Button(
                                    L10N.CacheFormat("#Principia_DiscreteSelector_Max"));
                            }
                            else if (UnityEngine.GUILayout.Button("+"))
                            {
                                ++max_steps_index_;
                                UpdateAdaptiveStepParameters(ref parameters);
                                var status =
                                    plugin.FlightPlanSetAdaptiveStepParameters(
                                        vessel_guid,
                                        parameters);
                                UpdateStatus(status, null);
                            }
                        }
                        using (new UnityEngine.GUILayout.HorizontalScope()) {
                            UnityEngine.GUILayout.Label(
                                L10N.CacheFormat("#Principia_PredictionSettings_ToleranceLabel"),
                                GUILayoutWidth(3));
                            // Prior to Ἵππαρχος the tolerances were powers of 2, see #3395.
                            if (length_integration_tolerance_index_ == 0 ||
                                speed_integration_tolerance_index_ == 0)
                            {
                                UnityEngine.GUILayout.Button(
                                    L10N.CacheFormat("#Principia_DiscreteSelector_Min"));
                            }
                            else if (UnityEngine.GUILayout.Button("−"))
                            {
                                --length_integration_tolerance_index_;
                                --speed_integration_tolerance_index_;
                                UpdateAdaptiveStepParameters(ref parameters);
                                var status =
                                    plugin.FlightPlanSetAdaptiveStepParameters(
                                        vessel_guid,
                                        parameters);
                                UpdateStatus(status, null);
                            }
                            UnityEngine.GUILayout.TextArea(
                                length_integration_tolerances_names_[
                                    length_integration_tolerance_index_],
                                GUILayoutWidth(3));
                            if (length_integration_tolerance_index_ ==
                                integration_tolerances_.Length - 1 ||
                                speed_integration_tolerance_index_ ==
                                integration_tolerances_.Length - 1)
                            {
                                UnityEngine.GUILayout.Button(
                                    L10N.CacheFormat("#Principia_DiscreteSelector_Max"));
                            }
                            else if (UnityEngine.GUILayout.Button("+"))
                            {
                                ++length_integration_tolerance_index_;
                                ++speed_integration_tolerance_index_;
                                UpdateAdaptiveStepParameters(ref parameters);
                                var status =
                                    plugin.FlightPlanSetAdaptiveStepParameters(
                                        vessel_guid,
                                        parameters);
                                UpdateStatus(status, null);
                            }
                        }
                    }

                    double Δv = (from burn_editor in burn_editors_
                                 select burn_editor.Δv()).Sum();
                    UnityEngine.GUILayout.Label(L10N.CacheFormat(
                                                    "#Principia_FlightPlan_TotalΔv",
                                                    Δv.ToString("0.000")));

                    {
                        var    style   = Style.Warning(Style.Multiline(UnityEngine.GUI.skin.label));
                        string message = GetStatusMessage();
                        // Size the label explicitly so that it doesn't decrease when the
                        // message goes away: that causes annoying flicker.  The enclosing
                        // window has a width of 20 units, but not all of that is available,
                        // hence 19.
                        warning_height_ = Math.Max(warning_height_,
                                                   style.CalcHeight(
                                                       new UnityEngine.GUIContent(message),
                                                       Width(19)));
                        UnityEngine.GUILayout.Label(message,
                                                    style,
                                                    UnityEngine.GUILayout.Height(
                                                        warning_height_));
                    }

                    if (burn_editors_.Count == 0 &&
                        UnityEngine.GUILayout.Button(
                            L10N.CacheFormat("#Principia_FlightPlan_Delete")))
                    {
                        final_trajectory_analyser_.DisposeWindow();
                        final_trajectory_analyser_ =
                            new PlannedOrbitAnalyser(adapter_, predicted_vessel_);
                        plugin.FlightPlanDelete(vessel_guid);
                        ResetStatus();
                        Shrink();
                        // The state change will happen the next time we go through OnGUI.
                    }
                    else
                    {
                        using (new UnityEngine.GUILayout.HorizontalScope()) {
                            if (UnityEngine.GUILayout.Button(
                                    L10N.CacheFormat("#Principia_FlightPlan_Rebase")))
                            {
                                var status = plugin.FlightPlanRebase(
                                    vessel_guid,
                                    predicted_vessel.GetTotalMass());
                                UpdateStatus(status, null);
                                if (status.ok())
                                {
                                    // The final time does not change, but since it is displayed with
                                    // respect to the beginning of the flight plan, the text must be
                                    // recomputed.
                                    final_time_.ResetValue(
                                        plugin.FlightPlanGetDesiredFinalTime(vessel_guid));
                                    return;
                                }
                            }
                            if (plugin.FlightPlanCount(vessel_guid) < max_flight_plans &&
                                UnityEngine.GUILayout.Button(
                                    L10N.CacheFormat("#Principia_FlightPlan_Duplicate")))
                            {
                                plugin.FlightPlanDuplicate(vessel_guid);
                            }
                        }

                        if (burn_editors_.Count > 0)
                        {
                            RenderUpcomingEvents();
                        }

                        // Compute the final times for each manœuvre before displaying them.
                        var final_times = new List <double>();
                        for (int i = 0; i < burn_editors_.Count - 1; ++i)
                        {
                            final_times.Add(plugin.FlightPlanGetManoeuvre(vessel_guid, i + 1).
                                            burn.initial_time);
                        }
                        // Allow extending the flight plan.
                        final_times.Add(double.PositiveInfinity);

                        for (int i = 0; i < burn_editors_.Count; ++i)
                        {
                            Style.HorizontalLine();
                            if (RenderCoast(i, out double?orbital_period))
                            {
                                return;
                            }
                            Style.HorizontalLine();
                            BurnEditor burn = burn_editors_[i];
                            switch (burn.Render(
                                        header          :
                                        L10N.CacheFormat("#Principia_FlightPlan_ManœuvreHeader", i + 1),
                                        anomalous       : i >=
                                        burn_editors_.Count -
                                        number_of_anomalous_manœuvres_,
                                        burn_final_time : final_times[i],
                                        orbital_period  : orbital_period))
                            {
                            case BurnEditor.Event.Deleted: {
                                var status = plugin.FlightPlanRemove(vessel_guid, i);
                                UpdateStatus(status, null);
                                burn_editors_[i].Close();
                                burn_editors_.RemoveAt(i);
                                UpdateBurnEditorIndices();
                                Shrink();
                                return;
                            }

                            case BurnEditor.Event.Minimized:
                            case BurnEditor.Event.Maximized: {
                                Shrink();
                                return;
                            }

                            case BurnEditor.Event.Changed: {
                                var status =
                                    plugin.FlightPlanReplace(vessel_guid, burn.Burn(), i);
                                UpdateStatus(status, i);
                                burn.Reset(plugin.FlightPlanGetManoeuvre(vessel_guid, i));
                                break;
                            }

                            case BurnEditor.Event.None: {
                                break;
                            }
                            }
                        }
                        Style.HorizontalLine();
                        if (RenderCoast(burn_editors_.Count, orbital_period: out _))
                        {
                            return;
                        }
                    }
                }
            }
            private void RenderSubtree(CelestialBody celestial, int depth)
            {
                // Horizontal offset between a node and its children.
                const int offset = 1;

                using (new UnityEngine.GUILayout.HorizontalScope()) {
                    UnityEngine.GUILayout.Space(Width(offset * depth));
                    if (celestial.is_leaf(target))
                    {
                        UnityEngine.GUILayout.Button(
                            "", UnityEngine.GUI.skin.label, GUILayoutWidth(offset));
                    }
                    else
                    {
                        string button_text = expanded_[celestial] ? "−" : "+";
                        if (UnityEngine.GUILayout.Button(
                                button_text, GUILayoutWidth(offset)))
                        {
                            Shrink();
                            expanded_[celestial] = !expanded_[celestial];
                        }
                    }
                    UnityEngine.GUILayout.Label(celestial.StandaloneName());
                    UnityEngine.GUILayout.FlexibleSpace();
                    if (celestial.is_root())
                    {
                        UnityEngine.GUILayout.Label(
                            L10N.CacheFormat("#Principia_ReferenceFrameSelector_Pin"));
                    }
                    else if (UnityEngine.GUILayout.Toggle(pinned[celestial], "") !=
                             pinned[celestial])
                    {
                        pinned[celestial] = !pinned[celestial];
                        Shrink();
                    }
                }
                if (!celestial.is_leaf(target))
                {
                    if ((expanded_[celestial] || target_pinned_) &&
                        target?.orbit.referenceBody == celestial)
                    {
                        using (new UnityEngine.GUILayout.HorizontalScope()) {
                            UnityEngine.GUILayout.Space(Width(offset * (depth + 1)));
                            UnityEngine.GUILayout.Button(
                                "", UnityEngine.GUI.skin.label, GUILayoutWidth(offset));
                            UnityEngine.GUILayout.Label(
                                L10N.CacheFormat("#Principia_ReferenceFrameSelector_Target",
                                                 target.vesselName));
                            UnityEngine.GUILayout.FlexibleSpace();
                            if (UnityEngine.GUILayout.Toggle(target_pinned_, "") !=
                                target_pinned_)
                            {
                                target_pinned_ = !target_pinned_;
                                Shrink();
                            }
                        }
                    }
                    foreach (CelestialBody child in celestial.orbitingBodies)
                    {
                        if (expanded_[celestial] || AnyDescendantPinned(child))
                        {
                            RenderSubtree(child, depth + 1);
                        }
                    }
                }
            }
示例#30
0
 public static string Standalone(string name)
 {
     return(L10N.CacheFormat("#Principia_GrammaticalForm_Standalone", name));
 }