Source code for nav.nav_model.nav_model_rings_simulated

"""Simulated ring navigation model.

This module provides a navigation model for simulated rings created in the GUI.

The simulated ring model uses a different rendering path from the real ring model
(``NavModelRings``): instead of computing backplane-based ring radii and applying
``RingFeature.render()``, it delegates image generation to
``nav.sim.sim_ring.render_ring()``, which operates entirely in pixel space.

The data model types (``RingFeature``, ``RingEdgeData``) are shared with the real
model for two purposes:

1. **Validation**: ``RingFeature.from_config()`` validates ``sim_params`` structure
   at construction time, catching authoring errors in the same way as the YAML config
   path.
2. **Annotations**: ``_create_edge_annotations`` requires an ``edge_info_list``; the
   feature's ``uncertainty`` field is wired to ``NavModelResult.uncertainty``.

The rendering path itself is NOT shared because simulated rings use pixel-space
geometry rather than backplane geometry.
"""

from typing import Any

import numpy as np
import oops

from nav.annotation import Annotations
from nav.config import Config
from nav.sim.sim_ring import compute_border_atop_simulated, render_ring
from nav.support.time import now_dt
from nav.support.types import NDArrayBoolType

from .nav_model_result import NavModelResult
from .nav_model_rings_base import NavModelRingsBase
from .rings import RingFeature






# ---------------------------------------------------------------------------
# Private helper
# ---------------------------------------------------------------------------


def _sim_params_to_feature_config(p: dict[str, Any]) -> dict[str, Any]:
    """Convert GUI sim_params dict to a feature config dict for RingFeature.from_config().

    The GUI stores ring parameters in a flat dict with inner_data / outer_data lists.
    This function adapts that format to the canonical feature config format expected by
    ``from_config()``, which validates all fields.

    Parameters:
        p: GUI sim_params dictionary.

    Returns:
        Feature config dict suitable for ``RingFeature.from_config()``.
    """
    raw_inner = p.get('inner_data') or None
    raw_outer = p.get('outer_data') or None

    feature_type_raw = p.get('feature_type', 'RINGLET')

    config: dict[str, Any] = {
        'feature_type': feature_type_raw,
        'name': p.get('name'),
    }
    if raw_inner is not None:
        config['inner_data'] = raw_inner
    if raw_outer is not None:
        config['outer_data'] = raw_outer

    return config