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; }
/// <summary> /// Update the 'sunsInfo' list and the 'mainSun', 'solarFluxTotal' variables. /// Uses discrete or analytic (for high timewarp speeds) evaluation methods based on the isAnalytic bool. /// Require the 'visibleBodies' variable to be set. /// </summary> // 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 sunlight/shadow period // - atmo_factor become an average atmospheric absorption factor over the daylight period (not the whole day) public static void UpdateSunsInfo(VesselData vd, Vector3d vesselPosition) { Vessel v = vd.Vessel; double lastSolarFlux = 0.0; vd.sunsInfo = new List <SunInfo>(Sim.suns.Count); vd.solarFluxTotal = 0.0; vd.rawSolarFluxTotal = 0.0; foreach (Sim.SunData sunData in Sim.suns) { SunInfo sunInfo = new SunInfo(sunData); if (vd.isAnalytic) { // get sun direction and distance Lib.DirectionAndDistance(vesselPosition, sunInfo.sunData.body, out sunInfo.direction, out sunInfo.distance); // analytical estimation of the portion of orbit that was in sunlight, current limitations : // - the result is dependant on the vessel altitude at the time of evaluation, // consequently it gives inconsistent behavior with highly eccentric orbits // - this totally ignore the orbit inclinaison, polar orbits will be treated as equatorial orbits sunInfo.sunlightFactor = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v); // get atmospheric absorbtion // for atmospheric bodies whose rotation period is less than 120 hours, // determine analytic atmospheric absorption over a single body revolution instead // of using a discrete value that would be unreliable at large timesteps : if (vd.inAtmosphere) { sunInfo.atmoFactor = Sim.AtmosphereFactorAnalytic(v.mainBody, vesselPosition, sunInfo.direction); } else { sunInfo.atmoFactor = 1.0; } } else { // determine if in sunlight, calculate sun direction and distance sunInfo.sunlightFactor = Sim.IsBodyVisible(v, vesselPosition, sunData.body, vd.visibleBodies, out sunInfo.direction, out sunInfo.distance) ? 1.0 : 0.0; // get atmospheric absorbtion sunInfo.atmoFactor = Sim.AtmosphereFactor(v.mainBody, vesselPosition, sunInfo.direction); } // get resulting solar flux in W/m² sunInfo.rawSolarFlux = sunInfo.sunData.SolarFlux(sunInfo.distance); sunInfo.solarFlux = sunInfo.rawSolarFlux * sunInfo.sunlightFactor * sunInfo.atmoFactor; // increment total flux from all stars vd.rawSolarFluxTotal += sunInfo.rawSolarFlux; vd.solarFluxTotal += sunInfo.solarFlux; // add the star to the list vd.sunsInfo.Add(sunInfo); // the most powerful star will be our "default" sun. Uses raw flux before atmo / sunlight factor if (sunInfo.rawSolarFlux > lastSolarFlux) { lastSolarFlux = sunInfo.rawSolarFlux; vd.mainSun = sunInfo; } } vd.sunlightFactor = 0.0; foreach (SunInfo sunInfo in vd.sunsInfo) { sunInfo.fluxProportion = sunInfo.rawSolarFlux / vd.rawSolarFluxTotal; vd.sunlightFactor += sunInfo.SunlightFactor * sunInfo.fluxProportion; } // avoid rounding errors if (vd.sunlightFactor > 0.99) { vd.sunlightFactor = 1.0; } }
public vessel_info(Vessel v, uint vessel_id, UInt64 inc) { // NOTE: anything used here can't in turn use cache, unless you know what you are doing // NOTE: you can't cache vessel position // at any point in time all vessel/body positions are relative to a different frame of reference // so comparing the current position of a vessel, with the cached one of another make no sense // associate with an unique incremental id this.inc = inc; // determine if this is a valid vessel is_vessel = Lib.IsVessel(v); if (!is_vessel) return; // determine if this is a rescue mission vessel is_rescue = Misc.IsRescueMission(v); if (is_rescue) return; // dead EVA are not valid vessels if (EVA.IsDead(v)) return; // shortcut for common tests is_valid = true; // generate id once id = vessel_id; // calculate crew info for the vessel crew_count = Lib.CrewCount(v); crew_capacity = Lib.CrewCapacity(v); // get vessel position Vector3d position = Lib.VesselPosition(v); // this should never happen again if (Vector3d.Distance(position, v.mainBody.position) < 1.0) { throw new Exception("Shit hit the fan for vessel " + v.vesselName); } // determine if in sunlight, calculate sun direction and distance sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0; // 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 if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f) { sunlight = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v); } // environment stuff atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir); gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude); underwater = Sim.Underwater(v); breathable = Sim.Breathable(v, underwater); landed = Lib.Landed(v); // temperature at vessel position temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux); temp_diff = Sim.TempDiff(temperature, v.mainBody, landed); // radiation radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar); // extended atmosphere thermosphere = Sim.InsideThermosphere(v); exosphere = Sim.InsideExosphere(v); // malfunction stuff malfunction = Reliability.HasMalfunction(v); critical = Reliability.HasCriticalFailure(v); // signal info antenna = new AntennaInfo(v); avoid_inf_recursion.Add(v.id); connection = Signal.connection(v, position, antenna, blackout, avoid_inf_recursion); transmitting = Science.transmitting(v, connection.linked); relaying = Signal.relaying(v, avoid_inf_recursion); avoid_inf_recursion.Remove(v.id); // habitat data volume = Habitat.tot_volume(v); surface = Habitat.tot_surface(v); pressure = Habitat.pressure(v); poisoning = Habitat.poisoning(v); shielding = Habitat.shielding(v); living_space = Habitat.living_space(v); comforts = new Comforts(v, landed, crew_count > 1, connection.linked); // data about greenhouses greenhouses = Greenhouse.Greenhouses(v); // other stuff gravioli = Sim.Graviolis(v); }
public vessel_info(Vessel v, uint vessel_id, UInt64 inc) { // NOTE: anything used here can't in turn use cache, unless you know what you are doing // associate with an unique incremental id this.inc = inc; // determine if this is a valid vessel is_vessel = Lib.IsVessel(v); if (!is_vessel) return; // determine if this is a resque mission vessel is_resque = Lib.IsResqueMission(v); if (is_resque) return; // dead EVA are not valid vessels if (v.isEVA && EVA.KerbalData(v).eva_dead) return; // shortcut for common tests is_valid = true; // generate id once id = vessel_id; // calculate crew info for the vessel crew_count = Lib.CrewCount(v); crew_capacity = Lib.CrewCapacity(v); // get vessel position once position = Lib.VesselPosition(v); // determine if in sunlight, calculate sun direction and distance sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0; // if the orbit length vs simulation step is lower than an acceptable threshold, use discrete sun visibility if (v.mainBody.flightGlobalsIndex != 0) { double orbit_period = Sim.OrbitalPeriod(v); if (orbit_period / Kerbalism.elapsed_s < 16.0) sunlight = 1.0 - Sim.ShadowPeriod(v) / orbit_period; } // calculate environment stuff atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir); gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude); breathable = Sim.Breathable(v); landed = Lib.Landed(v); // calculate temperature at vessel position temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux); // calculate radiation radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out inside_pause, out inside_belt); // calculate malfunction stuff max_malfunction = Reliability.MaxMalfunction(v); avg_quality = Reliability.AverageQuality(v); // calculate signal info antenna = new antenna_data(v); avoid_inf_recursion.Add(v.id); link = Signal.Link(v, position, antenna, blackout, avoid_inf_recursion); avoid_inf_recursion.Remove(v.id); // partial data about modules, used by vessel info/monitor scrubbers = Scrubber.PartialData(v); recyclers = Recycler.PartialData(v); greenhouses = Greenhouse.PartialData(v); // woot relativity time_dilation = Sim.TimeDilation(v); }
/// <summary> /// Update the 'sunsInfo' list and the 'mainSun', 'solarFluxTotal' variables. /// Uses discrete or analytic (for high timewarp speeds) evaluation methods based on the isAnalytic bool. /// Require the 'visibleBodies' variable to be set. /// </summary> // 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 sunlight/shadow period // - atmo_factor become an average atmospheric absorption factor over the daylight period (not the whole day) public static void UpdateSunsInfo(VesselData vd, Vector3d vesselPosition, double elapsedSeconds) { Vessel v = vd.Vessel; double lastSolarFlux = 0.0; vd.sunsInfo = new List <SunInfo>(Sim.suns.Count); vd.solarFluxTotal = 0.0; vd.rawSolarFluxTotal = 0.0; foreach (Sim.SunData sunData in Sim.suns) { SunInfo sunInfo = new SunInfo(sunData); if (vd.isAnalytic) { // get sun direction and distance Lib.DirectionAndDistance(vesselPosition, sunInfo.sunData.body, out sunInfo.direction, out sunInfo.distance); // analytical estimation of the portion of orbit that was in sunlight. // it has some limitations, see the comments on Sim.ShadowPeriod if (Settings.UseSamplingSunFactor) { // sampling estimation of the portion of orbit that is in sunlight // until we will calculate again sunInfo.sunlightFactor = Sim.SampleSunFactor(v, elapsedSeconds); } else { // analytical estimation of the portion of orbit that was in sunlight. // it has some limitations, see the comments on Sim.ShadowPeriod sunInfo.sunlightFactor = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v); } // get atmospheric absorbtion // for atmospheric bodies whose rotation period is less than 120 hours, // determine analytic atmospheric absorption over a single body revolution instead // of using a discrete value that would be unreliable at large timesteps : if (vd.inAtmosphere) { sunInfo.atmoFactor = Sim.AtmosphereFactorAnalytic(v.mainBody, vesselPosition, sunInfo.direction); } else { sunInfo.atmoFactor = 1.0; } } else { // determine if in sunlight, calculate sun direction and distance sunInfo.sunlightFactor = Sim.IsBodyVisible(v, vesselPosition, sunData.body, vd.visibleBodies, out sunInfo.direction, out sunInfo.distance) ? 1.0 : 0.0; // get atmospheric absorbtion sunInfo.atmoFactor = Sim.AtmosphereFactor(v.mainBody, vesselPosition, sunInfo.direction); } // get resulting solar flux in W/m² sunInfo.rawSolarFlux = sunInfo.sunData.SolarFlux(sunInfo.distance); sunInfo.solarFlux = sunInfo.rawSolarFlux * sunInfo.sunlightFactor * sunInfo.atmoFactor; // increment total flux from all stars vd.rawSolarFluxTotal += sunInfo.rawSolarFlux; vd.solarFluxTotal += sunInfo.solarFlux; // add the star to the list vd.sunsInfo.Add(sunInfo); // the most powerful star will be our "default" sun. Uses raw flux before atmo / sunlight factor if (sunInfo.rawSolarFlux > lastSolarFlux) { lastSolarFlux = sunInfo.rawSolarFlux; vd.mainSun = sunInfo; } } vd.sunlightFactor = 0.0; foreach (SunInfo sunInfo in vd.sunsInfo) { sunInfo.fluxProportion = sunInfo.rawSolarFlux / vd.rawSolarFluxTotal; vd.sunlightFactor += sunInfo.SunlightFactor * sunInfo.fluxProportion; } // avoid rounding errors if (vd.sunlightFactor > 0.99) { vd.sunlightFactor = 1.0; } }