75 lines
1.9 KiB
Go
75 lines
1.9 KiB
Go
// FILE: internal/normalizers/nws/day_night.go
|
|
package nws
|
|
|
|
import (
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
degToRad = math.Pi / 180.0
|
|
radToDeg = 180.0 / math.Pi
|
|
)
|
|
|
|
func observationLatLon(coords []float64) (lat *float64, lon *float64) {
|
|
if len(coords) < 2 {
|
|
return nil, nil
|
|
}
|
|
latVal := coords[1]
|
|
lonVal := coords[0]
|
|
return &latVal, &lonVal
|
|
}
|
|
|
|
// isDayFromLatLonTime estimates day/night from solar elevation.
|
|
// Uses a refraction-adjusted cutoff (-0.833 degrees).
|
|
func isDayFromLatLonTime(lat, lon float64, ts time.Time) *bool {
|
|
if ts.IsZero() || math.IsNaN(lat) || math.IsNaN(lon) || math.IsInf(lat, 0) || math.IsInf(lon, 0) {
|
|
return nil
|
|
}
|
|
if lat < -90.0 || lat > 90.0 || lon < -180.0 || lon > 180.0 {
|
|
return nil
|
|
}
|
|
|
|
t := ts.UTC()
|
|
day := float64(t.YearDay())
|
|
hour := float64(t.Hour())
|
|
min := float64(t.Minute())
|
|
sec := float64(t.Second()) + float64(t.Nanosecond())/1e9
|
|
utcHours := hour + min/60.0 + sec/3600.0
|
|
|
|
gamma := 2.0 * math.Pi / 365.0 * (day - 1.0 + (utcHours-12.0)/24.0)
|
|
|
|
eqtime := 229.18 * (0.000075 + 0.001868*math.Cos(gamma) - 0.032077*math.Sin(gamma) -
|
|
0.014615*math.Cos(2.0*gamma) - 0.040849*math.Sin(2.0*gamma))
|
|
|
|
decl := 0.006918 - 0.399912*math.Cos(gamma) + 0.070257*math.Sin(gamma) -
|
|
0.006758*math.Cos(2.0*gamma) + 0.000907*math.Sin(2.0*gamma) -
|
|
0.002697*math.Cos(3.0*gamma) + 0.00148*math.Sin(3.0*gamma)
|
|
|
|
timeOffset := eqtime + 4.0*lon
|
|
trueSolarMinutes := hour*60.0 + min + sec/60.0 + timeOffset
|
|
for trueSolarMinutes < 0 {
|
|
trueSolarMinutes += 1440.0
|
|
}
|
|
for trueSolarMinutes >= 1440.0 {
|
|
trueSolarMinutes -= 1440.0
|
|
}
|
|
|
|
hourAngleDeg := trueSolarMinutes/4.0 - 180.0
|
|
ha := hourAngleDeg * degToRad
|
|
latRad := lat * degToRad
|
|
|
|
cosZenith := math.Sin(latRad)*math.Sin(decl) + math.Cos(latRad)*math.Cos(decl)*math.Cos(ha)
|
|
if cosZenith > 1.0 {
|
|
cosZenith = 1.0
|
|
} else if cosZenith < -1.0 {
|
|
cosZenith = -1.0
|
|
}
|
|
|
|
zenith := math.Acos(cosZenith)
|
|
elevation := 90.0 - zenith*radToDeg
|
|
|
|
isDay := elevation > -0.833
|
|
return &isDay
|
|
}
|