diff --git a/src/k1link/viewer/recorded.py b/src/k1link/viewer/recorded.py index f7be466..e9f651c 100644 --- a/src/k1link/viewer/recorded.py +++ b/src/k1link/viewer/recorded.py @@ -19,8 +19,6 @@ SESSION_TIMELINE = "session_time" RECORDED_SPATIAL_VIEW_ID = UUID("5f5f11d5-3b0a-4a81-887b-2be767cba1c0") RECORDED_SPATIAL_RESET_VIEW_ID = UUID("1480abcc-a0ae-4287-ab69-4b606d15d947") -RECORDED_SPATIAL_FOLLOW_VIEW_ID = UUID("e96acd7f-1bb8-49e2-bff8-a661e5c6ceab") -RECORDED_SPATIAL_FOLLOW_RESET_VIEW_ID = UUID("f409403d-84ac-4309-82aa-501fc69905f5") RECORDED_ROOT_CONTAINER_ID = UUID("b02f2aca-8471-4dcb-b786-53df5a320fc8") RECORDED_SPATIAL_RESET_ROOT_CONTAINER_ID = UUID("27d95ad7-1e72-46ca-b854-d02cd99b7610") RECORDED_PERCEPTION_ROOT_CONTAINER_ID = UUID("70ea9fd5-bbbb-4b23-8ae8-8098af92b997") @@ -35,8 +33,6 @@ RECORDED_CAMERA_VIEW_ID = UUID("5c1db75b-07cd-479a-903d-f4f2ed554513") RECORDED_CAMERA_RESET_VIEW_ID = UUID("d0618e0c-c889-4222-a643-60a4a882935c") RECORDED_PERCEPTION_3D_VIEW_ID = UUID("0496bd2e-2b4d-4a4f-87b8-3ce4f9f7e114") RECORDED_PERCEPTION_3D_RESET_VIEW_ID = UUID("31f63ab8-ffdd-4751-ae40-e8e7b4462c8f") -RECORDED_PERCEPTION_3D_FOLLOW_VIEW_ID = UUID("6bb43236-9507-4e8f-bc54-3a73b31c07b5") -RECORDED_PERCEPTION_3D_FOLLOW_RESET_VIEW_ID = UUID("0e01e3c6-8b7b-47aa-b22b-e413301599eb") RECORDED_METRICS_VIEW_ID = UUID("f973fc11-0867-4732-ad3c-97008621fab7") RECORDED_UNIFIED_ROOT_CONTAINER_ID = UUID("e9934ef8-453f-432e-9136-2b0908190253") RECORDED_UNIFIED_RESET_ROOT_CONTAINER_ID = UUID("2781407d-9f4e-4405-86e8-bbe6065e83df") @@ -218,21 +214,20 @@ def recorded_blueprint( # Log an explicit empty range set so a previous accumulated blueprint # for this stable view id is cleared instead of surviving in Rerun. time_ranges=rrb.VisibleTimeRanges([]), - eye_controls=( - rrb.EyeControls3D( - kind=rrb.Eye3DKind.Orbital, - tracking_entity="/world/sensor_pose", - ) - if follow_trajectory - else None + # Follow is a property of the same operator eye, not another view. + # Keeping the view id stable preserves the current orbit offset when + # tracking is toggled. An explicit empty path clears tracking without + # overwriting the position/look-target saved by user interaction. + eye_controls=rrb.EyeControls3D.from_fields( + kind=rrb.Eye3DKind.Orbital if follow_trajectory else None, + tracking_entity="/world/sensor_pose" if follow_trajectory else "", ), ) - spatial_view.id = { - (False, 0): RECORDED_SPATIAL_VIEW_ID, - (False, 1): RECORDED_SPATIAL_RESET_VIEW_ID, - (True, 0): RECORDED_SPATIAL_FOLLOW_VIEW_ID, - (True, 1): RECORDED_SPATIAL_FOLLOW_RESET_VIEW_ID, - }[(follow_trajectory, view_reset_generation)] + spatial_view.id = ( + RECORDED_SPATIAL_RESET_VIEW_ID + if view_reset_generation + else RECORDED_SPATIAL_VIEW_ID + ) camera_view = rrb.Spatial2DView( origin="/perception/camera", name="Оригинальное видео · слои AI", @@ -279,21 +274,16 @@ def recorded_blueprint( # native cloud from /world/points. "/world/perception/lidar": rrb.EntityBehavior(visible=False), }, - eye_controls=( - rrb.EyeControls3D( - kind=rrb.Eye3DKind.Orbital, - tracking_entity="/world/sensor_pose", - ) - if follow_trajectory - else None + eye_controls=rrb.EyeControls3D.from_fields( + kind=rrb.Eye3DKind.Orbital if follow_trajectory else None, + tracking_entity="/world/sensor_pose" if follow_trajectory else "", ), ) - perception_3d_view.id = { - (False, 0): RECORDED_PERCEPTION_3D_VIEW_ID, - (False, 1): RECORDED_PERCEPTION_3D_RESET_VIEW_ID, - (True, 0): RECORDED_PERCEPTION_3D_FOLLOW_VIEW_ID, - (True, 1): RECORDED_PERCEPTION_3D_FOLLOW_RESET_VIEW_ID, - }[(follow_trajectory, view_reset_generation)] + perception_3d_view.id = ( + RECORDED_PERCEPTION_3D_RESET_VIEW_ID + if view_reset_generation + else RECORDED_PERCEPTION_3D_VIEW_ID + ) metrics_view = rrb.TimeSeriesView( origin="/metrics/device", name="Маршрут и время", diff --git a/tests/test_rrd_export.py b/tests/test_rrd_export.py index c0ef8d4..526168d 100644 --- a/tests/test_rrd_export.py +++ b/tests/test_rrd_export.py @@ -37,9 +37,6 @@ from k1link.device_plugins.xgrids_k1.rrd_export import ( export_k1mqtt_to_rrd, recorded_blueprint_rrd, ) -from k1link.viewer.recorded import ( - RECORDED_SPATIAL_FOLLOW_VIEW_ID, -) from k1link.viewer.recorded import ( recorded_blueprint as viewer_recorded_blueprint, ) @@ -453,7 +450,7 @@ def test_viewer_blueprint_reset_is_bounded_and_recreates_render_views() -> None: assert perception_behavior.visible.as_arrow_array().to_pylist() == [False] -def test_recorded_follow_mode_tracks_sensor_pose_with_an_independent_orbital_eye() -> None: +def test_recorded_follow_mode_tracks_sensor_pose_with_the_same_orbital_eye() -> None: normal = viewer_recorded_blueprint( RerunSceneSettings(), include_initial_playback_state=False, @@ -471,16 +468,23 @@ def test_recorded_follow_mode_tracks_sensor_pose_with_an_independent_orbital_eye normal_view = normal.root_container.contents[0] followed_view = followed.root_container.contents[0] + normal_eye = normal_view.properties["EyeControls3D"] followed_eye = followed_view.properties["EyeControls3D"] + normal_components = { + str(batch.component_descriptor()): batch.as_arrow_array().to_pylist() + for batch in normal_eye.as_component_batches() + } followed_components = { str(batch.component_descriptor()): batch.as_arrow_array().to_pylist() for batch in followed_eye.as_component_batches() } - assert "EyeControls3D" not in normal_view.properties - assert followed_view.id == RECORDED_SPATIAL_FOLLOW_VIEW_ID - assert followed_again.root_container.contents[0].id == RECORDED_SPATIAL_FOLLOW_VIEW_ID - assert followed_view.id != normal_view.id + assert followed_view.id == RECORDED_SPATIAL_VIEW_ID + assert followed_again.root_container.contents[0].id == RECORDED_SPATIAL_VIEW_ID + assert followed_view.id == normal_view.id + assert normal_components == { + "EyeControls3D:tracking_entity": [""], + } assert followed_components == { "EyeControls3D:kind": [2], "EyeControls3D:tracking_entity": ["/world/sensor_pose"],