Source code for stellium.components.fixed_stars

"""
Fixed Stars component for chart calculations.

This component calculates fixed star positions and integrates them into the chart.
Stars are calculated for the chart's Julian Day, with Swiss Ephemeris handling
precession automatically.

Usage:
    >>> from stellium import ChartBuilder
    >>> from stellium.components import FixedStarsComponent
    >>>
    >>> # All stars
    >>> chart = (ChartBuilder.from_native(native)
    ...     .add_component(FixedStarsComponent())
    ...     .calculate())
    >>>
    >>> # Royal stars only
    >>> chart = (ChartBuilder.from_native(native)
    ...     .add_component(FixedStarsComponent(tier=1))
    ...     .calculate())
    >>>
    >>> # Specific stars
    >>> chart = (ChartBuilder.from_native(native)
    ...     .add_component(FixedStarsComponent(stars=["Regulus", "Algol"]))
    ...     .calculate())
"""

from stellium.core.models import (
    CelestialPosition,
    ChartDateTime,
    ChartLocation,
    FixedStarPosition,
    HouseCusps,
)
from stellium.engines.fixed_stars import SwissEphemerisFixedStarsEngine


[docs] class FixedStarsComponent: """ Component that calculates fixed star positions for a chart. This component uses SwissEphemerisFixedStarsEngine to calculate precise positions for fixed stars and returns them as FixedStarPosition objects. Stars can be filtered by: - Specific star names - Tier (1=Royal, 2=Major, 3=Extended) - Royal stars only The calculated positions include all metadata from FIXED_STARS_REGISTRY, including traditional planetary nature, keywords, and constellation. Attributes: stars: List of specific star names to calculate (None = use tier/royal filters) tier: Tier level to calculate (None = all tiers) royal_only: If True, calculate only the four Royal Stars Example: >>> # Add all stars in registry >>> comp = FixedStarsComponent() >>> >>> # Add only Royal stars (Aldebaran, Regulus, Antares, Fomalhaut) >>> comp = FixedStarsComponent(royal_only=True) >>> >>> # Add only tier 1 and 2 stars >>> comp = FixedStarsComponent(tier=2, include_higher_tiers=True) >>> >>> # Add specific stars >>> comp = FixedStarsComponent(stars=["Sirius", "Algol", "Spica"]) """ def __init__( self, stars: list[str] | None = None, tier: int | None = None, royal_only: bool = False, include_higher_tiers: bool = False, ): """ Initialize the fixed stars component. Args: stars: Specific star names to calculate. If provided, overrides tier and royal_only settings. tier: Tier level to calculate (1=Royal, 2=Major, 3=Extended). If include_higher_tiers=False, only this tier is calculated. If include_higher_tiers=True, this tier and all higher (lower number) tiers are calculated. royal_only: If True, calculate only the four Royal Stars (tier 1). Equivalent to tier=1. include_higher_tiers: If True and tier is set, include all stars with tier <= the specified tier. """ self.stars = stars self.tier = tier self.royal_only = royal_only self.include_higher_tiers = include_higher_tiers self._engine = SwissEphemerisFixedStarsEngine() @property def component_name(self) -> str: """Name of this component.""" return "Fixed Stars"
[docs] def calculate( self, datetime: ChartDateTime, location: ChartLocation, positions: list[CelestialPosition], house_systems_map: dict[str, HouseCusps], house_placements_map: dict[str, dict[str, int]], ) -> list[CelestialPosition]: """ Calculate fixed star positions for the chart. Args: datetime: Chart datetime (used to get Julian Day) location: Chart location (unused for fixed stars, required by protocol) positions: Already-calculated positions (unused, required by protocol) house_systems_map: House systems map (unused, required by protocol) house_placements_map: House placements (unused, required by protocol) Returns: List of FixedStarPosition objects for the requested stars """ julian_day = datetime.julian_day # Determine which stars to calculate if self.stars is not None: # Explicit list overrides everything return self._engine.calculate_stars(julian_day, stars=self.stars) if self.royal_only: # Royal stars only return self._engine.calculate_royal_stars(julian_day) if self.tier is not None: if self.include_higher_tiers: # Include this tier and all higher priority tiers (lower numbers) results: list[FixedStarPosition] = [] for t in range(1, self.tier + 1): results.extend(self._engine.calculate_stars_by_tier(julian_day, t)) return results else: # Just this tier return self._engine.calculate_stars_by_tier(julian_day, self.tier) # Default: all stars return self._engine.calculate_stars(julian_day)