044f2f4381
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算 - 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询 - 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出 - 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解 - 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤 - 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持 - 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理 - 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
91 lines
3.8 KiB
Go
91 lines
3.8 KiB
Go
package eclipse
|
|
|
|
import (
|
|
"time"
|
|
|
|
"b612.me/astro/basic"
|
|
)
|
|
|
|
// SolarEclipseCandidateOptions 批量枚举配置,零值为全部食型的 NASA bulletin Split-K / enumeration options.
|
|
type SolarEclipseCandidateOptions struct {
|
|
// Model 月亮半径模型,零值为 NASA bulletin Split-K / lunar radius model.
|
|
Model SolarEclipseRadiusModel
|
|
// CentralOnly 只保留全食、环食与混合食,含中心线未落到地表的 T0/A0 事件。
|
|
// CentralOnly keeps total, annular, and hybrid eclipses, including T0/A0 events
|
|
// whose axis misses the Earth; the kind filter matches SearchLocalCentralSolarEclipse.
|
|
CentralOnly bool
|
|
// IncludeSaros 附带沙罗序列信息 / attach Saros metadata.
|
|
IncludeSaros bool
|
|
}
|
|
|
|
// SolarEclipseCandidate 一场日食的时刻表条目,不含几何 / geometry-free timetable entry.
|
|
type SolarEclipseCandidate struct {
|
|
// GreatestEclipse 食甚时刻 / greatest-eclipse instant.
|
|
GreatestEclipse time.Time
|
|
// Type 全局食型,Centrality 中心食类型 / global type and centrality.
|
|
Type SolarEclipseType
|
|
Centrality SolarEclipseCentrality
|
|
// Magnitude 与 Gamma 是全局食分与伽马 / global magnitude and gamma.
|
|
Magnitude float64
|
|
Gamma float64
|
|
// Saros 仅在 IncludeSaros 时有效 / valid only with IncludeSaros.
|
|
Saros SarosInfo
|
|
HasSaros bool
|
|
}
|
|
|
|
// 食甚可能早于朔,枚举上界要多留这么多天。
|
|
const solarEclipseCandidateGreatestLeadDays = 0.5
|
|
|
|
// solarEclipseCandidateIsCentral 按全局食型判定,与站心搜索的 Kind 口径一致。
|
|
func solarEclipseCandidateIsCentral(value basic.SolarEclipseType) bool {
|
|
switch value {
|
|
case basic.SolarEclipseTotal, basic.SolarEclipseAnnular, basic.SolarEclipseHybrid:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// SolarEclipseCandidates 枚举区间内的日食时刻表,按时间升序 / eclipses within a range, in time order.
|
|
func (module *Eclipse) SolarEclipseCandidates(
|
|
start, end time.Time, options SolarEclipseCandidateOptions,
|
|
) []SolarEclipseCandidate {
|
|
if !end.After(start) {
|
|
return nil
|
|
}
|
|
calculator := localSolarEclipseCalculatorForModel(options.Model, module)
|
|
startTT := solarEclipseTimeToTTJDE(start)
|
|
endTT := solarEclipseTimeToTTJDE(end)
|
|
candidates := make([]SolarEclipseCandidate, 0, 8)
|
|
candidateTT := basic.CalcMoonSHByJDEWithInstance(startTT, 0, module.inst)
|
|
for iteration := 0; iteration < localSolarEclipseSearchIterationCap; iteration++ {
|
|
// 食甚可能略早于朔,上界要多留一点余量,否则窗口末尾那场会被漏掉。
|
|
if candidateTT > endTT+solarEclipseCandidateGreatestLeadDays {
|
|
break
|
|
}
|
|
if isPotentialLocalSolarEclipse(candidateTT, module) {
|
|
globalResult := calculator.global(candidateTT)
|
|
if globalResult.Type != basic.SolarEclipseNone &&
|
|
(!options.CentralOnly || solarEclipseCandidateIsCentral(globalResult.Type)) {
|
|
greatest := solarEclipseTTJDEToTime(globalResult.GreatestEclipse, start.Location())
|
|
// 候选朔月取的是“最近”的朔,可能落在 start 之前或 end 之后(食甚早于朔),
|
|
// 按食甚时刻双侧过滤;注意不能 continue:候选推进在循环末尾,跳过它会原地打转。
|
|
if !greatest.Before(start) && !greatest.After(end) {
|
|
candidate := SolarEclipseCandidate{
|
|
GreatestEclipse: greatest,
|
|
Type: mapBasicSolarEclipseType(globalResult.Type),
|
|
Centrality: mapBasicSolarEclipseCentrality(globalResult.Centrality),
|
|
Magnitude: globalResult.Magnitude,
|
|
Gamma: globalResult.Gamma,
|
|
}
|
|
if options.IncludeSaros {
|
|
candidate.Saros, candidate.HasSaros = solarSarosInfo(globalResult.GreatestEclipse, module)
|
|
}
|
|
candidates = append(candidates, candidate)
|
|
}
|
|
}
|
|
}
|
|
candidateTT = nextEclipseSearchCandidateTT(candidateTT, 0, 1, localSolarEclipseSynodicMonthDays, module)
|
|
}
|
|
return candidates
|
|
}
|