diff --git a/apps/control-station/scripts/patch-rerun-web-viewer.mjs b/apps/control-station/scripts/patch-rerun-web-viewer.mjs index 0ca127b..b91a0ca 100644 --- a/apps/control-station/scripts/patch-rerun-web-viewer.mjs +++ b/apps/control-station/scripts/patch-rerun-web-viewer.mjs @@ -23,8 +23,8 @@ const vendorRuntime = [ packagePath: resolve(packageRoot, "re_viewer_bg.wasm"), vendorPath: resolve(vendorRoot, "re_viewer_bg.nodedc.wasm"), publishedSha256: "3fe7aab8ea6bb0fd03c3ef694932943411ee174029e398c539c390beb0824d35", - previousNodedcSha256: "38d19bac06b7c3b8e549489469cf7c4a24f319ec953849e4656b5827a6c105bb", - nodedcSha256: "e85dbad1569431620d4fabb18c1dbddd3a26d071eec1bb88a036fa755bc921da", + previousNodedcSha256: "e85dbad1569431620d4fabb18c1dbddd3a26d071eec1bb88a036fa755bc921da", + nodedcSha256: "6aca9da47ad561d2046ad0c7c0b8a7f653f023a77132c5c6304789320db512c2", }, { label: "wasm JavaScript glue", diff --git a/apps/control-station/src/workspaces/Workspaces.tsx b/apps/control-station/src/workspaces/Workspaces.tsx index 51800cf..ad01795 100644 --- a/apps/control-station/src/workspaces/Workspaces.tsx +++ b/apps/control-station/src/workspaces/Workspaces.tsx @@ -631,7 +631,7 @@ function SpatialWorkspace({ variant={followRecordedTrajectory ? "primary" : "secondary"} icon={} aria-pressed={followRecordedTrajectory} - title="Привязать orbital-пивот к текущему положению рига" + title="Удерживать orbital-пивот на риге до повторного нажатия" onClick={() => setFollowRecordedTrajectory((current) => !current)} > Следовать diff --git a/apps/control-station/test/rerunWebViewerVendor.test.mjs b/apps/control-station/test/rerunWebViewerVendor.test.mjs index 3554b6e..7184c43 100644 --- a/apps/control-station/test/rerunWebViewerVendor.test.mjs +++ b/apps/control-station/test/rerunWebViewerVendor.test.mjs @@ -17,7 +17,7 @@ test("NODE.DC Rerun runtime is the audited 0.34.1 spatial camera build", () => { const manifest = JSON.parse(readFileSync(resolve(packageRoot, "package.json"), "utf8")); assert.equal(manifest.version, "0.34.1"); - const expectedWasm = "e85dbad1569431620d4fabb18c1dbddd3a26d071eec1bb88a036fa755bc921da"; + const expectedWasm = "6aca9da47ad561d2046ad0c7c0b8a7f653f023a77132c5c6304789320db512c2"; const expectedGlue = "0f7b76c9f24cbd8437021b5d37499894aeadc586183e422ebc82ef556d7b8339"; assert.equal(sha256(resolve(vendorRoot, "re_viewer_bg.nodedc.wasm")), expectedWasm); @@ -55,7 +55,7 @@ test("custom Rerun WASM initializes and grows its externref table", () => { runtime.deinit(); }); -test("source patch carries pointer navigation, camera continuity, and geometry tests", () => { +test("source patch carries pointer navigation, persistent follow, and geometry tests", () => { const patch = readFileSync(resolve(vendorRoot, "NODEDC_ZOOM_TO_CURSOR.patch"), "utf8"); assert.match(patch, /fn pointer_ray_direction/); @@ -69,5 +69,7 @@ test("source patch carries pointer navigation, camera continuity, and geometry t assert.match(patch, /minimum_orbital_navigation_speed/); assert.match(patch, /orbital_rotation_keeps_selected_anchor_on_the_same_view_ray/); assert.match(patch, /orbital_navigation_speed_floor_tracks_scene_scale/); + assert.match(patch, /NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY/); + assert.match(patch, /nodedc_rig_orbit_tracking_is_persistent/); assert.match(patch, /previous_picking_result/); }); diff --git a/apps/control-station/vendor/rerun-web-viewer-0.34.1/BUILD_INFO.md b/apps/control-station/vendor/rerun-web-viewer-0.34.1/BUILD_INFO.md index ed5e301..ca5c545 100644 --- a/apps/control-station/vendor/rerun-web-viewer-0.34.1/BUILD_INFO.md +++ b/apps/control-station/vendor/rerun-web-viewer-0.34.1/BUILD_INFO.md @@ -13,6 +13,9 @@ This directory contains the audited Mission Core camera-controller override for silently ignoring the wheel or moving by imperceptible millimeters; - orbital navigation has a scene-scale speed floor, so WASD and post-limit dolly remain useful at the minimum radius; +- Mission Core's explicit `/world/sensor_pose` orbital follow keeps the current + eye radius and orientation when enabled, remains attached through manual + orbit and zoom, and releases only when the operator toggles follow off; - first-person movement, panning and Rerun's zoom-out cap are unchanged. ## Source identity @@ -57,13 +60,13 @@ generated `re_viewer.js` is transformed with | Artifact | SHA-256 | | --- | --- | -| `re_viewer_bg.nodedc.wasm` | `e85dbad1569431620d4fabb18c1dbddd3a26d071eec1bb88a036fa755bc921da` | +| `re_viewer_bg.nodedc.wasm` | `6aca9da47ad561d2046ad0c7c0b8a7f653f023a77132c5c6304789320db512c2` | | raw generated `re_viewer.js` | `cc196a93c5be972c801d46be4dc9934f7f042eb62941f0aa0678f1c8416c6874` | | `re_viewer.nodedc.js` | `0f7b76c9f24cbd8437021b5d37499894aeadc586183e422ebc82ef556d7b8339` | -The focused Rust suite completed with `7 passed, 0 failed`, including the +The focused Rust suite completed with `8 passed, 0 failed`, including the orbit-to-dolly boundary, pointer-anchored rotation and scene-scale speed-floor -cases. A Node `initSync` +cases, plus persistent rig-orbit tracking. A Node `initSync` smoke test completed successfully, including the `externref` table-growth step. The Mission Core Node suite also checks both artifact hashes and verifies that every `wasm.*` reference in the JavaScript glue exists in the paired WASM diff --git a/apps/control-station/vendor/rerun-web-viewer-0.34.1/NODEDC_ZOOM_TO_CURSOR.patch b/apps/control-station/vendor/rerun-web-viewer-0.34.1/NODEDC_ZOOM_TO_CURSOR.patch index 23fc05f..9854511 100644 --- a/apps/control-station/vendor/rerun-web-viewer-0.34.1/NODEDC_ZOOM_TO_CURSOR.patch +++ b/apps/control-station/vendor/rerun-web-viewer-0.34.1/NODEDC_ZOOM_TO_CURSOR.patch @@ -1,25 +1,39 @@ diff --git a/crates/viewer/re_view_spatial/src/eye.rs b/crates/viewer/re_view_spatial/src/eye.rs -index e59b311..7159aab 100644 +index e59b311..77ac8d7 100644 --- a/crates/viewer/re_view_spatial/src/eye.rs +++ b/crates/viewer/re_view_spatial/src/eye.rs @@ -207,0 +208,3 @@ pub struct EyeState { + /// World-space point selected when the current orbital drag started. + orbit_drag_anchor: Option, + -@@ -434 +437 @@ impl EyeController { +@@ -245,0 +249,13 @@ pub(crate) struct EyeController { ++/// NODE.DC's operator follow mode is explicitly toggled outside the embedded ++/// viewer. Unlike Rerun's transient entity tracking, manual orbit/zoom must ++/// therefore keep this rig pivot attached until the operator toggles it off. ++const NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY: &str = "/world/sensor_pose"; ++ ++fn keeps_orbital_tracking_after_interaction( ++ kind: Eye3DKind, ++ tracking_entity: &EntityPath, ++) -> bool { ++ kind == Eye3DKind::Orbital ++ && tracking_entity == &EntityPath::from(NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY) ++} ++ +@@ -434 +450 @@ impl EyeController { - let mut rot = self.rotation(); + let rot = self.rotation_after_delta(delta); -@@ -435,0 +439,2 @@ impl EyeController { +@@ -435,0 +452,2 @@ impl EyeController { + self.apply_rotation_and_radius(rot, radius); + } -@@ -436,0 +442,2 @@ impl EyeController { +@@ -436,0 +455,2 @@ impl EyeController { + fn rotation_after_delta(&self, delta: egui::Vec2) -> Quat { + let mut rot = self.rotation(); -@@ -452 +459,2 @@ impl EyeController { +@@ -452 +472,2 @@ impl EyeController { - rot = rot.normalize(); + rot.normalize() + } -@@ -454 +462,13 @@ impl EyeController { +@@ -454 +475,13 @@ impl EyeController { - self.apply_rotation_and_radius(rot, radius); + /// Rotate around the point selected under the pointer without moving that + /// point on screen. @@ -34,7 +48,7 @@ index e59b311..7159aab 100644 + fn rotate_around_anchor(&mut self, delta: egui::Vec2, anchor: Vec3) { + let sensitivity = 0.004; + self.rotate_radians_around_anchor(sensitivity * delta, anchor); -@@ -491 +511,10 @@ impl EyeController { +@@ -491 +524,10 @@ impl EyeController { - fn handle_drag(&mut self, response: &egui::Response, drag_threshold: f32) { + fn handle_drag( + &mut self, @@ -46,7 +60,7 @@ index e59b311..7159aab 100644 + if !response.dragged_by(ROTATE3D_BUTTON) { + eye_state.orbit_drag_anchor = None; + } -@@ -503 +532,15 @@ impl EyeController { +@@ -503 +545,15 @@ impl EyeController { - self.rotate(response.drag_delta()); + if self.kind == Eye3DKind::Orbital { + let anchor = *eye_state.orbit_drag_anchor.get_or_insert_with(|| { @@ -63,7 +77,7 @@ index e59b311..7159aab 100644 + } else { + self.rotate(response.drag_delta()); + } -@@ -514,0 +558,86 @@ impl EyeController { +@@ -514,0 +571,86 @@ impl EyeController { + /// Returns the world-space ray under the pointer. + /// + /// Keeping this calculation local to the eye controller lets orbital zoom use the pointer @@ -150,16 +164,16 @@ index e59b311..7159aab 100644 + self.did_interact = true; + } + -@@ -516 +645,2 @@ impl EyeController { +@@ -516 +658,2 @@ impl EyeController { - fn handle_zoom(&mut self, egui_ctx: &egui::Context, scene_bounding_box: &macaw::BoundingBox) { + fn handle_zoom(&mut self, response: &egui::Response, scene_bounding_box: &macaw::BoundingBox) { + let egui_ctx = &response.ctx; -@@ -531,2 +660,0 @@ impl EyeController { +@@ -531,2 +673,0 @@ impl EyeController { - let radius = self.pos.distance(self.look_target); - -@@ -534,0 +663 @@ impl EyeController { +@@ -534,0 +676 @@ impl EyeController { + let radius = self.radius(); -@@ -536,11 +665,2 @@ impl EyeController { +@@ -536,11 +678,2 @@ impl EyeController { - let new_radius = (radius / zoom_factor).clamp(Self::MIN_ORBIT_DISTANCE, max_radius); - - // The user may be scrolling to move the camera closer, but are not realizing @@ -173,21 +187,21 @@ index e59b311..7159aab 100644 - } + let pointer = response.ctx.pointer_latest_pos(); + self.zoom_orbit_towards_pointer(zoom_factor, max_radius, response.rect, pointer); -@@ -669,0 +790 @@ impl EyeController { +@@ -669,0 +803 @@ impl EyeController { + pointer_space_position: Option, -@@ -671,0 +793,5 @@ impl EyeController { +@@ -671,0 +806,5 @@ impl EyeController { + if self.kind == Eye3DKind::Orbital { + self.speed = self + .speed + .max(minimum_orbital_navigation_speed(scene_bounding_box) as f64); + } -@@ -687 +813 @@ impl EyeController { +@@ -687 +826 @@ impl EyeController { - self.handle_drag(response, drag_threshold); + self.handle_drag(eye_state, response, drag_threshold, pointer_space_position); -@@ -690 +816 @@ impl EyeController { +@@ -690 +829 @@ impl EyeController { - self.handle_zoom(&response.ctx, scene_bounding_box); + self.handle_zoom(response, scene_bounding_box); -@@ -728,0 +855,18 @@ fn max_orbital_radius(scene_bounding_box: &macaw::BoundingBox) -> f32 { +@@ -728,0 +868,18 @@ fn max_orbital_radius(scene_bounding_box: &macaw::BoundingBox) -> f32 { +/// Lower bound for free-flight and post-limit zoom speed in orbital mode. +/// +/// The default orbital speed is the current orbit radius. Close to the near @@ -206,15 +220,27 @@ index e59b311..7159aab 100644 + (scene_diagonal * SCENE_DIAGONAL_FACTOR).max(FALLBACK) +} + -@@ -773,0 +918 @@ impl EyeState { +@@ -773,0 +931 @@ impl EyeState { + pointer_space_position: Option, -@@ -816,0 +962 @@ impl EyeState { +@@ -816,0 +975 @@ impl EyeState { + pointer_space_position, -@@ -1189,0 +1336 @@ impl EyeState { +@@ -891,0 +1051,2 @@ impl EyeState { ++ let persistent_orbit_tracking = ++ keeps_orbital_tracking_after_interaction(eye_controller.kind, &tracking_entity); +@@ -946 +1107 @@ impl EyeState { +- if new_tracking { ++ if new_tracking && !persistent_orbit_tracking { +@@ -998 +1159,4 @@ impl EyeState { +- if eye_controller.did_interact && did_eye_orbit_center_change { ++ if eye_controller.did_interact ++ && did_eye_orbit_center_change ++ && !persistent_orbit_tracking ++ { +@@ -1189,0 +1354 @@ impl EyeState { + pointer_space_position: Option, -@@ -1203,0 +1351 @@ impl EyeState { +@@ -1203,0 +1369 @@ impl EyeState { + pointer_space_position, -@@ -1251,0 +1400,126 @@ impl EyeState { +@@ -1251,0 +1418,145 @@ impl EyeState { + +#[cfg(test)] +mod tests { @@ -340,6 +366,25 @@ index e59b311..7159aab 100644 + 0.25 + ); + } ++ ++ #[test] ++ fn nodedc_rig_orbit_tracking_is_persistent() { ++ let rig = EntityPath::from(NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY); ++ let other = EntityPath::from("/world/another_entity"); ++ ++ assert!(keeps_orbital_tracking_after_interaction( ++ Eye3DKind::Orbital, ++ &rig ++ )); ++ assert!(!keeps_orbital_tracking_after_interaction( ++ Eye3DKind::FirstPerson, ++ &rig ++ )); ++ assert!(!keeps_orbital_tracking_after_interaction( ++ Eye3DKind::Orbital, ++ &other ++ )); ++ } +} diff --git a/crates/viewer/re_view_spatial/src/ui_3d.rs b/crates/viewer/re_view_spatial/src/ui_3d.rs index 56257a8..07498ab 100644 diff --git a/apps/control-station/vendor/rerun-web-viewer-0.34.1/re_viewer_bg.nodedc.wasm b/apps/control-station/vendor/rerun-web-viewer-0.34.1/re_viewer_bg.nodedc.wasm index 13c6567..12e9c19 100644 --- a/apps/control-station/vendor/rerun-web-viewer-0.34.1/re_viewer_bg.nodedc.wasm +++ b/apps/control-station/vendor/rerun-web-viewer-0.34.1/re_viewer_bg.nodedc.wasm @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e85dbad1569431620d4fabb18c1dbddd3a26d071eec1bb88a036fa755bc921da -size 48596892 +oid sha256:6aca9da47ad561d2046ad0c7c0b8a7f653f023a77132c5c6304789320db512c2 +size 48580358