104 lines
3.0 KiB
Go
104 lines
3.0 KiB
Go
|
|
package basic
|
||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"math"
|
||
|
|
|
||
|
|
. "b612.me/astro/tools"
|
||
|
|
)
|
||
|
|
|
||
|
|
var (
|
||
|
|
ErrNeverRise = errors.New("rise event does not occur on this date")
|
||
|
|
ErrNeverSet = errors.New("set event does not occur on this date")
|
||
|
|
ErrNotOnThisDate = errors.New("rise/set event occurs on adjacent date")
|
||
|
|
)
|
||
|
|
|
||
|
|
func StandardAltitudeStar(aero bool, observerHeight, lat float64) float64 {
|
||
|
|
targetAltitude := 0.0
|
||
|
|
if aero {
|
||
|
|
targetAltitude = -0.566667
|
||
|
|
}
|
||
|
|
return targetAltitude - HeightDegreeByLat(observerHeight, lat)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StandardAltitudeSun(zenithShift, observerHeight, lat float64) float64 {
|
||
|
|
targetAltitude := 0.0
|
||
|
|
if zenithShift != 0 {
|
||
|
|
targetAltitude = -0.8333
|
||
|
|
}
|
||
|
|
return targetAltitude - HeightDegreeByLat(observerHeight, lat)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StandardAltitudePlanet(aeroCorrection, observerHeight, lat float64) float64 {
|
||
|
|
targetAltitude := 0.0
|
||
|
|
if aeroCorrection != 0 {
|
||
|
|
targetAltitude = -0.566667
|
||
|
|
}
|
||
|
|
return targetAltitude - HeightDegreeByLat(observerHeight, lat)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StandardAltitudeMoon(zenithShift, observerHeight, lat float64) float64 {
|
||
|
|
targetAltitude := 0.0
|
||
|
|
if zenithShift != 0 {
|
||
|
|
targetAltitude = -0.83333
|
||
|
|
}
|
||
|
|
return targetAltitude - HeightDegreeByLat(observerHeight, lat)
|
||
|
|
}
|
||
|
|
|
||
|
|
type planetCulminationFunc func(float64, float64, float64) float64
|
||
|
|
type planetHeightFunc func(float64, float64, float64, float64) float64
|
||
|
|
type planetDeclinationFunc func(float64) float64
|
||
|
|
|
||
|
|
func planetRiseDown(jd, lon, lat, timezone, aeroCorrection, observerHeight float64, isRise bool, culmination planetCulminationFunc, height planetHeightFunc, declination planetDeclinationFunc) (float64, error) {
|
||
|
|
jd = math.Floor(jd) + 0.5
|
||
|
|
localTimezone := math.Round(lon / 15)
|
||
|
|
targetAltitude := StandardAltitudePlanet(aeroCorrection, observerHeight, lat)
|
||
|
|
|
||
|
|
culminationJD := culmination(jd, lon, localTimezone)
|
||
|
|
if height(culminationJD, lon, lat, localTimezone) < targetAltitude {
|
||
|
|
return 0, ErrNeverRise
|
||
|
|
}
|
||
|
|
if height(culminationJD-0.5, lon, lat, localTimezone) > targetAltitude {
|
||
|
|
return 0, ErrNeverSet
|
||
|
|
}
|
||
|
|
|
||
|
|
dec := declination(TD2UT(culminationJD-localTimezone/24, true))
|
||
|
|
cosHourAngle := (Sin(targetAltitude) - Sin(dec)*Sin(lat)) / (Cos(dec) * Cos(lat))
|
||
|
|
|
||
|
|
var eventJD float64
|
||
|
|
if math.Abs(cosHourAngle) <= 1 {
|
||
|
|
hourOffset := ArcCos(cosHourAngle) / 15
|
||
|
|
if isRise {
|
||
|
|
eventJD = culminationJD - hourOffset/24 - 25.0/24.0/60.0
|
||
|
|
} else {
|
||
|
|
eventJD = culminationJD + hourOffset/24 - 25.0/24.0/60.0
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
eventJD = culminationJD
|
||
|
|
steps := 0
|
||
|
|
for height(eventJD, lon, lat, localTimezone) > targetAltitude {
|
||
|
|
steps++
|
||
|
|
if isRise {
|
||
|
|
eventJD -= 15.0 / 60.0 / 24.0
|
||
|
|
} else {
|
||
|
|
eventJD += 15.0 / 60.0 / 24.0
|
||
|
|
}
|
||
|
|
if steps > 48 {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
estimateJD := eventJD
|
||
|
|
for {
|
||
|
|
prevJD := estimateJD
|
||
|
|
altitudeDelta := height(prevJD, lon, lat, localTimezone) - targetAltitude
|
||
|
|
altitudeSlope := (height(prevJD+0.000005, lon, lat, localTimezone) - height(prevJD-0.000005, lon, lat, localTimezone)) / 0.00001
|
||
|
|
estimateJD = prevJD - altitudeDelta/altitudeSlope
|
||
|
|
if math.Abs(estimateJD-prevJD) <= 0.00001 {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return estimateJD - localTimezone/24 + timezone/24, nil
|
||
|
|
}
|