2bf8478639
- 新增日月食中心带、偏食带、阴影足迹、等时线、食分线及升落边界计算,支持极区与混合食拓扑 - 新增日食单时刻阴影求解器、站心状态查询、批量采样和 ΔT 覆盖接口 - 重构恒星与行星月掩路径,补充有限盘面接触、站心修正、掩带宽度、极区投影及升落边界 - 扩展 SVG 与 GeoJSON 输出,支持详细面板、全球/极区/地球投影、边界闭合、时间标记和拓扑签名 - 扩展日月食候选搜索、局地搜索、沙罗序列预计算与范围外推,补充系列锚点和成员一致性校验 - 补齐古历纪年、儒略历独有闰日、多公历候选、历法改革跨日及精确日期运算接口 - 优化 ΔT、章动、恒星时、月球地平线、事件根搜索和本地星历缓存,降低重复计算开销并提升边界稳定
121 lines
3.6 KiB
Go
121 lines
3.6 KiB
Go
package svg
|
|
|
|
import (
|
|
"math"
|
|
"sync"
|
|
|
|
"b612.me/astro/internal/geodata"
|
|
"b612.me/astro/moon"
|
|
)
|
|
|
|
// occultationBandPolygons 是一次紧凑掩带合并的只读结果。
|
|
type occultationBandPolygons struct {
|
|
polygons [][]geodata.GeoPoint
|
|
authoritative bool
|
|
}
|
|
|
|
type occultationBandCacheKey struct {
|
|
kind occultationFootprintSweepKind
|
|
digest [2]uint64
|
|
}
|
|
|
|
// occultationBandCacheCapacity 限制常驻的合并结果数量;掩带多边形可能上万点。
|
|
const occultationBandCacheCapacity = 6
|
|
|
|
var occultationBandCache = struct {
|
|
sync.RWMutex
|
|
entries map[occultationBandCacheKey]occultationBandPolygons
|
|
order []occultationBandCacheKey
|
|
}{entries: make(map[occultationBandCacheKey]occultationBandPolygons, occultationBandCacheCapacity)}
|
|
|
|
func lookupOccultationBandPolygons(key occultationBandCacheKey) (occultationBandPolygons, bool) {
|
|
occultationBandCache.RLock()
|
|
value, ok := occultationBandCache.entries[key]
|
|
occultationBandCache.RUnlock()
|
|
return value, ok
|
|
}
|
|
|
|
func storeOccultationBandPolygons(key occultationBandCacheKey, value occultationBandPolygons) {
|
|
occultationBandCache.Lock()
|
|
defer occultationBandCache.Unlock()
|
|
if _, exists := occultationBandCache.entries[key]; exists {
|
|
return
|
|
}
|
|
if len(occultationBandCache.order) >= occultationBandCacheCapacity {
|
|
delete(occultationBandCache.entries, occultationBandCache.order[0])
|
|
occultationBandCache.order = occultationBandCache.order[1:]
|
|
}
|
|
occultationBandCache.entries[key] = value
|
|
occultationBandCache.order = append(occultationBandCache.order, key)
|
|
}
|
|
|
|
// occultationBandDigest 汇总合并的全部输入;按 64 位字混合而不是逐字节,摘要成本必须远低于合并本身。
|
|
func occultationBandDigest(s occultationFootprintSweep) [2]uint64 {
|
|
const (
|
|
seed1 = 0x9e3779b97f4a7c15
|
|
seed2 = 0xc2b2ae3d27d4eb4f
|
|
prime = 0x100000001b3
|
|
)
|
|
first, second := uint64(seed1), uint64(seed2)
|
|
write := func(value uint64) {
|
|
first = (first ^ value) * prime
|
|
first ^= first >> 31
|
|
second = (second + value) * prime
|
|
second ^= second >> 33
|
|
}
|
|
writeFloat := func(value float64) { write(math.Float64bits(value)) }
|
|
writeTime := func(value int64) { write(uint64(value)) }
|
|
writePoint := func(point moon.OccultationPathPoint) {
|
|
writeTime(point.Time.UnixNano())
|
|
writeFloat(point.Longitude)
|
|
writeFloat(point.Latitude)
|
|
writeFloat(point.MoonAltitude)
|
|
writeFloat(point.WidthKM)
|
|
writeFloat(point.LimitSeparationKM)
|
|
}
|
|
writePolygons := func(polygons [][]moon.OccultationPathPoint) {
|
|
write(uint64(len(polygons)))
|
|
for _, polygon := range polygons {
|
|
write(uint64(len(polygon)))
|
|
for _, point := range polygon {
|
|
writePoint(point)
|
|
}
|
|
}
|
|
}
|
|
writeString := func(value string) {
|
|
write(uint64(len(value)))
|
|
for index := 0; index < len(value); index++ {
|
|
write(uint64(value[index]))
|
|
}
|
|
}
|
|
writeFootprints := func(footprints []moon.PlanetOccultationFootprint) {
|
|
write(uint64(len(footprints)))
|
|
for _, footprint := range footprints {
|
|
writeTime(footprint.Time.UnixNano())
|
|
writePolygons(footprint.Polygons)
|
|
writePolygons(footprint.InteriorPolygons)
|
|
writePolygons(footprint.Boundaries)
|
|
if footprint.Closed {
|
|
write(1)
|
|
} else {
|
|
write(0)
|
|
}
|
|
}
|
|
}
|
|
writeCurves := func(curves []moon.OccultationRiseSetCurve) {
|
|
write(uint64(len(curves)))
|
|
for _, curve := range curves {
|
|
writeString(string(curve.Phase))
|
|
writeString(string(curve.Direction))
|
|
writePolygons(curve.Segments)
|
|
}
|
|
}
|
|
write(uint64(s.kind))
|
|
writeFootprints(s.footprints)
|
|
writePolygons(s.contours)
|
|
writePolygons(s.visibilityContours)
|
|
writePolygons([][]moon.OccultationPathPoint{s.northern, s.southern})
|
|
writeCurves(s.curves)
|
|
return [2]uint64{first, second}
|
|
}
|