fix(viewer): preserve follow camera across layer toggles
This commit is contained in:
parent
a7babf60db
commit
ae2ce055c8
|
|
@ -23,8 +23,8 @@ const vendorRuntime = [
|
||||||
packagePath: resolve(packageRoot, "re_viewer_bg.wasm"),
|
packagePath: resolve(packageRoot, "re_viewer_bg.wasm"),
|
||||||
vendorPath: resolve(vendorRoot, "re_viewer_bg.nodedc.wasm"),
|
vendorPath: resolve(vendorRoot, "re_viewer_bg.nodedc.wasm"),
|
||||||
publishedSha256: "3fe7aab8ea6bb0fd03c3ef694932943411ee174029e398c539c390beb0824d35",
|
publishedSha256: "3fe7aab8ea6bb0fd03c3ef694932943411ee174029e398c539c390beb0824d35",
|
||||||
previousNodedcSha256: "e85dbad1569431620d4fabb18c1dbddd3a26d071eec1bb88a036fa755bc921da",
|
previousNodedcSha256: "6aca9da47ad561d2046ad0c7c0b8a7f653f023a77132c5c6304789320db512c2",
|
||||||
nodedcSha256: "6aca9da47ad561d2046ad0c7c0b8a7f653f023a77132c5c6304789320db512c2",
|
nodedcSha256: "ffe7543d28bb3394f289f6299de43d038767eef83d781c2b7f8f5683308a0469",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "wasm JavaScript glue",
|
label: "wasm JavaScript glue",
|
||||||
|
|
|
||||||
|
|
@ -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"));
|
const manifest = JSON.parse(readFileSync(resolve(packageRoot, "package.json"), "utf8"));
|
||||||
assert.equal(manifest.version, "0.34.1");
|
assert.equal(manifest.version, "0.34.1");
|
||||||
|
|
||||||
const expectedWasm = "6aca9da47ad561d2046ad0c7c0b8a7f653f023a77132c5c6304789320db512c2";
|
const expectedWasm = "ffe7543d28bb3394f289f6299de43d038767eef83d781c2b7f8f5683308a0469";
|
||||||
const expectedGlue = "0f7b76c9f24cbd8437021b5d37499894aeadc586183e422ebc82ef556d7b8339";
|
const expectedGlue = "0f7b76c9f24cbd8437021b5d37499894aeadc586183e422ebc82ef556d7b8339";
|
||||||
|
|
||||||
assert.equal(sha256(resolve(vendorRoot, "re_viewer_bg.nodedc.wasm")), expectedWasm);
|
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();
|
runtime.deinit();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("source patch carries pointer navigation, persistent follow, and geometry tests", () => {
|
test("source patch carries pointer navigation, persistent follow, and camera continuity tests", () => {
|
||||||
const patch = readFileSync(resolve(vendorRoot, "NODEDC_ZOOM_TO_CURSOR.patch"), "utf8");
|
const patch = readFileSync(resolve(vendorRoot, "NODEDC_ZOOM_TO_CURSOR.patch"), "utf8");
|
||||||
|
|
||||||
assert.match(patch, /fn pointer_ray_direction/);
|
assert.match(patch, /fn pointer_ray_direction/);
|
||||||
|
|
@ -71,5 +71,11 @@ test("source patch carries pointer navigation, persistent follow, and geometry t
|
||||||
assert.match(patch, /orbital_navigation_speed_floor_tracks_scene_scale/);
|
assert.match(patch, /orbital_navigation_speed_floor_tracks_scene_scale/);
|
||||||
assert.match(patch, /NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY/);
|
assert.match(patch, /NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY/);
|
||||||
assert.match(patch, /nodedc_rig_orbit_tracking_is_persistent/);
|
assert.match(patch, /nodedc_rig_orbit_tracking_is_persistent/);
|
||||||
|
assert.match(patch, /restore_persistent_orbit_eye_after_blueprint_update/);
|
||||||
|
assert.match(
|
||||||
|
patch,
|
||||||
|
/persistent_rig_follow_restores_the_last_rendered_eye_after_blueprint_update/,
|
||||||
|
);
|
||||||
|
assert.match(patch, /explicit_blueprint_pose_is_not_replaced_by_the_previous_eye/);
|
||||||
assert.match(patch, /previous_picking_result/);
|
assert.match(patch, /previous_picking_result/);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ This directory contains the audited Mission Core camera-controller override for
|
||||||
- Mission Core's explicit `/world/sensor_pose` orbital follow keeps the current
|
- Mission Core's explicit `/world/sensor_pose` orbital follow keeps the current
|
||||||
eye radius and orientation when enabled, remains attached through manual
|
eye radius and orientation when enabled, remains attached through manual
|
||||||
orbit and zoom, and releases only when the operator toggles follow off;
|
orbit and zoom, and releases only when the operator toggles follow off;
|
||||||
|
- repeated server-side blueprint activation for 2D detections, segmentation,
|
||||||
|
and 3D cuboids restores the last rendered operator eye instead of applying
|
||||||
|
Rerun's scene-bounds fallback, so layer toggles cannot reset the camera;
|
||||||
- first-person movement, panning and Rerun's zoom-out cap are unchanged.
|
- first-person movement, panning and Rerun's zoom-out cap are unchanged.
|
||||||
|
|
||||||
## Source identity
|
## Source identity
|
||||||
|
|
@ -33,6 +36,8 @@ This directory contains the audited Mission Core camera-controller override for
|
||||||
`sha256:e90e846de4124376164ddfbaab4b0774c7bdeef5e738866295e5a90a34a307a2`
|
`sha256:e90e846de4124376164ddfbaab4b0774c7bdeef5e738866295e5a90a34a307a2`
|
||||||
- Build-only system packages: `clang 14.0.6`, `libudev-dev 252.39`
|
- Build-only system packages: `clang 14.0.6`, `libudev-dev 252.39`
|
||||||
- Build date: `2026-07-23` (`Europe/Moscow`)
|
- Build date: `2026-07-23` (`Europe/Moscow`)
|
||||||
|
- Measured build stages: Rust to WASM `296.7 s`, JavaScript bindings
|
||||||
|
`8.5 s`, Binaryen `wasm-opt -O2` `1244.2 s`
|
||||||
|
|
||||||
## Reproduction
|
## Reproduction
|
||||||
|
|
||||||
|
|
@ -60,13 +65,14 @@ generated `re_viewer.js` is transformed with
|
||||||
|
|
||||||
| Artifact | SHA-256 |
|
| Artifact | SHA-256 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `re_viewer_bg.nodedc.wasm` | `6aca9da47ad561d2046ad0c7c0b8a7f653f023a77132c5c6304789320db512c2` |
|
| `re_viewer_bg.nodedc.wasm` | `ffe7543d28bb3394f289f6299de43d038767eef83d781c2b7f8f5683308a0469` |
|
||||||
| raw generated `re_viewer.js` | `cc196a93c5be972c801d46be4dc9934f7f042eb62941f0aa0678f1c8416c6874` |
|
| raw generated `re_viewer.js` | `cc196a93c5be972c801d46be4dc9934f7f042eb62941f0aa0678f1c8416c6874` |
|
||||||
| `re_viewer.nodedc.js` | `0f7b76c9f24cbd8437021b5d37499894aeadc586183e422ebc82ef556d7b8339` |
|
| `re_viewer.nodedc.js` | `0f7b76c9f24cbd8437021b5d37499894aeadc586183e422ebc82ef556d7b8339` |
|
||||||
|
|
||||||
The focused Rust suite completed with `8 passed, 0 failed`, including the
|
The focused Rust suite completed with `10 passed, 0 failed`, including the
|
||||||
orbit-to-dolly boundary, pointer-anchored rotation and scene-scale speed-floor
|
orbit-to-dolly boundary, pointer-anchored rotation and scene-scale speed-floor
|
||||||
cases, plus persistent rig-orbit tracking. A Node `initSync`
|
cases, persistent rig-orbit tracking, camera continuity across blueprint
|
||||||
|
reactivation, and explicit reset precedence. A Node `initSync`
|
||||||
smoke test completed successfully, including the `externref` table-growth step.
|
smoke test completed successfully, including the `externref` table-growth step.
|
||||||
The Mission Core Node suite also checks both artifact hashes and verifies that
|
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
|
every `wasm.*` reference in the JavaScript glue exists in the paired WASM
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
diff --git a/crates/viewer/re_view_spatial/src/eye.rs b/crates/viewer/re_view_spatial/src/eye.rs
|
diff --git a/crates/viewer/re_view_spatial/src/eye.rs b/crates/viewer/re_view_spatial/src/eye.rs
|
||||||
index e59b311..77ac8d7 100644
|
index e59b311..b98653a 100644
|
||||||
--- a/crates/viewer/re_view_spatial/src/eye.rs
|
--- a/crates/viewer/re_view_spatial/src/eye.rs
|
||||||
+++ b/crates/viewer/re_view_spatial/src/eye.rs
|
+++ b/crates/viewer/re_view_spatial/src/eye.rs
|
||||||
@@ -207,0 +208,3 @@ pub struct EyeState {
|
@@ -207,0 +208,3 @@ pub struct EyeState {
|
||||||
+ /// World-space point selected when the current orbital drag started.
|
+ /// World-space point selected when the current orbital drag started.
|
||||||
+ orbit_drag_anchor: Option<Vec3>,
|
+ orbit_drag_anchor: Option<Vec3>,
|
||||||
+
|
+
|
||||||
@@ -245,0 +249,13 @@ pub(crate) struct EyeController {
|
@@ -245,0 +249,50 @@ pub(crate) struct EyeController {
|
||||||
+/// NODE.DC's operator follow mode is explicitly toggled outside the embedded
|
+/// NODE.DC's operator follow mode is explicitly toggled outside the embedded
|
||||||
+/// viewer. Unlike Rerun's transient entity tracking, manual orbit/zoom must
|
+/// viewer. Unlike Rerun's transient entity tracking, manual orbit/zoom must
|
||||||
+/// therefore keep this rig pivot attached until the operator toggles it off.
|
+/// therefore keep this rig pivot attached until the operator toggles it off.
|
||||||
|
|
@ -20,20 +20,57 @@ index e59b311..77ac8d7 100644
|
||||||
+ && tracking_entity == &EntityPath::from(NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY)
|
+ && tracking_entity == &EntityPath::from(NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY)
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
@@ -434 +450 @@ impl EyeController {
|
+/// Keeps the last rendered operator eye when a server-side blueprint update
|
||||||
|
+/// reactivates the same persistent follow view without explicit pose fields.
|
||||||
|
+///
|
||||||
|
+/// Rerun normally falls back to the scene bounding box when a blueprint has no
|
||||||
|
+/// position or look target. Mission Core layer toggles intentionally omit those
|
||||||
|
+/// fields so that the browser-owned eye remains authoritative.
|
||||||
|
+fn restore_persistent_orbit_eye_after_blueprint_update(
|
||||||
|
+ eye_controller: &mut EyeController,
|
||||||
|
+ previous_eye: Option<&Eye>,
|
||||||
|
+ previous_orbit_radius: Option<f32>,
|
||||||
|
+ tracking_entity: Option<&EntityPath>,
|
||||||
|
+ has_blueprint_position: bool,
|
||||||
|
+ has_blueprint_look_target: bool,
|
||||||
|
+) -> bool {
|
||||||
|
+ let Some(tracking_entity) = tracking_entity else {
|
||||||
|
+ return false;
|
||||||
|
+ };
|
||||||
|
+ let persistent =
|
||||||
|
+ keeps_orbital_tracking_after_interaction(eye_controller.kind, tracking_entity);
|
||||||
|
+ if persistent
|
||||||
|
+ && !has_blueprint_position
|
||||||
|
+ && !has_blueprint_look_target
|
||||||
|
+ && let (Some(previous_eye), Some(previous_orbit_radius)) =
|
||||||
|
+ (previous_eye, previous_orbit_radius)
|
||||||
|
+ {
|
||||||
|
+ let pos = previous_eye.pos_in_world();
|
||||||
|
+ let radius = previous_orbit_radius.max(EyeController::MIN_ORBIT_DISTANCE);
|
||||||
|
+ eye_controller.pos = pos;
|
||||||
|
+ eye_controller.look_target = pos + previous_eye.forward_in_world() * radius;
|
||||||
|
+ eye_controller.eye_up = previous_eye
|
||||||
|
+ .world_from_rub_view
|
||||||
|
+ .transform_vector3(Vec3::Y);
|
||||||
|
+ eye_controller.fov_y = previous_eye.fov_y;
|
||||||
|
+ }
|
||||||
|
+ persistent
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
@@ -434 +487 @@ impl EyeController {
|
||||||
- let mut rot = self.rotation();
|
- let mut rot = self.rotation();
|
||||||
+ let rot = self.rotation_after_delta(delta);
|
+ let rot = self.rotation_after_delta(delta);
|
||||||
@@ -435,0 +452,2 @@ impl EyeController {
|
@@ -435,0 +489,2 @@ impl EyeController {
|
||||||
+ self.apply_rotation_and_radius(rot, radius);
|
+ self.apply_rotation_and_radius(rot, radius);
|
||||||
+ }
|
+ }
|
||||||
@@ -436,0 +455,2 @@ impl EyeController {
|
@@ -436,0 +492,2 @@ impl EyeController {
|
||||||
+ fn rotation_after_delta(&self, delta: egui::Vec2) -> Quat {
|
+ fn rotation_after_delta(&self, delta: egui::Vec2) -> Quat {
|
||||||
+ let mut rot = self.rotation();
|
+ let mut rot = self.rotation();
|
||||||
@@ -452 +472,2 @@ impl EyeController {
|
@@ -452 +509,2 @@ impl EyeController {
|
||||||
- rot = rot.normalize();
|
- rot = rot.normalize();
|
||||||
+ rot.normalize()
|
+ rot.normalize()
|
||||||
+ }
|
+ }
|
||||||
@@ -454 +475,13 @@ impl EyeController {
|
@@ -454 +512,13 @@ impl EyeController {
|
||||||
- self.apply_rotation_and_radius(rot, radius);
|
- self.apply_rotation_and_radius(rot, radius);
|
||||||
+ /// Rotate around the point selected under the pointer without moving that
|
+ /// Rotate around the point selected under the pointer without moving that
|
||||||
+ /// point on screen.
|
+ /// point on screen.
|
||||||
|
|
@ -48,7 +85,7 @@ index e59b311..77ac8d7 100644
|
||||||
+ fn rotate_around_anchor(&mut self, delta: egui::Vec2, anchor: Vec3) {
|
+ fn rotate_around_anchor(&mut self, delta: egui::Vec2, anchor: Vec3) {
|
||||||
+ let sensitivity = 0.004;
|
+ let sensitivity = 0.004;
|
||||||
+ self.rotate_radians_around_anchor(sensitivity * delta, anchor);
|
+ self.rotate_radians_around_anchor(sensitivity * delta, anchor);
|
||||||
@@ -491 +524,10 @@ impl EyeController {
|
@@ -491 +561,10 @@ impl EyeController {
|
||||||
- fn handle_drag(&mut self, response: &egui::Response, drag_threshold: f32) {
|
- fn handle_drag(&mut self, response: &egui::Response, drag_threshold: f32) {
|
||||||
+ fn handle_drag(
|
+ fn handle_drag(
|
||||||
+ &mut self,
|
+ &mut self,
|
||||||
|
|
@ -60,7 +97,7 @@ index e59b311..77ac8d7 100644
|
||||||
+ if !response.dragged_by(ROTATE3D_BUTTON) {
|
+ if !response.dragged_by(ROTATE3D_BUTTON) {
|
||||||
+ eye_state.orbit_drag_anchor = None;
|
+ eye_state.orbit_drag_anchor = None;
|
||||||
+ }
|
+ }
|
||||||
@@ -503 +545,15 @@ impl EyeController {
|
@@ -503 +582,15 @@ impl EyeController {
|
||||||
- self.rotate(response.drag_delta());
|
- self.rotate(response.drag_delta());
|
||||||
+ if self.kind == Eye3DKind::Orbital {
|
+ if self.kind == Eye3DKind::Orbital {
|
||||||
+ let anchor = *eye_state.orbit_drag_anchor.get_or_insert_with(|| {
|
+ let anchor = *eye_state.orbit_drag_anchor.get_or_insert_with(|| {
|
||||||
|
|
@ -77,7 +114,7 @@ index e59b311..77ac8d7 100644
|
||||||
+ } else {
|
+ } else {
|
||||||
+ self.rotate(response.drag_delta());
|
+ self.rotate(response.drag_delta());
|
||||||
+ }
|
+ }
|
||||||
@@ -514,0 +571,86 @@ impl EyeController {
|
@@ -514,0 +608,86 @@ impl EyeController {
|
||||||
+ /// Returns the world-space ray under the pointer.
|
+ /// Returns the world-space ray under the pointer.
|
||||||
+ ///
|
+ ///
|
||||||
+ /// Keeping this calculation local to the eye controller lets orbital zoom use the pointer
|
+ /// Keeping this calculation local to the eye controller lets orbital zoom use the pointer
|
||||||
|
|
@ -164,16 +201,16 @@ index e59b311..77ac8d7 100644
|
||||||
+ self.did_interact = true;
|
+ self.did_interact = true;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
@@ -516 +658,2 @@ impl EyeController {
|
@@ -516 +695,2 @@ impl EyeController {
|
||||||
- fn handle_zoom(&mut self, egui_ctx: &egui::Context, scene_bounding_box: &macaw::BoundingBox) {
|
- 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) {
|
+ fn handle_zoom(&mut self, response: &egui::Response, scene_bounding_box: &macaw::BoundingBox) {
|
||||||
+ let egui_ctx = &response.ctx;
|
+ let egui_ctx = &response.ctx;
|
||||||
@@ -531,2 +673,0 @@ impl EyeController {
|
@@ -531,2 +710,0 @@ impl EyeController {
|
||||||
- let radius = self.pos.distance(self.look_target);
|
- let radius = self.pos.distance(self.look_target);
|
||||||
-
|
-
|
||||||
@@ -534,0 +676 @@ impl EyeController {
|
@@ -534,0 +713 @@ impl EyeController {
|
||||||
+ let radius = self.radius();
|
+ let radius = self.radius();
|
||||||
@@ -536,11 +678,2 @@ impl EyeController {
|
@@ -536,11 +715,2 @@ impl EyeController {
|
||||||
- let new_radius = (radius / zoom_factor).clamp(Self::MIN_ORBIT_DISTANCE, max_radius);
|
- 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
|
- // The user may be scrolling to move the camera closer, but are not realizing
|
||||||
|
|
@ -187,21 +224,21 @@ index e59b311..77ac8d7 100644
|
||||||
- }
|
- }
|
||||||
+ let pointer = response.ctx.pointer_latest_pos();
|
+ let pointer = response.ctx.pointer_latest_pos();
|
||||||
+ self.zoom_orbit_towards_pointer(zoom_factor, max_radius, response.rect, pointer);
|
+ self.zoom_orbit_towards_pointer(zoom_factor, max_radius, response.rect, pointer);
|
||||||
@@ -669,0 +803 @@ impl EyeController {
|
@@ -669,0 +840 @@ impl EyeController {
|
||||||
+ pointer_space_position: Option<Vec3>,
|
+ pointer_space_position: Option<Vec3>,
|
||||||
@@ -671,0 +806,5 @@ impl EyeController {
|
@@ -671,0 +843,5 @@ impl EyeController {
|
||||||
+ if self.kind == Eye3DKind::Orbital {
|
+ if self.kind == Eye3DKind::Orbital {
|
||||||
+ self.speed = self
|
+ self.speed = self
|
||||||
+ .speed
|
+ .speed
|
||||||
+ .max(minimum_orbital_navigation_speed(scene_bounding_box) as f64);
|
+ .max(minimum_orbital_navigation_speed(scene_bounding_box) as f64);
|
||||||
+ }
|
+ }
|
||||||
@@ -687 +826 @@ impl EyeController {
|
@@ -687 +863 @@ impl EyeController {
|
||||||
- self.handle_drag(response, drag_threshold);
|
- self.handle_drag(response, drag_threshold);
|
||||||
+ self.handle_drag(eye_state, response, drag_threshold, pointer_space_position);
|
+ self.handle_drag(eye_state, response, drag_threshold, pointer_space_position);
|
||||||
@@ -690 +829 @@ impl EyeController {
|
@@ -690 +866 @@ impl EyeController {
|
||||||
- self.handle_zoom(&response.ctx, scene_bounding_box);
|
- self.handle_zoom(&response.ctx, scene_bounding_box);
|
||||||
+ self.handle_zoom(response, scene_bounding_box);
|
+ self.handle_zoom(response, scene_bounding_box);
|
||||||
@@ -728,0 +868,18 @@ fn max_orbital_radius(scene_bounding_box: &macaw::BoundingBox) -> f32 {
|
@@ -728,0 +905,18 @@ fn max_orbital_radius(scene_bounding_box: &macaw::BoundingBox) -> f32 {
|
||||||
+/// Lower bound for free-flight and post-limit zoom speed in orbital mode.
|
+/// 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
|
+/// The default orbital speed is the current orbit radius. Close to the near
|
||||||
|
|
@ -220,27 +257,82 @@ index e59b311..77ac8d7 100644
|
||||||
+ (scene_diagonal * SCENE_DIAGONAL_FACTOR).max(FALLBACK)
|
+ (scene_diagonal * SCENE_DIAGONAL_FACTOR).max(FALLBACK)
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
@@ -773,0 +931 @@ impl EyeState {
|
@@ -773,0 +968 @@ impl EyeState {
|
||||||
+ pointer_space_position: Option<Vec3>,
|
+ pointer_space_position: Option<Vec3>,
|
||||||
@@ -816,0 +975 @@ impl EyeState {
|
@@ -775 +970 @@ impl EyeState {
|
||||||
|
- ) -> Result<Eye, ViewPropertyQueryError> {
|
||||||
|
+ ) -> Result<(Eye, bool), ViewPropertyQueryError> {
|
||||||
|
@@ -777,0 +973,25 @@ impl EyeState {
|
||||||
|
+ let tracking_entity = eye_property
|
||||||
|
+ .component_or_empty::<re_sdk_types::components::EntityPath>(
|
||||||
|
+ EyeControls3D::descriptor_tracking_entity().component,
|
||||||
|
+ )?
|
||||||
|
+ .filter(|tracking_entity| !tracking_entity.is_empty());
|
||||||
|
+ let tracking_entity_path = tracking_entity
|
||||||
|
+ .as_ref()
|
||||||
|
+ .map(|tracking_entity| EntityPath::from(tracking_entity.as_str()));
|
||||||
|
+ let has_blueprint_position = eye_property
|
||||||
|
+ .component_or_empty::<Position3D>(EyeControls3D::descriptor_position().component)?
|
||||||
|
+ .is_some();
|
||||||
|
+ let has_blueprint_look_target = eye_property
|
||||||
|
+ .component_or_empty::<Position3D>(
|
||||||
|
+ EyeControls3D::descriptor_look_target().component,
|
||||||
|
+ )?
|
||||||
|
+ .is_some();
|
||||||
|
+ let persistent_orbit_tracking = restore_persistent_orbit_eye_after_blueprint_update(
|
||||||
|
+ &mut eye_controller,
|
||||||
|
+ self.last_eye.as_ref(),
|
||||||
|
+ self.last_orbit_radius,
|
||||||
|
+ tracking_entity_path.as_ref(),
|
||||||
|
+ has_blueprint_position,
|
||||||
|
+ has_blueprint_look_target,
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
@@ -794,6 +1013,0 @@ impl EyeState {
|
||||||
|
- let tracking_entity = eye_property
|
||||||
|
- .component_or_empty::<re_sdk_types::components::EntityPath>(
|
||||||
|
- EyeControls3D::descriptor_tracking_entity().component,
|
||||||
|
- )?
|
||||||
|
- .filter(|tracking_entity| !tracking_entity.is_empty());
|
||||||
|
-
|
||||||
|
@@ -816,0 +1031 @@ impl EyeState {
|
||||||
+ pointer_space_position,
|
+ pointer_space_position,
|
||||||
@@ -891,0 +1051,2 @@ impl EyeState {
|
@@ -865 +1080 @@ impl EyeState {
|
||||||
|
- return Ok(tracked_eye);
|
||||||
|
+ return Ok((tracked_eye, persistent_orbit_tracking));
|
||||||
|
@@ -872 +1087 @@ impl EyeState {
|
||||||
|
- Ok(eye_controller.get_eye())
|
||||||
|
+ Ok((eye_controller.get_eye(), persistent_orbit_tracking))
|
||||||
|
@@ -891,0 +1107,2 @@ impl EyeState {
|
||||||
+ let persistent_orbit_tracking =
|
+ let persistent_orbit_tracking =
|
||||||
+ keeps_orbital_tracking_after_interaction(eye_controller.kind, &tracking_entity);
|
+ keeps_orbital_tracking_after_interaction(eye_controller.kind, &tracking_entity);
|
||||||
@@ -946 +1107 @@ impl EyeState {
|
@@ -946 +1163 @@ impl EyeState {
|
||||||
- if new_tracking {
|
- if new_tracking {
|
||||||
+ if new_tracking && !persistent_orbit_tracking {
|
+ if new_tracking && !persistent_orbit_tracking {
|
||||||
@@ -998 +1159,4 @@ impl EyeState {
|
@@ -998 +1215,4 @@ impl EyeState {
|
||||||
- if eye_controller.did_interact && did_eye_orbit_center_change {
|
- if eye_controller.did_interact && did_eye_orbit_center_change {
|
||||||
+ if eye_controller.did_interact
|
+ if eye_controller.did_interact
|
||||||
+ && did_eye_orbit_center_change
|
+ && did_eye_orbit_center_change
|
||||||
+ && !persistent_orbit_tracking
|
+ && !persistent_orbit_tracking
|
||||||
+ {
|
+ {
|
||||||
@@ -1189,0 +1354 @@ impl EyeState {
|
@@ -1189,0 +1410 @@ impl EyeState {
|
||||||
+ pointer_space_position: Option<Vec3>,
|
+ pointer_space_position: Option<Vec3>,
|
||||||
@@ -1203,0 +1369 @@ impl EyeState {
|
@@ -1198 +1419 @@ impl EyeState {
|
||||||
|
- let target_eye = self.control_and_sync_with_blueprint(
|
||||||
|
+ let (target_eye, persistent_orbit_tracking) = self.control_and_sync_with_blueprint(
|
||||||
|
@@ -1203,0 +1425 @@ impl EyeState {
|
||||||
+ pointer_space_position,
|
+ pointer_space_position,
|
||||||
@@ -1251,0 +1418,145 @@ impl EyeState {
|
@@ -1210,3 +1432,6 @@ impl EyeState {
|
||||||
|
- if eye_property
|
||||||
|
- .component_or_empty::<Position3D>(EyeControls3D::descriptor_position().component)?
|
||||||
|
- .is_none()
|
||||||
|
+ if !persistent_orbit_tracking
|
||||||
|
+ && eye_property
|
||||||
|
+ .component_or_empty::<Position3D>(
|
||||||
|
+ EyeControls3D::descriptor_position().component,
|
||||||
|
+ )?
|
||||||
|
+ .is_none()
|
||||||
|
@@ -1251,0 +1477,196 @@ impl EyeState {
|
||||||
+
|
+
|
||||||
+#[cfg(test)]
|
+#[cfg(test)]
|
||||||
+mod tests {
|
+mod tests {
|
||||||
|
|
@ -385,6 +477,57 @@ index e59b311..77ac8d7 100644
|
||||||
+ &other
|
+ &other
|
||||||
+ ));
|
+ ));
|
||||||
+ }
|
+ }
|
||||||
|
+
|
||||||
|
+ #[test]
|
||||||
|
+ fn persistent_rig_follow_restores_the_last_rendered_eye_after_blueprint_update() {
|
||||||
|
+ let previous_controller =
|
||||||
|
+ orbital_controller(vec3(12.0, -7.0, 4.0), vec3(10.0, 2.0, 1.0));
|
||||||
|
+ let previous_eye = previous_controller.get_eye();
|
||||||
|
+ let previous_radius = previous_controller.radius();
|
||||||
|
+ let mut fallback_controller =
|
||||||
|
+ orbital_controller(vec3(500.0, -800.0, 300.0), Vec3::ZERO);
|
||||||
|
+ let rig = EntityPath::from(NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY);
|
||||||
|
+
|
||||||
|
+ assert!(restore_persistent_orbit_eye_after_blueprint_update(
|
||||||
|
+ &mut fallback_controller,
|
||||||
|
+ Some(&previous_eye),
|
||||||
|
+ Some(previous_radius),
|
||||||
|
+ Some(&rig),
|
||||||
|
+ false,
|
||||||
|
+ false,
|
||||||
|
+ ));
|
||||||
|
+ assert_vec3_close(fallback_controller.pos, previous_eye.pos_in_world());
|
||||||
|
+ assert!((fallback_controller.radius() - previous_radius).abs() < 1.0e-5);
|
||||||
|
+ assert!(
|
||||||
|
+ fallback_controller
|
||||||
|
+ .fwd()
|
||||||
|
+ .dot(previous_eye.forward_in_world())
|
||||||
|
+ > 0.99999
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ #[test]
|
||||||
|
+ fn explicit_blueprint_pose_is_not_replaced_by_the_previous_eye() {
|
||||||
|
+ let previous_controller =
|
||||||
|
+ orbital_controller(vec3(12.0, -7.0, 4.0), vec3(10.0, 2.0, 1.0));
|
||||||
|
+ let previous_eye = previous_controller.get_eye();
|
||||||
|
+ let mut explicit_controller =
|
||||||
|
+ orbital_controller(vec3(500.0, -800.0, 300.0), Vec3::ZERO);
|
||||||
|
+ let explicit_pos = explicit_controller.pos;
|
||||||
|
+ let explicit_target = explicit_controller.look_target;
|
||||||
|
+ let rig = EntityPath::from(NODEDC_PERSISTENT_ORBIT_TRACKING_ENTITY);
|
||||||
|
+
|
||||||
|
+ assert!(restore_persistent_orbit_eye_after_blueprint_update(
|
||||||
|
+ &mut explicit_controller,
|
||||||
|
+ Some(&previous_eye),
|
||||||
|
+ Some(previous_controller.radius()),
|
||||||
|
+ Some(&rig),
|
||||||
|
+ true,
|
||||||
|
+ true,
|
||||||
|
+ ));
|
||||||
|
+ assert_vec3_close(explicit_controller.pos, explicit_pos);
|
||||||
|
+ assert_vec3_close(explicit_controller.look_target, explicit_target);
|
||||||
|
+ }
|
||||||
+}
|
+}
|
||||||
diff --git a/crates/viewer/re_view_spatial/src/ui_3d.rs b/crates/viewer/re_view_spatial/src/ui_3d.rs
|
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
|
index 56257a8..07498ab 100644
|
||||||
|
|
|
||||||
BIN
apps/control-station/vendor/rerun-web-viewer-0.34.1/re_viewer_bg.nodedc.wasm (Stored with Git LFS)
vendored
BIN
apps/control-station/vendor/rerun-web-viewer-0.34.1/re_viewer_bg.nodedc.wasm (Stored with Git LFS)
vendored
Binary file not shown.
|
|
@ -3,6 +3,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from collections.abc import Callable
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from typing import Any, Literal
|
from typing import Any, Literal
|
||||||
|
|
@ -62,6 +63,7 @@ class _RecordedBlueprintStream:
|
||||||
self.view_reset_generation = view_reset_generation
|
self.view_reset_generation = view_reset_generation
|
||||||
self._lock = Lock()
|
self._lock = Lock()
|
||||||
self._sequence = 0
|
self._sequence = 0
|
||||||
|
self._follow_trajectory: bool | None = None
|
||||||
self._closed = False
|
self._closed = False
|
||||||
native = bindings.new_blueprint(
|
native = bindings.new_blueprint(
|
||||||
application_id=application_id,
|
application_id=application_id,
|
||||||
|
|
@ -78,10 +80,20 @@ class _RecordedBlueprintStream:
|
||||||
)
|
)
|
||||||
self._transport = rr.binary_stream(self._transport_recording)
|
self._transport = rr.binary_stream(self._transport_recording)
|
||||||
|
|
||||||
def render(self, blueprint: rrb.Blueprint) -> bytes:
|
def render(
|
||||||
|
self,
|
||||||
|
blueprint_factory: Callable[[bool], rrb.Blueprint],
|
||||||
|
*,
|
||||||
|
follow_trajectory: bool,
|
||||||
|
) -> bytes:
|
||||||
with self._lock:
|
with self._lock:
|
||||||
if self._closed:
|
if self._closed:
|
||||||
raise RecordedBlueprintError("stable blueprint stream is closed")
|
raise RecordedBlueprintError("stable blueprint stream is closed")
|
||||||
|
update_eye_controls = (
|
||||||
|
self._follow_trajectory is None
|
||||||
|
or self._follow_trajectory != follow_trajectory
|
||||||
|
)
|
||||||
|
blueprint = blueprint_factory(update_eye_controls)
|
||||||
self._blueprint_recording.set_time(
|
self._blueprint_recording.set_time(
|
||||||
"blueprint",
|
"blueprint",
|
||||||
sequence=self._sequence,
|
sequence=self._sequence,
|
||||||
|
|
@ -98,6 +110,7 @@ class _RecordedBlueprintStream:
|
||||||
payload = self._transport.read(flush=True, flush_timeout_sec=5.0)
|
payload = self._transport.read(flush=True, flush_timeout_sec=5.0)
|
||||||
if not payload:
|
if not payload:
|
||||||
raise RecordedBlueprintError("stable blueprint stream produced no data")
|
raise RecordedBlueprintError("stable blueprint stream produced no data")
|
||||||
|
self._follow_trajectory = follow_trajectory
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
|
|
@ -156,6 +169,7 @@ def recorded_blueprint(
|
||||||
show_segmentation: bool = False,
|
show_segmentation: bool = False,
|
||||||
show_cuboids_3d: bool = False,
|
show_cuboids_3d: bool = False,
|
||||||
follow_trajectory: bool = False,
|
follow_trajectory: bool = False,
|
||||||
|
update_eye_controls: bool = True,
|
||||||
) -> rrb.Blueprint:
|
) -> rrb.Blueprint:
|
||||||
accumulation = max(0.0, settings.accumulation_seconds)
|
accumulation = max(0.0, settings.accumulation_seconds)
|
||||||
time_ranges: list[rr.VisibleTimeRange] | None = None
|
time_ranges: list[rr.VisibleTimeRange] | None = None
|
||||||
|
|
@ -218,9 +232,13 @@ def recorded_blueprint(
|
||||||
# Keeping the view id stable preserves the current orbit offset when
|
# Keeping the view id stable preserves the current orbit offset when
|
||||||
# tracking is toggled. An explicit empty path clears tracking without
|
# tracking is toggled. An explicit empty path clears tracking without
|
||||||
# overwriting the position/look-target saved by user interaction.
|
# overwriting the position/look-target saved by user interaction.
|
||||||
eye_controls=rrb.EyeControls3D.from_fields(
|
eye_controls=(
|
||||||
kind=rrb.Eye3DKind.Orbital if follow_trajectory else None,
|
rrb.EyeControls3D.from_fields(
|
||||||
tracking_entity="/world/sensor_pose" if follow_trajectory else "",
|
kind=rrb.Eye3DKind.Orbital if follow_trajectory else None,
|
||||||
|
tracking_entity="/world/sensor_pose" if follow_trajectory else "",
|
||||||
|
)
|
||||||
|
if update_eye_controls
|
||||||
|
else None
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
spatial_view.id = (
|
spatial_view.id = (
|
||||||
|
|
@ -274,9 +292,13 @@ def recorded_blueprint(
|
||||||
# native cloud from /world/points.
|
# native cloud from /world/points.
|
||||||
"/world/perception/lidar": rrb.EntityBehavior(visible=False),
|
"/world/perception/lidar": rrb.EntityBehavior(visible=False),
|
||||||
},
|
},
|
||||||
eye_controls=rrb.EyeControls3D.from_fields(
|
eye_controls=(
|
||||||
kind=rrb.Eye3DKind.Orbital if follow_trajectory else None,
|
rrb.EyeControls3D.from_fields(
|
||||||
tracking_entity="/world/sensor_pose" if follow_trajectory else "",
|
kind=rrb.Eye3DKind.Orbital if follow_trajectory else None,
|
||||||
|
tracking_entity="/world/sensor_pose" if follow_trajectory else "",
|
||||||
|
)
|
||||||
|
if update_eye_controls
|
||||||
|
else None
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
perception_3d_view.id = (
|
perception_3d_view.id = (
|
||||||
|
|
@ -385,17 +407,20 @@ def recorded_blueprint_rrd(
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
"""Serialize a bounded active blueprint update without recorded data."""
|
"""Serialize a bounded active blueprint update without recorded data."""
|
||||||
|
|
||||||
blueprint = recorded_blueprint(
|
def build_blueprint(update_eye_controls: bool) -> rrb.Blueprint:
|
||||||
settings,
|
return recorded_blueprint(
|
||||||
include_initial_playback_state=False,
|
settings,
|
||||||
active_view=active_view,
|
include_initial_playback_state=False,
|
||||||
view_reset_generation=view_reset_generation,
|
active_view=active_view,
|
||||||
unified_perception=unified_perception,
|
view_reset_generation=view_reset_generation,
|
||||||
show_detections_2d=show_detections_2d,
|
unified_perception=unified_perception,
|
||||||
show_segmentation=show_segmentation,
|
show_detections_2d=show_detections_2d,
|
||||||
show_cuboids_3d=show_cuboids_3d,
|
show_segmentation=show_segmentation,
|
||||||
follow_trajectory=follow_trajectory,
|
show_cuboids_3d=show_cuboids_3d,
|
||||||
)
|
follow_trajectory=follow_trajectory,
|
||||||
|
update_eye_controls=update_eye_controls,
|
||||||
|
)
|
||||||
|
|
||||||
payload: bytes | None
|
payload: bytes | None
|
||||||
if blueprint_session_id is not None:
|
if blueprint_session_id is not None:
|
||||||
try:
|
try:
|
||||||
|
|
@ -404,12 +429,16 @@ def recorded_blueprint_rrd(
|
||||||
recording_id=recording_id,
|
recording_id=recording_id,
|
||||||
blueprint_session_id=blueprint_session_id,
|
blueprint_session_id=blueprint_session_id,
|
||||||
view_reset_generation=view_reset_generation,
|
view_reset_generation=view_reset_generation,
|
||||||
).render(blueprint)
|
).render(
|
||||||
|
build_blueprint,
|
||||||
|
follow_trajectory=follow_trajectory,
|
||||||
|
)
|
||||||
except RecordedBlueprintError:
|
except RecordedBlueprintError:
|
||||||
raise
|
raise
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise RecordedBlueprintError("failed to serialize stable recorded blueprint") from exc
|
raise RecordedBlueprintError("failed to serialize stable recorded blueprint") from exc
|
||||||
else:
|
else:
|
||||||
|
blueprint = build_blueprint(True)
|
||||||
recording = rr.RecordingStream(
|
recording = rr.RecordingStream(
|
||||||
application_id,
|
application_id,
|
||||||
recording_id=recording_id,
|
recording_id=recording_id,
|
||||||
|
|
|
||||||
|
|
@ -465,6 +465,12 @@ def test_recorded_follow_mode_tracks_sensor_pose_with_the_same_orbital_eye() ->
|
||||||
include_initial_playback_state=False,
|
include_initial_playback_state=False,
|
||||||
follow_trajectory=True,
|
follow_trajectory=True,
|
||||||
)
|
)
|
||||||
|
layer_only_update = viewer_recorded_blueprint(
|
||||||
|
RerunSceneSettings(show_grid=False),
|
||||||
|
include_initial_playback_state=False,
|
||||||
|
follow_trajectory=True,
|
||||||
|
update_eye_controls=False,
|
||||||
|
)
|
||||||
|
|
||||||
normal_view = normal.root_container.contents[0]
|
normal_view = normal.root_container.contents[0]
|
||||||
followed_view = followed.root_container.contents[0]
|
followed_view = followed.root_container.contents[0]
|
||||||
|
|
@ -482,6 +488,8 @@ def test_recorded_follow_mode_tracks_sensor_pose_with_the_same_orbital_eye() ->
|
||||||
assert followed_view.id == RECORDED_SPATIAL_VIEW_ID
|
assert followed_view.id == RECORDED_SPATIAL_VIEW_ID
|
||||||
assert followed_again.root_container.contents[0].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 followed_view.id == normal_view.id
|
||||||
|
assert "EyeControls3D" not in layer_only_update.root_container.contents[0].properties
|
||||||
|
assert "EyeControls3D" not in layer_only_update.root_container.contents[2].properties
|
||||||
assert normal_components == {
|
assert normal_components == {
|
||||||
"EyeControls3D:tracking_entity": [""],
|
"EyeControls3D:tracking_entity": [""],
|
||||||
}
|
}
|
||||||
|
|
@ -495,7 +503,9 @@ def test_recorded_blueprint_layer_updates_preserve_store_until_explicit_reset(
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
activations: list[tuple[object, bool, bool]] = []
|
activations: list[tuple[object, bool, bool]] = []
|
||||||
|
eye_control_updates: list[bool] = []
|
||||||
send_blueprint = viewer_recorded_module.bindings.send_blueprint
|
send_blueprint = viewer_recorded_module.bindings.send_blueprint
|
||||||
|
make_blueprint = viewer_recorded_module.recorded_blueprint
|
||||||
|
|
||||||
def capture_activation(
|
def capture_activation(
|
||||||
storage: object,
|
storage: object,
|
||||||
|
|
@ -511,6 +521,16 @@ def test_recorded_blueprint_layer_updates_preserve_store_until_explicit_reset(
|
||||||
"send_blueprint",
|
"send_blueprint",
|
||||||
capture_activation,
|
capture_activation,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def capture_eye_control_update(*args: object, **kwargs: object) -> object:
|
||||||
|
eye_control_updates.append(bool(kwargs["update_eye_controls"]))
|
||||||
|
return make_blueprint(*args, **kwargs)
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
viewer_recorded_module,
|
||||||
|
"recorded_blueprint",
|
||||||
|
capture_eye_control_update,
|
||||||
|
)
|
||||||
session_id = "b" * 32
|
session_id = "b" * 32
|
||||||
initial = viewer_recorded_blueprint_rrd(
|
initial = viewer_recorded_blueprint_rrd(
|
||||||
RerunSceneSettings(accumulation_seconds=12.0),
|
RerunSceneSettings(accumulation_seconds=12.0),
|
||||||
|
|
@ -527,6 +547,26 @@ def test_recorded_blueprint_layer_updates_preserve_store_until_explicit_reset(
|
||||||
show_segmentation=True,
|
show_segmentation=True,
|
||||||
show_cuboids_3d=True,
|
show_cuboids_3d=True,
|
||||||
)
|
)
|
||||||
|
follow_enabled = viewer_recorded_blueprint_rrd(
|
||||||
|
RerunSceneSettings(accumulation_seconds=12.0),
|
||||||
|
recording_id="stable-camera",
|
||||||
|
blueprint_session_id=session_id,
|
||||||
|
unified_perception=True,
|
||||||
|
show_detections_2d=True,
|
||||||
|
show_segmentation=True,
|
||||||
|
show_cuboids_3d=True,
|
||||||
|
follow_trajectory=True,
|
||||||
|
)
|
||||||
|
layer_disabled_while_following = viewer_recorded_blueprint_rrd(
|
||||||
|
RerunSceneSettings(accumulation_seconds=12.0),
|
||||||
|
recording_id="stable-camera",
|
||||||
|
blueprint_session_id=session_id,
|
||||||
|
unified_perception=True,
|
||||||
|
show_detections_2d=False,
|
||||||
|
show_segmentation=True,
|
||||||
|
show_cuboids_3d=True,
|
||||||
|
follow_trajectory=True,
|
||||||
|
)
|
||||||
reset = viewer_recorded_blueprint_rrd(
|
reset = viewer_recorded_blueprint_rrd(
|
||||||
RerunSceneSettings(accumulation_seconds=12.0),
|
RerunSceneSettings(accumulation_seconds=12.0),
|
||||||
recording_id="stable-camera",
|
recording_id="stable-camera",
|
||||||
|
|
@ -536,25 +576,37 @@ def test_recorded_blueprint_layer_updates_preserve_store_until_explicit_reset(
|
||||||
show_detections_2d=True,
|
show_detections_2d=True,
|
||||||
show_segmentation=True,
|
show_segmentation=True,
|
||||||
show_cuboids_3d=True,
|
show_cuboids_3d=True,
|
||||||
|
follow_trajectory=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
store_pattern = rb"rec_[0-9a-f]{32}"
|
store_pattern = rb"rec_[0-9a-f]{32}"
|
||||||
initial_store_ids = set(re.findall(store_pattern, initial))
|
initial_store_ids = set(re.findall(store_pattern, initial))
|
||||||
layer_store_ids = set(re.findall(store_pattern, layers_enabled))
|
layer_store_ids = set(re.findall(store_pattern, layers_enabled))
|
||||||
|
follow_store_ids = set(re.findall(store_pattern, follow_enabled))
|
||||||
|
followed_layer_store_ids = set(re.findall(store_pattern, layer_disabled_while_following))
|
||||||
reset_store_ids = set(re.findall(store_pattern, reset))
|
reset_store_ids = set(re.findall(store_pattern, reset))
|
||||||
assert len(initial_store_ids) == 1
|
assert len(initial_store_ids) == 1
|
||||||
assert layer_store_ids == initial_store_ids
|
assert layer_store_ids == initial_store_ids
|
||||||
|
assert follow_store_ids == initial_store_ids
|
||||||
|
assert followed_layer_store_ids == initial_store_ids
|
||||||
assert len(reset_store_ids) == 1
|
assert len(reset_store_ids) == 1
|
||||||
assert reset_store_ids.isdisjoint(initial_store_ids)
|
assert reset_store_ids.isdisjoint(initial_store_ids)
|
||||||
|
assert eye_control_updates == [True, False, True, False, True]
|
||||||
assert [activation[1:] for activation in activations] == [
|
assert [activation[1:] for activation in activations] == [
|
||||||
(True, False),
|
(True, False),
|
||||||
(True, False),
|
(True, False),
|
||||||
(True, False),
|
(True, False),
|
||||||
|
(True, False),
|
||||||
|
(True, False),
|
||||||
]
|
]
|
||||||
assert activations[0][0] is activations[1][0]
|
assert activations[0][0] is activations[1][0]
|
||||||
assert activations[2][0] is not activations[0][0]
|
assert activations[2][0] is activations[0][0]
|
||||||
|
assert activations[3][0] is activations[0][0]
|
||||||
|
assert activations[4][0] is not activations[0][0]
|
||||||
assert len(initial) < 350_000
|
assert len(initial) < 350_000
|
||||||
assert len(layers_enabled) < 350_000
|
assert len(layers_enabled) < 350_000
|
||||||
|
assert len(follow_enabled) < 350_000
|
||||||
|
assert len(layer_disabled_while_following) < 350_000
|
||||||
assert len(reset) < 350_000
|
assert len(reset) < 350_000
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue