2424
2525using System ;
2626using Microsoft . Xna . Framework ;
27+ using Orts . Formats . Msts ;
2728
2829namespace Orts . Viewer3D . Common
2930{
@@ -35,26 +36,18 @@ static class SunMoonPos
3536 /// </summary>
3637 /// <param name="latitude">Latitude, radians.</param>
3738 /// <param name="longitude">Longitude, radians.</param>
39+ /// <param name="sun">Sun satellite information (including rise/set time).</param>
3840 /// <param name="clockTime">Wall clock time since start of activity, days.</param>
3941 /// <param name="date">Structure made up of day, month, year and ordinal date.</param>
4042 /// <returns>A normalize 3D vector indicating the sun's position from the viewer's location.</returns>
41- public static Vector3 SolarAngle ( double latitude , double longitude , float clockTime , SkyViewer . SkyDate date )
43+ public static Vector3 SolarAngle ( double latitude , double longitude , EnvironmentFile . SkySatellite sun , float clockTime , SkyViewer . SkyDate date )
4244 {
4345 Vector3 sunDirection ;
44-
45- // For these calculations, west longitude is in positive degrees
46- var noaaLongitude = - MathHelper . ToDegrees ( ( float ) longitude ) ;
46+ double solarHourAngle ;
4747
4848 // Fractional year, radians
4949 var fYear = ( MathHelper . TwoPi / 365 ) * ( date . OrdinalDate - 1 + ( clockTime - 0.5 ) ) ;
5050
51- // Equation of time, minutes
52- var eqTime = 229.18 * ( 0.000075
53- + ( 0.001868 * Math . Cos ( fYear ) )
54- - ( 0.032077 * Math . Sin ( fYear ) )
55- - ( 0.014615 * Math . Cos ( 2 * fYear ) )
56- - ( 0.040849 * Math . Sin ( 2 * fYear ) ) ) ;
57-
5851 // Solar declination, radians
5952 var solarDeclination = 0.006918
6053 - ( 0.399912 * Math . Cos ( fYear ) )
@@ -64,14 +57,37 @@ public static Vector3 SolarAngle(double latitude, double longitude, float clockT
6457 - ( 0.002697 * Math . Cos ( 3 * fYear ) )
6558 + ( 0.001480 * Math . Sin ( 3 * fYear ) ) ;
6659
67- // Time offset at present longitude, minutes
68- var timeOffset = eqTime - ( 4 * noaaLongitude ) + ( 60 * Math . Round ( noaaLongitude / 15 ) ) ;
60+ // How much the latitude and solar declination changes the horizon so that we can correctly calculate
61+ // the solar angle based on sun rise/set times
62+ var horizonSolarHourAngle = Math . Acos ( - ( Math . Sin ( latitude ) * Math . Sin ( solarDeclination ) ) / ( Math . Cos ( latitude ) * Math . Cos ( solarDeclination ) ) ) ;
6963
70- // True solar time, minutes (since midnight)
71- var trueSolar = ( clockTime * 24 * 60 ) + timeOffset ;
64+ if ( sun ? . RiseTime != 0 && sun ? . SetTime != 0 && sun ? . RiseTime < sun ? . SetTime && ! double . IsNaN ( horizonSolarHourAngle ) )
65+ {
66+ var noonTimeD = ( float ) ( sun . RiseTime + sun . SetTime ) / 2 / 86400 ;
67+ var riseSetScale = 90 / ( noonTimeD - ( ( float ) sun . RiseTime / 86400 ) ) ;
68+ solarHourAngle = MathHelper . ToRadians ( ( clockTime - noonTimeD ) * riseSetScale * ( float ) ( horizonSolarHourAngle / MathHelper . PiOver2 ) ) ;
69+ }
70+ else
71+ {
72+ // For these calculations, west longitude is in positive degrees
73+ var noaaLongitude = - MathHelper . ToDegrees ( ( float ) longitude ) ;
7274
73- // Solar hour angle, radians
74- var solarHourAngle = MathHelper . ToRadians ( ( float ) ( trueSolar / 4 ) - 180 ) ;
75+ // Equation of time, minutes
76+ var eqTime = 229.18 * ( 0.000075
77+ + ( 0.001868 * Math . Cos ( fYear ) )
78+ - ( 0.032077 * Math . Sin ( fYear ) )
79+ - ( 0.014615 * Math . Cos ( 2 * fYear ) )
80+ - ( 0.040849 * Math . Sin ( 2 * fYear ) ) ) ;
81+
82+ // Time offset at present longitude, minutes
83+ var timeOffset = eqTime - ( 4 * noaaLongitude ) + ( 60 * Math . Round ( noaaLongitude / 15 ) ) ;
84+
85+ // True solar time, minutes (since midnight)
86+ var trueSolar = ( clockTime * 24 * 60 ) + timeOffset ;
87+
88+ // Solar hour angle, radians
89+ solarHourAngle = MathHelper . ToRadians ( ( float ) ( trueSolar / 4 ) - 180 ) ;
90+ }
7591
7692 // Solar zenith cosine. This is the Y COORDINATE of the solar Vector.
7793 var solarZenithCosine = ( Math . Sin ( latitude ) * Math . Sin ( solarDeclination ) )
0 commit comments