from __future__ import annotations from dataclasses import dataclass, field from typing import Any import numpy as np @dataclass(slots=True) class FrameHypothesis: name: str axes: np.ndarray origin: np.ndarray score: float bottom_score: float symmetry_score: float flatness_score: float hole_score: float continuity_score: float @dataclass(slots=True) class CandidateBand: candidate_id: str slice_index: int x_start: float x_end: float x_center: float y_min: float y_max: float y_center: float z_low: float width: float point_count: int low_point_count: int flatness: float normal_alignment: float score: float edge_ratio: float side: str y_mid: float bin_start: int bin_end: int @dataclass(slots=True) class SliceResult: slice_index: int x_start: float x_end: float x_center: float y_mid: float candidate_bands: list[CandidateBand] = field(default_factory=list) left_candidates: list[CandidateBand] = field(default_factory=list) right_candidates: list[CandidateBand] = field(default_factory=list) point_count: int = 0 @dataclass(slots=True) class TrackSolution: side: str rank: int score: float coverage_ratio: float coverage_count: int candidate_ids: list[str | None] candidates: list[CandidateBand] score_margin: float | None confidence: float @dataclass(slots=True) class RepresentativePoint: side: str slice_index: int x: float y: float z: float width: float point_count: int residual: float confidence: float x_start: float x_end: float @dataclass(slots=True) class FittedLine: side: str x_support: np.ndarray y_support: np.ndarray z_support: np.ndarray y_spline: Any z_spline: Any y_residual_rms: float z_residual_rms: float low_confidence_segments: list[tuple[float, float]] gaps: list[tuple[float, float]] @dataclass(slots=True) class HoleCandidate: side: str region: str axis: str center: np.ndarray radius: float score: float inlier_count: int coverage_ratio: float residual: float confidence: float @dataclass(slots=True) class ReferenceLine: side: str available: bool point_front: np.ndarray | None point_back: np.ndarray | None direction: np.ndarray | None confidence: float residual: float | None candidates_front: list[HoleCandidate] = field(default_factory=list) candidates_back: list[HoleCandidate] = field(default_factory=list) alternates: list[dict[str, Any]] = field(default_factory=list)