feat: 新增月掩与日月食地理绘图并提升观测计算精度
- 新增月掩恒星和行星:支持搜索、掩甚点、全球掩带及固定地点轨迹计算 - 支持恒星星表坐标转换、有限盘面行星接触事件和月掩 SVG 输出 - 新增日月食及月掩全球投影图、时间标记和 GeoJSON 地理数据接口 - 扩展日食中心线、南北界及偏食足迹采样,支持极区投影 - 修正站心时角、月出月落、月球视半径、折射和恒星自行计算 - 优化内外行星事件搜索、边界选择、极端输入处理和计算稳定性
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package basic
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestStarOccultationDiagramUsesSolvedLocalContacts(t *testing.T) {
|
||||
location := time.FixedZone("CST", 8*3600)
|
||||
star := StarCoordinate{
|
||||
ID: "HR 4799",
|
||||
RA: 189.1975,
|
||||
Dec: -5.831944444444,
|
||||
Epoch: time.Date(2000, 1, 1, 12, 0, 0, 0, time.UTC),
|
||||
Frame: CoordinateFrameJ2000,
|
||||
ProperMotionRACosDecMasPerYear: -28,
|
||||
ProperMotionDecMasPerYear: -18,
|
||||
}
|
||||
events, err := FindStarOccultations(
|
||||
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, OccultationSearchOptions{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("FindStarOccultations() error = %v", err)
|
||||
}
|
||||
if len(events) != 1 {
|
||||
t.Fatalf("FindStarOccultations() returned %d events, want 1", len(events))
|
||||
}
|
||||
|
||||
diagram := StarOccultationDiagram(events[0], star, StarOccultationDiagramOptions{StepDays: 2.0 / 1440})
|
||||
if len(diagram.Frames) < 3 {
|
||||
t.Fatalf("StarOccultationDiagram() frame count = %d, want at least 3", len(diagram.Frames))
|
||||
}
|
||||
if !starOccultationDiagramFrameHasLabel(diagram.Frames[0], "Immersion") {
|
||||
t.Fatalf("first frame labels = %v, want Immersion", diagram.Frames[0].Labels)
|
||||
}
|
||||
last := diagram.Frames[len(diagram.Frames)-1]
|
||||
if !starOccultationDiagramFrameHasLabel(last, "Emersion") {
|
||||
t.Fatalf("last frame labels = %v, want Emersion", last.Labels)
|
||||
}
|
||||
if residual := math.Abs(diagram.Frames[0].SeparationArcsec - diagram.Frames[0].MoonRadiusArcsec); residual > 0.1 {
|
||||
t.Fatalf("immersion limb residual = %.6f arcsec, want <= 0.1", residual)
|
||||
}
|
||||
if residual := math.Abs(last.SeparationArcsec - last.MoonRadiusArcsec); residual > 0.1 {
|
||||
t.Fatalf("emersion limb residual = %.6f arcsec, want <= 0.1", residual)
|
||||
}
|
||||
greatest, ok := starOccultationDiagramFrameByLabel(diagram.Frames, "Greatest")
|
||||
if !ok {
|
||||
t.Fatalf("diagram does not contain Greatest frame")
|
||||
}
|
||||
if !greatest.BehindMoon || greatest.SeparationArcsec >= greatest.MoonRadiusArcsec {
|
||||
t.Fatalf("greatest frame is not behind Moon: separation=%.6f radius=%.6f", greatest.SeparationArcsec, greatest.MoonRadiusArcsec)
|
||||
}
|
||||
|
||||
wrongStar := star
|
||||
wrongStar.RA += 30
|
||||
if frames := StarOccultationDiagram(events[0], wrongStar, StarOccultationDiagramOptions{}).Frames; len(frames) != 0 {
|
||||
t.Fatalf("same-ID wrong coordinate produced %d frames, want none", len(frames))
|
||||
}
|
||||
infoWithoutID := events[0]
|
||||
infoWithoutID.TargetID = ""
|
||||
wrongStar.ID = ""
|
||||
if frames := StarOccultationDiagram(infoWithoutID, wrongStar, StarOccultationDiagramOptions{}).Frames; len(frames) != 0 {
|
||||
t.Fatalf("empty-ID wrong coordinate produced %d frames, want none", len(frames))
|
||||
}
|
||||
}
|
||||
|
||||
func starOccultationDiagramFrameHasLabel(frame StarOccultationDiagramFrame, label string) bool {
|
||||
for _, current := range frame.Labels {
|
||||
if current == label {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func starOccultationDiagramFrameByLabel(frames []StarOccultationDiagramFrame, label string) (StarOccultationDiagramFrame, bool) {
|
||||
for _, frame := range frames {
|
||||
if starOccultationDiagramFrameHasLabel(frame, label) {
|
||||
return frame, true
|
||||
}
|
||||
}
|
||||
return StarOccultationDiagramFrame{}, false
|
||||
}
|
||||
Reference in New Issue
Block a user