ccf5880269
- 基于平均下合周期与节点相位预筛候选,减少无效星历计算;跳过无法求解的单个会合周期,避免有限覆盖星历导致搜索提前终止 - 引入影轴 γ、半影半径及地球尺度几何判定,结合站心可见性识别地心无接触、仅部分地区可见的掠凌 - 添加金星 243 年、水星 46 年周期族编号,并明确编号适用范围及未分配时的零值语义 - 为 SVG、GeoJSON 和 KML 增加站心部分凌日可见区,适配接触等时线、几何元数据、图层样式及取景;为地心无接触凌日事件增加正射图,按可见区球面面积加权居中
68 lines
2.7 KiB
Go
68 lines
2.7 KiB
Go
package basic
|
|
|
|
import "math"
|
|
|
|
const (
|
|
planetTransitEarthRadiusKM = 6378.137
|
|
planetTransitEarthEccentricitySquared = 0.00669437999014
|
|
)
|
|
|
|
func planetTransitShadowGeometry(tt float64, cfg planetTransitConfig, inst *Instance) (float64, float64, Observer, bool) {
|
|
sunRA, sunDec := HSunApparentRaDecNWithInstance(tt, -1, inst)
|
|
planetRA, planetDec := cfg.apparentRaDecN(tt, -1)
|
|
sunDistance := EarthAwayNWithInstance(tt, -1, inst) * angularDiameterAstronomicalUnitKM
|
|
planetDistance := cfg.earthDistanceN(tt, -1) * angularDiameterAstronomicalUnitKM
|
|
sun := eclipticCartesian(sunRA, sunDec, sunDistance)
|
|
body := eclipticCartesian(planetRA, planetDec, planetDistance)
|
|
axis, length := pn(Vector3{body[0] - sun[0], body[1] - sun[1], body[2] - sun[2]})
|
|
projection := -(body[0]*axis[0] + body[1]*axis[1] + body[2]*axis[2])
|
|
impact := Vector3{body[0] + projection*axis[0], body[1] + projection*axis[1], body[2] + projection*axis[2]}
|
|
_, distance := pn(impact)
|
|
planetRadius := venusEquatorialRadiusKM
|
|
if cfg.planetIndex == 1 {
|
|
planetRadius = mercuryEquatorialRadiusKM
|
|
}
|
|
sine := (sunEquatorialRadiusKM + planetRadius) / length
|
|
cosine := math.Sqrt(1 - sine*sine)
|
|
penumbra := (planetRadius + projection*sine) / cosine / planetTransitEarthRadiusKM
|
|
gamma := math.Copysign(distance/planetTransitEarthRadiusKM, impact[2])
|
|
sidereal := ApparentSiderealTime(TT2UT1(tt)) * 15
|
|
seed := Observer{
|
|
Longitude: normalizeLongitude180(math.Atan2(impact[1], impact[0])*180/math.Pi - sidereal),
|
|
Latitude: math.Atan2(impact[2], math.Hypot(impact[0], impact[1])*(1-planetTransitEarthEccentricitySquared)) * 180 / math.Pi,
|
|
}
|
|
possible := isFiniteFloat(gamma) && isFiniteFloat(penumbra) && projection > 0 && planetDistance < sunDistance && math.Abs(gamma) <= penumbra+1/cosine
|
|
return gamma, penumbra, seed, possible
|
|
}
|
|
|
|
func planetTransitSurfaceOverlap(transit PlanetTransitResult, seed Observer, inst *Instance) bool {
|
|
snapshot, ok := buildPlanetTransitSnapshot(transit, inst)
|
|
if !ok {
|
|
return false
|
|
}
|
|
best := math.Inf(1)
|
|
for step := 4.0; step > 0.0001; step /= 2 {
|
|
center := seed
|
|
for _, latitudeStep := range []float64{-step, 0, step} {
|
|
for _, longitudeStep := range []float64{-step, 0, step} {
|
|
observer := Observer{Longitude: normalizeLongitude180(center.Longitude + longitudeStep), Latitude: math.Max(-90, math.Min(90, center.Latitude+latitudeStep))}
|
|
tt, valid := snapshot.localGreatestTT(UTC2TT(transit.Greatest), observer)
|
|
state, stateOK := snapshot.stateAt(tt, observer)
|
|
if !valid || !stateOK {
|
|
continue
|
|
}
|
|
if state.external < 0 {
|
|
local := snapshot.local(transit, observer)
|
|
if local.Valid && local.Visible {
|
|
return true
|
|
}
|
|
}
|
|
if state.external < best {
|
|
best, seed = state.external, observer
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|