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); }
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; }
/// <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); }
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; } } }
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 + "'"); } } } }
// 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); }
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>")); }
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(); }