예제 #1
0
  Signal()
  {
    // enable global access
    instance = this;

    // keep it alive
    DontDestroyOnLoad(this);

    // determine nearest and furthest planets from home body
    CelestialBody sun = Sim.Sun();
    CelestialBody home = Lib.PlanetarySystem(FlightGlobals.GetHomeBody());
    CelestialBody near = null;
    CelestialBody far = null;
    double min_dist = double.MaxValue;
    double max_dist = double.MinValue;
    foreach(CelestialBody body in FlightGlobals.Bodies)
    {
      if (body == sun || body == home) continue;
      if (body.referenceBody != sun) continue;
      double dist = Math.Abs(home.orbit.semiMajorAxis - body.orbit.semiMajorAxis);
      if (dist < min_dist) { min_dist = dist; near = body; }
      if (dist > max_dist) { max_dist = dist; far = body; }
    }
    range_values.Add("orbit", home.sphereOfInfluence * 1.05);
    range_values.Add("home", home.sphereOfInfluence * 4.0 * 1.05);
    range_values.Add("near", (Sim.Apoapsis(home) + Sim.Apoapsis(near)) * 1.6);
    range_values.Add("far", (Sim.Apoapsis(home) + Sim.Apoapsis(far)) * 1.1);
    range_values.Add("extreme", (Sim.Apoapsis(home) + Sim.Apoapsis(far)) * 4.0);
  }
예제 #2
0
  public static environment_data analyze_environment(CelestialBody body, double altitude_mult)
  {
    // shortcuts
    CelestialBody sun = Sim.Sun();

    // calculate data
    environment_data env = new environment_data();
    env.body = body;
    env.altitude = body.Radius * altitude_mult;
    env.landed = env.altitude <= double.Epsilon;
    env.breathable = env.landed && body.atmosphereContainsOxygen;
    env.sun_dist = Sim.Apoapsis(Lib.PlanetarySystem(body)) - sun.Radius - body.Radius;
    Vector3d sun_dir = (sun.position - body.position).normalized;
    env.sun_flux = Sim.SolarFlux(env.sun_dist);
    env.body_flux = Sim.BodyFlux(body, body.position + sun_dir * (body.Radius + env.altitude));
    env.body_back_flux = Sim.BodyFlux(body, body.position - sun_dir * (body.Radius + env.altitude));
    env.background_temp = Sim.BackgroundTemperature();
    env.sun_temp = Sim.BlackBody(env.sun_flux);
    env.body_temp = Sim.BlackBody(env.body_flux);
    env.body_back_temp = Sim.BlackBody(env.body_back_flux);
    env.light_temp = env.background_temp + env.sun_temp + env.body_temp;
    env.shadow_temp = env.background_temp + env.body_back_temp;
    env.atmo_temp = body.GetTemperature(0.0);
    env.orbital_period = Sim.OrbitalPeriod(body, env.altitude);
    env.shadow_period = Sim.ShadowPeriod(body, env.altitude);
    env.shadow_time = env.shadow_period / env.orbital_period;
    env.temp_diff = env.landed && body.atmosphere
      ? Math.Abs(Settings.SurvivalTemperature - env.atmo_temp)
      : Lib.Mix(Math.Abs(Settings.SurvivalTemperature - env.light_temp), Math.Abs(Settings.SurvivalTemperature - env.shadow_temp), env.shadow_time);
    env.atmo_factor = env.landed ? Sim.AtmosphereFactor(body, 0.7071) : 1.0;

    // return data
    return env;
  }
예제 #3
0
        /// <summary>Estimated solar flux from the first parent sun of the given body, including other neighbouring stars/suns (binary systems handling)</summary>
        /// <param name="body"></param>
        /// <param name="worstCase">if true, we use the largest distance between the body and the sun</param>
        /// <param name="mainSun"></param>
        /// <param name="mainSunDirection"></param>
        /// <param name="mainSunDistance"></param>
        /// <returns></returns>
        public static double SolarFluxAtBody(CelestialBody body, bool worstCase, out CelestialBody mainSun, out Vector3d mainSunDirection, out double mainSunDistance)
        {
            // get first parent sun
            mainSun = Lib.GetParentSun(body);

            // get direction and distance
            mainSunDirection = (mainSun.position - body.position).normalized;
            if (worstCase)
            {
                mainSunDistance = Sim.Apoapsis(Lib.GetParentPlanet(body)) - mainSun.Radius - body.Radius;
            }
            else
            {
                mainSunDistance = Sim.SunDistance(body.position, mainSun);
            }

            // get solar flux
            int mainSunIndex = mainSun.flightGlobalsIndex;

            Sim.SunData mainSunData = Sim.suns.Find(pr => pr.bodyIndex == mainSunIndex);
            double      solarFlux   = mainSunData.SolarFlux(mainSunDistance);

            // multiple suns handling (binary systems...)
            foreach (Sim.SunData otherSun in Sim.suns)
            {
                if (otherSun.body == mainSun)
                {
                    continue;
                }
                Vector3d otherSunDir = (otherSun.body.position - body.position).normalized;
                double   otherSunDist;
                if (worstCase)
                {
                    otherSunDist = Sim.Apoapsis(Lib.GetParentPlanet(body)) - otherSun.body.Radius;
                }
                else
                {
                    otherSunDist = Sim.SunDistance(body.position, otherSun.body);
                }
                // account only for other suns that have approximatively the same direction (+/- 30°), discard the others
                if (Vector3d.Angle(otherSunDir, mainSunDirection) > 30.0)
                {
                    continue;
                }
                solarFlux += otherSun.SolarFlux(otherSunDist);
            }
            return(solarFlux);
        }
예제 #4
0
 protected override void OnUpdate()
 {
   foreach(Vessel v in FlightGlobals.Vessels)
   {
     vessel_info vi = Cache.VesselInfo(v);
     if (!vi.is_valid) continue;
     bool manned = v.loaded ? v.GetCrewCount() > 0 : v.protoVessel.GetVesselCrew().Count > 0;
     bool in_orbit = Sim.Apoapsis(v) > v.mainBody.atmosphereDepth && Sim.Periapsis(v) > v.mainBody.atmosphereDepth;
     bool for_30days = v.missionTime > 60.0 * 60.0 * Lib.HoursInDay() * 30.0;
     if (manned && in_orbit && for_30days && DB.Ready())
     {
       base.SetComplete();
       DB.Landmarks().manned_orbit = 1; //< remember that contract was completed
       break;
     }
   }
 }
예제 #5
0
        Signal()
        {
            // enable global access
            instance = this;

            // keep it alive
            DontDestroyOnLoad(this);

            // determine nearest and furthest planets from home body
            CelestialBody sun      = Sim.Sun();
            CelestialBody home     = Lib.PlanetarySystem(FlightGlobals.GetHomeBody());
            CelestialBody near     = null;
            CelestialBody far      = null;
            double        min_dist = double.MaxValue;
            double        max_dist = double.MinValue;

            foreach (CelestialBody body in FlightGlobals.Bodies)
            {
                if (body == sun || body == home)
                {
                    continue;
                }
                if (body.referenceBody != sun)
                {
                    continue;
                }
                double dist = Math.Abs(home.orbit.semiMajorAxis - body.orbit.semiMajorAxis);
                if (dist < min_dist)
                {
                    min_dist = dist; near = body;
                }
                if (dist > max_dist)
                {
                    max_dist = dist; far = body;
                }
            }

            // generate default antenna scopes
            range_values.Add("orbit", home.sphereOfInfluence * 1.05);
            range_values.Add("home", home.sphereOfInfluence * 4.0 * 1.05);
            range_values.Add("near", (Sim.Apoapsis(home) + Sim.Apoapsis(near)) * 1.6);
            range_values.Add("far", (Sim.Apoapsis(home) + Sim.Apoapsis(far)) * 1.1);
            range_values.Add("extreme", (Sim.Apoapsis(home) + Sim.Apoapsis(far)) * 4.0);
            range_values.Add("medium", (range_values["near"] + range_values["far"]) * 0.5);

            // parse user-defined antenna scopes
            var user_scopes = Lib.ParseConfigs("AntennaScope");

            foreach (var scope in user_scopes)
            {
                string scope_name  = Lib.ConfigValue(scope, "name", "").Trim();
                double scope_range = Lib.ConfigValue(scope, "range", 0.0);

                if (scope_name.Length > 0 && scope_range > double.Epsilon)
                {
                    if (!range_values.ContainsKey(scope_name))
                    {
                        range_values.Add(scope_name, scope_range);
                        Lib.Log("Added user-defined antenna scope '" + scope_name + "' with range " + Lib.HumanReadableRange(scope_range));
                    }
                    else
                    {
                        range_values[scope_name] = scope_range;
                        Lib.Log("Using user-defined range " + Lib.HumanReadableRange(scope_range) + " for antenna scope '" + scope_name + "'");
                    }
                }
            }
        }
예제 #6
0
  // draw the window
  void render(int _)
  {
    // shortcut
    CelestialBody sun = FlightGlobals.Bodies[0];

    // get selected body
    CelestialBody body = Lib.SelectedBody();

    // calculate simulation values
    double atmo_factor = Sim.AtmosphereFactor(body, 0.7071);
    double gamma_factor = Sim.GammaTransparency(body, 0.0);
    double sun_dist = Sim.Apoapsis(Lib.PlanetarySystem(body)) - sun.Radius - body.Radius;
    Vector3d sun_dir = (sun.position - body.position).normalized;
    double solar_flux = Sim.SolarFlux(sun_dist) * atmo_factor;
    double albedo_flux = Sim.AlbedoFlux(body, body.position + sun_dir * body.Radius);
    double body_flux = Sim.BodyFlux(body, 0.0);
    double total_flux = solar_flux + albedo_flux + body_flux + Sim.BackgroundFlux();
    double temperature = body.atmosphere ? body.GetTemperature(0.0) : Sim.BlackBodyTemperature(total_flux);

    // calculate night-side temperature
    double total_flux_min = Sim.AlbedoFlux(body, body.position - sun_dir * body.Radius) + body_flux + Sim.BackgroundFlux();
    double temperature_min = Sim.BlackBodyTemperature(total_flux_min);

    // calculate radiation at body surface
    double radiation = Radiation.ComputeSurface(body, gamma_factor);

    // draw pseudo-title
    GUILayout.BeginHorizontal();
    GUILayout.Label(body.bodyName.ToUpper(), top_style);
    GUILayout.EndHorizontal();

    // surface panel
    string temperature_str = body.atmosphere
      ? Lib.HumanReadableTemp(temperature)
      : Lib.BuildString(Lib.HumanReadableTemp(temperature_min), " / ", Lib.HumanReadableTemp(temperature));
    render_title("SURFACE");
    render_content("temperature", temperature_str);
    render_content("radiation", Lib.HumanReadableRadiationRate(radiation));
    render_content("solar flux", Lib.HumanReadableFlux(solar_flux));
    render_space();

    // atmosphere panel
    if (body.atmosphere)
    {
      render_title("ATMOSPHERE");
      render_content("breathable", body.atmosphereContainsOxygen ? "yes" : "no");
      render_content("light absorption", Lib.HumanReadablePerc(1.0 - Sim.AtmosphereFactor(body, 0.7071)));
      render_content("gamma absorption", Lib.HumanReadablePerc(1.0 - Sim.GammaTransparency(body, 0.0)));
      render_space();
    }

    // rendering panel
    render_title("RENDERING");
    render_content("inner belt", ref Radiation.show_inner);
    render_content("outer belt", ref Radiation.show_outer);
    render_content("magnetopause", ref Radiation.show_pause);
    render_space();


    // draw footer
    GUILayout.BeginHorizontal();
    GUILayout.Label("(ALT+N to open and close)", bot_style);
    if (Lib.IsClicked()) Close();
    GUILayout.EndHorizontal();

    // enable dragging
    GUI.DragWindow(drag_rect);
  }
예제 #7
0
  public static void body_info(this Panel p)
  {
    // only show in mapview
    if (!MapView.MapIsEnabled) return;

    // only show if there is a selected body and that body is not the sun
    CelestialBody body = Lib.SelectedBody();
    if (body == null || (body.flightGlobalsIndex == 0 && !Features.Radiation)) return;

    // shortcut
    CelestialBody sun = FlightGlobals.Bodies[0];

    // for all bodies except the sun
    if (body != sun)
    {
      // calculate simulation values
      double atmo_factor = Sim.AtmosphereFactor(body, 0.7071);
      double gamma_factor = Sim.GammaTransparency(body, 0.0);
      double sun_dist = Sim.Apoapsis(Lib.PlanetarySystem(body)) - sun.Radius - body.Radius;
      Vector3d sun_dir = (sun.position - body.position).normalized;
      double solar_flux = Sim.SolarFlux(sun_dist) * atmo_factor;
      double albedo_flux = Sim.AlbedoFlux(body, body.position + sun_dir * body.Radius);
      double body_flux = Sim.BodyFlux(body, 0.0);
      double total_flux = solar_flux + albedo_flux + body_flux + Sim.BackgroundFlux();
      double temperature = body.atmosphere ? body.GetTemperature(0.0) : Sim.BlackBodyTemperature(total_flux);

      // calculate night-side temperature
      double total_flux_min = Sim.AlbedoFlux(body, body.position - sun_dir * body.Radius) + body_flux + Sim.BackgroundFlux();
      double temperature_min = Sim.BlackBodyTemperature(total_flux_min);

      // calculate radiation at body surface
      double radiation = Radiation.ComputeSurface(body, gamma_factor);

      // surface panel
      string temperature_str = body.atmosphere
        ? Lib.HumanReadableTemp(temperature)
        : Lib.BuildString(Lib.HumanReadableTemp(temperature_min), " / ", Lib.HumanReadableTemp(temperature));
      p.section("SURFACE");
      p.content("temperature", temperature_str);
      p.content("solar flux", Lib.HumanReadableFlux(solar_flux));
      if (Features.Radiation) p.content("radiation", Lib.HumanReadableRadiation(radiation));

      // atmosphere panel
      if (body.atmosphere)
      {
        p.section("ATMOSPHERE");
        p.content("breathable", Sim.Breathable(body) ? "yes" : "no");
        p.content("light absorption", Lib.HumanReadablePerc(1.0 - Sim.AtmosphereFactor(body, 0.7071)));
        if (Features.Radiation) p.content("gamma absorption", Lib.HumanReadablePerc(1.0 - Sim.GammaTransparency(body, 0.0)));
      }
    }

    // rendering panel
    if (Features.Radiation)
    {
      p.section("RENDERING");
      p.content("inner belt",   Radiation.show_inner ? "<color=green>show</color>" : "<color=red>hide</color>", string.Empty, () => p.toggle(ref Radiation.show_inner));
      p.content("outer belt",   Radiation.show_outer ? "<color=green>show</color>" : "<color=red>hide</color>", string.Empty, () => p.toggle(ref Radiation.show_outer));
      p.content("magnetopause", Radiation.show_pause ? "<color=green>show</color>" : "<color=red>hide</color>", string.Empty, () => p.toggle(ref Radiation.show_pause));
    }

    // explain the user how to toggle the BodyInfo window
    p.content(string.Empty);
    p.content("<i>Press <b>B</b> to open this window again</i>");

    // set metadata
    p.title(Lib.BuildString(Lib.Ellipsis(body.bodyName, 24), " <color=#cccccc>BODY INFO</color>"));
  }
예제 #8
0
  void render_signal(signal_data signal, environment_data env, crew_data crew)
  {
    // approximate min/max distance between home and target body
    CelestialBody home = FlightGlobals.GetHomeBody();
    double home_dist_min = 0.0;
    double home_dist_max = 0.0;
    if (env.body == home)
    {
      home_dist_min = env.altitude;
      home_dist_max = env.altitude;
    }
    else if (env.body.referenceBody == home)
    {
      home_dist_min = Sim.Periapsis(env.body);
      home_dist_max = Sim.Apoapsis(env.body);
    }
    else
    {
      double home_p = Sim.Periapsis(Lib.PlanetarySystem(home));
      double home_a = Sim.Apoapsis(Lib.PlanetarySystem(home));
      double body_p = Sim.Periapsis(Lib.PlanetarySystem(env.body));
      double body_a = Sim.Apoapsis(Lib.PlanetarySystem(env.body));
      home_dist_min = Math.Min(Math.Abs(home_a - body_p), Math.Abs(home_p - body_a));
      home_dist_max = home_a + body_a;
    }

    // calculate if antenna is out of range from target body
    string range_tooltip = "";
    if (signal.range > double.Epsilon)
    {
      if (signal.range < home_dist_min) range_tooltip = "<color=#ff0000>out of range</color>";
      else if (signal.range < home_dist_max) range_tooltip = "<color=#ffff00>partially out of range</color>";
      else range_tooltip = "<color=#00ff00>in range</color>";
      if (home_dist_max > double.Epsilon) //< if not landed at home
      {
        range_tooltip += "\nbody distance (min): <b>" + Lib.HumanReadableRange(home_dist_min) + "</b>"
        + "\nbody distance (max): <b>" + Lib.HumanReadableRange(home_dist_max) + "</b>";
      }
    }
    else if (crew.capacity == 0) range_tooltip = "<color=#ff0000>no antenna on unmanned vessel</color>";

    // calculate transmission cost
    double cost = signal.range > double.Epsilon
      ? signal.transmission_cost_min + (signal.transmission_cost_max - signal.transmission_cost_min) * Math.Min(home_dist_max, signal.range) / signal.range
      : 0.0;
    string cost_str = signal.range > double.Epsilon ? cost.ToString("F1") + " EC/Mbit" : "none";

    // generate ecc table
    Func<double, double, double, string> deduce_color = (double range, double dist_min, double dist_max) =>
    {
      if (range < dist_min) return "<color=#ff0000>";
      else if (range < dist_max) return "<color=#ffff00>";
      else return "<color=#ffffff>";
    };
    double signal_100 = signal.range / signal.ecc;
    double signal_15 = signal_100 * 0.15;
    double signal_33 = signal_100 * 0.33;
    double signal_66 = signal_100 * 0.66;
    string ecc_tooltip = signal.range > double.Epsilon
      ? "<align=left /><b>ecc</b>\t<b>range</b>"
      + "\n15%\t"  + deduce_color(signal_15, home_dist_min, home_dist_max) + Lib.HumanReadableRange(signal_15) + "</color>"
      + "\n33%\t"  + deduce_color(signal_33, home_dist_min, home_dist_max) + Lib.HumanReadableRange(signal_33) + "</color>"
      + "\n66%\t"  + deduce_color(signal_66, home_dist_min, home_dist_max) + Lib.HumanReadableRange(signal_66) + "</color>"
      + "\n100%\t" + deduce_color(signal_100,home_dist_min, home_dist_max) + Lib.HumanReadableRange(signal_100) + "</color>"
      : "";


    render_title("SIGNAL");
    render_content("range", Lib.HumanReadableRange(signal.range), range_tooltip);
    render_content("relay", signal.relay_range <= double.Epsilon ? "none" : signal.relay_range < signal.range ? Lib.HumanReadableRange(signal.relay_range) : "yes");
    render_content("transmission", cost_str, "worst case data transmission cost\nfrom destination body");
    render_content("error correction", (signal.ecc * 100.0).ToString("F0") + "%", ecc_tooltip);
    render_space();
  }