1
- // COPYRIGHT 2010 by the Open Rails project.
2
- //
1
+ // COPYRIGHT 2009 - 2023 by the Open Rails project.
2
+ //
3
3
// This file is part of Open Rails.
4
- //
4
+ //
5
5
// Open Rails is free software: you can redistribute it and/or modify
6
6
// it under the terms of the GNU General Public License as published by
7
7
// the Free Software Foundation, either version 3 of the License, or
8
8
// (at your option) any later version.
9
- //
9
+ //
10
10
// Open Rails is distributed in the hope that it will be useful,
11
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
// GNU General Public License for more details.
14
- //
14
+ //
15
15
// You should have received a copy of the GNU General Public License
16
16
// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
17
17
18
18
/*
19
19
* Contains equations to calculate the sun and moon position for any latitude
20
20
* and longitude on any date
21
- * Solar postion equations are NOAA equations adapted from "Astronomical Algorithms," by Jean Meeus,
21
+ * Solar position equations are NOAA equations adapted from "Astronomical Algorithms," by Jean Meeus,
22
22
* Lunar equations are adapted by Keith Burnett from the US Naval Observatory Astronomical Almanac.
23
23
*/
24
- // Principal Author:
25
- // Rick Grout
26
- //
27
24
28
- using Microsoft . Xna . Framework ;
29
25
using System ;
26
+ using Microsoft . Xna . Framework ;
30
27
31
28
namespace Orts . Viewer3D . Common
32
29
{
@@ -36,67 +33,67 @@ static class SunMoonPos
36
33
/// Calculates the solar direction vector.
37
34
/// Used for locating the sun graphic and as the location of the main scenery light source.
38
35
/// </summary>
39
- /// <param name="latitude">latitude</param>
40
- /// <param name="longitude">longitude</param>
41
- /// <param name="clockTime">wall clock time since start of activity, days</param>
42
- /// <param name="date">structure made up of day, month, year and ordinal date</param>
36
+ /// <param name="latitude">Latitude, radians.</param>
37
+ /// <param name="longitude">Longitude, radians.</param>
38
+ /// <param name="clockTime">Wall clock time since start of activity, days.</param>
39
+ /// <param name="date">Structure made up of day, month, year and ordinal date.</param>
40
+ /// <returns>A normalize 3D vector indicating the sun's position from the viewer's location.</returns>
43
41
public static Vector3 SolarAngle ( double latitude , double longitude , float clockTime , SkyViewer . SkyDate date )
44
42
{
45
43
Vector3 sunDirection ;
46
44
47
- // For these calculations, west longitude is in positive degrees,
48
- float NOAAlongitude = - MathHelper . ToDegrees ( ( float ) longitude ) ;
45
+ // For these calculations, west longitude is in positive degrees
46
+ var noaaLongitude = - MathHelper . ToDegrees ( ( float ) longitude ) ;
47
+
49
48
// Fractional year, radians
50
- double fYear = ( MathHelper . TwoPi / 365 ) * ( date . OrdinalDate - 1 + ( clockTime - 0.5 ) ) ;
49
+ var fYear = ( MathHelper . TwoPi / 365 ) * ( date . OrdinalDate - 1 + ( clockTime - 0.5 ) ) ;
50
+
51
51
// Equation of time, minutes
52
- double 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 ) ) ;
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
+
57
58
// Solar declination, radians
58
- double solarDeclination = 0.006918
59
- - 0.399912 * Math . Cos ( fYear )
60
- + 0.070257 * Math . Sin ( fYear )
61
- - 0.006758 * Math . Cos ( 2 * fYear )
62
- + 0.000907 * Math . Sin ( 2 * fYear )
63
- - 0.002697 * Math . Cos ( 3 * fYear )
64
- + 0.001480 * Math . Sin ( 3 * fYear ) ;
59
+ var solarDeclination = 0.006918
60
+ - ( 0.399912 * Math . Cos ( fYear ) )
61
+ + ( 0.070257 * Math . Sin ( fYear ) )
62
+ - ( 0.006758 * Math . Cos ( 2 * fYear ) )
63
+ + ( 0.000907 * Math . Sin ( 2 * fYear ) )
64
+ - ( 0.002697 * Math . Cos ( 3 * fYear ) )
65
+ + ( 0.001480 * Math . Sin ( 3 * fYear ) ) ;
66
+
65
67
// Time offset at present longitude, minutes
66
- double timeOffset = eqTime - 4 * NOAAlongitude + 60 * Math . Round ( NOAAlongitude / 15 ) ;
68
+ var timeOffset = eqTime - ( 4 * noaaLongitude ) + ( 60 * Math . Round ( noaaLongitude / 15 ) ) ;
69
+
67
70
// True solar time, minutes (since midnight)
68
- double trueSolar = clockTime * 24 * 60 + timeOffset ;
71
+ var trueSolar = ( clockTime * 24 * 60 ) + timeOffset ;
72
+
69
73
// Solar hour angle, radians
70
- double solarHourAngle = MathHelper . ToRadians ( ( float ) ( trueSolar / 4 ) - 180 ) ;
74
+ var solarHourAngle = MathHelper . ToRadians ( ( float ) ( trueSolar / 4 ) - 180 ) ;
71
75
72
76
// Solar zenith cosine. This is the Y COORDINATE of the solar Vector.
73
- double solarZenithCosine = Math . Sin ( latitude )
74
- * Math . Sin ( solarDeclination )
75
- + Math . Cos ( latitude )
76
- * Math . Cos ( solarDeclination )
77
- * Math . Cos ( solarHourAngle ) ;
77
+ var solarZenithCosine = ( Math . Sin ( latitude ) * Math . Sin ( solarDeclination ) )
78
+ + ( Math . Cos ( latitude ) * Math . Cos ( solarDeclination ) * Math . Cos ( solarHourAngle ) ) ;
78
79
79
80
// Solar elevation angle, radians. Currently not used.
80
81
// double solarElevationAngle = MathHelper.PiOver2 - Math.Acos(solarZenithCosine);
81
82
82
83
// Solar azimuth cosine. This is the Z COORDINATE of the solar Vector.
83
- double solarAzimuthCosine = - ( Math . Sin ( latitude )
84
- * solarZenithCosine
85
- - Math . Sin ( solarDeclination ) ) / (
86
- + Math . Cos ( latitude )
87
- * Math . Sin ( Math . Acos ( solarZenithCosine ) ) ) ;
84
+ var solarAzimuthCosine = - ( ( Math . Sin ( latitude ) * solarZenithCosine ) - Math . Sin ( solarDeclination ) )
85
+ / ( Math . Cos ( latitude ) * Math . Sin ( Math . Acos ( solarZenithCosine ) ) ) ;
88
86
89
87
// Running at 64 bit solarAzimuthCosine can be slightly below -1, generating NaN results
90
- if ( solarAzimuthCosine > 1.0d ) solarAzimuthCosine = 1.0d ;
91
- if ( solarAzimuthCosine < - 1.0d ) solarAzimuthCosine = - 1.0d ;
88
+ solarAzimuthCosine = MathHelper . Clamp ( ( float ) solarAzimuthCosine , - 1 , 1 ) ;
92
89
93
90
// Solar azimuth angle, radians. Currently not used.
94
91
// double solarAzimuthAngle = Math.Acos(solarAzimuthCosine);
95
92
// if (clockTime > 0.5)
96
93
// solarAzimuthAngle = MathHelper.TwoPi - solarAzimuthAngle;
97
94
98
95
// Solar azimuth sine. This is the X COORDINATE of the solar Vector.
99
- double solarAzimuthSine = Math . Sin ( Math . Acos ( solarAzimuthCosine ) ) * ( clockTime > 0.5 ? 1 : - 1 ) ;
96
+ var solarAzimuthSine = Math . Sin ( Math . Acos ( solarAzimuthCosine ) ) * ( clockTime > 0.5 ? 1 : - 1 ) ;
100
97
101
98
sunDirection . X = - ( float ) solarAzimuthSine ;
102
99
sunDirection . Y = ( float ) solarZenithCosine ;
@@ -106,83 +103,102 @@ public static Vector3 SolarAngle(double latitude, double longitude, float clockT
106
103
}
107
104
108
105
/// <summary>
109
- /// Calculates the lunar direction vector.
106
+ /// Calculates the lunar direction vector.
110
107
/// </summary>
111
- /// <param name="latitude">latitude</param>
112
- /// <param name="longitude">longitude</param>
113
- /// <param name="clockTime">wall clock time since start of activity</param>
114
- /// <param name="date">structure made up of day, month, year and ordinal date</param>
108
+ /// <param name="latitude">Latitude, radians.</param>
109
+ /// <param name="longitude">Longitude, radians.</param>
110
+ /// <param name="clockTime">Wall clock time since start of activity, days.</param>
111
+ /// <param name="date">Structure made up of day, month, year and ordinal date.</param>
112
+ /// <returns>A normalize 3D vector indicating the moon's position from the viewer's location.</returns>
115
113
public static Vector3 LunarAngle ( double latitude , double longitude , float clockTime , SkyViewer . SkyDate date )
116
114
{
117
115
Vector3 moonDirection ;
118
116
119
117
// Julian day.
120
- double JEday = ( float ) 367 * date . Year - 7 * ( date . Year + ( date . Month + 9 ) / 12 ) / 4 + 275 * date . Month / 9 + date . Day - 730531.5 + clockTime ;
118
+ var jEday = ( 367f * date . Year ) - ( 7 * ( date . Year + ( ( date . Month + 9 ) / 12 ) ) / 4 ) + ( 275 * date . Month / 9 ) + date . Day - 730531.5 + clockTime ;
119
+
121
120
// Fractional time within current 100-year epoch, days
122
- double Ftime = JEday / 36525 ;
121
+ var fTime = jEday / 36525 ;
122
+
123
123
// Ecliptic longitude, radians
124
- double GeoLong = Normalize ( Normalize ( 3.8104 + 8399.71 * Ftime , MathHelper . TwoPi )
125
- + 0.10978 * Math . Sin ( Normalize ( 2.3544 + 8328.69 * Ftime , MathHelper . TwoPi ) )
126
- - 0.02216 * Math . Sin ( Normalize ( 4.5239 - 7214.12 * Ftime , MathHelper . TwoPi ) )
127
- + 0.0115 * Math . Sin ( Normalize ( 4.11374 + 15542.75 * Ftime , MathHelper . TwoPi ) )
128
- + 0.003665 * Math . Sin ( Normalize ( 4.7106 + 16657.38 * Ftime , MathHelper . TwoPi ) )
129
- - 0.003316 * Math . Sin ( Normalize ( 6.2396 + 628.3 * Ftime , MathHelper . TwoPi ) )
130
- - 0.00192 * Math . Sin ( Normalize ( 3.2568 + 16866.93 * Ftime , MathHelper . TwoPi ) ) , MathHelper . TwoPi ) ;
124
+ var geoLong = Normalize (
125
+ Normalize ( 3.8104 + ( 8399.71 * fTime ) , MathHelper . TwoPi )
126
+ + ( 0.10978 * Math . Sin ( Normalize ( 2.3544 + ( 8328.69 * fTime ) , MathHelper . TwoPi ) ) )
127
+ - ( 0.02216 * Math . Sin ( Normalize ( 4.5239 - ( 7214.12 * fTime ) , MathHelper . TwoPi ) ) )
128
+ + ( 0.0115 * Math . Sin ( Normalize ( 4.11374 + ( 15542.75 * fTime ) , MathHelper . TwoPi ) ) )
129
+ + ( 0.003665 * Math . Sin ( Normalize ( 4.7106 + ( 16657.38 * fTime ) , MathHelper . TwoPi ) ) )
130
+ - ( 0.003316 * Math . Sin ( Normalize ( 6.2396 + ( 628.3 * fTime ) , MathHelper . TwoPi ) ) )
131
+ - ( 0.00192 * Math . Sin ( Normalize ( 3.2568 + ( 16866.93 * fTime ) , MathHelper . TwoPi ) ) ) , MathHelper . TwoPi ) ;
132
+
131
133
// Ecliptic latitude, radians
132
- double GeoLat = 0.08954 * Math . Sin ( Normalize ( 1.6284 + 8433.47 * Ftime , MathHelper . TwoPi ) )
133
- + 0.004887 * Math . Sin ( Normalize ( 3.9828 + 16762.16 * Ftime , MathHelper . TwoPi ) )
134
- - 0.004887 * Math . Sin ( Normalize ( 5.5554 + 104.76 * Ftime , MathHelper . TwoPi ) )
135
- - 0.002967 * Math . Sin ( Normalize ( 3.7978 - 7109.29 * Ftime , MathHelper . TwoPi ) ) ;
134
+ var geoLat = ( 0.08954 * Math . Sin ( Normalize ( 1.6284 + ( 8433.47 * fTime ) , MathHelper . TwoPi ) ) )
135
+ + ( 0.004887 * Math . Sin ( Normalize ( 3.9828 + ( 16762.16 * fTime ) , MathHelper . TwoPi ) ) )
136
+ - ( 0.004887 * Math . Sin ( Normalize ( 5.5554 + ( 104.76 * fTime ) , MathHelper . TwoPi ) ) )
137
+ - ( 0.002967 * Math . Sin ( Normalize ( 3.7978 - ( 7109.29 * fTime ) , MathHelper . TwoPi ) ) ) ;
138
+
136
139
// Parallax, radians
137
- double Parallax = 0.0165946
138
- + 0.0009041 * Math . Cos ( Normalize ( 2.3544 + 832869 * Ftime , MathHelper . TwoPi ) )
139
- + 0.000166 * Math . Cos ( Normalize ( 4.5238 - 7214.06 * Ftime , MathHelper . TwoPi ) )
140
- + 0.000136 * Math . Cos ( Normalize ( 4.1137 + 15542.75 * Ftime , MathHelper . TwoPi ) )
141
- + 0.000489 * Math . Cos ( Normalize ( 4.7106 + 16657.38 * Ftime , MathHelper . TwoPi ) ) ;
140
+ var parallax = 0.0165946
141
+ + ( 0.0009041 * Math . Cos ( Normalize ( 2.3544 + ( 832869 * fTime ) , MathHelper . TwoPi ) ) )
142
+ + ( 0.000166 * Math . Cos ( Normalize ( 4.5238 - ( 7214.06 * fTime ) , MathHelper . TwoPi ) ) )
143
+ + ( 0.000136 * Math . Cos ( Normalize ( 4.1137 + ( 15542.75 * fTime ) , MathHelper . TwoPi ) ) )
144
+ + ( 0.000489 * Math . Cos ( Normalize ( 4.7106 + ( 16657.38 * fTime ) , MathHelper . TwoPi ) ) ) ;
145
+
142
146
// Geocentric distance, dimensionless
143
- double GeoDist = 1 / Math . Sin ( Parallax ) ;
147
+ var geoDist = 1 / Math . Sin ( parallax ) ;
148
+
144
149
// Geocentric vector coordinates, dimensionless
145
- double geoX = GeoDist * Math . Cos ( GeoLong ) * Math . Cos ( GeoLat ) ;
146
- double geoY = GeoDist * Math . Sin ( GeoLong ) * Math . Cos ( GeoLat ) ;
147
- double geoZ = GeoDist * Math . Sin ( GeoLat ) ;
150
+ var geoX = geoDist * Math . Cos ( geoLong ) * Math . Cos ( geoLat ) ;
151
+ var geoY = geoDist * Math . Sin ( geoLong ) * Math . Cos ( geoLat ) ;
152
+ var geoZ = geoDist * Math . Sin ( geoLat ) ;
153
+
148
154
// Mean obliquity of ecliptic, radians
149
- double Ecliptic = ( 0.4091 - 0.00000000623 * JEday ) ;
155
+ var ecliptic = 0.4091 - ( 0.00000000623 * jEday ) ;
156
+
150
157
// Equator of ordinalDate vector coordinates, dimensionless
151
- double eclX = geoX ;
152
- double eclY = geoY * Math . Cos ( Ecliptic ) - geoZ * Math . Sin ( Ecliptic ) ;
153
- double eclZ = geoY * Math . Sin ( Ecliptic ) + geoZ * Math . Cos ( Ecliptic ) ;
158
+ var eclX = geoX ;
159
+ var eclY = ( geoY * Math . Cos ( ecliptic ) ) - ( geoZ * Math . Sin ( ecliptic ) ) ;
160
+ var eclZ = ( geoY * Math . Sin ( ecliptic ) ) + ( geoZ * Math . Cos ( ecliptic ) ) ;
161
+
154
162
// Right ascension and declination, radians
155
- double RightAsc = Math . Atan ( eclY / eclX ) ;
163
+ var rightAsc = Math . Atan ( eclY / eclX ) ;
156
164
if ( eclX < 0 )
157
- RightAsc += MathHelper . Pi ;
165
+ {
166
+ rightAsc += MathHelper . Pi ;
167
+ }
168
+
158
169
if ( ( eclY < 0 ) && ( eclX > 0 ) )
159
- RightAsc += MathHelper . TwoPi ;
160
- double Declination = Math . Atan ( eclZ / ( Math . Pow ( ( Math . Pow ( eclX , 2 ) + Math . Pow ( eclY , 2 ) ) , 0.5 ) ) ) ;
170
+ {
171
+ rightAsc += MathHelper . TwoPi ;
172
+ }
173
+
174
+ var declination = Math . Atan ( eclZ / Math . Pow ( Math . Pow ( eclX , 2 ) + Math . Pow ( eclY , 2 ) , 0.5 ) ) ;
175
+
161
176
// Convert right ascension and declination to altitude and azimuth.
162
177
// Equations by Stephen R. Schmitt.
163
178
// Greenwich Mean Sidereal Time, degrees
164
- double GMST = 280.46061837 + 360.98564736629 * JEday ;
165
- GMST = Normalize ( GMST , 360 ) ;
179
+ var gMST = 280.46061837 + ( 360.98564736629 * jEday ) ;
180
+ gMST = Normalize ( gMST , 360 ) ;
181
+
166
182
// Local Mean Sidereal Time, degrees
167
- double LMST = GMST + MathHelper . ToDegrees ( ( float ) longitude ) / 15 ;
183
+ var lMST = gMST + ( MathHelper . ToDegrees ( ( float ) longitude ) / 15 ) ;
184
+
168
185
// Hour angle, degrees
169
- double HA = LMST - MathHelper . ToDegrees ( ( float ) RightAsc ) / 15 ;
186
+ var hA = lMST - ( MathHelper . ToDegrees ( ( float ) rightAsc ) / 15 ) ;
187
+
170
188
// Hour angle, radians
171
- double lunarHourAngle = MathHelper . ToRadians ( ( float ) HA ) ;
189
+ var lunarHourAngle = MathHelper . ToRadians ( ( float ) hA ) ;
190
+
172
191
// Lunar Altitude, radians from its Sine
173
- double lunarAltSin = Math . Sin ( latitude ) * Math . Sin ( Declination ) + Math . Cos ( latitude ) * Math . Cos ( lunarHourAngle ) ;
174
- double lunarAltitude = Math . Asin ( lunarAltSin ) ;
192
+ var lunarAltSin = ( Math . Sin ( latitude ) * Math . Sin ( declination ) ) + ( Math . Cos ( latitude ) * Math . Cos ( lunarHourAngle ) ) ;
193
+ var lunarAltitude = Math . Asin ( lunarAltSin ) ;
194
+
175
195
// Lunar Azimuth, radians from its Cosine
176
- double lunarAltCos = Math . Cos ( lunarAltitude ) ;
177
- double hourAngleSin = Math . Sin ( lunarHourAngle ) ;
178
- double lunarAzCos = ( Math . Sin ( Declination ) - lunarAltSin * Math . Sin ( latitude ) ) / ( lunarAltCos * Math . Cos ( latitude ) ) ;
196
+ var lunarAltCos = Math . Cos ( lunarAltitude ) ;
197
+ var hourAngleSin = Math . Sin ( lunarHourAngle ) ;
198
+ var lunarAzCos = ( Math . Sin ( declination ) - ( lunarAltSin * Math . Sin ( latitude ) ) ) / ( lunarAltCos * Math . Cos ( latitude ) ) ;
179
199
lunarAzCos = lunarAzCos < - 1 ? - 1 : lunarAzCos ;
180
200
lunarAzCos = lunarAzCos > 1 ? 1 : lunarAzCos ;
181
- double lunarAzimuth ;
182
- if ( hourAngleSin < 0 )
183
- lunarAzimuth = Math . Acos ( lunarAzCos ) ;
184
- else
185
- lunarAzimuth = MathHelper . TwoPi - Math . Acos ( lunarAzCos ) ;
201
+ var lunarAzimuth = hourAngleSin < 0 ? Math . Acos ( lunarAzCos ) : MathHelper . TwoPi - Math . Acos ( lunarAzCos ) ;
186
202
187
203
moonDirection . X = ( float ) Math . Sin ( lunarAzimuth ) ;
188
204
moonDirection . Y = ( float ) lunarAltSin ;
@@ -194,13 +210,11 @@ public static Vector3 LunarAngle(double latitude, double longitude, float clockT
194
210
/// <summary>
195
211
/// Removes all multiples of "divisor" from the input number.
196
212
/// </summary>
197
- /// <param name="input">the raw number</param>
198
- /// <param name="divisor">the number, or its multiples, we want to remove</param>
213
+ /// <param name="input">the raw number. </param>
214
+ /// <param name="divisor">the number, or its multiples, we want to remove. </param>
199
215
static double Normalize ( double input , double divisor )
200
216
{
201
- double output = input - divisor * Math . Floor ( input / divisor ) ;
202
- return output ;
217
+ return input - ( divisor * Math . Floor ( input / divisor ) ) ;
203
218
}
204
-
205
219
}
206
220
}
0 commit comments