diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/spatial_information.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/spatial_information.fbs index 143287b52665..5b80b0d6595c 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/spatial_information.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/spatial_information.fbs @@ -4,6 +4,11 @@ namespace rerun.blueprint.archetypes; table SpatialInformation ( "attr.rerun.scope": "blueprint" ) { + /// The target reference frame for all transformations. + /// + /// Defaults to the coordinate frame used by the space origin entity. + target_frame: rerun.components.TransformFrameId ("attr.rerun.component_optional", order: 50); + /// Whether axes should be shown at the origin. show_axes: rerun.blueprint.components.Enabled ("attr.rerun.component_optional", nullable, order: 100); diff --git a/crates/store/re_types/src/blueprint/archetypes/spatial_information.rs b/crates/store/re_types/src/blueprint/archetypes/spatial_information.rs index 6fad270fbbac..f7dfbaecac6e 100644 --- a/crates/store/re_types/src/blueprint/archetypes/spatial_information.rs +++ b/crates/store/re_types/src/blueprint/archetypes/spatial_information.rs @@ -26,6 +26,11 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; /// ⚠️ **This type is _unstable_ and may change significantly in a way that the data won't be backwards compatible.** #[derive(Clone, Debug, Default)] pub struct SpatialInformation { + /// The target reference frame for all transformations. + /// + /// Defaults to the frame derived from the space origin. + pub target_frame: Option, + /// Whether axes should be shown at the origin. pub show_axes: Option, @@ -34,6 +39,18 @@ pub struct SpatialInformation { } impl SpatialInformation { + /// Returns the [`ComponentDescriptor`] for [`Self::target_frame`]. + /// + /// The corresponding component is [`crate::components::TransformFrameId`]. + #[inline] + pub fn descriptor_target_frame() -> ComponentDescriptor { + ComponentDescriptor { + archetype: Some("rerun.blueprint.archetypes.SpatialInformation".into()), + component: "SpatialInformation:target_frame".into(), + component_type: Some("rerun.components.TransformFrameId".into()), + } + } + /// Returns the [`ComponentDescriptor`] for [`Self::show_axes`]. /// /// The corresponding component is [`crate::blueprint::components::Enabled`]. @@ -65,25 +82,27 @@ static REQUIRED_COMPONENTS: std::sync::LazyLock<[ComponentDescriptor; 0usize]> = static RECOMMENDED_COMPONENTS: std::sync::LazyLock<[ComponentDescriptor; 0usize]> = std::sync::LazyLock::new(|| []); -static OPTIONAL_COMPONENTS: std::sync::LazyLock<[ComponentDescriptor; 2usize]> = +static OPTIONAL_COMPONENTS: std::sync::LazyLock<[ComponentDescriptor; 3usize]> = std::sync::LazyLock::new(|| { [ + SpatialInformation::descriptor_target_frame(), SpatialInformation::descriptor_show_axes(), SpatialInformation::descriptor_show_bounding_box(), ] }); -static ALL_COMPONENTS: std::sync::LazyLock<[ComponentDescriptor; 2usize]> = +static ALL_COMPONENTS: std::sync::LazyLock<[ComponentDescriptor; 3usize]> = std::sync::LazyLock::new(|| { [ + SpatialInformation::descriptor_target_frame(), SpatialInformation::descriptor_show_axes(), SpatialInformation::descriptor_show_bounding_box(), ] }); impl SpatialInformation { - /// The total number of components in the archetype: 0 required, 0 recommended, 2 optional - pub const NUM_COMPONENTS: usize = 2usize; + /// The total number of components in the archetype: 0 required, 0 recommended, 3 optional + pub const NUM_COMPONENTS: usize = 3usize; } impl ::re_types_core::Archetype for SpatialInformation { @@ -124,6 +143,11 @@ impl ::re_types_core::Archetype for SpatialInformation { re_tracing::profile_function!(); use ::re_types_core::{Loggable as _, ResultExt as _}; let arrays_by_descr: ::nohash_hasher::IntMap<_, _> = arrow_data.into_iter().collect(); + let target_frame = arrays_by_descr + .get(&Self::descriptor_target_frame()) + .map(|array| { + SerializedComponentBatch::new(array.clone(), Self::descriptor_target_frame()) + }); let show_axes = arrays_by_descr .get(&Self::descriptor_show_axes()) .map(|array| { @@ -135,6 +159,7 @@ impl ::re_types_core::Archetype for SpatialInformation { SerializedComponentBatch::new(array.clone(), Self::descriptor_show_bounding_box()) }); Ok(Self { + target_frame, show_axes, show_bounding_box, }) @@ -145,10 +170,14 @@ impl ::re_types_core::AsComponents for SpatialInformation { #[inline] fn as_serialized_batches(&self) -> Vec { use ::re_types_core::Archetype as _; - [self.show_axes.clone(), self.show_bounding_box.clone()] - .into_iter() - .flatten() - .collect() + [ + self.target_frame.clone(), + self.show_axes.clone(), + self.show_bounding_box.clone(), + ] + .into_iter() + .flatten() + .collect() } } @@ -157,8 +186,9 @@ impl ::re_types_core::ArchetypeReflectionMarker for SpatialInformation {} impl SpatialInformation { /// Create a new `SpatialInformation`. #[inline] - pub fn new() -> Self { + pub fn new(target_frame: impl Into) -> Self { Self { + target_frame: try_serialize_field(Self::descriptor_target_frame(), [target_frame]), show_axes: None, show_bounding_box: None, } @@ -175,6 +205,10 @@ impl SpatialInformation { pub fn clear_fields() -> Self { use ::re_types_core::Loggable as _; Self { + target_frame: Some(SerializedComponentBatch::new( + crate::components::TransformFrameId::arrow_empty(), + Self::descriptor_target_frame(), + )), show_axes: Some(SerializedComponentBatch::new( crate::blueprint::components::Enabled::arrow_empty(), Self::descriptor_show_axes(), @@ -186,6 +220,18 @@ impl SpatialInformation { } } + /// The target reference frame for all transformations. + /// + /// Defaults to the frame derived from the space origin. + #[inline] + pub fn with_target_frame( + mut self, + target_frame: impl Into, + ) -> Self { + self.target_frame = try_serialize_field(Self::descriptor_target_frame(), [target_frame]); + self + } + /// Whether axes should be shown at the origin. #[inline] pub fn with_show_axes( @@ -211,6 +257,8 @@ impl SpatialInformation { impl ::re_byte_size::SizeBytes for SpatialInformation { #[inline] fn heap_size_bytes(&self) -> u64 { - self.show_axes.heap_size_bytes() + self.show_bounding_box.heap_size_bytes() + self.target_frame.heap_size_bytes() + + self.show_axes.heap_size_bytes() + + self.show_bounding_box.heap_size_bytes() } } diff --git a/crates/store/re_types/src/reflection/mod.rs b/crates/store/re_types/src/reflection/mod.rs index d7d6dbb44391..c31e08f545c1 100644 --- a/crates/store/re_types/src/reflection/mod.rs +++ b/crates/store/re_types/src/reflection/mod.rs @@ -3927,6 +3927,13 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { scope: Some("blueprint"), view_types: &[], fields: vec![ + ArchetypeFieldReflection { + name: "target_frame", + display_name: "Target frame", + component_type: "rerun.components.TransformFrameId".into(), + docstring_md: "The target reference frame for all transformations.\n\nDefaults to the frame derived from the space origin.", + is_required: false, + }, ArchetypeFieldReflection { name: "show_axes", display_name: "Show axes", diff --git a/crates/viewer/re_component_ui/src/lib.rs b/crates/viewer/re_component_ui/src/lib.rs index 8e3bd51fadfc..00a8aa7faa75 100644 --- a/crates/viewer/re_component_ui/src/lib.rs +++ b/crates/viewer/re_component_ui/src/lib.rs @@ -48,8 +48,8 @@ use re_types::{ AggregationPolicy, AlbedoFactor, AxisLength, Color, DepthMeter, DrawOrder, FillMode, FillRatio, GammaCorrection, GraphType, ImagePlaneDistance, LinearSpeed, MagnificationFilter, MarkerSize, Name, Opacity, Position2D, Position3D, Range1D, Scale3D, - SeriesVisible, ShowLabels, StrokeWidth, Text, Timestamp, TransformRelation, Translation3D, - ValueRange, Vector3D, VideoCodec, Visible, + SeriesVisible, ShowLabels, StrokeWidth, Text, Timestamp, TransformFrameId, + TransformRelation, Translation3D, ValueRange, Vector3D, VideoCodec, Visible, }, }; use re_viewer_context::gpu_bridge::colormap_edit_or_view_ui; @@ -121,6 +121,7 @@ pub fn create_component_ui_registry() -> re_viewer_context::ComponentUiRegistry registry.add_multiline_edit_or_view::(edit_multiline_string); registry.add_singleline_edit_or_view::(edit_singleline_string); registry.add_multiline_edit_or_view::(edit_multiline_string); + registry.add_singleline_edit_or_view::(edit_singleline_string); // Enums: // TODO(#6974): Enums editors trivial and always the same, provide them automatically! diff --git a/crates/viewer/re_view_spatial/src/contexts/mod.rs b/crates/viewer/re_view_spatial/src/contexts/mod.rs index 2ffd3341da21..5701ce6a69f1 100644 --- a/crates/viewer/re_view_spatial/src/contexts/mod.rs +++ b/crates/viewer/re_view_spatial/src/contexts/mod.rs @@ -6,7 +6,7 @@ use re_tf::TransformInfo; use re_types::ViewClassIdentifier; use re_view::AnnotationSceneContext; -pub use transform_tree_context::TransformTreeContext; +pub use transform_tree_context::{TransformTreeContext, UNKNOWN_SPACE_ORIGIN}; // ----------------------------------------------------------------------------- diff --git a/crates/viewer/re_view_spatial/src/contexts/transform_tree_context.rs b/crates/viewer/re_view_spatial/src/contexts/transform_tree_context.rs index cef0a6ae6417..6826433a1cf6 100644 --- a/crates/viewer/re_view_spatial/src/contexts/transform_tree_context.rs +++ b/crates/viewer/re_view_spatial/src/contexts/transform_tree_context.rs @@ -4,16 +4,23 @@ use nohash_hasher::IntMap; use re_chunk_store::LatestAtQuery; use re_log_types::EntityPathHash; use re_tf::{TransformFrameId, TransformFrameIdHash}; -use re_types::{archetypes, components::ImagePlaneDistance}; +use re_types::{archetypes, blueprint, components::ImagePlaneDistance}; use re_view::{DataResultQuery as _, latest_at_with_blueprint_resolved_data}; use re_viewer_context::{ DataResult, IdentifiedViewSystem, TransformDatabaseStoreCache, ViewContext, ViewContextSystem, ViewContextSystemOncePerFrameResult, typed_fallback_for, }; +use re_viewport_blueprint::ViewProperty; use vec1::smallvec_v1::SmallVec1; type FrameIdMapping = IntMap; +/// Currently, there is no straightforward way to retrieve the space origin +/// when registering fallbacks. So, if unknown we set the target frame to a +/// dummy string and rely on the view to supply that information after the +/// first frame. +pub const UNKNOWN_SPACE_ORIGIN: &str = ""; + /// Provides a transform tree for the view & time it operates on. /// /// Will do the necessary bulk processing of transform information and make it available @@ -106,8 +113,35 @@ impl ViewContextSystem for TransformTreeContext { // Currently, we don't keep it around during the frame, but we may do so in the future. self.entity_transform_id_mapping = EntityTransformIdMapping::new(ctx, query); - // Target frame is the coordinate frame of the space origin entity. - self.target_frame = self.transform_frame_id_for(query.space_origin.hash()); + // Target frame - check for blueprint override first, otherwise use space origin's coordinate frame. + self.target_frame = { + let spatial_info_prop = ViewProperty::from_archetype::< + blueprint::archetypes::SpatialInformation, + >( + ctx.blueprint_db(), ctx.blueprint_query(), ctx.view_id + ); + + let target_frame_component = spatial_info_prop + .component_or_fallback::( + ctx, + blueprint::archetypes::SpatialInformation::descriptor_target_frame().component, + ); + + match target_frame_component { + Ok(target_frame) => { + let target_frame_str = target_frame.as_str(); + if target_frame_str == UNKNOWN_SPACE_ORIGIN { + self.transform_frame_id_for(query.space_origin.hash()) + } else { + TransformFrameIdHash::from_str(target_frame.as_str()) + } + } + Err(err) => { + re_log::error_once!("Failed to query target frame: {err}"); + self.transform_frame_id_for(query.space_origin.hash()) + } + } + }; let latest_at_query = query.latest_at_query(); diff --git a/crates/viewer/re_view_spatial/src/shared_fallbacks.rs b/crates/viewer/re_view_spatial/src/shared_fallbacks.rs index 88c498a651cb..19dd99e82481 100644 --- a/crates/viewer/re_view_spatial/src/shared_fallbacks.rs +++ b/crates/viewer/re_view_spatial/src/shared_fallbacks.rs @@ -1,4 +1,4 @@ -use re_types::{archetypes, components, image::ImageKind}; +use re_types::{archetypes, blueprint, components, image::ImageKind}; use re_view::DataResultQuery as _; use re_viewer_context::{IdentifiedViewSystem as _, QueryContext, ViewStateExt as _}; diff --git a/crates/viewer/re_view_spatial/src/ui.rs b/crates/viewer/re_view_spatial/src/ui.rs index 0f4d028363a5..8d4fbf258dc0 100644 --- a/crates/viewer/re_view_spatial/src/ui.rs +++ b/crates/viewer/re_view_spatial/src/ui.rs @@ -65,6 +65,10 @@ pub struct SpatialViewState { pub pinhole_at_origin: Option, pub visual_bounds_2d: Option, + + /// The target frame, i.e., the coordinate frame that transforms are resolved to. + /// Computed from the space origin via the transform tree. + pub target_frame: Option, } impl ViewState for SpatialViewState { diff --git a/crates/viewer/re_view_spatial/src/view_2d.rs b/crates/viewer/re_view_spatial/src/view_2d.rs index 33adb9ca7594..5803ae415e82 100644 --- a/crates/viewer/re_view_spatial/src/view_2d.rs +++ b/crates/viewer/re_view_spatial/src/view_2d.rs @@ -13,7 +13,7 @@ use re_viewer_context::{ }; use crate::{ - contexts::register_spatial_contexts, + contexts::{TransformTreeContext, register_spatial_contexts}, heuristics::default_visualized_entities_for_visualizer_kind, max_image_dimension_subscriber::{ImageTypes, MaxDimensions}, shared_fallbacks, @@ -259,6 +259,11 @@ impl ViewClass for SpatialView2D { let state = state.downcast_mut::()?; state.update_frame_statistics(ui, &system_output, SpatialViewKind::TwoD); + // Store the target frame for display in the selection panel + if let Ok(transforms) = system_output.context_systems.get::() { + state.target_frame = Some(transforms.format_frame(transforms.target_frame())); + } + self.view_2d(ctx, ui, state, query, system_output) } } diff --git a/crates/viewer/re_view_spatial/src/view_3d.rs b/crates/viewer/re_view_spatial/src/view_3d.rs index b21c46f06b4a..716cb74fb32b 100644 --- a/crates/viewer/re_view_spatial/src/view_3d.rs +++ b/crates/viewer/re_view_spatial/src/view_3d.rs @@ -11,7 +11,7 @@ use re_types::{ archetypes::{Background, EyeControls3D, LineGrid3D, SpatialInformation}, components::Eye3DKind, }, - components::{LinearSpeed, Plane3D, Position3D, Vector3D}, + components::{LinearSpeed, Plane3D, Position3D, TransformFrameId, Vector3D}, datatypes::Vec3D, view_coordinates::SignedAxis3, }; @@ -27,7 +27,7 @@ use re_viewer_context::{ use re_viewport_blueprint::ViewProperty; use crate::{ - contexts::register_spatial_contexts, + contexts::{TransformTreeContext, UNKNOWN_SPACE_ORIGIN, register_spatial_contexts}, heuristics::default_visualized_entities_for_visualizer_kind, spatial_topology::{HeuristicHints, SpatialTopology, SubSpaceConnectionFlags}, ui::SpatialViewState, @@ -251,6 +251,24 @@ impl ViewClass for SpatialView3D { }, ); + system_registry.register_fallback_provider( + SpatialInformation::descriptor_target_frame().component, + |ctx| { + let unknown_space_origin = || TransformFrameId(UNKNOWN_SPACE_ORIGIN.into()); + + let Ok(state) = ctx.view_state().downcast_ref::() else { + return unknown_space_origin(); + }; + + // Return the computed target frame from the view state + state + .target_frame + .as_ref() + .map(|frame_str| TransformFrameId(frame_str.clone().into())) + .unwrap_or_else(unknown_space_origin) + }, + ); + shared_fallbacks::register_fallbacks(system_registry); // Ensure spatial topology is registered. @@ -515,10 +533,10 @@ impl ViewClass for SpatialView3D { re_ui::list_item::list_item_scope(ui, "spatial_view3d_selection_ui", |ui| { let view_ctx = self.view_context(ctx, view_id, state); + view_property_ui::(&view_ctx, ui); view_property_ui::(&view_ctx, ui); view_property_ui::(&view_ctx, ui); view_property_ui_grid3d(&view_ctx, ui); - view_property_ui::(&view_ctx, ui); }); Ok(()) @@ -538,6 +556,11 @@ impl ViewClass for SpatialView3D { let state = state.downcast_mut::()?; state.update_frame_statistics(ui, &system_output, SpatialViewKind::ThreeD); + // Store the target frame for display in the selection panel + if let Ok(transforms) = system_output.context_systems.get::() { + state.target_frame = Some(transforms.format_frame(transforms.target_frame())); + } + self.view_3d(ctx, ui, state, query, system_output) } } diff --git a/crates/viewer/re_viewer/tests/snapshots/all_component_fallbacks__arch_fallback_rerun.blueprint.archetypes.SpatialInformation.snap b/crates/viewer/re_viewer/tests/snapshots/all_component_fallbacks__arch_fallback_rerun.blueprint.archetypes.SpatialInformation.snap index a9cb42ccb961..77d168810367 100644 --- a/crates/viewer/re_viewer/tests/snapshots/all_component_fallbacks__arch_fallback_rerun.blueprint.archetypes.SpatialInformation.snap +++ b/crates/viewer/re_viewer/tests/snapshots/all_component_fallbacks__arch_fallback_rerun.blueprint.archetypes.SpatialInformation.snap @@ -2,5 +2,6 @@ source: crates/viewer/re_viewer/tests/all_component_fallbacks.rs expression: arch_display --- +target_frame: [] show_axes: [false] show_bounding_box: [false] diff --git a/crates/viewer/re_viewer/tests/snapshots/all_view_selection_uis/Dark/3D.png b/crates/viewer/re_viewer/tests/snapshots/all_view_selection_uis/Dark/3D.png index b451a981789c..9f3c3e7d30ac 100644 --- a/crates/viewer/re_viewer/tests/snapshots/all_view_selection_uis/Dark/3D.png +++ b/crates/viewer/re_viewer/tests/snapshots/all_view_selection_uis/Dark/3D.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c753a2ee1c97e0e843430e345a516f824901bf8a8e351a9ce2638a4b27df3018 -size 67827 +oid sha256:3c9dfbd5723bc2b5ef3b610b11213bbd00bae902a274b7da56d6e86678630499 +size 69073 diff --git a/crates/viewer/re_viewer/tests/snapshots/all_view_selection_uis/Light/3D.png b/crates/viewer/re_viewer/tests/snapshots/all_view_selection_uis/Light/3D.png index 27062d2dfdf8..2a95c8689ae9 100644 --- a/crates/viewer/re_viewer/tests/snapshots/all_view_selection_uis/Light/3D.png +++ b/crates/viewer/re_viewer/tests/snapshots/all_view_selection_uis/Light/3D.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a94f15a1527e6e16fb5a9fe3b56c5b6a03f12d9fa1316dcbcd6cd9579b1cefc2 -size 67830 +oid sha256:373389b0dafb7d6100f0cd7e40e78a3a9d940250c2633af912609008849fd796 +size 69031 diff --git a/docs/content/reference/types/views/spatial3d_view.md b/docs/content/reference/types/views/spatial3d_view.md index c5d66e42a50e..d0bf2296b82f 100644 --- a/docs/content/reference/types/views/spatial3d_view.md +++ b/docs/content/reference/types/views/spatial3d_view.md @@ -24,6 +24,7 @@ Configuration for the 3D line grid. ### `spatial_information` Configuration of debug drawing in the 3D view. +* `target_frame`: The target reference frame for all transformations. * `show_axes`: Whether axes should be shown at the origin. * `show_bounding_box`: Whether the bounding box should be shown. ### `eye_controls` diff --git a/docs/snippets/all/views/spatial3d.py b/docs/snippets/all/views/spatial3d.py index 6d86a62b0cc9..9427e795e2c3 100644 --- a/docs/snippets/all/views/spatial3d.py +++ b/docs/snippets/all/views/spatial3d.py @@ -41,6 +41,7 @@ color=[255, 255, 255, 128], # Colors the grid a half-transparent white. ), spatial_information=rrb.SpatialInformation( + target_frame="tf#/", show_axes=True, show_bounding_box=True, ), diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/spatial_information.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/spatial_information.cpp index 80c511619f74..58997a6fa771 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/spatial_information.cpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/spatial_information.cpp @@ -8,6 +8,9 @@ namespace rerun::blueprint::archetypes { SpatialInformation SpatialInformation::clear_fields() { auto archetype = SpatialInformation(); + archetype.target_frame = + ComponentBatch::empty(Descriptor_target_frame) + .value_or_throw(); archetype.show_axes = ComponentBatch::empty(Descriptor_show_axes) .value_or_throw(); @@ -20,7 +23,10 @@ namespace rerun::blueprint::archetypes { Collection SpatialInformation::columns(const Collection& lengths_) { std::vector columns; - columns.reserve(2); + columns.reserve(3); + if (target_frame.has_value()) { + columns.push_back(target_frame.value().partitioned(lengths_).value_or_throw()); + } if (show_axes.has_value()) { columns.push_back(show_axes.value().partitioned(lengths_).value_or_throw()); } @@ -31,6 +37,9 @@ namespace rerun::blueprint::archetypes { } Collection SpatialInformation::columns() { + if (target_frame.has_value()) { + return columns(std::vector(target_frame.value().length(), 1)); + } if (show_axes.has_value()) { return columns(std::vector(show_axes.value().length(), 1)); } @@ -49,8 +58,11 @@ namespace rerun { ) { using namespace blueprint::archetypes; std::vector cells; - cells.reserve(2); + cells.reserve(3); + if (archetype.target_frame.has_value()) { + cells.push_back(archetype.target_frame.value()); + } if (archetype.show_axes.has_value()) { cells.push_back(archetype.show_axes.value()); } diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/spatial_information.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/spatial_information.hpp index 0c99f4386784..102b1b4bb227 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/spatial_information.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/spatial_information.hpp @@ -7,6 +7,7 @@ #include "../../collection.hpp" #include "../../component_batch.hpp" #include "../../component_column.hpp" +#include "../../components/transform_frame_id.hpp" #include "../../result.hpp" #include @@ -20,6 +21,11 @@ namespace rerun::blueprint::archetypes { /// ⚠ **This type is _unstable_ and may change significantly in a way that the data won't be backwards compatible.** /// struct SpatialInformation { + /// The target reference frame for all transformations. + /// + /// Defaults to the frame derived from the space origin. + std::optional target_frame; + /// Whether axes should be shown at the origin. std::optional show_axes; @@ -31,6 +37,11 @@ namespace rerun::blueprint::archetypes { static constexpr const char ArchetypeName[] = "rerun.blueprint.archetypes.SpatialInformation"; + /// `ComponentDescriptor` for the `target_frame` field. + static constexpr auto Descriptor_target_frame = ComponentDescriptor( + ArchetypeName, "SpatialInformation:target_frame", + Loggable::ComponentType + ); /// `ComponentDescriptor` for the `show_axes` field. static constexpr auto Descriptor_show_axes = ComponentDescriptor( ArchetypeName, "SpatialInformation:show_axes", @@ -49,6 +60,12 @@ namespace rerun::blueprint::archetypes { SpatialInformation& operator=(const SpatialInformation& other) = default; SpatialInformation& operator=(SpatialInformation&& other) = default; + explicit SpatialInformation(rerun::components::TransformFrameId _target_frame) + : target_frame( + ComponentBatch::from_loggable(std::move(_target_frame), Descriptor_target_frame) + .value_or_throw() + ) {} + /// Update only some specific fields of a `SpatialInformation`. static SpatialInformation update_fields() { return SpatialInformation(); @@ -57,6 +74,17 @@ namespace rerun::blueprint::archetypes { /// Clear all the fields of a `SpatialInformation`. static SpatialInformation clear_fields(); + /// The target reference frame for all transformations. + /// + /// Defaults to the frame derived from the space origin. + SpatialInformation with_target_frame( + const rerun::components::TransformFrameId& _target_frame + ) && { + target_frame = ComponentBatch::from_loggable(_target_frame, Descriptor_target_frame) + .value_or_throw(); + return std::move(*this); + } + /// Whether axes should be shown at the origin. SpatialInformation with_show_axes(const rerun::blueprint::components::Enabled& _show_axes ) && { diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/spatial_information.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/spatial_information.py index 1b1b8146ef65..058463211d78 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/spatial_information.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/spatial_information.py @@ -5,19 +5,17 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import Any from attrs import define, field +from ... import components, datatypes from ..._baseclasses import ( Archetype, ) from ...blueprint import components as blueprint_components from ...error_utils import catch_and_log_exceptions -if TYPE_CHECKING: - from ... import datatypes - __all__ = ["SpatialInformation"] @@ -30,13 +28,21 @@ class SpatialInformation(Archetype): """ def __init__( - self: Any, *, show_axes: datatypes.BoolLike | None = None, show_bounding_box: datatypes.BoolLike | None = None + self: Any, + target_frame: datatypes.Utf8Like, + *, + show_axes: datatypes.BoolLike | None = None, + show_bounding_box: datatypes.BoolLike | None = None, ) -> None: """ Create a new instance of the SpatialInformation archetype. Parameters ---------- + target_frame: + The target reference frame for all transformations. + + Defaults to the frame derived from the space origin. show_axes: Whether axes should be shown at the origin. show_bounding_box: @@ -46,13 +52,14 @@ def __init__( # You can define your own __init__ function as a member of SpatialInformationExt in spatial_information_ext.py with catch_and_log_exceptions(context=self.__class__.__name__): - self.__attrs_init__(show_axes=show_axes, show_bounding_box=show_bounding_box) + self.__attrs_init__(target_frame=target_frame, show_axes=show_axes, show_bounding_box=show_bounding_box) return self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" self.__attrs_init__( + target_frame=None, show_axes=None, show_bounding_box=None, ) @@ -69,6 +76,7 @@ def from_fields( cls, *, clear_unset: bool = False, + target_frame: datatypes.Utf8Like | None = None, show_axes: datatypes.BoolLike | None = None, show_bounding_box: datatypes.BoolLike | None = None, ) -> SpatialInformation: @@ -79,6 +87,10 @@ def from_fields( ---------- clear_unset: If true, all unspecified fields will be explicitly cleared. + target_frame: + The target reference frame for all transformations. + + Defaults to the frame derived from the space origin. show_axes: Whether axes should be shown at the origin. show_bounding_box: @@ -89,6 +101,7 @@ def from_fields( inst = cls.__new__(cls) with catch_and_log_exceptions(context=cls.__name__): kwargs = { + "target_frame": target_frame, "show_axes": show_axes, "show_bounding_box": show_bounding_box, } @@ -107,6 +120,17 @@ def cleared(cls) -> SpatialInformation: """Clear all the fields of a `SpatialInformation`.""" return cls.from_fields(clear_unset=True) + target_frame: components.TransformFrameIdBatch | None = field( + metadata={"component": True}, + default=None, + converter=components.TransformFrameIdBatch._converter, # type: ignore[misc] + ) + # The target reference frame for all transformations. + # + # Defaults to the frame derived from the space origin. + # + # (Docstring intentionally commented out to hide this field from the docs) + show_axes: blueprint_components.EnabledBatch | None = field( metadata={"component": True}, default=None, diff --git a/rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py b/rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py index 6bfae663740c..a36ffeaa768c 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py @@ -73,6 +73,7 @@ class Spatial3DView(View): color=[255, 255, 255, 128], # Colors the grid a half-transparent white. ), spatial_information=rrb.SpatialInformation( + target_frame="tf#/", show_axes=True, show_bounding_box=True, ), diff --git a/tests/rust/re_integration_test/tests/snapshots/add_entity_to_view_boxes3d_3.png b/tests/rust/re_integration_test/tests/snapshots/add_entity_to_view_boxes3d_3.png index 1ede45470e93..8fb761f7e91a 100644 --- a/tests/rust/re_integration_test/tests/snapshots/add_entity_to_view_boxes3d_3.png +++ b/tests/rust/re_integration_test/tests/snapshots/add_entity_to_view_boxes3d_3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c64484e6e8b52e1d4a43fb671f5bf57820bbb272f6207e66d65bb6521ea2266d -size 222665 +oid sha256:604811d71df99d600752da400f4e6dc63a2a95b9fa5782e37cb7486420100555 +size 225768 diff --git a/tests/rust/re_integration_test/tests/snapshots/add_entity_to_view_boxes3d_4.png b/tests/rust/re_integration_test/tests/snapshots/add_entity_to_view_boxes3d_4.png index 84c515805e5c..359520d96661 100644 --- a/tests/rust/re_integration_test/tests/snapshots/add_entity_to_view_boxes3d_4.png +++ b/tests/rust/re_integration_test/tests/snapshots/add_entity_to_view_boxes3d_4.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4220e036880049d57f0872624a5a2886640c8aab2c2174d1ce5330d9f9a6712a -size 238230 +oid sha256:a301620bba9c92a07e7da88a0307757570b2398149bc6c160865d1300f529151 +size 241321 diff --git a/tests/rust/re_integration_test/tests/snapshots/add_visualizer_axes_2.png b/tests/rust/re_integration_test/tests/snapshots/add_visualizer_axes_2.png index c8d517ccb205..2727f59b9c58 100644 --- a/tests/rust/re_integration_test/tests/snapshots/add_visualizer_axes_2.png +++ b/tests/rust/re_integration_test/tests/snapshots/add_visualizer_axes_2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51f150935371956a78fdf88793017272eb1d8e09e4b39efad3e476ef0c33540b -size 186507 +oid sha256:22181bae7e7272a9708d812373b3158628ed4fe829ee6687faabf0e33aefab0d +size 188826 diff --git a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_2.png b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_2.png index 7f6d7f2f75f8..303b08addcd3 100644 --- a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_2.png +++ b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73c83ce4373fd8dc0ca8a3b1baced70e57330cfd3785881bac4c453a22c30a43 -size 183950 +oid sha256:f93d6cf486c6598be8b720ec2e4431cd60711dedd4299b32c580e09ca3ffc740 +size 177058 diff --git a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_3.png b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_3.png index d2ef932694a8..57ddf6648aaa 100644 --- a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_3.png +++ b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e45076568bca0dc74b065a0b83094273046a016dd3c63ca33353031cc0bb90f -size 174511 +oid sha256:e4c57d7e6ff69ea51ce58c82dd427d11f3295f6bdb227121ad4d21d4d8533cab +size 150943 diff --git a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_4.png b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_4.png index ffac29ab2d19..e0c08460dd8e 100644 --- a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_4.png +++ b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_4.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e3b135ad6368d8a56d31b5ba0cc9a7089e9c5d5b66ffc02c724d61e435bc13c -size 213332 +oid sha256:28b97d30e95f521677b3eb349e15eb4b77ada22dc6a4ed5de0c67b22d609096a +size 215936 diff --git a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_5.png b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_5.png index a10325e2a2b2..a314905a5830 100644 --- a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_5.png +++ b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24d06cfe6237fb2571c8da889536d8a4ac922b45a4f83fa05b35800e9e1deec2 -size 174738 +oid sha256:a27c9af0b947ec0644e0fde2dc75a5548889ad4bac801b4a9ae56332c88fa5cd +size 177063 diff --git a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_6.png b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_6.png index 6ef87cc6c00d..f666556df857 100644 --- a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_6.png +++ b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_6.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:40fbf6dffa9d8ab785115472bd71ec49c120f08f1dbc1e8119ab763141097d7c -size 191658 +oid sha256:f65f79a30a3a0c7c1a0c5a8edcfcb24db4b283231bfeb86c8ebc138bf033541e +size 193958 diff --git a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_7.png b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_7.png index a10325e2a2b2..a314905a5830 100644 --- a/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_7.png +++ b/tests/rust/re_integration_test/tests/snapshots/deselect_on_escape_7.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24d06cfe6237fb2571c8da889536d8a4ac922b45a4f83fa05b35800e9e1deec2 -size 174738 +oid sha256:a27c9af0b947ec0644e0fde2dc75a5548889ad4bac801b4a9ae56332c88fa5cd +size 177063 diff --git a/tests/rust/re_integration_test/tests/snapshots/origin_camera_3d.png b/tests/rust/re_integration_test/tests/snapshots/origin_camera_3d.png index f39d54802219..689b59d55c21 100644 --- a/tests/rust/re_integration_test/tests/snapshots/origin_camera_3d.png +++ b/tests/rust/re_integration_test/tests/snapshots/origin_camera_3d.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd029f681e1523492009dd99bcf4f7327bf96492d16678d2b89def9abdde2204 -size 202112 +oid sha256:5531c9ec044a25d3d9e5ea9092ddd0058e30d2e2763bdeb42c78b470e681da0e +size 198422 diff --git a/tests/rust/re_integration_test/tests/snapshots/origin_image_3d.png b/tests/rust/re_integration_test/tests/snapshots/origin_image_3d.png index a622c7b51dc0..da7b5cb47080 100644 --- a/tests/rust/re_integration_test/tests/snapshots/origin_image_3d.png +++ b/tests/rust/re_integration_test/tests/snapshots/origin_image_3d.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f1b6e06130fa9a93469c7208b4cdb0407cfed3deddd869c545849d6267fbec3 -size 202934 +oid sha256:bd4c805a7e56c39ffb996d2f1ad537774bc35724468f1e971304659112fb23b9 +size 199245 diff --git a/tests/rust/re_integration_test/tests/snapshots/origin_keypoint_3d.png b/tests/rust/re_integration_test/tests/snapshots/origin_keypoint_3d.png index c43ef1409efc..2473572aeab4 100644 --- a/tests/rust/re_integration_test/tests/snapshots/origin_keypoint_3d.png +++ b/tests/rust/re_integration_test/tests/snapshots/origin_keypoint_3d.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7989b081f4f99a4499efd9eadc7e82ede003a98817655d2dc51c32590c1d907d -size 198541 +oid sha256:189b8fa55af4ebbefdb1d76d1af37d58db8e9e0f821a803effbcabb2aed9d367 +size 194853 diff --git a/tests/rust/re_integration_test/tests/snapshots/origin_root_3d.png b/tests/rust/re_integration_test/tests/snapshots/origin_root_3d.png index d003edea35b6..930269e2551f 100644 --- a/tests/rust/re_integration_test/tests/snapshots/origin_root_3d.png +++ b/tests/rust/re_integration_test/tests/snapshots/origin_root_3d.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b81e0a64355f84edf4a2998e97e1ed22f3e6872a118db26be08a165abed03fab -size 214997 +oid sha256:7d15c20619c76c038d9126746bf1aa03cc31b1bec6a2f678d22b0a1cc9fde4a5 +size 210022 diff --git a/tests/rust/re_integration_test/tests/snapshots/origin_world_3d.png b/tests/rust/re_integration_test/tests/snapshots/origin_world_3d.png index 0b7090d4f01b..58bdd20a3955 100644 --- a/tests/rust/re_integration_test/tests/snapshots/origin_world_3d.png +++ b/tests/rust/re_integration_test/tests/snapshots/origin_world_3d.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ea16ab0b8a3e354da2a6e10ea4d6242d87a63ad6e760b1f28746d5b211c56bf -size 201086 +oid sha256:cf93f95505092d2b247814a6ba5519f720187c16061894ecbf4398bddcc33f86 +size 197403