/// <summary>
        /// Calculate the position of the sun
        /// </summary>
        /// <param name="sunInfo">Calculates and receives sun info, including position, etc. Parameters marked as calculation parameters need to be set first.</param>
        /// <param name="rotateYDegrees">Rotate around the Y axis</param>
        public static void CalculateSunPosition(SunInfo sunInfo, float rotateYDegrees)
        {
            // dateTime should already be UTC format
            double d        = (sunInfo.DateTime.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds / dayMs) + jDiff;
            double e        = degreesToRadians * sunInfo.AxisTilt; // obliquity of the Earth
            double m        = SolarMeanAnomaly(d);
            double l        = EclipticLongitude(m);
            double dec      = Declination(e, l, 0);
            double ra       = RightAscension(e, l, 0);
            double lw       = -degreesToRadians * sunInfo.Longitude;
            double phi      = degreesToRadians * sunInfo.Latitude;
            double h        = SiderealTime(d, lw) - ra;
            double azimuth  = Azimuth(h, phi, dec);
            double altitude = Altitude(h, phi, dec);

            ConvertAzimuthAtltitudeToUnitVector(azimuth, altitude, ref sunInfo.UnitVectorUp);

            sunInfo.UnitVectorUp      = Quaternion.AngleAxis(rotateYDegrees, Vector3.up) * sunInfo.UnitVectorUp;
            sunInfo.UnitVectorDown    = -sunInfo.UnitVectorUp;
            sunInfo.JulianDays        = d;
            sunInfo.Declination       = dec;
            sunInfo.RightAscension    = ra;
            sunInfo.Azimuth           = azimuth;
            sunInfo.Altitude          = altitude;
            sunInfo.SolarMeanAnomaly  = m;
            sunInfo.EclipticLongitude = l;
            sunInfo.SiderealTime      = h;
        }
Esempio n. 2
0
        /// <summary>
        /// Calculate moon position
        /// </summary>
        /// <param name="sunInfo">Sun info, already calculated</param>
        /// <param name="moonInfo">Receives moon info</param>
        /// <param name="rotateYDegrees">Rotate the moon in the sky around the y axis by this degrees</param>
        public static void CalculateMoonPosition(SunInfo sunInfo, MoonInfo moonInfo, float rotateYDegrees)
        {
            double       d           = sunInfo.JulianDays;
            double       e           = degreesToRadians * sunInfo.AxisTilt;          // obliquity of the Earth
            double       L           = degreesToRadians * (218.316 + 13.176396 * d); // ecliptic longitude
            double       M           = degreesToRadians * (134.963 + 13.064993 * d); // mean anomaly
            double       F           = degreesToRadians * (93.272 + 13.229350 * d);  // mean distance
            double       l           = L + degreesToRadians * 6.289 * Math.Sin(M);   // longitude
            double       b           = degreesToRadians * 5.128 * Math.Sin(F);       // latitude
            double       dist        = 385001.0 - (20905.0 * Math.Cos(M));           // distance to the moon in km
            double       ra          = RightAscension(e, l, b);
            double       dec         = Declination(e, l, b);
            const double sunDistance = 149598000.0; // avg sun distance to Earth
            double       phi         = Math.Acos(Math.Sin(sunInfo.Declination) * Math.Sin(dec) + Math.Cos(sunInfo.Declination) * Math.Cos(dec) * Math.Cos(sunInfo.RightAscension - ra));
            double       inc         = Math.Atan2(sunDistance * Math.Sin(phi), dist - sunDistance * Math.Cos(phi));
            double       angle       = Math.Atan2(Math.Cos(sunInfo.Declination) * Math.Sin(sunInfo.RightAscension - ra), Math.Sin(sunInfo.Declination) * Math.Cos(dec) - Math.Cos(sunInfo.Declination) * Math.Sin(dec) * Math.Cos(sunInfo.RightAscension - ra));
            double       fraction    = (1.0 + Math.Cos(inc)) * 0.5;
            double       phase       = 0.5 + (0.5 * inc * Math.Sign(angle) * (1.0 / Math.PI));
            double       lw          = -degreesToRadians * sunInfo.Longitude;

            phi = degreesToRadians * sunInfo.Latitude;
            double H = SiderealTime(d, lw) - ra;
            double h = Altitude(H, phi, dec);

            // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
            double pa = Math.Atan2(Math.Sin(H), Math.Tan(phi) * Math.Cos(dec) - Math.Sin(dec) * Math.Cos(H));

            h = h + AstroRefraction(h); // altitude correction for refraction
            double azimuth  = Azimuth(H, phi, dec);
            double altitude = h;

            ConvertAzimuthAtltitudeToUnitVector(azimuth, altitude, ref moonInfo.UnitVectorUp);

            // set moon position and look at the origin
            moonInfo.UnitVectorUp      = Quaternion.AngleAxis(rotateYDegrees, Vector3.up) * moonInfo.UnitVectorUp;
            moonInfo.UnitVectorDown    = -moonInfo.UnitVectorUp;
            moonInfo.Distance          = dist;
            moonInfo.Phase             = phase;
            moonInfo.PercentFull       = 1.0 - Math.Abs((0.5 - phase) * 2.0);
            moonInfo.Angle             = angle;
            moonInfo.Fraction          = fraction;
            moonInfo.Azimuth           = azimuth;
            moonInfo.Altitude          = altitude;
            moonInfo.RightAscension    = ra;
            moonInfo.Declination       = dec;
            moonInfo.LunarMeanAnomaly  = M;
            moonInfo.EclipticLongitude = L;
            moonInfo.SiderealTime      = H;
            moonInfo.ParallacticAngle  = pa;
        }
Esempio n. 3
0
        /// <summary>
        /// Calculate the position of the sun
        /// </summary>
        /// <param name="sunInfo">Calculates and receives sun info, including position, etc. Parameters marked as calculation parameters need to be set first.</param>
        /// <param name="rotateYDegrees">Rotate around the Y axis</param>
        public static void CalculateSunPosition(SunInfo sunInfo, float rotateYDegrees)
        {
            // dateTime should already be UTC format
            double d = (sunInfo.DateTime.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds / dayMs) + jDiff;
            //double d = sunInfo.DateTime.ToOADate() + 2415018.5;
            double e        = degreesToRadians * sunInfo.AxisTilt; // obliquity of the Earth
            double m        = SolarMeanAnomaly(d);
            double l        = EclipticLongitude(m);
            double dec      = Declination(e, l, 0);
            double ra       = RightAscension(e, l, 0);
            double lw       = -degreesToRadians * sunInfo.Longitude;
            double phi      = degreesToRadians * sunInfo.Latitude;
            double h        = SiderealTime(d, lw) - ra;
            double azimuth  = Azimuth(h, phi, dec);
            double altitude = Altitude(h, phi, dec);

            ConvertAzimuthAtltitudeToUnitVector(azimuth, altitude, ref sunInfo.UnitVectorUp);

            sunInfo.UnitVectorUp      = Quaternion.AngleAxis(rotateYDegrees, Vector3.up) * sunInfo.UnitVectorUp;
            sunInfo.UnitVectorDown    = -sunInfo.UnitVectorUp;
            sunInfo.JulianDays        = d;
            sunInfo.Declination       = dec;
            sunInfo.RightAscension    = ra;
            sunInfo.Azimuth           = azimuth;
            sunInfo.Altitude          = altitude;
            sunInfo.SolarMeanAnomaly  = m;
            sunInfo.EclipticLongitude = l;
            sunInfo.SiderealTime      = h;

            double n        = JulianCycle(d, lw);
            double ds       = ApproxTransit(0, lw, n);
            double jnoon    = SolarTransit(ds, m, l);
            double jSunSet  = JulianDateForSunAltitude(-0.8 * (Math.PI / 180.0), lw, phi, dec, n, m, l);
            double jSunRise = jnoon - (jSunSet - jnoon);
            double jDusk    = JulianDateForSunAltitude(-10.0 * (Math.PI / 180.0), lw, phi, dec, n, m, l);
            double jDawn    = jnoon - (jDusk - jnoon);

            try
            {
                sunInfo.Dawn    = JulianToDateTime(jDawn).TimeOfDay;
                sunInfo.Dusk    = JulianToDateTime(jDusk).TimeOfDay;
                sunInfo.SunRise = JulianToDateTime(jSunRise).TimeOfDay;
                sunInfo.SunSet  = JulianToDateTime(jSunSet).TimeOfDay;
            }
            catch
            {
                // don't crash if date time is out of bounds
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Decompile entire suninfo block into Vector of separate elements.
        /// </summary>
        /// <param name="byteptr_t">Pointer to the beginning of suninfo block in Global data.</param>
        /// <param name="length">Length of the block to be read.</param>
        /// <param name="db">Database to which add classes.</param>
        private static unsafe void E_SunInfo(byte *byteptr_t, uint length, Database.Underground2 db)
        {
            const uint size = 0x110;

            for (uint loop = 0; loop < length / size; ++loop)
            {
                uint offset = 8 + loop * size; // current offset of the suninfo (padding included)

                // Get CollectionName
                string CName = ScriptX.NullTerminatedString(byteptr_t + offset + 8, 0x18);

                CName = Resolve.GetPathFromCollection(CName);
                Map.BinKeys[Bin.Hash(CName)] = CName;

                var Class = new SunInfo((IntPtr)(byteptr_t + offset), CName, db);
                db.SunInfos.Collections.Add(Class);
            }
        }
Esempio n. 5
0
        private void EvaluateEnvironment(double elapsedSeconds)
        {
            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.EvaluateStatus");
            // we use analytic mode if more than 2 minutes of game time has passed since last evaluation (~ x6000 timewarp speed)
            isAnalytic = elapsedSeconds > 120.0;

            // get vessel position
            Vector3d position = Lib.VesselPosition(Vessel);

            // this should never happen again
            if (Vector3d.Distance(position, Vessel.mainBody.position) < 1.0)
            {
                throw new Exception("Shit hit the fan for vessel " + Vessel.vesselName);
            }

            // situation
            underwater = Sim.Underwater(Vessel);
            breathable = Sim.Breathable(Vessel, EnvUnderwater);
            landed     = Lib.Landed(Vessel);

            inAtmosphere = Vessel.mainBody.atmosphere && Vessel.altitude < Vessel.mainBody.atmosphereDepth;
            zeroG        = !EnvLanded && !inAtmosphere;

            visibleBodies = Sim.GetLargeBodies(position);

            // get solar info (with multiple stars / Kopernicus support)
            // get the 'visibleBodies' and 'sunsInfo' lists, the 'mainSun', 'solarFluxTotal' variables.
            // require the situation variables to be evaluated first
            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Sunlight");
            SunInfo.UpdateSunsInfo(this, position);
            UnityEngine.Profiling.Profiler.EndSample();
            sunBodyAngle = Sim.SunBodyAngle(Vessel, position, mainSun.SunData.body);

            // temperature at vessel position
            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Temperature");
            temperature = Sim.Temperature(Vessel, position, solarFluxTotal, out albedoFlux, out bodyFlux, out totalFlux);
            tempDiff    = Sim.TempDiff(EnvTemperature, Vessel.mainBody, EnvLanded);
            UnityEngine.Profiling.Profiler.EndSample();

            // radiation
            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Radiation");
            gammaTransparency = Sim.GammaTransparency(Vessel.mainBody, Vessel.altitude);

            bool new_innerBelt, new_outerBelt, new_magnetosphere;

            radiation = Radiation.Compute(Vessel, position, EnvGammaTransparency, mainSun.SunlightFactor, out blackout, out new_magnetosphere, out new_innerBelt, out new_outerBelt, out interstellar, out shieldedRadiation);

            if (new_innerBelt != innerBelt || new_outerBelt != outerBelt || new_magnetosphere != magnetosphere)
            {
                innerBelt     = new_innerBelt;
                outerBelt     = new_outerBelt;
                magnetosphere = new_magnetosphere;
                if (Evaluated)
                {
                    API.OnRadiationFieldChanged.Notify(Vessel, innerBelt, outerBelt, magnetosphere);
                }
            }
            UnityEngine.Profiling.Profiler.EndSample();

            thermosphere = Sim.InsideThermosphere(Vessel);
            exosphere    = Sim.InsideExosphere(Vessel);
            inStorm      = Storm.InProgress(Vessel);
            vesselSituations.Update();

            // other stuff
            gravioli = Sim.Graviolis(Vessel);
            UnityEngine.Profiling.Profiler.EndSample();
        }
Esempio n. 6
0
            /// <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;
                }
            }
        private void sunInformationButton_Click(object sender, RoutedEventArgs e)
        {
            SunInfo sunInfo = new SunInfo();

            sunInfo.Show();
        }
Esempio n. 8
0
            /// <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;
                }
            }