astro/basic/star_catalog_data.go
starainrt 3ffdbe0034
feat: 扩展天文计算能力
- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息
- 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算
- 新增木星伽利略卫星位置、现象与接触事件计算
- 新增恒星星表、星座判定、自行修正与观测辅助能力
- 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包
- 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算
- 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试
- 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试
- 更新中文和英文 README,补充示例、精度说明、SVG 配图
2026-05-01 22:38:44 +08:00

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
}