- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息 - 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算 - 新增木星伽利略卫星位置、现象与接触事件计算 - 新增恒星星表、星座判定、自行修正与观测辅助能力 - 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包 - 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算 - 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试 - 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试 - 更新中文和英文 README,补充示例、精度说明、SVG 配图
121 lines
3.5 KiB
Go
121 lines
3.5 KiB
Go
package basic
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
_ "embed"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// star_catalog.dat layout after gzip decompression:
|
|
// magic[8] | version[1] | rawDataLen[4] | rawData | stringCount[2] |
|
|
// repeated(stringLen[uvarint] + stringBytes) |
|
|
// maxHR[2] | repeated(maxHR * 6 * stringIndex[2]) | repeated(maxHR * hip[4]).
|
|
const starCatalogMagic = "STRCAT01"
|
|
|
|
//go:embed star_catalog.dat
|
|
var starCatalogCompressed []byte
|
|
|
|
func initStarCatalogData() []byte {
|
|
reader, err := gzip.NewReader(bytes.NewReader(starCatalogCompressed))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer reader.Close()
|
|
payload, err := io.ReadAll(reader)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
data, detail, hip, err := decodeStarCatalogPayload(payload)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
hr2detail = detail
|
|
hr2hip = hip
|
|
return data
|
|
}
|
|
|
|
func decodeStarCatalogPayload(payload []byte) ([]byte, map[uint16][]string, map[uint16]uint32, error) {
|
|
reader := bytes.NewReader(payload)
|
|
|
|
var magic [len(starCatalogMagic)]byte
|
|
if _, err := io.ReadFull(reader, magic[:]); err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog magic: %w", err)
|
|
}
|
|
if string(magic[:]) != starCatalogMagic {
|
|
return nil, nil, nil, fmt.Errorf("invalid star catalog magic %q", string(magic[:]))
|
|
}
|
|
|
|
version, err := reader.ReadByte()
|
|
if err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog version: %w", err)
|
|
}
|
|
if version != 1 {
|
|
return nil, nil, nil, fmt.Errorf("unsupported star catalog version %d", version)
|
|
}
|
|
|
|
var rawLen uint32
|
|
if err := binary.Read(reader, binary.LittleEndian, &rawLen); err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog data length: %w", err)
|
|
}
|
|
data := make([]byte, rawLen)
|
|
if _, err := io.ReadFull(reader, data); err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog data: %w", err)
|
|
}
|
|
|
|
var stringCount uint16
|
|
if err := binary.Read(reader, binary.LittleEndian, &stringCount); err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog string count: %w", err)
|
|
}
|
|
stringsTable := make([]string, int(stringCount)+1)
|
|
for i := 1; i < len(stringsTable); i++ {
|
|
length, err := binary.ReadUvarint(reader)
|
|
if err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog string length: %w", err)
|
|
}
|
|
value := make([]byte, length)
|
|
if _, err := io.ReadFull(reader, value); err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog string: %w", err)
|
|
}
|
|
stringsTable[i] = string(value)
|
|
}
|
|
|
|
var maxHR uint16
|
|
if err := binary.Read(reader, binary.LittleEndian, &maxHR); err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog max HR: %w", err)
|
|
}
|
|
detail := make(map[uint16][]string)
|
|
for hr := uint16(1); hr <= maxHR; hr++ {
|
|
record := make([]string, 6)
|
|
hasValue := false
|
|
for i := range record {
|
|
var index uint16
|
|
if err := binary.Read(reader, binary.LittleEndian, &index); err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog detail index: %w", err)
|
|
}
|
|
if int(index) >= len(stringsTable) {
|
|
return nil, nil, nil, fmt.Errorf("detail string index out of range: hr=%d index=%d", hr, index)
|
|
}
|
|
record[i] = stringsTable[index]
|
|
hasValue = hasValue || index != 0
|
|
}
|
|
if hasValue {
|
|
detail[hr] = record
|
|
}
|
|
}
|
|
|
|
hip := make(map[uint16]uint32)
|
|
for hr := uint16(1); hr <= maxHR; hr++ {
|
|
var value uint32
|
|
if err := binary.Read(reader, binary.LittleEndian, &value); err != nil {
|
|
return nil, nil, nil, fmt.Errorf("read star catalog HIP: %w", err)
|
|
}
|
|
if value != 0 {
|
|
hip[hr] = value
|
|
}
|
|
}
|
|
return data, detail, hip, nil
|
|
}
|