Files
astro/moon/svg/occultation_local_test.go
T
b612 9ee2163cc7 feat: 新增月掩与日月食地理绘图并提升观测计算精度
- 新增月掩恒星和行星:支持搜索、掩甚点、全球掩带及固定地点轨迹计算
- 支持恒星星表坐标转换、有限盘面行星接触事件和月掩 SVG 输出
- 新增日月食及月掩全球投影图、时间标记和 GeoJSON 地理数据接口
- 扩展日食中心线、南北界及偏食足迹采样,支持极区投影
- 修正站心时角、月出月落、月球视半径、折射和恒星自行计算
- 优化内外行星事件搜索、边界选择、极端输入处理和计算稳定性
2026-08-06 12:00:56 +08:00

174 lines
6.4 KiB
Go

package svg
import (
"errors"
"math"
"strings"
"testing"
"time"
"b612.me/astro/moon"
)
func TestFindLocalStarOccultationSVGsHR4799(t *testing.T) {
location := time.FixedZone("UTC+8", 8*3600)
diagrams, err := FindLocalStarOccultationSVGs(
time.Date(2025, 6, 5, 0, 0, 0, 0, location),
time.Date(2025, 6, 6, 0, 0, 0, 0, location),
hr4799StarCoordinate(),
121.56601, 6.80706, 0,
moon.OccultationSearchOptions{},
LocalStarOccultationSVGOptions{Width: 720, Height: 560, Location: location},
)
if err != nil {
t.Fatalf("FindLocalStarOccultationSVGs() error = %v", err)
}
if len(diagrams) != 1 {
t.Fatalf("FindLocalStarOccultationSVGs() returned %d diagrams, want 1", len(diagrams))
}
diagram := diagrams[0]
for _, want := range []string{
`<svg`, `width="720"`, `height="560"`, "2025-06-05", "HR 4799",
"指定地点月掩", "观测点", "站心恒星轨迹", "掩始、掩甚与掩终视圆",
"本地接触时刻", "掩始", "掩甚", "掩终", "左东右西", "UTC+8",
`class="local-star-track"`, `class="overview-moon"`, `class="overview-star"`,
`class="lunar-path-line"`, `class="lunar-path-label"`, "白道",
`<symbol id="le-moon"`, `href="#le-moon"`,
} {
if !strings.Contains(diagram, want) {
t.Fatalf("local SVG missing %q", want)
}
}
if strings.Contains(diagram, "local-occultation-moon") || strings.Contains(diagram, "<radialGradient") {
t.Fatalf("local SVG still contains the temporary synthetic Moon rendering")
}
if strings.Contains(diagram, "全球掩带") || strings.Contains(diagram, "全球中心线") {
t.Fatalf("local SVG unexpectedly contains global-path labels")
}
if got := strings.Count(diagram, `class="stage-moon"`); got != 3 {
t.Fatalf("stage Moon count = %d, want 3", got)
}
if got := strings.Count(diagram, `class="stage-star"`); got != 3 {
t.Fatalf("stage star count = %d, want 3", got)
}
if err := validateXML(diagram); err != nil {
t.Fatalf("generated local SVG is not valid XML: %v", err)
}
}
func TestLocalStarOccultationSVGEnglishAndCustomText(t *testing.T) {
info := localHR4799Occultation(t)
diagram, err := LocalStarOccultationSVG(info, hr4799StarCoordinate(), LocalStarOccultationSVGOptions{
Language: "en",
Location: time.UTC,
Title: "Custom local title",
SummaryText: "Custom local summary",
GreatestText: "Custom local greatest",
OverviewTitle: "Custom local overview",
PhasePanelsTitle: "Custom local stages",
ContactsTitle: "Custom local contacts",
DirectionText: "Custom local direction",
FooterNote: "Custom local footer",
})
if err != nil {
t.Fatalf("LocalStarOccultationSVG() error = %v", err)
}
for _, want := range []string{
"Custom local title", "Custom local summary", "Custom local greatest",
"Custom local overview", "Custom local stages", "Custom local contacts",
"Custom local direction", "Custom local footer", "Immersion", "Greatest", "Emersion", "Lunar path",
} {
if !strings.Contains(diagram, want) {
t.Fatalf("English local SVG missing %q", want)
}
}
}
func TestLocalStarOccultationSVGLunarPathUsesGreatestTangent(t *testing.T) {
frames := []moon.StarOccultationDiagramFrame{
{StarXArcsec: 100, StarYArcsec: 100},
{StarXArcsec: -1, StarYArcsec: -2},
{StarXArcsec: 0, StarYArcsec: 0, Label: "Greatest", Labels: []string{"Greatest"}},
{StarXArcsec: 1, StarYArcsec: 2},
{StarXArcsec: -100, StarYArcsec: 100},
}
unitX, unitY, ok := localStarOccultationSVGLunarPathDirection(frames)
if !ok {
t.Fatalf("localStarOccultationSVGLunarPathDirection() returned no direction")
}
if math.Abs(unitX-1/math.Sqrt(5)) > 1e-12 || math.Abs(unitY-2/math.Sqrt(5)) > 1e-12 {
t.Fatalf("lunar path direction = %.12f %.12f, want greatest tangent", unitX, unitY)
}
}
func TestFindLocalStarOccultationSVGsNoEvent(t *testing.T) {
location := time.FixedZone("CST", 8*3600)
star := hr4799StarCoordinate()
star.Dec = 80
diagrams, err := FindLocalStarOccultationSVGs(
time.Date(2025, 6, 5, 0, 0, 0, 0, location),
time.Date(2025, 6, 6, 0, 0, 0, 0, location),
star, 121.56601, 6.80706, 0,
moon.OccultationSearchOptions{}, LocalStarOccultationSVGOptions{},
)
if err != nil {
t.Fatalf("FindLocalStarOccultationSVGs() error = %v", err)
}
if len(diagrams) != 0 {
t.Fatalf("FindLocalStarOccultationSVGs() returned %d diagrams, want none", len(diagrams))
}
}
func TestLocalStarOccultationSVGRejectsInvalidInput(t *testing.T) {
info := localHR4799Occultation(t)
_, err := LocalStarOccultationSVG(info, hr4799StarCoordinate(), LocalStarOccultationSVGOptions{Width: 1})
if !errors.Is(err, ErrInvalidLocalStarOccultationSVGOptions) {
t.Fatalf("invalid canvas error = %v, want ErrInvalidLocalStarOccultationSVGOptions", err)
}
info.ContactsComplete = false
_, err = LocalStarOccultationSVG(info, hr4799StarCoordinate(), LocalStarOccultationSVGOptions{})
if !errors.Is(err, ErrInvalidLocalStarOccultationInfo) {
t.Fatalf("incomplete event error = %v, want ErrInvalidLocalStarOccultationInfo", err)
}
info = localHR4799Occultation(t)
otherStar := hr4799StarCoordinate()
otherStar.ID = "another-star"
_, err = LocalStarOccultationSVG(info, otherStar, LocalStarOccultationSVGOptions{})
if !errors.Is(err, ErrInvalidLocalStarOccultationInfo) {
t.Fatalf("mismatched target error = %v, want ErrInvalidLocalStarOccultationInfo", err)
}
info = localHR4799Occultation(t)
wrongCoordinate := hr4799StarCoordinate()
wrongCoordinate.RA += 30
_, err = LocalStarOccultationSVG(info, wrongCoordinate, LocalStarOccultationSVGOptions{})
if !errors.Is(err, ErrInvalidLocalStarOccultationInfo) {
t.Fatalf("same-ID wrong coordinate error = %v, want ErrInvalidLocalStarOccultationInfo", err)
}
info.TargetID = ""
wrongCoordinate.ID = ""
_, err = LocalStarOccultationSVG(info, wrongCoordinate, LocalStarOccultationSVGOptions{})
if !errors.Is(err, ErrInvalidLocalStarOccultationInfo) {
t.Fatalf("empty-ID wrong coordinate error = %v, want ErrInvalidLocalStarOccultationInfo", err)
}
}
func localHR4799Occultation(t *testing.T) moon.StarOccultationInfo {
t.Helper()
location := time.FixedZone("CST", 8*3600)
events, err := moon.FindStarOccultations(
time.Date(2025, 6, 5, 0, 0, 0, 0, location),
time.Date(2025, 6, 6, 0, 0, 0, 0, location),
hr4799StarCoordinate(), 121.56601, 6.80706, 0, moon.OccultationSearchOptions{},
)
if err != nil {
t.Fatalf("FindStarOccultations() error = %v", err)
}
if len(events) != 1 {
t.Fatalf("FindStarOccultations() returned %d events, want 1", len(events))
}
return events[0]
}