- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息 - 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算 - 新增木星伽利略卫星位置、现象与接触事件计算 - 新增恒星星表、星座判定、自行修正与观测辅助能力 - 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包 - 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算 - 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试 - 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试 - 更新中文和英文 README,补充示例、精度说明、SVG 配图
126 lines
5.1 KiB
Go
126 lines
5.1 KiB
Go
package jupiter
|
||
|
||
import (
|
||
"time"
|
||
|
||
"b612.me/astro/basic"
|
||
)
|
||
|
||
// GalileanPhenomenonContactPhase 接触阶段 / contact phase.
|
||
type GalileanPhenomenonContactPhase string
|
||
|
||
const (
|
||
// GalileanPhenomenonContactDisappearance 初亏/初入接触阶段 / disappearance ingress contact.
|
||
GalileanPhenomenonContactDisappearance GalileanPhenomenonContactPhase = "disappearance"
|
||
// GalileanPhenomenonContactReappearance 复圆/复出接触阶段 / reappearance egress contact.
|
||
GalileanPhenomenonContactReappearance GalileanPhenomenonContactPhase = "reappearance"
|
||
)
|
||
|
||
// GalileanPhenomenonContact 伽利略卫星接触窗口 / Galilean-satellite contact window.
|
||
//
|
||
// Start/End 是有限圆盘或有限影斑开始/结束接触的时刻;ModelCrossing 是这套连续接触模型下,
|
||
// 零半径参考点穿越边界的时刻。
|
||
// Start/End mark the beginning/end of the finite-disk or finite-shadow contact interval.
|
||
// ModelCrossing is the zero-radius boundary crossing in this continuous contact model.
|
||
type GalileanPhenomenonContact struct {
|
||
Valid bool
|
||
Phase GalileanPhenomenonContactPhase
|
||
|
||
Start time.Time
|
||
ModelCrossing time.Time
|
||
End time.Time
|
||
|
||
Duration time.Duration
|
||
}
|
||
|
||
// GalileanPhenomenonContactEvent IMCCE 风格的 D/F 接触事件 / IMCCE-style D/F contact event.
|
||
//
|
||
// 这个 API 返回有限圆盘/有限影斑的接触窗口,适合和 IMCCE 的 `TR.D/TR.F/OC.D/OC.F/EC.D/EC.F/SH.D/SH.F` 对齐;
|
||
// 现有 `GalileanPhenomenonEvent` 返回的是零半径几何模型保持 active 的整段区间,两者语义不同。
|
||
// 其中 `shadow_transit` 先用半影/本影边界求部分相持续时间,再把这段持续时间中心放在旧影轴过盘时刻上。
|
||
// This API returns finite-disk / finite-shadow contact windows and is intended to align with IMCCE
|
||
// `TR.D/TR.F/OC.D/OC.F/EC.D/EC.F/SH.D/SH.F` rows. The existing `GalileanPhenomenonEvent` returns the
|
||
// whole active interval of the zero-radius geometric model, so the semantics are different.
|
||
// For `shadow_transit`, the partial-phase duration comes from penumbra/umbra boundaries,
|
||
// while the reported D/F time is centered on the shadow-axis limb crossing from the existing full-event model.
|
||
type GalileanPhenomenonContactEvent struct {
|
||
Valid bool
|
||
Satellite int
|
||
Type GalileanPhenomenonType
|
||
|
||
Disappearance GalileanPhenomenonContact
|
||
Greatest time.Time
|
||
Reappearance GalileanPhenomenonContact
|
||
|
||
GreatestState GalileanSatellitePhenomenon
|
||
}
|
||
|
||
// LastGalileanPhenomenonContactEvent 上一次 IMCCE 风格接触事件 / previous IMCCE-style contact event.
|
||
func LastGalileanPhenomenonContactEvent(date time.Time, satellite int, phenomenonType GalileanPhenomenonType) GalileanPhenomenonContactEvent {
|
||
return galileanPhenomenonContactEventFromBasic(
|
||
basic.LastJupiterGalileanPhenomenonContactEvent(
|
||
basic.Date2JDE(date.UTC()),
|
||
satellite,
|
||
basic.JupiterGalileanPhenomenonType(phenomenonType),
|
||
),
|
||
date.Location(),
|
||
)
|
||
}
|
||
|
||
// NextGalileanPhenomenonContactEvent 下一次 IMCCE 风格接触事件 / next IMCCE-style contact event.
|
||
func NextGalileanPhenomenonContactEvent(date time.Time, satellite int, phenomenonType GalileanPhenomenonType) GalileanPhenomenonContactEvent {
|
||
return galileanPhenomenonContactEventFromBasic(
|
||
basic.NextJupiterGalileanPhenomenonContactEvent(
|
||
basic.Date2JDE(date.UTC()),
|
||
satellite,
|
||
basic.JupiterGalileanPhenomenonType(phenomenonType),
|
||
),
|
||
date.Location(),
|
||
)
|
||
}
|
||
|
||
// ClosestGalileanPhenomenonContactEvent 最近一次 IMCCE 风格接触事件 / closest IMCCE-style contact event.
|
||
func ClosestGalileanPhenomenonContactEvent(date time.Time, satellite int, phenomenonType GalileanPhenomenonType) GalileanPhenomenonContactEvent {
|
||
return galileanPhenomenonContactEventFromBasic(
|
||
basic.ClosestJupiterGalileanPhenomenonContactEvent(
|
||
basic.Date2JDE(date.UTC()),
|
||
satellite,
|
||
basic.JupiterGalileanPhenomenonType(phenomenonType),
|
||
),
|
||
date.Location(),
|
||
)
|
||
}
|
||
|
||
func galileanPhenomenonContactEventFromBasic(event basic.JupiterGalileanPhenomenonContactEvent, loc *time.Location) GalileanPhenomenonContactEvent {
|
||
if !event.Valid {
|
||
return GalileanPhenomenonContactEvent{}
|
||
}
|
||
greatest := basic.JDE2DateByZone(event.Greatest, loc, false)
|
||
return GalileanPhenomenonContactEvent{
|
||
Valid: true,
|
||
Satellite: event.Satellite,
|
||
Type: GalileanPhenomenonType(event.Type),
|
||
Disappearance: galileanPhenomenonContactFromBasic(event.Disappearance, loc),
|
||
Greatest: greatest,
|
||
Reappearance: galileanPhenomenonContactFromBasic(event.Reappearance, loc),
|
||
GreatestState: galileanPhenomenonFromBasic(event.GreatestPhenomenon),
|
||
}
|
||
}
|
||
|
||
func galileanPhenomenonContactFromBasic(contact basic.JupiterGalileanPhenomenonContact, loc *time.Location) GalileanPhenomenonContact {
|
||
if !contact.Valid {
|
||
return GalileanPhenomenonContact{}
|
||
}
|
||
start := basic.JDE2DateByZone(contact.Start, loc, false)
|
||
modelCrossing := basic.JDE2DateByZone(contact.ModelCrossing, loc, false)
|
||
end := basic.JDE2DateByZone(contact.End, loc, false)
|
||
return GalileanPhenomenonContact{
|
||
Valid: true,
|
||
Phase: GalileanPhenomenonContactPhase(contact.Phase),
|
||
Start: start,
|
||
ModelCrossing: modelCrossing,
|
||
End: end,
|
||
Duration: end.Sub(start),
|
||
}
|
||
}
|