static double CurvedPanelOutput(Vessel vessel, ProtoPartSnapshot part, Part prefab, PartModule m, Vector3d sun_dir, double sun_dist, double atmo_factor) { // if, for whatever reason, sun_dist is zero (or negative), we do not return any output if (sun_dist <= double.Epsilon) return 0.0; // shortcuts Quaternion rot = part.rotation; // get values from part string transform_name = Lib.ReflectionValue<string>(m, "PanelTransformName"); float tot_rate = Lib.ReflectionValue<float>(m, "TotalEnergyRate"); // get components Transform[] components = prefab.FindModelTransforms(transform_name); if (components.Length == 0) return 0.0; // calculate solar flux double solar_flux = Sim.SolarFlux(sun_dist); // reduce solar flux inside atmosphere solar_flux *= atmo_factor; // for each one of the components the curved panel is composed of double output = 0.0; foreach(Transform t in components) { double cosine_factor = Math.Max(Vector3d.Dot(sun_dir, (vessel.transform.rotation * rot * t.forward.normalized).normalized), 0.0); output += (double)tot_rate / (double)components.Length * cosine_factor * solar_flux / Sim.SolarFluxAtHome(); } return output; }
static double CurvedPanelOutput(Vessel vessel, ProtoPartSnapshot part, Part prefab, Vector3d sun_dir, double sun_dist, double atmo_factor) { // if, for whatever reason, sun_dist is zero (or negative), we do not return any output if (sun_dist <= double.Epsilon) return 0.0; // shortcuts Quaternion rot = part.rotation; // get values from part string transform_name = part.partData.GetValue("PanelTransformName"); float k = Convert.ToSingle(part.partData.GetValue("chargePerTransform")); // get components Transform[] components = prefab.FindModelTransforms(transform_name); if (components.Length == 0) return 0.0; // calculate solar flux double solar_flux = Sim.SolarFlux(sun_dist); // reduce solar flux inside atmosphere solar_flux *= atmo_factor; // normalize against solar flux at home solar_flux /= Sim.SolarFluxAtHome(); solar_flux *= k; // for each one of the components the curved panel is composed of double output = 0.0; foreach(Transform t in prefab.FindModelTransforms(transform_name)) { double cosine_factor = Math.Max(Vector3d.Dot(sun_dir, (vessel.transform.rotation * rot * t.forward).normalized), 0.0); output += cosine_factor * solar_flux; } return output; }
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; }
// at the two highest timewarp speed, the number of sun visibility samples drop to the point that // the quantization error first became noticeable, and then exceed 100% // to solve this, we switch to an analytical estimation of the portion of orbit that was in sunlight // - we check against timewarp rate, instead of index, to avoid issues during timewarp blending public void highspeedWarp(Vessel v) { // don't re-calculate this on every tick. So, if sunlight is not 1.0 or 0.0, do nothing here if (sunlight > 0.0001 && sunlight < 0.9999) { return; } sunlight = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v); solar_flux = Sim.SolarFlux(Sim.SunDistance(Lib.VesselPosition(v))) * atmo_factor; }
// return solar panel EC output // note: we ignore temperature curve, and make sure it is not relavant in the MM patch static double PanelOutput(Vessel vessel, ProtoPartSnapshot part, ModuleDeployableSolarPanel panel, Vector3d sun_dir, double sun_dist, double atmo_factor) { // if, for whatever reason, sun_dist is zero (or negative), we do not return any output if (sun_dist <= double.Epsilon) return 0.0; // shortcuts Quaternion rot = part.rotation; Vector3d normal = panel.part.FindModelComponent<Transform>(panel.raycastTransformName).forward; // calculate cosine factor // note: for gameplay reasons, we ignore tracking panel pivots double cosine_factor = panel.sunTracking ? 1.0 : Math.Max(Vector3d.Dot(sun_dir, (vessel.transform.rotation * rot * normal).normalized), 0.0); // calculate solar flux double solar_flux = Sim.SolarFlux(sun_dist); // reduce solar flux inside atmosphere solar_flux *= atmo_factor; // finally, calculate output return panel.chargeRate * cosine_factor * (panel.useCurve ? panel.powerCurve.Evaluate((float)sun_dist) : solar_flux / Sim.SolarFluxAtHome()); }
// return normalized natural lighting at specified distance from the sun (1 in the home world) public static double NaturalLighting(double sun_dist) { // return natural lighting // note: should be 1 at kerbin return Sim.SolarFlux(sun_dist) / Sim.SolarFluxAtHome(); }
// 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>")); }