044f2f4381
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算 - 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询 - 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出 - 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解 - 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤 - 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持 - 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理 - 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
194 lines
3.8 KiB
Go
194 lines
3.8 KiB
Go
package planets
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"math/bits"
|
|
)
|
|
|
|
// bitReader 按位读取,字节内高位在前。
|
|
type bitReader struct {
|
|
b []byte
|
|
p int // 位位置
|
|
err error
|
|
}
|
|
|
|
// window 返回从当前位开始的 64 位窗口(高位对齐,越界补零),有效位至少 57 位。
|
|
func (br *bitReader) window() uint64 {
|
|
i := br.p >> 3
|
|
var w uint64
|
|
if i+8 <= len(br.b) {
|
|
w = binary.BigEndian.Uint64(br.b[i:])
|
|
} else {
|
|
for k := 0; k < 8; k++ {
|
|
w <<= 8
|
|
if i+k < len(br.b) {
|
|
w |= uint64(br.b[i+k])
|
|
}
|
|
}
|
|
}
|
|
return w << uint(br.p&7)
|
|
}
|
|
|
|
func (br *bitReader) skip(n int) {
|
|
br.p += n
|
|
if br.p > 8*len(br.b) {
|
|
br.err = errors.New("planets: truncated bit stream")
|
|
}
|
|
}
|
|
|
|
func (br *bitReader) get(n int) uint64 {
|
|
if n == 0 || br.err != nil {
|
|
return 0
|
|
}
|
|
if n > 56 {
|
|
hi := br.get(n - 32)
|
|
return hi<<32 | br.get(32)
|
|
}
|
|
v := br.window() >> uint(64-n)
|
|
br.skip(n)
|
|
return v
|
|
}
|
|
|
|
// gamma Elias-gamma,编码值为 n+1。
|
|
func (br *bitReader) gamma() int {
|
|
if br.err != nil {
|
|
return 0
|
|
}
|
|
z := bits.LeadingZeros64(br.window())
|
|
if z > 28 {
|
|
br.err = errors.New("planets: bad gamma code")
|
|
return 0
|
|
}
|
|
v := br.get(2*z + 1)
|
|
return int(v) - 1
|
|
}
|
|
|
|
func unzigzag(z int) int {
|
|
if z&1 == 0 {
|
|
return z >> 1
|
|
}
|
|
return -(z >> 1) - 1
|
|
}
|
|
|
|
// readElement3 读取 PLN3 元件位流:包络游程、幅角号(定长或同阶升序间隔)、成对共享位宽的量化系数。
|
|
func readElement3(r *reader, e *element, secDeg, nk int, sortedArgs bool) error {
|
|
if secDeg > maxDeg {
|
|
return errors.New("planets: secular degree too high")
|
|
}
|
|
n64 := r.uvar()
|
|
if n64 > uint64(nk) {
|
|
return errors.New("planets: too many terms")
|
|
}
|
|
nint := int(n64)
|
|
e.secular = make([]float64, secDeg+1)
|
|
for i := range e.secular {
|
|
e.secular[i] = r.f64()
|
|
}
|
|
step := r.f64()
|
|
size := r.uvar()
|
|
if r.err != nil {
|
|
return r.err
|
|
}
|
|
if size > uint64(len(r.b)-r.p) {
|
|
return errors.New("planets: truncated table")
|
|
}
|
|
br := &bitReader{b: r.take(int(size))}
|
|
if r.err != nil {
|
|
return r.err
|
|
}
|
|
env := make([]int, 0, nint)
|
|
for runs := br.gamma(); runs > 0 && br.err == nil; runs-- {
|
|
d := int(br.get(4))
|
|
cnt := br.gamma() + 1
|
|
if d > maxDeg || len(env)+cnt > nint {
|
|
return errors.New("planets: bad envelope runs")
|
|
}
|
|
for ; cnt > 0; cnt-- {
|
|
env = append(env, d)
|
|
}
|
|
}
|
|
if br.err != nil {
|
|
return br.err
|
|
}
|
|
if len(env) != nint {
|
|
return errors.New("planets: envelope count mismatch")
|
|
}
|
|
args := make([]int32, nint)
|
|
nbits := bits.Len(uint(nk - 1))
|
|
if nbits == 0 {
|
|
nbits = 1
|
|
}
|
|
prev, cur := -1, -1
|
|
for j := 0; j < nint; j++ {
|
|
a := 0
|
|
if sortedArgs {
|
|
if env[j] != cur {
|
|
prev, cur = -1, env[j]
|
|
}
|
|
a = prev + 1 + br.gamma()
|
|
prev = a
|
|
} else {
|
|
a = int(br.get(nbits))
|
|
}
|
|
if a >= nk {
|
|
return errors.New("planets: argument index out of range")
|
|
}
|
|
args[j] = int32(a)
|
|
}
|
|
top := 0
|
|
for _, d := range env {
|
|
if d > top {
|
|
top = d
|
|
}
|
|
}
|
|
// 按包络阶降序的稳定排序:pos[j] 为位流第 j 项的新位置
|
|
pos := make([]int, nint)
|
|
e.arg = make([]int32, nint)
|
|
k := 0
|
|
for d := top; d >= 0; d-- {
|
|
for j := 0; j < nint; j++ {
|
|
if env[j] == d {
|
|
pos[j], e.arg[k] = k, args[j]
|
|
k++
|
|
}
|
|
}
|
|
}
|
|
if nint == 0 {
|
|
return br.err
|
|
}
|
|
e.cnt = make([]int, top+1)
|
|
e.c, e.s = make([][]float64, top+1), make([][]float64, top+1)
|
|
for d := 0; d <= top; d++ {
|
|
for j := 0; j < nint; j++ {
|
|
if env[j] >= d {
|
|
e.cnt[d]++
|
|
}
|
|
}
|
|
e.c[d], e.s[d] = make([]float64, e.cnt[d]), make([]float64, e.cnt[d])
|
|
}
|
|
width := 0
|
|
coef := func() float64 {
|
|
neg := br.get(1) != 0
|
|
v := float64(br.get(width))
|
|
if neg {
|
|
v = -v
|
|
}
|
|
return v * step
|
|
}
|
|
for d := 0; d <= top; d++ {
|
|
for j := 0; j < nint; j++ {
|
|
if env[j] < d {
|
|
continue
|
|
}
|
|
width += unzigzag(br.gamma())
|
|
if width < 0 || width > 63 {
|
|
return errors.New("planets: bad coefficient width")
|
|
}
|
|
e.c[d][pos[j]] = coef()
|
|
e.s[d][pos[j]] = coef()
|
|
}
|
|
}
|
|
return br.err
|
|
}
|