astro/basic/rise_set.go
starainrt 3ffdbe0034
feat: 扩展天文计算能力
- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息
- 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算
- 新增木星伽利略卫星位置、现象与接触事件计算
- 新增恒星星表、星座判定、自行修正与观测辅助能力
- 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包
- 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算
- 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试
- 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试
- 更新中文和英文 README,补充示例、精度说明、SVG 配图
2026-05-01 22:38:44 +08:00

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
}