feat: 完善日月食与月掩几何链路并扩展历法接口
- 新增日月食中心带、偏食带、阴影足迹、等时线、食分线及升落边界计算,支持极区与混合食拓扑 - 新增日食单时刻阴影求解器、站心状态查询、批量采样和 ΔT 覆盖接口 - 重构恒星与行星月掩路径,补充有限盘面接触、站心修正、掩带宽度、极区投影及升落边界 - 扩展 SVG 与 GeoJSON 输出,支持详细面板、全球/极区/地球投影、边界闭合、时间标记和拓扑签名 - 扩展日月食候选搜索、局地搜索、沙罗序列预计算与范围外推,补充系列锚点和成员一致性校验 - 补齐古历纪年、儒略历独有闰日、多公历候选、历法改革跨日及精确日期运算接口 - 优化 ΔT、章动、恒星时、月球地平线、事件根搜索和本地星历缓存,降低重复计算开销并提升边界稳定
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package geojson_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"b612.me/astro/internal/geodata"
|
||||
"b612.me/astro/internal/occultationgeo"
|
||||
)
|
||||
|
||||
func TestMars20250729TotalBandIsSingleMergedFace(t *testing.T) {
|
||||
collection := mars20250729TestFixture(t, time.Minute, true).collection
|
||||
totalBand := featureWithRole(t, collection, "total-band")
|
||||
rings := geoJSONMultiPolygonOuterRings(t, totalBand)
|
||||
if len(rings) != 1 {
|
||||
t.Fatalf("total-band polygons=%d, want one merged face", len(rings))
|
||||
}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
probe geodata.GeoPoint
|
||||
inside bool
|
||||
}{
|
||||
{name: "visible-sweep", probe: geodata.GeoPoint{Longitude: -129.8230, Latitude: -77.4030}, inside: true},
|
||||
{name: "selected-west", probe: geodata.GeoPoint{Longitude: -134.6060, Latitude: -78.5601}, inside: true},
|
||||
{name: "selected-center", probe: geodata.GeoPoint{Longitude: -134.2300, Latitude: -78.0725}, inside: true},
|
||||
} {
|
||||
inside := geodata.SphericalPolygonsContainPoints(rings, []geodata.GeoPoint{test.probe})[0]
|
||||
if inside != test.inside {
|
||||
t.Fatalf("total-band probe %s (%.4f, %.4f) inside=%v, want %v", test.name, test.probe.Longitude, test.probe.Latitude, inside, test.inside)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMars20250729FinalTotalBandHasWidePolarShoulderRepair(t *testing.T) {
|
||||
collection := mars20250729TestFixture(t, time.Minute, true).collection
|
||||
partial := geoJSONMultiPolygonOuterRings(t, featureWithRole(t, collection, "partial-band"))
|
||||
total := geoJSONMultiPolygonOuterRings(t, featureWithRole(t, collection, "total-band"))
|
||||
|
||||
// The final GeoJSON pass must already have applied the total-only broad
|
||||
// polar repair. Reapplying it should therefore be geometrically inert.
|
||||
rerounded := occultationgeo.RoundAuthoritativeTotalBandJunctions(total)
|
||||
remainingRepairKM := math.Max(
|
||||
geodata.SphericalPolygonsPathMissDistanceKM(total, rerounded, true),
|
||||
geodata.SphericalPolygonsPathMissDistanceKM(rerounded, total, true),
|
||||
)
|
||||
if remainingRepairKM > 1 {
|
||||
t.Fatalf("final total-band still has a %.1f km repairable polar shoulder", remainingRepairKM)
|
||||
}
|
||||
if miss := geodata.SphericalPolygonsPathMissDistanceKM(partial, total, true); miss > 1 {
|
||||
t.Fatalf("smoothed total-band lies %.1f km outside partial-band", miss)
|
||||
}
|
||||
|
||||
roundedPartial := occultationgeo.RoundAuthoritativeBandJunctions(partial)
|
||||
partialChangeKM := math.Max(
|
||||
geodata.SphericalPolygonsPathMissDistanceKM(partial, roundedPartial, true),
|
||||
geodata.SphericalPolygonsPathMissDistanceKM(roundedPartial, partial, true),
|
||||
)
|
||||
if partialChangeKM > 1 {
|
||||
t.Fatalf("final partial-band unexpectedly needs %.1f km of further repair", partialChangeKM)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user