Files
astro/moon/svg/occultation_band_cache_test.go
T
b612 2bf8478639 feat: 完善日月食与月掩几何链路并扩展历法接口
- 新增日月食中心带、偏食带、阴影足迹、等时线、食分线及升落边界计算,支持极区与混合食拓扑
- 新增日食单时刻阴影求解器、站心状态查询、批量采样和 ΔT 覆盖接口
- 重构恒星与行星月掩路径,补充有限盘面接触、站心修正、掩带宽度、极区投影及升落边界
- 扩展 SVG 与 GeoJSON 输出,支持详细面板、全球/极区/地球投影、边界闭合、时间标记和拓扑签名
- 扩展日月食候选搜索、局地搜索、沙罗序列预计算与范围外推,补充系列锚点和成员一致性校验
- 补齐古历纪年、儒略历独有闰日、多公历候选、历法改革跨日及精确日期运算接口
- 优化 ΔT、章动、恒星时、月球地平线、事件根搜索和本地星历缓存,降低重复计算开销并提升边界稳定
2026-09-17 12:27:40 +08:00

91 lines
3.1 KiB
Go

package svg
import (
"testing"
"time"
"b612.me/astro/moon"
)
// 本文件钉住紧凑掩带合并缓存的契约:同输入复用只读结果、不同几何不会串味、产物逐字节确定。
func occultationTestCompactSweep(t *testing.T) occultationFootprintSweep {
t.Helper()
path := occultationTestSaturnPath(t)
if len(path.PartialBandFootprints) == 0 {
t.Fatal("fixture carries no compact band footprints")
}
return occultationFootprintSweep{
footprints: path.PartialBandFootprints,
contours: path.PartialBandContours,
visibilityContours: path.PartialVisibilityContours,
northern: path.NorthernLimit,
southern: path.SouthernLimit,
curves: path.RiseSetCurves,
compactBand: true,
kind: partialOccultationFootprintSweep,
}
}
func TestOccultationBandCacheReusesIdenticalGeometry(t *testing.T) {
sweep := occultationTestCompactSweep(t)
first, firstAuthoritative, err := sweep.mergedBandPolygons()
if err != nil {
t.Fatalf("first mergedBandPolygons() error = %v", err)
}
if len(first) == 0 {
t.Fatal("compact band merge produced no polygon")
}
second, secondAuthoritative, err := sweep.mergedBandPolygons()
if err != nil {
t.Fatalf("second mergedBandPolygons() error = %v", err)
}
if len(second) != len(first) || &second[0][0] != &first[0][0] {
t.Fatal("identical band geometry was merged again instead of reusing the cached polygons")
}
if secondAuthoritative != firstAuthoritative {
t.Fatalf("cached authoritative flag = %v, want %v", secondAuthoritative, firstAuthoritative)
}
}
func TestOccultationBandCacheSeparatesDifferentGeometry(t *testing.T) {
sweep := occultationTestCompactSweep(t)
first, _, err := sweep.mergedBandPolygons()
if err != nil {
t.Fatalf("first mergedBandPolygons() error = %v", err)
}
mutated := sweep
mutated.footprints = append([]moon.PlanetOccultationFootprint(nil), sweep.footprints...)
last := len(mutated.footprints) - 1
mutated.footprints[last].Polygons = append([][]moon.OccultationPathPoint(nil), mutated.footprints[last].Polygons...)
polygon := append([]moon.OccultationPathPoint(nil), mutated.footprints[last].Polygons[0]...)
polygon[0].Longitude += 1.5
mutated.footprints[last].Polygons[0] = polygon
second, _, err := mutated.mergedBandPolygons()
if err != nil {
t.Fatalf("mutated mergedBandPolygons() error = %v", err)
}
if len(second) > 0 && len(first) > 0 && &second[0][0] == &first[0][0] {
t.Fatal("a shifted footprint reused the cached band polygons")
}
}
func TestCompactBandRenderIsDeterministic(t *testing.T) {
path := occultationTestSaturnPath(t)
options := StarOccultationSVGOptions{Width: 1200, Height: 800, Location: time.UTC}
first, err := PlanetOccultationPathSVG(path, options)
if err != nil {
t.Fatalf("first render: %v", err)
}
second, err := PlanetOccultationPathSVG(path, options)
if err != nil {
t.Fatalf("second render: %v", err)
}
if first != second {
t.Fatal("compact-band SVG changed between renders after the merge was cached")
}
if len(first) == 0 {
t.Fatal("compact-band render is empty")
}
}