Files
astro/geojson/occultation_limit_separation_test.go
T

128 lines
4.8 KiB
Go
Raw Normal View History

package geojson_test
import (
"math"
"testing"
"time"
"b612.me/astro/geojson"
"b612.me/astro/moon"
)
// 导出属性必须同时给出 WidthKM(width_km)与限线间距(greatest_limit_separation_km),且两者口径不同。
func occultationLimitSeparationJSONValue(t *testing.T, feature decodedFeature, key string) float64 {
t.Helper()
raw, ok := feature.Properties[key]
if !ok {
t.Fatalf("feature role=%v has no %s property", feature.Properties["role"], key)
}
value, ok := raw.(float64)
if !ok || math.IsNaN(value) || math.IsInf(value, 0) {
t.Fatalf("feature role=%v %s=%v, want a finite number", feature.Properties["role"], key, raw)
}
return value
}
func TestMarshalPlanetOccultationCarriesGreatestLimitSeparation(t *testing.T) {
start := time.Date(1962, time.October, 10, 0, 0, 0, 0, time.UTC)
paths, err := moon.FindPlanetOccultationPaths(
start, start.Add(24*time.Hour), moon.OccultationJupiter,
moon.OccultationPathOptions{
Step: 10 * time.Minute, TargetSpacingKM: 900,
DisableFootprints: true, DisableRiseSet: true,
},
)
if err != nil || len(paths) != 1 {
t.Fatalf("FindPlanetOccultationPaths() paths=%d err=%v, want one", len(paths), err)
}
data, err := geojson.MarshalPlanetOccultation(paths[0])
if err != nil {
t.Fatalf("MarshalPlanetOccultation: %v", err)
}
collection := decodeCollection(t, data)
var greatestWidth, limitSeparation float64
foundSeparation, foundGreatest := false, false
for _, feature := range collection.Features {
if value := occultationLimitSeparationJSONValue(t, feature, "greatest_limit_separation_km"); !foundSeparation {
limitSeparation = value
foundSeparation = true
}
if feature.Properties["role"] == "greatest" {
greatestWidth = occultationLimitSeparationJSONValue(t, feature, "width_km")
foundGreatest = true
}
}
if !foundSeparation || !foundGreatest {
t.Fatalf("limit separation=%v greatest width=%v, want both properties present", foundSeparation, foundGreatest)
}
if math.Abs(limitSeparation-3593.197135) > 0.5 {
t.Fatalf("greatest_limit_separation_km=%.6f, want 3593.197135 within 0.5 km", limitSeparation)
}
if math.Abs(greatestWidth-5319.263900) > 0.5 {
t.Fatalf("greatest width_km=%.6f, want 5319.263900 within 0.5 km", greatestWidth)
}
if math.Abs(greatestWidth-limitSeparation) < 1000 {
t.Fatalf("width_km=%.3f and greatest_limit_separation_km=%.3f are too close, want the two distinct constructions",
greatestWidth, limitSeparation)
}
}
func TestMarshalPlanetOccultationRejectsNonFiniteLimitSeparation(t *testing.T) {
start := time.Date(1962, time.October, 10, 0, 0, 0, 0, time.UTC)
paths, err := moon.FindPlanetOccultationPaths(
start, start.Add(24*time.Hour), moon.OccultationJupiter,
moon.OccultationPathOptions{
Step: 10 * time.Minute, TargetSpacingKM: 900,
DisableFootprints: true, DisableRiseSet: true,
},
)
if err != nil || len(paths) != 1 {
t.Fatalf("FindPlanetOccultationPaths() paths=%d err=%v, want one", len(paths), err)
}
broken := paths[0]
broken.NorthernLimit = append([]moon.OccultationPathPoint(nil), paths[0].NorthernLimit...)
broken.NorthernLimit[1].LimitSeparationKM = math.NaN()
if _, err := geojson.MarshalPlanetOccultation(broken); err == nil {
t.Fatal("MarshalPlanetOccultation accepted a NaN limit separation on a limit point")
}
broken = paths[0]
broken.GreatestLimitSeparationKM = math.Inf(1)
if _, err := geojson.MarshalPlanetOccultation(broken); err == nil {
t.Fatal("MarshalPlanetOccultation accepted a non-finite greatest limit separation")
}
}
func TestMarshalStarOccultationCarriesGreatestLimitSeparation(t *testing.T) {
start := time.Date(2025, time.June, 5, 0, 0, 0, 0, time.UTC)
paths, err := moon.FindStarOccultationPaths(
start, start.Add(24*time.Hour), hr4799OccultationCoordinateForGeoJSONLimitTest(),
moon.OccultationPathOptions{
Step: 20 * time.Minute, TargetSpacingKM: 900,
DisableFootprints: true, DisableRiseSet: true,
},
)
if err != nil || len(paths) != 1 {
t.Fatalf("FindStarOccultationPaths() paths=%d err=%v, want one", len(paths), err)
}
data, err := geojson.MarshalStarOccultation(paths[0])
if err != nil {
t.Fatalf("MarshalStarOccultation: %v", err)
}
collection := decodeCollection(t, data)
value := occultationLimitSeparationJSONValue(t, collection.Features[0], "greatest_limit_separation_km")
if math.Abs(value-3666.576690) > 0.5 {
t.Fatalf("greatest_limit_separation_km=%.6f, want 3666.576690 within 0.5 km", value)
}
}
func hr4799OccultationCoordinateForGeoJSONLimitTest() moon.StarCoordinate {
return moon.StarCoordinate{
ID: "HR 4799", RA: 189.1975, Dec: -5.831944444444,
Epoch: time.Date(2000, time.January, 1, 12, 0, 0, 0, time.UTC),
Frame: moon.CoordinateFrameJ2000,
ProperMotionRACosDecMasPerYear: -28,
ProperMotionDecMasPerYear: -18,
}
}