feat(viewer): add recorded point colors and trajectory follow

This commit is contained in:
DCCONSTRUCTIONS
2026-07-23 13:33:08 +03:00
parent 9f712bf353
commit ecd95a22f0
16 changed files with 1218 additions and 36 deletions
+73
View File
@@ -33,6 +33,7 @@ from k1link.sessions import (
SessionStore,
validate_recorded_media_timeline,
)
from k1link.sessions.plugin_contract import RecordedPointColorRenderer
from k1link.viewer.recorded import (
APPLICATION_ID as RECORDED_APPLICATION_ID,
)
@@ -108,6 +109,7 @@ class RecordedBlueprintRequest(StrictApiModel):
show_trajectory: StrictBool
show_grid: StrictBool
point_size: float = Field(default=2.5, strict=True, ge=0.1, le=32.0)
color_mode: Literal["intensity", "height", "distance", "rgb", "class"] = "intensity"
palette: Literal["turbo", "viridis", "plasma", "grayscale", "custom"] = "turbo"
custom_color: str = Field(default="#f7f8f4", pattern=r"^#[0-9A-Fa-f]{6}$")
active_view: Literal["spatial", "perception", "perception3d", "metrics"] = "spatial"
@@ -116,6 +118,7 @@ class RecordedBlueprintRequest(StrictApiModel):
show_detections_2d: StrictBool = False
show_segmentation: StrictBool = False
show_cuboids_3d: StrictBool = False
follow_trajectory: StrictBool = False
class RecordedPerceptionRequest(StrictApiModel):
@@ -127,6 +130,18 @@ class RecordedPerceptionRequest(StrictApiModel):
)
class RecordedPointColorsRequest(StrictApiModel):
application_id: Literal["nodedc_mission_core_recorded"]
recording_id: str = Field(
min_length=1,
max_length=128,
pattern=r"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
)
color_mode: Literal["intensity", "height", "distance", "rgb", "class"]
palette: Literal["turbo", "viridis", "plasma", "grayscale", "custom"]
custom_color: str = Field(pattern=r"^#[0-9A-Fa-f]{6}$")
class SceneSettingsDocument(StrictApiModel):
projection: Literal["3d", "2d", "map"]
point_size: float = Field(ge=0.1, le=32.0)
@@ -284,6 +299,7 @@ def build_session_router(
media_inspector: RecordedMediaInspector | None = None,
perception_overlay_provider: RecordedPerceptionOverlayProvider | None = None,
perception_media_provider: RecordedPerceptionMediaProvider | None = None,
point_color_renderers: Mapping[str, RecordedPointColorRenderer] | None = None,
allow_synchronous_recording_fallback: bool = False,
replay_action_id: str = DEFAULT_REPLAY_ACTION_ID,
) -> APIRouter:
@@ -796,6 +812,7 @@ def build_session_router(
recorded_blueprint_rrd,
RerunSceneSettings(
point_size=request.point_size,
color_mode=request.color_mode,
palette=request.palette,
custom_color=request.custom_color,
accumulation_seconds=request.accumulation_seconds,
@@ -812,6 +829,7 @@ def build_session_router(
show_detections_2d=request.show_detections_2d,
show_segmentation=request.show_segmentation,
show_cuboids_3d=request.show_cuboids_3d,
follow_trajectory=request.follow_trajectory,
)
except SessionNotFoundError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@@ -887,6 +905,61 @@ def build_session_router(
},
)
@router.post("/api/v1/observation-sessions/{session_id}/point-colors.rrd")
async def get_observation_session_point_colors(
session_id: str,
request: RecordedPointColorsRequest,
) -> Response:
try:
command = await run_in_threadpool(
_prepare_replay,
store,
catalog_refresher,
session_id,
1.0,
False,
False,
)
point_color_renderer = (point_color_renderers or {}).get(command.plugin_id)
if point_color_renderer is None:
raise HTTPException(
status_code=409,
detail="Сервис архивной окраски точек не настроен.",
)
payload = await run_in_threadpool(
point_color_renderer,
command,
application_id=request.application_id,
recording_id=request.recording_id,
color_mode=request.color_mode,
palette=request.palette,
custom_color=request.custom_color,
)
except SessionNotFoundError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except (SessionNotReplayableError, SessionIntegrityError) as exc:
raise HTTPException(status_code=409, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(
status_code=422,
detail="Некорректные параметры окраски точек.",
) from exc
except RuntimeError as exc:
raise HTTPException(
status_code=500,
detail="Не удалось подготовить окраску облака точек.",
) from exc
return Response(
content=payload,
media_type="application/vnd.rerun.rrd",
headers={
"Cache-Control": "private, no-cache, no-transform",
"Content-Length": str(len(payload)),
"X-Content-Type-Options": "nosniff",
"Content-Disposition": 'inline; filename="point-colors.rrd"',
},
)
@router.get(
"/api/v1/observation-sessions/{session_id}/perception-media/"
"{result_id}/manifest"