Source code for spindoctor.nav_model.nav_model

"""NavModel — the base class for predicted-scene generators.

Each NavModel renders the predicted appearance of one part of the scene
(stars, a body, or rings) given the observation's SPICE prediction.  The
orchestrator iterates registered NavModel instances and asks each to
contribute features and annotations to the navigation pipeline:

- ``create_model`` populates the model's internal state and metadata.
- ``to_features(context)`` returns ``NavFeature`` instances ready for
  technique consumption.
- ``to_annotations(context)`` returns an ``Annotations`` collection for
  the summary PNG.

Concrete NavModel subclasses self-register via ``__init_subclass__``.  The
module-level ``build_models_for_obs`` function iterates the registry and
asks each subclass to construct whatever instances apply to the
observation; this is what the top-level navigation driver uses so it does
not need to know which scene categories exist.

Every NavModel inherits from ``NavBase`` so it gets the project logger and
config plumbing automatically.
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, ClassVar

from spindoctor.annotation import Annotations
from spindoctor.config import Config
from spindoctor.feature.feature import NavFeature
from spindoctor.obs import ObsSnapshot
from spindoctor.support.nav_base import NavBase

if TYPE_CHECKING:  # pragma: no cover - typing-only import
    from spindoctor.nav_orchestrator.nav_context import NavContext

__all__ = ['NavModel', 'build_models_for_obs']






[docs] def build_models_for_obs(obs: ObsSnapshot, *, config: Config | None = None) -> list[NavModel]: """Construct every NavModel applicable to ``obs``. Iterates ``NavModel._registry`` and lets each registered concrete subclass build whatever instances apply. The top-level navigation driver uses this so the choice of which scene categories are represented (stars, body, rings, ...) lives entirely inside the NavModel subclasses, not in the driver. Parameters: obs: Observation snapshot. config: Configuration used both to decide which instances apply and to construct them, so a per-run override changes model selection the same way it changes model behavior. None uses ``DEFAULT_CONFIG``. Returns: Flat list of NavModel instances ready for the orchestrator. """ out: list[NavModel] = [] for cls in NavModel._registry: out.extend(cls.instances_for_obs(obs, config=config)) return out