"""Result payload lookup and GPR display filtering.""" from __future__ import annotations import numpy as np from python_app.models.dataset_model import ResultCollection, ResultPayload def collection_payload_by_name( collection: ResultCollection, name: str, kind: int | None = None, ) -> ResultPayload | None: """Return the first collection payload matching name and optional kind.""" for payload in collection.collection_payloads: if payload.processing_name != name: continue if kind is not None and int(payload.kind) != int(kind): continue return payload return None def collection_payloads_by_prefix( collection: ResultCollection, prefix: str, kind: int | None = None, ) -> list[ResultPayload]: """Return collection payloads matching a processing-name prefix.""" payloads: list[ResultPayload] = [] for payload in collection.collection_payloads: if not str(payload.processing_name).startswith(prefix): continue if kind is not None and int(payload.kind) != int(kind): continue payloads.append(payload) return payloads def gpr_object_rows(collection: ResultCollection) -> np.ndarray: """Return object rows as `[x_m, z_m, score]` from a GPR collection.""" points_payload = collection_payload_by_name(collection, "gpr_points", kind=4) if points_payload is not None: points = np.asarray(points_payload.table, dtype=np.float32) if points.ndim == 2 and points.shape[1] >= 3: return points[:, :3] centers_payload = collection_payload_by_name(collection, "gpr_region_centers", kind=4) if centers_payload is not None: centers = np.asarray(centers_payload.table, dtype=np.float32) if centers.ndim == 2 and centers.shape[1] >= 3: return centers[:, :3] return np.zeros((0, 3), dtype=np.float32) def filter_object_rows( rows: np.ndarray, *, min_score: float, x_bounds: tuple[float, float], z_bounds: tuple[float, float], ) -> np.ndarray: """Keep finite objects inside the visible window and above the score threshold.""" if rows.size == 0: return rows x_min, x_max = x_bounds z_min, z_max = z_bounds visible_mask = ( np.all(np.isfinite(rows[:, :3]), axis=1) & (rows[:, 2] >= min_score) & (rows[:, 0] >= x_min) & (rows[:, 0] <= x_max) & (rows[:, 1] >= z_min) & (rows[:, 1] <= z_max) ) return rows[visible_mask]