Files

67 lines
2.7 KiB
Go
Raw Permalink Normal View History

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
}