@@ -64,22 +64,10 @@ internal object Astro {
64
64
n : Double ,
65
65
y1 : Double ,
66
66
y2 : Double ,
67
- y3 : Double ,
68
- normalize : Boolean = false
67
+ y3 : Double
69
68
): Double {
70
69
var a = y2 - y1
71
70
var b = y3 - y2
72
-
73
- if (normalize) {
74
- if (a < 0 ) {
75
- a + = 360
76
- }
77
-
78
- if (b < 0 ) {
79
- b + = 360
80
- }
81
- }
82
-
83
71
val c = b - a
84
72
85
73
return y2 + (n / 2.0 ) * (a + b + n * c)
@@ -129,8 +117,7 @@ internal object Astro {
129
117
fun julianDay (date : LocalDateTime ): Double {
130
118
var Y = date.year.toDouble()
131
119
var M = date.month.value.toDouble()
132
- val D =
133
- date.dayOfMonth.toDouble() + timeToAngle(date.hour, date.minute, date.second) / 360.0
120
+ val D = date.dayOfMonth.toDouble() + timeToAngle(date.hour, date.minute, date.second) / 360.0
134
121
135
122
if (M <= 2 ) {
136
123
Y --
@@ -143,6 +130,14 @@ internal object Astro {
143
130
return floor(365.25 * (Y + 4716 )) + floor(30.6001 * (M + 1 )) + D + B - 1524.5
144
131
}
145
132
133
+ fun julianCenturies (julianDay : Double ): Double {
134
+ return (julianDay - 2451545.0 ) / 36525.0
135
+ }
136
+
137
+ fun julianDateFromCenturies (julianCenturies : Double ): Double {
138
+ return julianCenturies * 36525.0 + 2451545.0
139
+ }
140
+
146
141
/* *
147
142
* The time difference between TT and UT (TT - UT) in seconds
148
143
*/
@@ -237,6 +232,38 @@ internal object Astro {
237
232
)
238
233
}
239
234
235
+ fun equationOfTime (julianDay : Double ): Double {
236
+ val obliquity = obliquityCorrection(julianDay)
237
+ val L = sunGeometricLongitude(julianDay)
238
+ val e = eccentricity(julianDay)
239
+ val M = sunMeanAnomaly(julianDay)
240
+ val y = square(tanDegrees(obliquity / 2.0 ))
241
+
242
+ val radTime = y * sinDegrees(2.0 * L ) - 2.0 * e * sinDegrees(M ) +
243
+ 4.0 * e * y * sinDegrees(M ) * cosDegrees(2.0 * L ) -
244
+ 0.5 * square(y) * sinDegrees(4.0 * L ) -
245
+ 1.25 * square(e) * sinDegrees(2.0 * M )
246
+ return radTime.toDegrees() * 4.0
247
+ }
248
+
249
+ fun refraction (elevation : Double ): Double {
250
+ if (elevation > 85.0 ){
251
+ return 0.0
252
+ }
253
+
254
+ val tanElev = tanDegrees(elevation)
255
+
256
+ if (elevation > 5.0 ){
257
+ return 58.1 / tanElev - 0.07 / cube(tanElev) + 0.000086 / power(tanElev, 5 ) / 3600.0
258
+ }
259
+
260
+ if (elevation > - 0.575 ){
261
+ return polynomial(elevation, 1735.0 , - 518.2 , 103.4 , - 12.79 , 0.711 ) / 3600.0
262
+ }
263
+
264
+ return - 20.774 / tanElev / 3600.0
265
+ }
266
+
240
267
fun riseSetTransitTimes (
241
268
latitude : Double ,
242
269
longitude : Double ,
@@ -277,40 +304,39 @@ internal object Astro {
277
304
val n1 = m1 + deltaT / 86400
278
305
val n2 = m2 + deltaT / 86400
279
306
307
+ val normalizedRas = normalizeRightAscensions(rightAscensions)
308
+
280
309
val ra0 =
281
- interpolate(
310
+ reduceAngleDegrees( interpolate(
282
311
n0,
283
- rightAscensions.first,
284
- rightAscensions.second,
285
- rightAscensions.third,
286
- true
287
- )
312
+ normalizedRas.first,
313
+ normalizedRas.second,
314
+ normalizedRas.third
315
+ ))
288
316
val ra1 =
289
- interpolate(
317
+ reduceAngleDegrees( interpolate(
290
318
n1,
291
- rightAscensions.first,
292
- rightAscensions.second,
293
- rightAscensions.third,
294
- true
295
- )
296
- val ra2 = interpolate(
319
+ normalizedRas.first,
320
+ normalizedRas.second,
321
+ normalizedRas.third
322
+ ))
323
+ val ra2 = reduceAngleDegrees(interpolate(
297
324
n2,
298
- rightAscensions.first,
299
- rightAscensions.second,
300
- rightAscensions.third,
301
- true
302
- )
325
+ normalizedRas.first,
326
+ normalizedRas.second,
327
+ normalizedRas.third
328
+ ))
303
329
val declination1 =
304
330
interpolate(n1, declinations.first, declinations.second, declinations.third)
305
331
val declination2 =
306
332
interpolate(n2, declinations.first, declinations.second, declinations.third)
307
333
308
- val hourAngle0 = wrap (hourAngle(sidereal0, longitude, ra0), - 180.0 , 180.0 )
309
- val hourAngle1 = wrap (hourAngle(sidereal1, longitude, ra1), - 180.0 , 180.0 )
310
- val hourAngle2 = wrap (hourAngle(sidereal2, longitude, ra2), - 180.0 , 180.0 )
334
+ val hourAngle0 = reduceAngleDegrees (hourAngle(sidereal0, longitude, ra0))
335
+ val hourAngle1 = reduceAngleDegrees (hourAngle(sidereal1, longitude, ra1))
336
+ val hourAngle2 = reduceAngleDegrees (hourAngle(sidereal2, longitude, ra2))
311
337
312
- val altitude1 = wrap( altitude(hourAngle1, latitude, declination1), - 180.0 , 180.0 )
313
- val altitude2 = wrap( altitude(hourAngle2, latitude, declination2), - 180.0 , 180.0 )
338
+ val altitude1 = altitude(hourAngle1, latitude, declination1)
339
+ val altitude2 = altitude(hourAngle2, latitude, declination2)
314
340
315
341
val dm0 = - hourAngle0 / 360
316
342
val dm1 = (altitude1 - standardAltitude) / (360 * cosDegrees(declination1) * cosDegrees(
@@ -433,17 +459,18 @@ internal object Astro {
433
459
}
434
460
435
461
fun sunMeanAnomaly (julianDay : Double ): Double {
436
- val T = (julianDay - 2451545.0 ) / 36525
437
- return reduceAngleDegrees(polynomial(T , 357.52772 , 35999.050340 , - 0.0001603 , - 1 / 300000.0 ))
462
+ val T = julianCenturies(julianDay)
463
+ // TODO: Maybe don't reduce here?
464
+ return reduceAngleDegrees(polynomial(T , 357.52911 , 35999.05029 , - 0.0001537 ))
438
465
}
439
466
440
467
fun sunGeometricLongitude (julianDay : Double ): Double {
441
- val T = (julianDay - 2451545.0 ) / 36525
442
- return polynomial(T , 280.46646 , 36000.76983 , 0.0003032 )
468
+ val T = julianCenturies (julianDay)
469
+ return reduceAngleDegrees( polynomial(T , 280.46646 , 36000.76983 , 0.0003032 ) )
443
470
}
444
471
445
472
fun moonMeanAnomaly (julianDay : Double ): Double {
446
- val T = (julianDay - 2451545.0 ) / 36525
473
+ val T = julianCenturies (julianDay)
447
474
return reduceAngleDegrees(
448
475
polynomial(
449
476
T ,
@@ -499,18 +526,27 @@ internal object Astro {
499
526
}
500
527
501
528
fun meanObliquityOfEcliptic (julianDay : Double ): Double {
502
- val T = (julianDay - 2451545.0 ) / 36525
503
- return polynomial(T , 23.43929 , - 0.01300417 , - 1 .638889e- 7 , 5 .036111e- 7 )
529
+ val T = julianCenturies(julianDay)
530
+ val seconds = polynomial(T , 21.448 , - 46.815 , - 0.00059 , 0.001813 )
531
+ return 23.0 + (26.0 + seconds / 60.0 ) / 60.0
532
+ // return polynomial(T, 23.43929, -0.01300417, -1.638889e-7, 5.036111e-7)
533
+ }
534
+
535
+ fun obliquityCorrection (julianDay : Double ): Double {
536
+ val T = julianCenturies(julianDay)
537
+ val e = meanObliquityOfEcliptic(julianDay)
538
+ val omega = polynomial(T , 125.04 , - 1934.136 )
539
+ return e + 0.00256 * cosDegrees(omega)
504
540
}
505
541
506
542
fun trueObliquityOfEcliptic (julianDay : Double ): Double {
507
543
return meanObliquityOfEcliptic(julianDay) + nutationInObliquity(julianDay)
508
544
}
509
545
510
- // fun eccentricity(julianDay: Double): Double {
511
- // val T = (julianDay - 2451545.0) / 36525
512
- // return polynomial(T, 0.016708634, -0.000042037, -0.0000001267)
513
- // }
546
+ fun eccentricity (julianDay : Double ): Double {
547
+ val T = julianCenturies (julianDay)
548
+ return polynomial(T , 0.016708634 , - 0.000042037 , - 0.0000001267 )
549
+ }
514
550
515
551
fun lunarCoordinates (julianDay : Double ): AstroCoordinates {
516
552
val T = (julianDay - 2451545.0 ) / 36525
@@ -616,25 +652,56 @@ internal object Astro {
616
652
).toDegrees()
617
653
}
618
654
619
- fun solarCoordinates (julianDay : Double ): AstroCoordinates {
620
- val T = (julianDay - 2451545.0 ) / 36525
655
+ private fun sunCenter (julianDay : Double ): Double {
656
+ val T = julianCenturies (julianDay)
621
657
val M = sunMeanAnomaly(julianDay)
622
- val L = sunGeometricLongitude(julianDay)
623
- val C = polynomial(T , 1.914602 , - 0.004817 , - 0.000014 ) * sinDegrees(M ) +
658
+ // TODO: Maybe restrict to between 0 and 360
659
+ return polynomial(T , 1.914602 , - 0.004817 , - 0.000014 ) * sinDegrees(M ) +
624
660
polynomial(T , 0.019993 , - 0.000101 ) * sinDegrees(2 * M ) +
625
661
0.000289 * sinDegrees(3 * M )
626
- val trueLng = reduceAngleDegrees(L + C )
627
- val sunAscendingNodeLongitude = 125.04 - 1934.136 * T
628
- val apparentLongitude = trueLng - 0.00569 - 0.00478 * sinDegrees(sunAscendingNodeLongitude)
629
- val obliquity = meanObliquityOfEcliptic(julianDay)
630
- val correctedObliquity = obliquity + 0.00256 * cosDegrees(sunAscendingNodeLongitude)
631
- val rightAscension = atan2(
632
- cosDegrees(correctedObliquity) * sinDegrees(apparentLongitude),
633
- cosDegrees(apparentLongitude)
634
- ).toDegrees()
635
- val declination =
636
- asin(sinDegrees(correctedObliquity) * sinDegrees(apparentLongitude)).toDegrees()
662
+ }
637
663
664
+ fun sunTrueLongitude (julianDay : Double ): Double {
665
+ val L = sunGeometricLongitude(julianDay)
666
+ val C = sunCenter(julianDay)
667
+ // TODO: Maybe reduce this
668
+ return L + C
669
+ }
670
+
671
+ fun sunTrueAnomaly (julianDay : Double ): Double {
672
+ val M = sunMeanAnomaly(julianDay)
673
+ val C = sunCenter(julianDay)
674
+ // TODO: Reduce degrees?
675
+ return M + C
676
+ }
677
+
678
+ fun sunRadiusVector (julianDay : Double ): Double {
679
+ val v = sunTrueAnomaly(julianDay)
680
+ val e = eccentricity(julianDay)
681
+ return (1.000001018 * (1 - e * e)) / (1 + e * cosDegrees(v))
682
+ }
683
+
684
+ fun sunApparentLongitude (julianDay : Double ): Double {
685
+ val T = julianCenturies(julianDay)
686
+ val trueLng = sunTrueLongitude(julianDay)
687
+ val omega = polynomial(T , 125.04 , - 1934.136 )
688
+ return trueLng - 0.00569 - 0.00478 * sinDegrees(omega)
689
+ }
690
+
691
+ fun solarCoordinates (julianDay : Double ): AstroCoordinates {
692
+ val apparentLongitude = sunApparentLongitude(julianDay)
693
+ val correctedObliquity = obliquityCorrection(julianDay)
694
+ val rightAscension = reduceAngleDegrees(
695
+ atan2(
696
+ cosDegrees(correctedObliquity) * sinDegrees(apparentLongitude),
697
+ cosDegrees(apparentLongitude)
698
+ ).toDegrees()
699
+ )
700
+ val declination = wrap(
701
+ asin(sinDegrees(correctedObliquity) * sinDegrees(apparentLongitude)).toDegrees(),
702
+ - 90.0 , 90.0
703
+ )
704
+ // TODO: Reduce angle or not?
638
705
return AstroCoordinates (declination, rightAscension)
639
706
}
640
707
@@ -706,6 +773,20 @@ internal object Astro {
706
773
return ((1 + cosDegrees(phaseAngle - 180 )) / 2 ) * 100
707
774
}
708
775
776
+ private fun normalizeRightAscensions (rightAscensions : Triple <Double , Double , Double >): Triple <Double , Double , Double > {
777
+ val ra1 = rightAscensions.first
778
+ val ra2 = if (rightAscensions.second < ra1){
779
+ rightAscensions.second + 360
780
+ } else {
781
+ rightAscensions.second
782
+ }
783
+ val ra3 = if (rightAscensions.third < ra2){
784
+ rightAscensions.third + 360
785
+ } else {
786
+ rightAscensions.third
787
+ }
788
+ return Triple (ra1, ra2, ra3)
789
+ }
709
790
710
791
private fun wrap (value : Double , min : Double , max : Double ): Double {
711
792
val range = max - min
0 commit comments