Files
2026-07-13 20:00:07 +02:00

89 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""Constellation identification.
Constellation identification is tradionally performed with:
http://cdsarc.u-strasbg.fr/viz-bin/Cat?VI/42
https://iopscience.iop.org/article/10.1086/132034/pdf
Given a position, a binary search can be used to index into its roughly
12k data table for a matching declination, but the table then needs to
be scanned linearly for the first subsequent segment that contains the
target right ascension within its bounds. The big problem for Skyfield:
that algorithm can't be constructed from vectorized NumPy primitives.
So we here take an approach that requires no linear search. The sky is
divided into a grid, with a grid line at every right ascension and
declination that is mentioned in a constellation boundary. This is a
bit wasteful, as many values are only ever used for one boundary, but
makes the search easy: do a binary search for right ascension, then for
declination, then look up the indexes in the grid. Memory requirement:
1.8k right ascension table
1.6k declination table
46.6k grid table
1k constellation name abbreviations
"""
import zlib
from numpy import searchsorted
from pkgutil import get_data
from .functions import load_bundled_npy
from .timelib import Time, julian_date_of_besselian_epoch
def load_constellation_map():
"""Load Skyfield's constellation boundaries and return a lookup function.
Skyfield carries an internal map of constellation boundaries that is
optimized for quick position lookup. Call this function to load the
map and return a function mapping position to constellation name.
>>> from skyfield.api import position_of_radec, load_constellation_map
>>> constellation_at = load_constellation_map()
>>> north_pole = position_of_radec(0, 90)
>>> constellation_at(north_pole)
'UMi'
If you pass an array of positions, you'll receive an array of names.
"""
t1875 = Time(None, julian_date_of_besselian_epoch(1875))
arrays = load_bundled_npy('constellations.npz')
sorted_ra = arrays['sorted_ra']
sorted_dec = arrays['sorted_dec']
radec_to_index = arrays['radec_to_index']
indexed_abbreviations = arrays['indexed_abbreviations']
def constellation_at(position):
ra, dec, distance = position.radec(epoch=t1875)
i = searchsorted(sorted_ra, ra.hours)
j = searchsorted(sorted_dec, dec.degrees, side='right')
k = radec_to_index[i, j]
return indexed_abbreviations[k]
return constellation_at
def load_constellation_names():
"""Return a list of abbreviation-name tuples, like ``('Aql', 'Aquila')``.
You can pass the list to Python’s ``dict()`` to build a dictionary
that turns a constellation abbreviation into a full name:
>>> from skyfield.api import load_constellation_names
>>> d = dict(load_constellation_names())
>>> d['UMa']
'Ursa Major'
By swapping the order of the two items, you can map the other way,
from a full name back to an abbreviation:
>>> f = dict(reversed(item) for item in load_constellation_names())
>>> f['Ursa Major']
'UMa'
"""
data = get_data('skyfield', 'data/constellations.gz')
data = zlib.decompress(data, zlib.MAX_WBITS+32).decode('ascii')
return [line.split(' ', 1) for line in data.splitlines()]