feat: 引入可切换星历模型并扩展天象观测链路
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算 - 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询 - 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出 - 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解 - 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤 - 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持 - 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理 - 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
This commit is contained in:
+306
-220
@@ -3,7 +3,6 @@ package basic
|
||||
import (
|
||||
"math"
|
||||
|
||||
"b612.me/astro/planet"
|
||||
. "b612.me/astro/tools"
|
||||
)
|
||||
|
||||
@@ -51,11 +50,13 @@ type mercuryConjunctionResult struct {
|
||||
geoLightDays float64
|
||||
}
|
||||
|
||||
func mercuryHelioN(planetIndex int, jde float64, n int) mercuryConjunctionLBR {
|
||||
func mercuryHelioN(planetIndex int, jde float64, n int, instances ...*Instance) mercuryConjunctionLBR {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
return mercuryConjunctionLBR{
|
||||
lo: planet.WherePlanetN(planetIndex, 0, jde, n),
|
||||
bo: planet.WherePlanetN(planetIndex, 1, jde, n),
|
||||
r: planet.WherePlanetN(planetIndex, 2, jde, n),
|
||||
lo: PlanetCoordinateNWithInstance(planetIndex, 0, jde, n, inst),
|
||||
bo: PlanetCoordinateNWithInstance(planetIndex, 1, jde, n, inst),
|
||||
r: PlanetCoordinateNWithInstance(planetIndex, 2, jde, n, inst),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,17 +83,21 @@ func mercuryConjunctionAngleDelta(diff float64) float64 {
|
||||
return diff
|
||||
}
|
||||
|
||||
func mercuryConjunctionHeliocentricDelta(jde, targetDeg float64, n int) float64 {
|
||||
planetLo := planet.WherePlanetN(1, 0, jde, n)
|
||||
earthLo := planet.WherePlanetN(-1, 0, jde, n)
|
||||
func mercuryConjunctionHeliocentricDelta(jde, targetDeg float64, n int, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
planetLo := PlanetCoordinateNWithInstance(1, 0, jde, n, inst)
|
||||
earthLo := PlanetCoordinateNWithInstance(-1, 0, jde, n, inst)
|
||||
return mercuryConjunctionAngleDelta(planetLo - earthLo - targetDeg)
|
||||
}
|
||||
|
||||
func mercuryConjunctionDifference(jd float64, n int, targetDeg, sunLightDays, geoLightDays float64) mercuryConjunctionResult {
|
||||
earthForSun := mercuryHelioN(-1, jd-sunLightDays, n)
|
||||
func mercuryConjunctionDifference(jd float64, n int, targetDeg, sunLightDays, geoLightDays float64, instances ...*Instance) mercuryConjunctionResult {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
earthForSun := mercuryHelioN(-1, jd-sunLightDays, n, inst)
|
||||
sunLo := Limit360(earthForSun.lo + 180)
|
||||
earth := mercuryHelioN(-1, jd-geoLightDays, n)
|
||||
planetPos := mercuryHelioN(1, jd-geoLightDays, n)
|
||||
earth := mercuryHelioN(-1, jd-geoLightDays, n, inst)
|
||||
planetPos := mercuryHelioN(1, jd-geoLightDays, n, inst)
|
||||
geo := mercuryGeocentric(planetPos, earth)
|
||||
return mercuryConjunctionResult{
|
||||
diff: mercuryConjunctionAngleDelta(geo.lo - sunLo - targetDeg),
|
||||
@@ -101,38 +106,44 @@ func mercuryConjunctionDifference(jd float64, n int, targetDeg, sunLightDays, ge
|
||||
}
|
||||
}
|
||||
|
||||
func mercuryConjunctionExactDelta(jde float64) float64 {
|
||||
return mercuryConjunctionAngleDelta(MercuryApparentLo(jde) - HSunApparentLo(jde))
|
||||
func mercuryConjunctionExactDelta(jde float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
return mercuryConjunctionAngleDelta(MercuryApparentLoWithInstance(jde, inst) - HSunApparentLoWithInstance(jde, inst))
|
||||
}
|
||||
|
||||
func mercuryConjunctionApproxTT(seed float64, inferior bool) float64 {
|
||||
func mercuryConjunctionApproxTT(seed float64, inferior bool, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
heliocentricTarget := 180.0
|
||||
if inferior {
|
||||
heliocentricTarget = 0
|
||||
}
|
||||
jde := seed
|
||||
for i := 0; i < 6; i++ {
|
||||
jde -= mercuryConjunctionHeliocentricDelta(jde, heliocentricTarget, 8) / (360.0 / MERCURY_S_PERIOD)
|
||||
jde -= mercuryConjunctionHeliocentricDelta(jde, heliocentricTarget, 8, inst) / (360.0 / MERCURY_S_PERIOD)
|
||||
}
|
||||
|
||||
startSample := mercuryConjunctionDifference(jde, 8, 0, 0, 0)
|
||||
nextSample := mercuryConjunctionDifference(jde+mercuryConjunctionDerivativeStepDay, 8, 0, 0, 0)
|
||||
startSample := mercuryConjunctionDifference(jde, 8, 0, 0, 0, inst)
|
||||
nextSample := mercuryConjunctionDifference(jde+mercuryConjunctionDerivativeStepDay, 8, 0, 0, 0, inst)
|
||||
diffSlope := mercuryConjunctionAngleDelta(nextSample.diff-startSample.diff) / mercuryConjunctionDerivativeStepDay
|
||||
|
||||
refined := mercuryConjunctionDifference(jde, 40, 0, startSample.sunLightDays, startSample.geoLightDays)
|
||||
refined := mercuryConjunctionDifference(jde, 40, 0, startSample.sunLightDays, startSample.geoLightDays, inst)
|
||||
jde -= refined.diff / diffSlope
|
||||
final := mercuryConjunctionDifference(jde, -1, 0, refined.sunLightDays, refined.geoLightDays)
|
||||
final := mercuryConjunctionDifference(jde, -1, 0, refined.sunLightDays, refined.geoLightDays, inst)
|
||||
jde -= final.diff / diffSlope
|
||||
return jde
|
||||
}
|
||||
|
||||
func mercuryConjunctionExactTT(seed float64, inferior bool) float64 {
|
||||
estimateJD := mercuryConjunctionApproxTT(seed, inferior)
|
||||
func mercuryConjunctionExactTT(seed float64, inferior bool, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
estimateJD := mercuryConjunctionApproxTT(seed, inferior, inst)
|
||||
converged := false
|
||||
for i := 0; i < eventNewtonMaxIterations; i++ {
|
||||
prevJDE := estimateJD
|
||||
longitudeDelta := mercuryConjunctionExactDelta(prevJDE)
|
||||
longitudeSlope := (mercuryConjunctionExactDelta(prevJDE+0.000005) - mercuryConjunctionExactDelta(prevJDE-0.000005)) / 0.00001
|
||||
longitudeDelta := mercuryConjunctionExactDelta(prevJDE, inst)
|
||||
longitudeSlope := (mercuryConjunctionExactDelta(prevJDE+0.000005, inst) - mercuryConjunctionExactDelta(prevJDE-0.000005, inst)) / 0.00001
|
||||
nextJD := prevJDE - longitudeDelta/longitudeSlope
|
||||
estimateJD = nextJD
|
||||
if math.Abs(nextJD-prevJDE) <= 0.00001 {
|
||||
@@ -153,15 +164,17 @@ func mercuryConjunctionExactTT(seed float64, inferior bool) float64 {
|
||||
// 并且下游的类型化「留」会因此返回错事件、甚至让 Last 返回未来。
|
||||
// 新实现改成方向性括号扫描:截断级数逐段找异号区间(顺序扫描 ⇒ 一定取最近的一个合),
|
||||
// 再用全项级数在括号内抛光;扫满 640 天仍无括号时有界返回 NaN。
|
||||
func mercuryConjunction(jde float64, next uint8) float64 {
|
||||
func mercuryConjunction(jde float64, next uint8, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
//0=last 1=next
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
if math.Abs(mercuryConjunctionExactDelta(jde)) <= mercuryConjunctionSameInstantDegrees {
|
||||
if math.Abs(mercuryConjunctionExactDelta(jde, inst)) <= mercuryConjunctionSameInstantDegrees {
|
||||
best := math.NaN()
|
||||
consider := func(inferior bool) {
|
||||
eventUT := TT2UTC(mercuryConjunctionExactTT(jde, inferior))
|
||||
eventUT := TT2UTC(mercuryConjunctionExactTT(jde, inferior, inst))
|
||||
if !isFiniteFloat(eventUT) {
|
||||
return
|
||||
}
|
||||
@@ -187,18 +200,18 @@ func mercuryConjunction(jde float64, next uint8) float64 {
|
||||
direction = -1
|
||||
}
|
||||
leftJDE := jde
|
||||
leftValue := mercuryConjunctionDeltaN(leftJDE, mercuryEventSearchN)
|
||||
leftValue := mercuryConjunctionDeltaN(leftJDE, mercuryEventSearchN, inst)
|
||||
if !isFiniteFloat(leftValue) {
|
||||
return math.NaN()
|
||||
}
|
||||
for i := 0; i < mercuryConjunctionScanMaxSteps; i++ {
|
||||
rightJDE := jde + direction*mercuryConjunctionScanStepDay*float64(i+1)
|
||||
rightValue := mercuryConjunctionDeltaN(rightJDE, mercuryEventSearchN)
|
||||
rightValue := mercuryConjunctionDeltaN(rightJDE, mercuryEventSearchN, inst)
|
||||
if !isFiniteFloat(rightValue) {
|
||||
return math.NaN()
|
||||
}
|
||||
if leftValue == 0 || rightValue == 0 || leftValue*rightValue < 0 {
|
||||
return mercuryConjunctionPolish(jde, leftJDE, rightJDE, direction)
|
||||
return mercuryConjunctionPolish(jde, leftJDE, rightJDE, direction, inst)
|
||||
}
|
||||
leftJDE, leftValue = rightJDE, rightValue
|
||||
}
|
||||
@@ -206,24 +219,28 @@ func mercuryConjunction(jde float64, next uint8) float64 {
|
||||
}
|
||||
|
||||
// mercuryConjunctionDeltaN 截断级数下的水星-太阳视黄经差(度,[-180,180]),用于方向性括号扫描。
|
||||
func mercuryConjunctionDeltaN(jde float64, n int) float64 {
|
||||
return mercuryConjunctionAngleDelta(MercuryApparentLoN(jde, n) - HSunApparentLoN(jde, n))
|
||||
func mercuryConjunctionDeltaN(jde float64, n int, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
return mercuryConjunctionAngleDelta(MercuryApparentLoNWithInstance(jde, n, inst) - HSunApparentLoNWithInstance(jde, n, inst))
|
||||
}
|
||||
|
||||
// mercuryConjunctionPolish 用全项级数在截断级数给出的括号内抛光。
|
||||
// 截断误差可能让括号两端在全项函数上同号(罕见),此时沿扫描方向再扩一两个扫描步;
|
||||
// 若仍未被确认(典型情形:查询几乎正好落在合上,截断级数在根两侧的符号与全项不一致),
|
||||
// 退回全项级数的方向扫描,保证有界且不返回 NaN。
|
||||
func mercuryConjunctionPolish(jde, leftJDE, rightJDE, direction float64) float64 {
|
||||
func mercuryConjunctionPolish(jde, leftJDE, rightJDE, direction float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
for attempt := 0; attempt < 3; attempt++ {
|
||||
leftValue := mercuryConjunctionExactDelta(leftJDE)
|
||||
rightValue := mercuryConjunctionExactDelta(rightJDE)
|
||||
leftValue := mercuryConjunctionExactDelta(leftJDE, inst)
|
||||
rightValue := mercuryConjunctionExactDelta(rightJDE, inst)
|
||||
if !isFiniteFloat(leftValue) || !isFiniteFloat(rightValue) {
|
||||
return math.NaN()
|
||||
}
|
||||
if leftValue == 0 || rightValue == 0 || leftValue*rightValue < 0 {
|
||||
root, ok := eventBracketSecantRoot(leftJDE, rightJDE, leftValue, rightValue,
|
||||
mercuryConjunctionPolishToleranceDay, mercuryConjunctionExactDelta)
|
||||
mercuryConjunctionPolishToleranceDay, func(jde float64) float64 { return mercuryConjunctionExactDelta(jde, inst) })
|
||||
if !ok {
|
||||
return math.NaN()
|
||||
}
|
||||
@@ -235,25 +252,27 @@ func mercuryConjunctionPolish(jde, leftJDE, rightJDE, direction float64) float64
|
||||
}
|
||||
leftJDE -= mercuryConjunctionScanStepDay
|
||||
}
|
||||
return mercuryConjunctionFullDirectionalScan(jde, direction)
|
||||
return mercuryConjunctionFullDirectionalScan(jde, direction, inst)
|
||||
}
|
||||
|
||||
// mercuryConjunctionFullDirectionalScan 全项级数的方向扫描(截断括号未被确认时的兜底)。
|
||||
func mercuryConjunctionFullDirectionalScan(jde, direction float64) float64 {
|
||||
func mercuryConjunctionFullDirectionalScan(jde, direction float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
leftJDE := jde
|
||||
leftValue := mercuryConjunctionExactDelta(leftJDE)
|
||||
leftValue := mercuryConjunctionExactDelta(leftJDE, inst)
|
||||
if !isFiniteFloat(leftValue) {
|
||||
return math.NaN()
|
||||
}
|
||||
for i := 0; i < mercuryConjunctionScanMaxSteps; i++ {
|
||||
rightJDE := jde + direction*mercuryConjunctionScanStepDay*float64(i+1)
|
||||
rightValue := mercuryConjunctionExactDelta(rightJDE)
|
||||
rightValue := mercuryConjunctionExactDelta(rightJDE, inst)
|
||||
if !isFiniteFloat(rightValue) {
|
||||
return math.NaN()
|
||||
}
|
||||
if leftValue == 0 || rightValue == 0 || leftValue*rightValue < 0 {
|
||||
root, ok := eventBracketSecantRoot(leftJDE, rightJDE, leftValue, rightValue,
|
||||
mercuryConjunctionPolishToleranceDay, mercuryConjunctionExactDelta)
|
||||
mercuryConjunctionPolishToleranceDay, func(jde float64) float64 { return mercuryConjunctionExactDelta(jde, inst) })
|
||||
if !ok {
|
||||
return math.NaN()
|
||||
}
|
||||
@@ -264,56 +283,66 @@ func mercuryConjunctionFullDirectionalScan(jde, direction float64) float64 {
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
func LastMercuryConjunction(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercuryConjunctionStrict, NextMercuryConjunctionStrict)
|
||||
// LastMercuryConjunctionWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryConjunctionWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercuryConjunctionStrictWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryConjunctionStrictWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryConjunction(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercuryConjunctionStrict, NextMercuryConjunctionStrict)
|
||||
// NextMercuryConjunctionWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryConjunctionWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercuryConjunctionStrictWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryConjunctionStrictWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func LastMercuryConjunctionStrict(jde float64) float64 {
|
||||
return mercuryConjunction(jde, 0)
|
||||
// LastMercuryConjunctionStrictWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryConjunctionStrictWithInstance(jde float64, inst *Instance) float64 {
|
||||
return mercuryConjunction(jde, 0, inst)
|
||||
}
|
||||
|
||||
func NextMercuryConjunctionStrict(jde float64) float64 {
|
||||
return mercuryConjunction(jde, 1)
|
||||
// NextMercuryConjunctionStrictWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryConjunctionStrictWithInstance(jde float64, inst *Instance) float64 {
|
||||
return mercuryConjunction(jde, 1, inst)
|
||||
}
|
||||
|
||||
func NextMercuryInferiorConjunction(jde float64) float64 {
|
||||
date := NextMercuryConjunctionStrict(jde)
|
||||
if EarthMercuryAway(date) > EarthAway(date) {
|
||||
return NextMercuryConjunctionStrict(date + 2)
|
||||
// NextMercuryInferiorConjunctionWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryInferiorConjunctionWithInstance(jde float64, inst *Instance) float64 {
|
||||
date := NextMercuryConjunctionStrictWithInstance(jde, inst)
|
||||
if EarthMercuryAwayWithInstance(date, inst) > EarthAwayWithInstance(date, inst) {
|
||||
return NextMercuryConjunctionStrictWithInstance(date+2, inst)
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
func NextMercurySuperiorConjunction(jde float64) float64 {
|
||||
date := NextMercuryConjunctionStrict(jde)
|
||||
if EarthMercuryAway(date) < EarthAway(date) {
|
||||
return NextMercuryConjunctionStrict(date + 2)
|
||||
// NextMercurySuperiorConjunctionWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercurySuperiorConjunctionWithInstance(jde float64, inst *Instance) float64 {
|
||||
date := NextMercuryConjunctionStrictWithInstance(jde, inst)
|
||||
if EarthMercuryAwayWithInstance(date, inst) < EarthAwayWithInstance(date, inst) {
|
||||
return NextMercuryConjunctionStrictWithInstance(date+2, inst)
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
func LastMercuryInferiorConjunction(jde float64) float64 {
|
||||
date := LastMercuryConjunctionStrict(jde)
|
||||
if EarthMercuryAway(date) > EarthAway(date) {
|
||||
return LastMercuryConjunctionStrict(date - 2)
|
||||
// LastMercuryInferiorConjunctionWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryInferiorConjunctionWithInstance(jde float64, inst *Instance) float64 {
|
||||
date := LastMercuryConjunctionStrictWithInstance(jde, inst)
|
||||
if EarthMercuryAwayWithInstance(date, inst) > EarthAwayWithInstance(date, inst) {
|
||||
return LastMercuryConjunctionStrictWithInstance(date-2, inst)
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
func LastMercurySuperiorConjunction(jde float64) float64 {
|
||||
date := LastMercuryConjunctionStrict(jde)
|
||||
if EarthMercuryAway(date) < EarthAway(date) {
|
||||
return LastMercuryConjunctionStrict(date - 2)
|
||||
// LastMercurySuperiorConjunctionWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercurySuperiorConjunctionWithInstance(jde float64, inst *Instance) float64 {
|
||||
date := LastMercuryConjunctionStrictWithInstance(jde, inst)
|
||||
if EarthMercuryAwayWithInstance(date, inst) < EarthAwayWithInstance(date, inst) {
|
||||
return LastMercuryConjunctionStrictWithInstance(date-2, inst)
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
func mercuryRADerivative(jde, delta float64) float64 {
|
||||
sub := MercuryApparentRa(jde+delta) - MercuryApparentRa(jde-delta)
|
||||
func mercuryRADerivative(jde, delta float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
sub := MercuryApparentRaWithInstance(jde+delta, inst) - MercuryApparentRaWithInstance(jde-delta, inst)
|
||||
if sub > 180 {
|
||||
sub -= 360
|
||||
}
|
||||
@@ -323,8 +352,10 @@ func mercuryRADerivative(jde, delta float64) float64 {
|
||||
return sub / (2 * delta)
|
||||
}
|
||||
|
||||
func mercuryRADerivativeN(jde, delta float64, n int) float64 {
|
||||
sub := MercuryApparentRaN(jde+delta, n) - MercuryApparentRaN(jde-delta, n)
|
||||
func mercuryRADerivativeN(jde, delta float64, n int, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
sub := MercuryApparentRaNWithInstance(jde+delta, n, inst) - MercuryApparentRaNWithInstance(jde-delta, n, inst)
|
||||
if sub > 180 {
|
||||
sub -= 360
|
||||
}
|
||||
@@ -334,16 +365,20 @@ func mercuryRADerivativeN(jde, delta float64, n int) float64 {
|
||||
return sub / (2 * delta)
|
||||
}
|
||||
|
||||
func mercuryStationInWindow(startTT, endTT float64) float64 {
|
||||
func mercuryStationInWindow(startTT, endTT float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
bestJDE := zeroEventInWindow(startTT, endTT, mercuryStationCoarseStepDay, mercuryStationHalfWindowDay, 30.0/86400.0, func(jd float64) float64 {
|
||||
return mercuryRADerivativeN(jd, mercuryStationDerivativeStepDay, mercuryEventSearchN)
|
||||
return mercuryRADerivativeN(jd, mercuryStationDerivativeStepDay, mercuryEventSearchN, inst)
|
||||
}, func(jd float64) float64 {
|
||||
return mercuryRADerivative(jd, mercuryStationDerivativeStepDay)
|
||||
return mercuryRADerivative(jd, mercuryStationDerivativeStepDay, inst)
|
||||
})
|
||||
return TT2UTC(bestJDE)
|
||||
}
|
||||
|
||||
func mercuryStationBetween(startTT, endTT float64) bool {
|
||||
func mercuryStationBetween(startTT, endTT float64, instances ...*Instance) bool {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
if endTT < startTT {
|
||||
startTT, endTT = endTT, startTT
|
||||
}
|
||||
@@ -360,13 +395,13 @@ func mercuryStationBetween(startTT, endTT float64) bool {
|
||||
}
|
||||
// 截断扫描足以判断单候选快速路径是否安全 / A truncated scan is enough to decide whether the one-candidate fast path is safe.
|
||||
left := startTT
|
||||
leftValue := mercuryRADerivativeN(left, mercuryStationDerivativeStepDay, mercuryEventSearchN)
|
||||
leftValue := mercuryRADerivativeN(left, mercuryStationDerivativeStepDay, mercuryEventSearchN, inst)
|
||||
for left < endTT {
|
||||
right := left + mercuryStationCoarseStepDay
|
||||
if right > endTT {
|
||||
right = endTT
|
||||
}
|
||||
rightValue := mercuryRADerivativeN(right, mercuryStationDerivativeStepDay, mercuryEventSearchN)
|
||||
rightValue := mercuryRADerivativeN(right, mercuryStationDerivativeStepDay, mercuryEventSearchN, inst)
|
||||
if leftValue == 0 || leftValue*rightValue < 0 || rightValue == 0 {
|
||||
return true
|
||||
}
|
||||
@@ -376,76 +411,81 @@ func mercuryStationBetween(startTT, endTT float64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func mercuryProgradeToRetrogradeAroundInferior(inferiorUT float64) float64 {
|
||||
func mercuryProgradeToRetrogradeAroundInferior(inferiorUT float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
inferiorTT := UTC2TT(inferiorUT)
|
||||
return mercuryStationInWindow(inferiorTT-mercuryStationWindowDays, inferiorTT)
|
||||
return mercuryStationInWindow(inferiorTT-mercuryStationWindowDays, inferiorTT, inst)
|
||||
}
|
||||
|
||||
func mercuryRetrogradeToProgradeAroundInferior(inferiorUT float64) float64 {
|
||||
func mercuryRetrogradeToProgradeAroundInferior(inferiorUT float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
inferiorTT := UTC2TT(inferiorUT)
|
||||
return mercuryStationInWindow(inferiorTT, inferiorTT+mercuryStationWindowDays)
|
||||
return mercuryStationInWindow(inferiorTT, inferiorTT+mercuryStationWindowDays, inst)
|
||||
}
|
||||
|
||||
// 类型化「留」统一结构:以下合为锚点求候选,再用侧向不变量(Next 不得早于查询、
|
||||
// Last 不得晚于查询)校验;不满足则把锚点推进/回退一个会合周期重试,最多
|
||||
// mercuryStationAnchorAttempts 次,最终仍有界失败为 NaN。
|
||||
// 这保证 Last* 永远不会返回未来、Next* 永远不会返回过去的事件。
|
||||
func NextMercuryProgradeToRetrograde(jde float64) float64 {
|
||||
// NextMercuryProgradeToRetrogradeWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryProgradeToRetrogradeWithInstance(jde float64, inst *Instance) float64 {
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
inferior := NextMercuryInferiorConjunction(jde)
|
||||
// 以下合为锚点求候选,不满足 Next 不早于查询时推进一个会合周期,保证不返回过去的事件。
|
||||
inferior := NextMercuryInferiorConjunctionWithInstance(jde, inst)
|
||||
for i := 0; i < mercuryStationAnchorAttempts && isFiniteFloat(inferior); i++ {
|
||||
date := mercuryProgradeToRetrogradeAroundInferior(inferior)
|
||||
date := mercuryProgradeToRetrogradeAroundInferior(inferior, inst)
|
||||
if isFiniteFloat(date) && stationUTQueryAfterOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
inferior = NextMercuryInferiorConjunction(eventUTNextQueryTT(inferior))
|
||||
inferior = NextMercuryInferiorConjunctionWithInstance(eventUTNextQueryTT(inferior), inst)
|
||||
}
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
func NextMercuryRetrogradeToPrograde(jde float64) float64 {
|
||||
// NextMercuryRetrogradeToProgradeWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryRetrogradeToProgradeWithInstance(jde float64, inst *Instance) float64 {
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
inferior := LastMercuryInferiorConjunction(jde)
|
||||
inferior := LastMercuryInferiorConjunctionWithInstance(jde, inst)
|
||||
for i := 0; i < mercuryStationAnchorAttempts && isFiniteFloat(inferior); i++ {
|
||||
date := mercuryRetrogradeToProgradeAroundInferior(inferior)
|
||||
date := mercuryRetrogradeToProgradeAroundInferior(inferior, inst)
|
||||
if isFiniteFloat(date) && stationUTQueryAfterOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
inferior = NextMercuryInferiorConjunction(eventUTNextQueryTT(inferior))
|
||||
inferior = NextMercuryInferiorConjunctionWithInstance(eventUTNextQueryTT(inferior), inst)
|
||||
}
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
func LastMercuryProgradeToRetrograde(jde float64) float64 {
|
||||
// LastMercuryProgradeToRetrogradeWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryProgradeToRetrogradeWithInstance(jde float64, inst *Instance) float64 {
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
inferior := NextMercuryInferiorConjunction(jde)
|
||||
inferior := NextMercuryInferiorConjunctionWithInstance(jde, inst)
|
||||
for i := 0; i < mercuryStationAnchorAttempts && isFiniteFloat(inferior); i++ {
|
||||
date := mercuryProgradeToRetrogradeAroundInferior(inferior)
|
||||
date := mercuryProgradeToRetrogradeAroundInferior(inferior, inst)
|
||||
if isFiniteFloat(date) && stationUTQueryBeforeOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
inferior = LastMercuryInferiorConjunction(eventUTLastQueryTT(inferior))
|
||||
inferior = LastMercuryInferiorConjunctionWithInstance(eventUTLastQueryTT(inferior), inst)
|
||||
}
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
func LastMercuryRetrogradeToPrograde(jde float64) float64 {
|
||||
// LastMercuryRetrogradeToProgradeWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryRetrogradeToProgradeWithInstance(jde float64, inst *Instance) float64 {
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
inferior := LastMercuryInferiorConjunction(jde)
|
||||
inferior := LastMercuryInferiorConjunctionWithInstance(jde, inst)
|
||||
for i := 0; i < mercuryStationAnchorAttempts && isFiniteFloat(inferior); i++ {
|
||||
date := mercuryRetrogradeToProgradeAroundInferior(inferior)
|
||||
date := mercuryRetrogradeToProgradeAroundInferior(inferior, inst)
|
||||
if isFiniteFloat(date) && stationUTQueryBeforeOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
inferior = LastMercuryInferiorConjunction(eventUTLastQueryTT(inferior))
|
||||
inferior = LastMercuryInferiorConjunctionWithInstance(eventUTLastQueryTT(inferior), inst)
|
||||
}
|
||||
return math.NaN()
|
||||
}
|
||||
@@ -477,72 +517,78 @@ func latestFiniteEventUT(candidates ...float64) float64 {
|
||||
return best
|
||||
}
|
||||
|
||||
func nextMercuryRetrogradeFromTyped(jde float64) float64 {
|
||||
return earliestFiniteEventUT(NextMercuryProgradeToRetrograde(jde), NextMercuryRetrogradeToPrograde(jde))
|
||||
func nextMercuryRetrogradeFromTyped(jde float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
return earliestFiniteEventUT(NextMercuryProgradeToRetrogradeWithInstance(jde, inst), NextMercuryRetrogradeToProgradeWithInstance(jde, inst))
|
||||
}
|
||||
|
||||
func NextMercuryRetrograde(jde float64) float64 {
|
||||
// NextMercuryRetrogradeWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryRetrogradeWithInstance(jde float64, inst *Instance) float64 {
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
motion := mercuryRADerivative(jde, mercuryStationDerivativeStepDay)
|
||||
motion := mercuryRADerivative(jde, mercuryStationDerivativeStepDay, inst)
|
||||
if motion > mercuryStationMotionTolerance {
|
||||
p2r := NextMercuryProgradeToRetrograde(jde)
|
||||
if isFiniteFloat(p2r) && !mercuryStationBetween(jde, UTC2TT(p2r)) {
|
||||
p2r := NextMercuryProgradeToRetrogradeWithInstance(jde, inst)
|
||||
if isFiniteFloat(p2r) && !mercuryStationBetween(jde, UTC2TT(p2r), inst) {
|
||||
return p2r
|
||||
}
|
||||
best := earliestFiniteEventUT(p2r, NextMercuryRetrogradeToPrograde(jde))
|
||||
best := earliestFiniteEventUT(p2r, NextMercuryRetrogradeToProgradeWithInstance(jde, inst))
|
||||
if !stationUTQueryAfterOrEqual(best, jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
return best
|
||||
}
|
||||
if motion < -mercuryStationMotionTolerance {
|
||||
r2p := NextMercuryRetrogradeToPrograde(jde)
|
||||
if isFiniteFloat(r2p) && !mercuryStationBetween(jde, UTC2TT(r2p)) {
|
||||
r2p := NextMercuryRetrogradeToProgradeWithInstance(jde, inst)
|
||||
if isFiniteFloat(r2p) && !mercuryStationBetween(jde, UTC2TT(r2p), inst) {
|
||||
return r2p
|
||||
}
|
||||
best := earliestFiniteEventUT(NextMercuryProgradeToRetrograde(jde), r2p)
|
||||
best := earliestFiniteEventUT(NextMercuryProgradeToRetrogradeWithInstance(jde, inst), r2p)
|
||||
if !stationUTQueryAfterOrEqual(best, jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
return best
|
||||
}
|
||||
return nextMercuryRetrogradeFromTyped(jde)
|
||||
return nextMercuryRetrogradeFromTyped(jde, inst)
|
||||
}
|
||||
|
||||
func lastMercuryRetrogradeFromTyped(jde float64) float64 {
|
||||
return latestFiniteEventUT(LastMercuryProgradeToRetrograde(jde), LastMercuryRetrogradeToPrograde(jde))
|
||||
func lastMercuryRetrogradeFromTyped(jde float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
return latestFiniteEventUT(LastMercuryProgradeToRetrogradeWithInstance(jde, inst), LastMercuryRetrogradeToProgradeWithInstance(jde, inst))
|
||||
}
|
||||
|
||||
func LastMercuryRetrograde(jde float64) float64 {
|
||||
// LastMercuryRetrogradeWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryRetrogradeWithInstance(jde float64, inst *Instance) float64 {
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
motion := mercuryRADerivative(jde, mercuryStationDerivativeStepDay)
|
||||
motion := mercuryRADerivative(jde, mercuryStationDerivativeStepDay, inst)
|
||||
if motion > mercuryStationMotionTolerance {
|
||||
r2p := LastMercuryRetrogradeToPrograde(jde)
|
||||
if isFiniteFloat(r2p) && !mercuryStationBetween(UTC2TT(r2p), jde) {
|
||||
r2p := LastMercuryRetrogradeToProgradeWithInstance(jde, inst)
|
||||
if isFiniteFloat(r2p) && !mercuryStationBetween(UTC2TT(r2p), jde, inst) {
|
||||
return r2p
|
||||
}
|
||||
best := latestFiniteEventUT(LastMercuryProgradeToRetrograde(jde), r2p)
|
||||
best := latestFiniteEventUT(LastMercuryProgradeToRetrogradeWithInstance(jde, inst), r2p)
|
||||
if !stationUTQueryBeforeOrEqual(best, jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
return best
|
||||
}
|
||||
if motion < -mercuryStationMotionTolerance {
|
||||
p2r := LastMercuryProgradeToRetrograde(jde)
|
||||
if isFiniteFloat(p2r) && !mercuryStationBetween(UTC2TT(p2r), jde) {
|
||||
p2r := LastMercuryProgradeToRetrogradeWithInstance(jde, inst)
|
||||
if isFiniteFloat(p2r) && !mercuryStationBetween(UTC2TT(p2r), jde, inst) {
|
||||
return p2r
|
||||
}
|
||||
best := latestFiniteEventUT(p2r, LastMercuryRetrogradeToPrograde(jde))
|
||||
best := latestFiniteEventUT(p2r, LastMercuryRetrogradeToProgradeWithInstance(jde, inst))
|
||||
if !stationUTQueryBeforeOrEqual(best, jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
return best
|
||||
}
|
||||
return lastMercuryRetrogradeFromTyped(jde)
|
||||
return lastMercuryRetrogradeFromTyped(jde, inst)
|
||||
}
|
||||
|
||||
func LastMercuryRetrogradeStrict(jde float64) float64 {
|
||||
@@ -553,258 +599,298 @@ func NextMercuryRetrogradeStrict(jde float64) float64 {
|
||||
return NextMercuryRetrograde(jde)
|
||||
}
|
||||
|
||||
func MercurySunElongation(jde float64) float64 {
|
||||
lo1, bo1 := MercuryApparentLoBo(jde)
|
||||
lo2 := HSunApparentLo(jde)
|
||||
bo2 := HSunTrueBo(jde)
|
||||
// MercurySunElongationWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func MercurySunElongationWithInstance(jde float64, inst *Instance) float64 {
|
||||
lo1, bo1 := MercuryApparentLoBoWithInstance(jde, inst)
|
||||
lo2 := HSunApparentLoWithInstance(jde, inst)
|
||||
bo2 := HSunTrueBoWithInstance(jde, inst)
|
||||
return StarAngularSeparation(lo1, bo1, lo2, bo2)
|
||||
}
|
||||
|
||||
func mercurySunElongationN(jde float64, n int) float64 {
|
||||
lo1, bo1 := MercuryApparentLoBoN(jde, n)
|
||||
lo2 := HSunApparentLoN(jde, n)
|
||||
bo2 := HSunTrueBoN(jde, n)
|
||||
func mercurySunElongationN(jde float64, n int, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
lo1, bo1 := MercuryApparentLoBoNWithInstance(jde, n, inst)
|
||||
lo2 := HSunApparentLoNWithInstance(jde, n, inst)
|
||||
bo2 := HSunTrueBoNWithInstance(jde, n, inst)
|
||||
return StarAngularSeparation(lo1, bo1, lo2, bo2)
|
||||
}
|
||||
|
||||
// mercuryGreatestElongationInWindow 求窗口内大距:目标是公开 MercurySunElongation 的极大(视距角),
|
||||
// 而不是忽略光行差/视位置修正的真距角,否则返回的时刻不是调用方能量到的那个极值。
|
||||
// 窗口两端是世界时,目标函数收力学时,因此逐次换算。
|
||||
func mercuryGreatestElongationInWindow(start, end float64) float64 {
|
||||
func mercuryGreatestElongationInWindow(start, end float64, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
return maximizeInWindow(start, end, 2.0, func(utJD float64) float64 {
|
||||
return mercurySunElongationN(UTC2TT(utJD), mercuryEventSearchN)
|
||||
return mercurySunElongationN(UTC2TT(utJD), mercuryEventSearchN, inst)
|
||||
}, func(utJD float64) float64 {
|
||||
return MercurySunElongation(UTC2TT(utJD))
|
||||
return MercurySunElongationWithInstance(UTC2TT(utJD), inst)
|
||||
})
|
||||
}
|
||||
|
||||
func mercuryEastElongationWindowEndingAt(inferior float64) (float64, float64) {
|
||||
lastSuperior := LastMercurySuperiorConjunction(eventUTLastQueryTT(inferior))
|
||||
func mercuryEastElongationWindowEndingAt(inferior float64, instances ...*Instance) (float64, float64) {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
lastSuperior := LastMercurySuperiorConjunctionWithInstance(eventUTLastQueryTT(inferior), inst)
|
||||
return lastSuperior + innerEventWindowPadding, inferior - innerEventWindowPadding
|
||||
}
|
||||
|
||||
func mercuryWestElongationWindowEndingAt(superior float64) (float64, float64) {
|
||||
lastInferior := LastMercuryInferiorConjunction(eventUTLastQueryTT(superior))
|
||||
func mercuryWestElongationWindowEndingAt(superior float64, instances ...*Instance) (float64, float64) {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
lastInferior := LastMercuryInferiorConjunctionWithInstance(eventUTLastQueryTT(superior), inst)
|
||||
return lastInferior + innerEventWindowPadding, superior - innerEventWindowPadding
|
||||
}
|
||||
|
||||
func mercuryEastElongationWindowContaining(jde float64) (float64, float64) {
|
||||
nextInferior := NextMercuryInferiorConjunction(jde)
|
||||
start, end := mercuryEastElongationWindowEndingAt(nextInferior)
|
||||
func mercuryEastElongationWindowContaining(jde float64, instances ...*Instance) (float64, float64) {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
nextInferior := NextMercuryInferiorConjunctionWithInstance(jde, inst)
|
||||
start, end := mercuryEastElongationWindowEndingAt(nextInferior, inst)
|
||||
if eventUTQueryBeforeOrEqual(start, jde) {
|
||||
return start, end
|
||||
}
|
||||
currentInferior := LastMercuryInferiorConjunction(jde)
|
||||
return mercuryEastElongationWindowEndingAt(currentInferior)
|
||||
currentInferior := LastMercuryInferiorConjunctionWithInstance(jde, inst)
|
||||
return mercuryEastElongationWindowEndingAt(currentInferior, inst)
|
||||
}
|
||||
|
||||
func mercuryWestElongationWindowContaining(jde float64) (float64, float64) {
|
||||
nextSuperior := NextMercurySuperiorConjunction(jde)
|
||||
start, end := mercuryWestElongationWindowEndingAt(nextSuperior)
|
||||
func mercuryWestElongationWindowContaining(jde float64, instances ...*Instance) (float64, float64) {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
nextSuperior := NextMercurySuperiorConjunctionWithInstance(jde, inst)
|
||||
start, end := mercuryWestElongationWindowEndingAt(nextSuperior, inst)
|
||||
if eventUTQueryBeforeOrEqual(start, jde) {
|
||||
return start, end
|
||||
}
|
||||
currentSuperior := LastMercurySuperiorConjunction(jde)
|
||||
return mercuryWestElongationWindowEndingAt(currentSuperior)
|
||||
currentSuperior := LastMercurySuperiorConjunctionWithInstance(jde, inst)
|
||||
return mercuryWestElongationWindowEndingAt(currentSuperior, inst)
|
||||
}
|
||||
|
||||
func nextMercuryGreatestElongationTyped(jde float64, east bool) float64 {
|
||||
func nextMercuryGreatestElongationTyped(jde float64, east bool, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
if east {
|
||||
start, windowEnd := mercuryEastElongationWindowContaining(jde)
|
||||
start, windowEnd := mercuryEastElongationWindowContaining(jde, inst)
|
||||
for i := 0; i < eventDirectionalSearchIterations; i++ {
|
||||
date := mercuryGreatestElongationInWindow(start, windowEnd)
|
||||
date := mercuryGreatestElongationInWindow(start, windowEnd, inst)
|
||||
if !isFiniteFloat(date) {
|
||||
return math.NaN()
|
||||
}
|
||||
if eventUTQueryAfterOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
nextInferior := NextMercuryInferiorConjunction(eventUTNextQueryTT(windowEnd))
|
||||
start, windowEnd = mercuryEastElongationWindowEndingAt(nextInferior)
|
||||
nextInferior := NextMercuryInferiorConjunctionWithInstance(eventUTNextQueryTT(windowEnd), inst)
|
||||
start, windowEnd = mercuryEastElongationWindowEndingAt(nextInferior, inst)
|
||||
}
|
||||
return math.NaN()
|
||||
}
|
||||
start, windowEnd := mercuryWestElongationWindowContaining(jde)
|
||||
start, windowEnd := mercuryWestElongationWindowContaining(jde, inst)
|
||||
for i := 0; i < eventDirectionalSearchIterations; i++ {
|
||||
date := mercuryGreatestElongationInWindow(start, windowEnd)
|
||||
date := mercuryGreatestElongationInWindow(start, windowEnd, inst)
|
||||
if !isFiniteFloat(date) {
|
||||
return math.NaN()
|
||||
}
|
||||
if eventUTQueryAfterOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
nextSuperior := NextMercurySuperiorConjunction(eventUTNextQueryTT(windowEnd))
|
||||
start, windowEnd = mercuryWestElongationWindowEndingAt(nextSuperior)
|
||||
nextSuperior := NextMercurySuperiorConjunctionWithInstance(eventUTNextQueryTT(windowEnd), inst)
|
||||
start, windowEnd = mercuryWestElongationWindowEndingAt(nextSuperior, inst)
|
||||
}
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
func lastMercuryGreatestElongationTyped(jde float64, east bool) float64 {
|
||||
func lastMercuryGreatestElongationTyped(jde float64, east bool, instances ...*Instance) float64 {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
if east {
|
||||
start, windowEnd := mercuryEastElongationWindowContaining(jde)
|
||||
start, windowEnd := mercuryEastElongationWindowContaining(jde, inst)
|
||||
for i := 0; i < eventDirectionalSearchIterations; i++ {
|
||||
date := mercuryGreatestElongationInWindow(start, windowEnd)
|
||||
date := mercuryGreatestElongationInWindow(start, windowEnd, inst)
|
||||
if !isFiniteFloat(date) {
|
||||
return math.NaN()
|
||||
}
|
||||
if eventUTQueryBeforeOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
prevInferior := LastMercuryInferiorConjunction(eventUTLastQueryTT(start))
|
||||
start, windowEnd = mercuryEastElongationWindowEndingAt(prevInferior)
|
||||
prevInferior := LastMercuryInferiorConjunctionWithInstance(eventUTLastQueryTT(start), inst)
|
||||
start, windowEnd = mercuryEastElongationWindowEndingAt(prevInferior, inst)
|
||||
}
|
||||
return math.NaN()
|
||||
}
|
||||
start, windowEnd := mercuryWestElongationWindowContaining(jde)
|
||||
start, windowEnd := mercuryWestElongationWindowContaining(jde, inst)
|
||||
for i := 0; i < eventDirectionalSearchIterations; i++ {
|
||||
date := mercuryGreatestElongationInWindow(start, windowEnd)
|
||||
date := mercuryGreatestElongationInWindow(start, windowEnd, inst)
|
||||
if !isFiniteFloat(date) {
|
||||
return math.NaN()
|
||||
}
|
||||
if eventUTQueryBeforeOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
prevSuperior := LastMercurySuperiorConjunction(eventUTLastQueryTT(start))
|
||||
start, windowEnd = mercuryWestElongationWindowEndingAt(prevSuperior)
|
||||
prevSuperior := LastMercurySuperiorConjunctionWithInstance(eventUTLastQueryTT(start), inst)
|
||||
start, windowEnd = mercuryWestElongationWindowEndingAt(prevSuperior, inst)
|
||||
}
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
// mercuryElongationWindowAt 返回包含 jde 的该侧大距窗口;查询落在合的 4 秒内边距里时两侧都不包含。
|
||||
func mercuryElongationWindowAt(jde float64, east bool) (float64, float64, bool) {
|
||||
func mercuryElongationWindowAt(jde float64, east bool, instances ...*Instance) (float64, float64, bool) {
|
||||
inst := instanceValue(instances)
|
||||
|
||||
if east {
|
||||
start, end := mercuryEastElongationWindowEndingAt(NextMercuryInferiorConjunction(jde))
|
||||
start, end := mercuryEastElongationWindowEndingAt(NextMercuryInferiorConjunctionWithInstance(jde, inst), inst)
|
||||
return start, end, eventUTQueryBeforeOrEqual(start, jde) && eventUTQueryAfterOrEqual(end, jde)
|
||||
}
|
||||
start, end := mercuryWestElongationWindowEndingAt(NextMercurySuperiorConjunction(jde))
|
||||
start, end := mercuryWestElongationWindowEndingAt(NextMercurySuperiorConjunctionWithInstance(jde, inst), inst)
|
||||
return start, end, eventUTQueryBeforeOrEqual(start, jde) && eventUTQueryAfterOrEqual(end, jde)
|
||||
}
|
||||
|
||||
// 无东西侧参数的 Next/Last 先只看查询所在窗口那一侧:该侧大距未过就是答案,已过则另一侧紧接着的
|
||||
// 下一个才是答案,因此只有在查询贴住合(两侧窗口都不含)时才退化为两侧都算。赤经差在合附近会提前
|
||||
// 变号,不能用它定窗口。
|
||||
func NextMercuryGreatestElongation(jde float64) float64 {
|
||||
// NextMercuryGreatestElongationWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryGreatestElongationWithInstance(jde float64, inst *Instance) float64 {
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
// 先只看查询所在一侧的窗口,未过即答案,已过则取另一侧的下一个;赤经差在合附近会提前变号,不能用来定窗口。
|
||||
for _, east := range [2]bool{true, false} {
|
||||
start, end, ok := mercuryElongationWindowAt(jde, east)
|
||||
start, end, ok := mercuryElongationWindowAt(jde, east, inst)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if date := mercuryGreatestElongationInWindow(start, end); isFiniteFloat(date) && eventUTQueryAfterOrEqual(date, jde) {
|
||||
if date := mercuryGreatestElongationInWindow(start, end, inst); isFiniteFloat(date) && eventUTQueryAfterOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
if date := nextMercuryGreatestElongationTyped(jde, !east); isFiniteFloat(date) && eventUTQueryAfterOrEqual(date, jde) {
|
||||
if date := nextMercuryGreatestElongationTyped(jde, !east, inst); isFiniteFloat(date) && eventUTQueryAfterOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
break
|
||||
}
|
||||
return earliestFiniteEventUT(nextMercuryGreatestElongationTyped(jde, true), nextMercuryGreatestElongationTyped(jde, false))
|
||||
return earliestFiniteEventUT(nextMercuryGreatestElongationTyped(jde, true, inst), nextMercuryGreatestElongationTyped(jde, false, inst))
|
||||
}
|
||||
|
||||
func LastMercuryGreatestElongation(jde float64) float64 {
|
||||
// LastMercuryGreatestElongationWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryGreatestElongationWithInstance(jde float64, inst *Instance) float64 {
|
||||
if !isFiniteFloat(jde) {
|
||||
return math.NaN()
|
||||
}
|
||||
// 先只看查询所在一侧的窗口,未过即答案,已过则取另一侧的下一个;赤经差在合附近会提前变号,不能用来定窗口。
|
||||
for _, east := range [2]bool{true, false} {
|
||||
start, end, ok := mercuryElongationWindowAt(jde, east)
|
||||
start, end, ok := mercuryElongationWindowAt(jde, east, inst)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if date := mercuryGreatestElongationInWindow(start, end); isFiniteFloat(date) && eventUTQueryBeforeOrEqual(date, jde) {
|
||||
if date := mercuryGreatestElongationInWindow(start, end, inst); isFiniteFloat(date) && eventUTQueryBeforeOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
if date := lastMercuryGreatestElongationTyped(jde, !east); isFiniteFloat(date) && eventUTQueryBeforeOrEqual(date, jde) {
|
||||
if date := lastMercuryGreatestElongationTyped(jde, !east, inst); isFiniteFloat(date) && eventUTQueryBeforeOrEqual(date, jde) {
|
||||
return date
|
||||
}
|
||||
break
|
||||
}
|
||||
return latestFiniteEventUT(lastMercuryGreatestElongationTyped(jde, true), lastMercuryGreatestElongationTyped(jde, false))
|
||||
return latestFiniteEventUT(lastMercuryGreatestElongationTyped(jde, true, inst), lastMercuryGreatestElongationTyped(jde, false, inst))
|
||||
}
|
||||
|
||||
func LastMercuryInferiorConjunctionInclusive(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercuryInferiorConjunction, NextMercuryInferiorConjunction)
|
||||
// LastMercuryInferiorConjunctionInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryInferiorConjunctionInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercuryInferiorConjunctionWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryInferiorConjunctionWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryInferiorConjunctionInclusive(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercuryInferiorConjunction, NextMercuryInferiorConjunction)
|
||||
// NextMercuryInferiorConjunctionInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryInferiorConjunctionInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercuryInferiorConjunctionWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryInferiorConjunctionWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func LastMercurySuperiorConjunctionInclusive(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercurySuperiorConjunction, NextMercurySuperiorConjunction)
|
||||
// LastMercurySuperiorConjunctionInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercurySuperiorConjunctionInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercurySuperiorConjunctionWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercurySuperiorConjunctionWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercurySuperiorConjunctionInclusive(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercurySuperiorConjunction, NextMercurySuperiorConjunction)
|
||||
// NextMercurySuperiorConjunctionInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercurySuperiorConjunctionInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercurySuperiorConjunctionWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercurySuperiorConjunctionWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func LastMercuryRetrogradeInclusive(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercuryRetrograde, NextMercuryRetrograde)
|
||||
// LastMercuryRetrogradeInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryRetrogradeInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercuryRetrogradeWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryRetrogradeWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryRetrogradeInclusive(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercuryRetrograde, NextMercuryRetrograde)
|
||||
// NextMercuryRetrogradeInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryRetrogradeInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercuryRetrogradeWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryRetrogradeWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func LastMercuryProgradeToRetrogradeInclusive(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercuryProgradeToRetrograde, NextMercuryProgradeToRetrograde)
|
||||
// LastMercuryProgradeToRetrogradeInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryProgradeToRetrogradeInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercuryProgradeToRetrogradeWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryProgradeToRetrogradeWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryProgradeToRetrogradeInclusive(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercuryProgradeToRetrograde, NextMercuryProgradeToRetrograde)
|
||||
// NextMercuryProgradeToRetrogradeInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryProgradeToRetrogradeInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercuryProgradeToRetrogradeWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryProgradeToRetrogradeWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func LastMercuryRetrogradeToProgradeInclusive(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercuryRetrogradeToPrograde, NextMercuryRetrogradeToPrograde)
|
||||
// LastMercuryRetrogradeToProgradeInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryRetrogradeToProgradeInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercuryRetrogradeToProgradeWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryRetrogradeToProgradeWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryRetrogradeToProgradeInclusive(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercuryRetrogradeToPrograde, NextMercuryRetrogradeToPrograde)
|
||||
// NextMercuryRetrogradeToProgradeInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryRetrogradeToProgradeInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercuryRetrogradeToProgradeWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryRetrogradeToProgradeWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func LastMercuryGreatestElongationInclusive(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercuryGreatestElongation, NextMercuryGreatestElongation)
|
||||
// LastMercuryGreatestElongationInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryGreatestElongationInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercuryGreatestElongationWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryGreatestElongationWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryGreatestElongationInclusive(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercuryGreatestElongation, NextMercuryGreatestElongation)
|
||||
// NextMercuryGreatestElongationInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryGreatestElongationInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercuryGreatestElongationWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryGreatestElongationWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func LastMercuryGreatestElongationEastInclusive(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercuryGreatestElongationEast, NextMercuryGreatestElongationEast)
|
||||
// LastMercuryGreatestElongationEastInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryGreatestElongationEastInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercuryGreatestElongationEastWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryGreatestElongationEastWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryGreatestElongationEastInclusive(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercuryGreatestElongationEast, NextMercuryGreatestElongationEast)
|
||||
// NextMercuryGreatestElongationEastInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryGreatestElongationEastInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercuryGreatestElongationEastWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryGreatestElongationEastWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func LastMercuryGreatestElongationWestInclusive(jde float64) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, LastMercuryGreatestElongationWest, NextMercuryGreatestElongationWest)
|
||||
// LastMercuryGreatestElongationWestInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryGreatestElongationWestInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveLastSimpleEvent(jde, func(jde float64) float64 { return LastMercuryGreatestElongationWestWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryGreatestElongationWestWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryGreatestElongationWestInclusive(jde float64) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, LastMercuryGreatestElongationWest, NextMercuryGreatestElongationWest)
|
||||
// NextMercuryGreatestElongationWestInclusiveWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryGreatestElongationWestInclusiveWithInstance(jde float64, inst *Instance) float64 {
|
||||
return inclusiveNextSimpleEvent(jde, func(jde float64) float64 { return LastMercuryGreatestElongationWestWithInstance(jde, inst) }, func(jde float64) float64 { return NextMercuryGreatestElongationWestWithInstance(jde, inst) })
|
||||
}
|
||||
|
||||
func NextMercuryGreatestElongationEast(jde float64) float64 {
|
||||
return nextMercuryGreatestElongationTyped(jde, true)
|
||||
// NextMercuryGreatestElongationEastWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryGreatestElongationEastWithInstance(jde float64, inst *Instance) float64 {
|
||||
return nextMercuryGreatestElongationTyped(jde, true, inst)
|
||||
}
|
||||
|
||||
func NextMercuryGreatestElongationWest(jde float64) float64 {
|
||||
return nextMercuryGreatestElongationTyped(jde, false)
|
||||
// NextMercuryGreatestElongationWestWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func NextMercuryGreatestElongationWestWithInstance(jde float64, inst *Instance) float64 {
|
||||
return nextMercuryGreatestElongationTyped(jde, false, inst)
|
||||
}
|
||||
|
||||
func LastMercuryGreatestElongationEast(jde float64) float64 {
|
||||
return lastMercuryGreatestElongationTyped(jde, true)
|
||||
// LastMercuryGreatestElongationEastWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryGreatestElongationEastWithInstance(jde float64, inst *Instance) float64 {
|
||||
return lastMercuryGreatestElongationTyped(jde, true, inst)
|
||||
}
|
||||
|
||||
func LastMercuryGreatestElongationWest(jde float64) float64 {
|
||||
return lastMercuryGreatestElongationTyped(jde, false)
|
||||
// LastMercuryGreatestElongationWestWithInstance 用指定星历实例求值;inst 为 nil 时用进程当前模型 / evaluation with an explicit instance; nil uses the process model.
|
||||
func LastMercuryGreatestElongationWestWithInstance(jde float64, inst *Instance) float64 {
|
||||
return lastMercuryGreatestElongationTyped(jde, false, inst)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user