Source code for nav.nav_model.rings.ring_render_result

"""Result object for ring feature backplane rendering.

This module defines ``RingRenderResult``, the structured output of
``RingFeature.render()``. Returning a typed dataclass instead of a tuple of
arrays makes the return value self-documenting and lets the orchestrator access
the uncertainty and annotation data without relying on positional unpacking.

The ``edge_info_list`` is computed during rendering rather than in a separate
annotation pass. This avoids recomputing the edge radius backplanes a second
time: the render method already has the computed backplane results in scope
when it creates the edge masks for ``border_atop``.
"""

import math
from dataclasses import dataclass, field

import numpy as np

from nav.support.types import NDArrayBoolType, NDArrayFloatType


[docs] @dataclass(slots=True) class RingRenderResult: """Result of rendering a single ring feature edge or band. Returned by ``RingFeature.render()``. Contains the rendered model image and mask, the feature uncertainty (for ``NavModelResult``), and pre-computed annotation edge data. ``edge_info_list`` contains ``(edge_mask, label_text, edge_label)`` tuples for annotation creation. ``render()`` computes these during rendering to avoid recomputing the edge radius backplanes a second time. The orchestrator passes this list to ``NavModelRingsBase._create_edge_annotations()``. Parameters: model_img: Float64 array of rendered ring brightness values. Shape matches the extended FOV. model_mask: Boolean mask array where True indicates pixels with non-zero ring model contribution. uncertainty: Maximum RMS across all rendered edges (km). Sourced from ``RingEdgeData.rms`` via ``RingFeature.uncertainty``. edge_info_list: Pre-computed annotation data: list of ``(edge_mask, label_text, edge_label)`` tuples. ``edge_mask`` is a boolean array in extended FOV coordinates. """ model_img: NDArrayFloatType model_mask: NDArrayBoolType uncertainty: float edge_info_list: list[tuple[NDArrayBoolType, str, str]] = field(default_factory=list)
[docs] def __post_init__(self) -> None: """Validate image/mask shape, uncertainty, and edge annotation tuples.""" if not isinstance(self.model_img, np.ndarray): raise TypeError('RingRenderResult.model_img must be a numpy ndarray') if not isinstance(self.model_mask, np.ndarray): raise TypeError('RingRenderResult.model_mask must be a numpy ndarray') if self.model_img.shape != self.model_mask.shape: raise ValueError( 'RingRenderResult.model_img and model_mask must have the same shape, got ' f'{self.model_img.shape} and {self.model_mask.shape}' ) if isinstance(self.uncertainty, bool) or not isinstance(self.uncertainty, (int, float)): raise TypeError('RingRenderResult.uncertainty must be int or float') u = float(self.uncertainty) if not math.isfinite(u) or u < 0.0: raise ValueError( f'RingRenderResult.uncertainty must be finite and non-negative (km RMS), got ' f'{self.uncertainty!r}' ) for k, entry in enumerate(self.edge_info_list): if not isinstance(entry, tuple) or len(entry) != 3: raise ValueError( f'RingRenderResult.edge_info_list[{k}] must be ' f'(edge_mask, label_text, edge_label)' ) em, t1, t2 = entry if not isinstance(em, np.ndarray): raise TypeError(f'RingRenderResult.edge_info_list[{k}][0] must be ndarray') if not np.issubdtype(em.dtype, np.bool_): raise ValueError(f'RingRenderResult.edge_info_list[{k}][0] must have boolean dtype') if em.shape != self.model_mask.shape: raise ValueError( f'RingRenderResult.edge_info_list[{k}][0] shape {em.shape} must match ' f'model_mask shape {self.model_mask.shape}' ) if not isinstance(t1, str) or not isinstance(t2, str): raise TypeError(f'RingRenderResult.edge_info_list[{k}][1] and [2] must be str')