Files
astro/eclipse/svg/transit_local_test.go
T
b612 044f2f4381 feat: 引入可切换星历模型并扩展天象观测链路
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算
- 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询
- 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出
- 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解
- 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤
- 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持
- 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理
- 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
2026-10-15 23:54:15 +08:00

83 lines
3.6 KiB
Go

package svg
import (
"regexp"
"strconv"
"strings"
"testing"
"time"
"b612.me/astro"
"b612.me/astro/internal/svgchart"
)
func TestTransitLocalSVG(t *testing.T) {
venus := time.Date(2012, 6, 6, 0, 0, 0, 0, time.UTC)
chart, ok := TransitLocalSVG(TransitVenus, venus, 116.4, 39.9, 50, TransitLocalSVGOptions{Location: time.FixedZone("UTC+8", 8*3600)})
if !ok {
t.Fatal("Beijing 2012 render failed")
}
for _, want := range []string{"金星凌日站心图", `class="transit-track"`, "transit-planet-c1", "transit-planet-c2",
"transit-planet-g", "transit-planet-c3", "transit-planet-c4", "一触 06:10:13", "四触 12:49:17"} {
if !strings.Contains(chart, want) {
t.Fatalf("Beijing: missing %s", want)
}
}
if strings.Contains(chart, "transit-track-below-horizon") || strings.Contains(chart, "NaN") {
t.Fatal("Beijing sees the whole transit in daylight")
}
// 伦敦:日出时凌日已在进行,日出前的轨迹画成地平下虚线。
chart, ok = TransitLocalSVG(TransitVenus, venus, -0.1, 51.5, 20, TransitLocalSVGOptions{Language: "en"})
if !ok || !strings.Contains(chart, "transit-track-below-horizon") || !strings.Contains(chart, "Sunrise during transit") ||
!strings.Contains(chart, "Local Circumstances") {
t.Fatal("London must show the below-horizon track and sunrise row in English")
}
// 1999 水星掠凌,南纬 60° 只有一触、凌甚、四触。
chart, ok = TransitLocalSVG(TransitMercury, time.Date(1999, 11, 15, 0, 0, 0, 0, time.UTC), 150, -60, 0, TransitLocalSVGOptions{})
if !ok || !strings.Contains(chart, "掠凌") || strings.Contains(chart, "transit-planet-c2") || strings.Contains(chart, "transit-planet-c3") {
t.Fatal("grazing site must omit internal contacts")
}
if !strings.Contains(chart, "1999-11-15") {
t.Fatal("same-day query must find the 1999-11-15 transit")
}
// 一、二触相隔约 2 分钟,二触标签不得被避让丢弃。
chart, ok = TransitLocalSVG(TransitMercury, time.Date(2032, 11, 13, 0, 0, 0, 0, time.UTC), 116.4074, 39.9042, 0,
TransitLocalSVGOptions{Location: time.FixedZone("UTC+8", 8*3600)})
if !ok {
t.Fatal("Beijing 2032 render failed")
}
for _, want := range []string{">一触 ", ">二触 ", ">凌甚 ", ">三触 ", ">四触 "} {
if strings.Count(chart, want) != 1 {
t.Fatalf("Beijing 2032: label %s must appear exactly once on the disk", want)
}
}
for _, match := range regexp.MustCompile(`class="transit-event-label" x="([0-9.-]+)" y="([0-9.-]+)"[^>]*text-anchor="(\w+)">([^<]*)<`).FindAllStringSubmatch(chart, -1) {
x, _ := strconv.ParseFloat(match[1], 64)
y, _ := strconv.ParseFloat(match[2], 64)
if box := svgchart.LabelTextBox(x, y, 11, match[4], match[3]); box.X < 30 || box.X+box.Width > 960-344 {
t.Fatalf("Beijing 2032: label %q leaves the disk frame (box x %.1f..%.1f)", match[4], box.X, box.X+box.Width)
}
}
}
func TestTransitLocalSVGOptions(t *testing.T) {
venus := time.Date(2012, 6, 6, 0, 0, 0, 0, time.UTC)
if _, ok := TransitLocalSVG(3, venus, 0, 0, 0, TransitLocalSVGOptions{}); ok {
t.Fatal("unsupported planet must fail")
}
if _, ok := TransitLocalSVG(TransitVenus, venus, 0, 0, 0, TransitLocalSVGOptions{
TimeScale: astro.TimeScaleUT1, Location: time.FixedZone("CST", 8*3600)}); ok {
t.Fatal("UT1 with non-UTC location must fail")
}
if _, ok := TransitLocalSVG(TransitVenus, venus, 0, 95, 0, TransitLocalSVGOptions{}); ok {
t.Fatal("invalid latitude must fail")
}
chart, ok := TransitLocalSVG(TransitVenus, venus, 116.4, 39.9, 0, TransitLocalSVGOptions{TimeScale: astro.TimeScaleUT1, Title: "X"})
if !ok || !strings.Contains(chart, ">X<") || !strings.Contains(chart, "UT1") {
t.Fatal("UT1 labels and custom title")
}
}