Files
astro/basic/star_catalog_names.go
T

109 lines
3.1 KiB
Go
Raw Normal View History

package basic
import (
"bytes"
"compress/gzip"
_ "embed"
"errors"
"fmt"
"io/ioutil"
"strconv"
"strings"
)
// star_catalog_names.tsv.gz 由同名 .tsv 压缩生成,测试校验两者一致。
//
//go:embed star_catalog_names.tsv.gz
var starCatalogNamesCompressed []byte
// starCatalogNameHeader 单一星名表的列顺序,生成端与加载端必须一致。
var starCatalogNameHeader = []string{"hr", "chinese", "aliases", "bayer_zh", "common", "cst", "cst_zh", "region"}
type starNameRecord struct {
chinese string
aliases []string
bayerZH string
common string
cst string
cstZH string
region string
}
func decodeStarNameTable(compressed []byte, starCount int) (map[uint16]starNameRecord, error) {
reader, err := gzip.NewReader(bytes.NewReader(compressed))
if err != nil {
return nil, fmt.Errorf("open star name table: %w", err)
}
defer reader.Close()
text, err := ioutil.ReadAll(reader)
if err != nil {
return nil, fmt.Errorf("read star name table: %w", err)
}
lines := strings.Split(string(text), "\n")
if len(lines) == 0 || strings.TrimSpace(lines[0]) == "" {
return nil, errors.New("empty star name table")
}
header := strings.Split(strings.TrimSuffix(lines[0], "\r"), "\t")
if len(header) != len(starCatalogNameHeader) {
return nil, fmt.Errorf("star name header has %d columns, want %d", len(header), len(starCatalogNameHeader))
}
for i, want := range starCatalogNameHeader {
if header[i] != want {
return nil, fmt.Errorf("star name header column %d = %q, want %q", i+1, header[i], want)
}
}
names := make(map[uint16]starNameRecord)
for index, line := range lines[1:] {
line = strings.TrimSuffix(line, "\r")
if line == "" {
continue
}
fields := strings.Split(line, "\t")
if len(fields) != len(starCatalogNameHeader) {
return nil, fmt.Errorf("star name line %d has %d columns, want %d", index+2, len(fields), len(starCatalogNameHeader))
}
hr, err := strconv.ParseUint(fields[0], 10, 16)
if err != nil || hr == 0 || int(hr) > starCount {
return nil, fmt.Errorf("star name line %d has invalid HR %q", index+2, fields[0])
}
key := uint16(hr)
if _, ok := names[key]; ok {
return nil, fmt.Errorf("star name line %d repeats HR %d", index+2, key)
}
chinese := fields[1]
region := fields[7]
rec := starNameRecord{
chinese: chinese,
aliases: splitStarAliases(fields[2]),
bayerZH: fields[3],
common: fields[4],
cst: fields[5],
cstZH: fields[6],
region: region,
}
if chinese == "" && len(rec.aliases) == 0 && rec.bayerZH == "" && rec.common == "" &&
rec.cst == "" && rec.cstZH == "" && rec.region == "" {
continue
}
names[key] = rec
}
if len(names) == 0 {
return nil, errors.New("empty star name table")
}
return names, nil
}
func splitStarAliases(value string) []string {
if strings.TrimSpace(value) == "" {
return nil
}
parts := strings.FieldsFunc(value, func(r rune) bool { return r == ';' || r == ';' })
out := make([]string, 0, len(parts))
for _, part := range parts {
if part = strings.TrimSpace(part); part != "" {
out = append(out, part)
}
}
return out
}