diff --git a/Cargo.lock b/Cargo.lock index b409b8c2cac1..5216e431fa74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4820,6 +4820,7 @@ dependencies = [ "re_log", "re_log_types", "re_renderer", + "re_space_view", "re_space_view_spatial", "re_space_view_time_series", "re_tracing", diff --git a/crates/re_entity_db/src/entity_properties.rs b/crates/re_entity_db/src/entity_properties.rs index 794b2e81324f..9518682af83e 100644 --- a/crates/re_entity_db/src/entity_properties.rs +++ b/crates/re_entity_db/src/entity_properties.rs @@ -99,11 +99,6 @@ pub struct EntityProperties { /// What kind of color mapping should be applied (none, map, texture, transfer..)? pub color_mapper: EditableAutoValue, // TODO(andreas): should become a component and be part of the DepthImage and regular Images (with limitation to mono channel image). - /// Distance of the projection plane (frustum far plane). - /// - /// Only applies to pinhole cameras when in a spatial view, using 3D navigation. - pub pinhole_image_plane_distance: EditableAutoValue, // TODO(#6084): should be a regular component on the Pinhole archetype. - /// Should the depth texture be backprojected into a point cloud? /// /// Only applies to tensors with meaning=depth that are affected by a pinhole transform. @@ -149,7 +144,6 @@ impl Default for EntityProperties { Self { interactive: true, color_mapper: EditableAutoValue::default(), - pinhole_image_plane_distance: EditableAutoValue::Auto(1.0), backproject_depth: EditableAutoValue::Auto(true), depth_from_world_scale: EditableAutoValue::Auto(1.0), backproject_radius_scale: EditableAutoValue::Auto(1.0), @@ -171,11 +165,6 @@ impl EntityProperties { color_mapper: self.color_mapper.or(&child.color_mapper).clone(), - pinhole_image_plane_distance: self - .pinhole_image_plane_distance - .or(&child.pinhole_image_plane_distance) - .clone(), - backproject_depth: self.backproject_depth.or(&child.backproject_depth).clone(), depth_from_world_scale: self .depth_from_world_scale @@ -214,11 +203,6 @@ impl EntityProperties { color_mapper: other.color_mapper.or(&self.color_mapper).clone(), - pinhole_image_plane_distance: other - .pinhole_image_plane_distance - .or(&self.pinhole_image_plane_distance) - .clone(), - backproject_depth: other.backproject_depth.or(&self.backproject_depth).clone(), depth_from_world_scale: other .depth_from_world_scale @@ -249,7 +233,6 @@ impl EntityProperties { let Self { interactive, color_mapper, - pinhole_image_plane_distance, backproject_depth, depth_from_world_scale, backproject_radius_scale, @@ -262,7 +245,6 @@ impl EntityProperties { interactive != &other.interactive || color_mapper.has_edits(&other.color_mapper) - || pinhole_image_plane_distance.has_edits(&other.pinhole_image_plane_distance) || backproject_depth.has_edits(&other.backproject_depth) || depth_from_world_scale.has_edits(&other.depth_from_world_scale) || backproject_radius_scale.has_edits(&other.backproject_radius_scale) diff --git a/crates/re_query/src/promise.rs b/crates/re_query/src/promise.rs index 702544b2f0c2..54666232a2db 100644 --- a/crates/re_query/src/promise.rs +++ b/crates/re_query/src/promise.rs @@ -67,7 +67,7 @@ impl Promise { // --- /// Resolves and keeps track of [`Promise`]s. -#[derive(Default)] +#[derive(Debug, Default)] pub struct PromiseResolver {} impl PromiseResolver { diff --git a/crates/re_selection_panel/Cargo.toml b/crates/re_selection_panel/Cargo.toml index 203a1717fa06..b6fa6b3c090e 100644 --- a/crates/re_selection_panel/Cargo.toml +++ b/crates/re_selection_panel/Cargo.toml @@ -26,6 +26,7 @@ re_entity_db = { workspace = true, features = ["serde"] } re_log.workspace = true re_log_types.workspace = true re_renderer.workspace = true +re_space_view.workspace = true re_space_view_time_series.workspace = true re_space_view_spatial.workspace = true re_tracing.workspace = true diff --git a/crates/re_selection_panel/src/selection_panel.rs b/crates/re_selection_panel/src/selection_panel.rs index 0c4db45c155d..009c786d32a4 100644 --- a/crates/re_selection_panel/src/selection_panel.rs +++ b/crates/re_selection_panel/src/selection_panel.rs @@ -11,18 +11,22 @@ use re_entity_db::{ ColorMapper, Colormap, EditableAutoValue, EntityPath, EntityProperties, InstancePath, }; use re_log_types::EntityPathFilter; +use re_space_view::DataResultQuery as _; use re_space_view_time_series::TimeSeriesSpaceView; use re_types::{ - components::{PinholeProjection, Transform3D}, + archetypes::Pinhole, + components::{ImagePlaneDistance, PinholeProjection, Transform3D}, tensor_data::TensorDataMeaning, }; use re_ui::{icons, list_item, ContextExt as _, DesignTokens, SyntaxHighlighting as _, UiExt as _}; use re_viewer_context::{ contents_name_style, gpu_bridge::colormap_dropdown_button_ui, icon_for_container_kind, - ContainerId, Contents, DataQueryResult, HoverHighlight, Item, SpaceViewClass, SpaceViewId, - UiLayout, ViewStates, ViewerContext, + ContainerId, Contents, DataQueryResult, DataResult, HoverHighlight, Item, SpaceViewClass, + SpaceViewId, UiLayout, ViewContext, ViewStates, ViewerContext, +}; +use re_viewport_blueprint::{ + ui::show_add_space_view_or_container_modal, SpaceViewBlueprint, ViewportBlueprint, }; -use re_viewport_blueprint::{ui::show_add_space_view_or_container_modal, ViewportBlueprint}; use crate::override_ui::{override_ui, override_visualizer_ui}; use crate::space_view_entity_picker::SpaceViewEntityPicker; @@ -221,7 +225,34 @@ impl SelectionPanel { } Item::DataResult(space_view_id, instance_path) => { - blueprint_ui_for_data_result(ctx, blueprint, ui, *space_view_id, instance_path); + let Some(space_view) = blueprint.space_view(space_view_id) else { + return; + }; + + let visualizer_collection = ctx + .space_view_class_registry + .new_visualizer_collection(space_view.class_identifier()); + + let Some(view_state) = view_states + .get(*space_view_id) + .map(|states| states.view_state.as_ref()) + else { + return; + }; + + let view_ctx = ViewContext { + viewer_ctx: ctx, + view_state, + visualizer_collection: &visualizer_collection, + }; + + blueprint_ui_for_data_result( + &view_ctx, + space_view, + ui, + *space_view_id, + instance_path, + ); } } } @@ -1131,58 +1162,56 @@ fn has_blueprint_section(item: &Item) -> bool { } fn blueprint_ui_for_data_result( - ctx: &ViewerContext<'_>, - blueprint: &ViewportBlueprint, + ctx: &ViewContext<'_>, + space_view: &SpaceViewBlueprint, ui: &mut Ui, space_view_id: SpaceViewId, instance_path: &InstancePath, ) { - if let Some(space_view) = blueprint.space_view(&space_view_id) { - if instance_path.instance.is_all() { - // the whole entity - let entity_path = &instance_path.entity_path; - - let query_result = ctx.lookup_query_result(space_view.id); - if let Some(data_result) = query_result - .tree - .lookup_result_by_path(entity_path) - .cloned() - { - let mut accumulated_legacy_props = data_result.accumulated_properties().clone(); - let accumulated_legacy_props_before = accumulated_legacy_props.clone(); + if instance_path.instance.is_all() { + // the whole entity + let entity_path = &instance_path.entity_path; + + let query_result = ctx.lookup_query_result(space_view.id); + if let Some(data_result) = query_result + .tree + .lookup_result_by_path(entity_path) + .cloned() + { + let mut accumulated_legacy_props = data_result.accumulated_properties().clone(); + let accumulated_legacy_props_before = accumulated_legacy_props.clone(); - entity_props_ui( - ctx, - ui, - ctx.lookup_query_result(space_view_id), - entity_path, - &mut accumulated_legacy_props, + entity_props_ui( + ctx, + ui, + ctx.lookup_query_result(space_view_id), + &data_result, + &mut accumulated_legacy_props, + ); + if accumulated_legacy_props != accumulated_legacy_props_before { + data_result.save_individual_override_properties( + ctx.viewer_ctx, + Some(accumulated_legacy_props), ); - if accumulated_legacy_props != accumulated_legacy_props_before { - data_result - .save_individual_override_properties(ctx, Some(accumulated_legacy_props)); - } } } } } fn entity_props_ui( - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, ui: &mut egui::Ui, query_result: &DataQueryResult, - entity_path: &EntityPath, + data_result: &DataResult, entity_props: &mut EntityProperties, ) { use re_types::blueprint::components::Visible; use re_types::Loggable as _; - let Some(data_result) = query_result.tree.lookup_result_by_path(entity_path) else { - return; - }; + let entity_path = &data_result.entity_path; { - let visible_before = data_result.is_visible(ctx); + let visible_before = data_result.is_visible(ctx.viewer_ctx); let mut visible = visible_before; let override_source = @@ -1199,7 +1228,7 @@ fn entity_props_ui( if visible_before != visible { data_result.save_recursive_override_or_clear_if_redundant( - ctx, + ctx.viewer_ctx, &query_result.tree, &Visible(visible), ); @@ -1209,16 +1238,16 @@ fn entity_props_ui( ui.re_checkbox(&mut entity_props.interactive, "Interactive") .on_hover_text("If disabled, the entity will not react to any mouse interaction"); - query_range_ui_data_result(ctx, ui, data_result); + query_range_ui_data_result(ctx.viewer_ctx, ui, data_result); egui::Grid::new("entity_properties") .num_columns(2) .show(ui, |ui| { // TODO(wumpf): It would be nice to only show pinhole & depth properties in the context of a 3D view. // if *view_state.state_spatial.nav_mode.get() == SpatialNavigationMode::ThreeD { - pinhole_props_ui(ctx, ui, entity_path, entity_props); - depth_props_ui(ctx, ui, entity_path, entity_props); - transform3d_visualization_ui(ctx, ui, entity_path, entity_props); + pinhole_props_ui(ctx, ui, data_result); + depth_props_ui(ctx.viewer_ctx, ui, entity_path, entity_props); + transform3d_visualization_ui(ctx.viewer_ctx, ui, entity_path, entity_props); }); } @@ -1252,30 +1281,34 @@ fn colormap_props_ui( ui.end_row(); } -fn pinhole_props_ui( - ctx: &ViewerContext<'_>, - ui: &mut egui::Ui, - entity_path: &EntityPath, - entity_props: &mut EntityProperties, -) { - let (query, store) = guess_query_and_db_for_selected_entity(ctx, entity_path); +fn pinhole_props_ui(ctx: &ViewContext<'_>, ui: &mut egui::Ui, data_result: &DataResult) { + let (query, store) = + guess_query_and_db_for_selected_entity(ctx.viewer_ctx, &data_result.entity_path); + if store - .latest_at_component::(entity_path, &query) + .latest_at_component::(&data_result.entity_path, &query) .is_some() { + let results = data_result.latest_at_with_overrides::(ctx, &query); + + let mut image_plane_value: f32 = results + .get_mono_with_fallback::() + .into(); + ui.label("Image plane distance"); - let mut distance = *entity_props.pinhole_image_plane_distance; - let speed = (distance * 0.05).at_least(0.01); + let speed = (image_plane_value * 0.05).at_least(0.01); if ui .add( - egui::DragValue::new(&mut distance) + egui::DragValue::new(&mut image_plane_value) .clamp_range(0.0..=1.0e8) .speed(speed), ) .on_hover_text("Controls how far away the image plane is") .changed() { - entity_props.pinhole_image_plane_distance = EditableAutoValue::UserEdited(distance); + let new_image_plane: ImagePlaneDistance = image_plane_value.into(); + + data_result.save_individual_override(ctx.viewer_ctx, &new_image_plane); } ui.end_row(); } diff --git a/crates/re_space_view/src/lib.rs b/crates/re_space_view/src/lib.rs index 86aa9a7835f8..96310303fea0 100644 --- a/crates/re_space_view/src/lib.rs +++ b/crates/re_space_view/src/lib.rs @@ -11,8 +11,8 @@ mod screenshot; mod view_property_ui; pub use heuristics::suggest_space_view_for_each_entity; -pub use query::{latest_at_with_overrides, range_with_overrides, HybridResults}; -pub use results_ext::RangeResultsExt; +pub use query::{latest_at_with_overrides, range_with_overrides, DataResultQuery}; +pub use results_ext::{HybridResults, RangeResultsExt}; pub use screenshot::ScreenshotMode; pub use view_property_ui::view_property_ui; diff --git a/crates/re_space_view/src/query.rs b/crates/re_space_view/src/query.rs index edc506f54c7e..f7ad00de8670 100644 --- a/crates/re_space_view/src/query.rs +++ b/crates/re_space_view/src/query.rs @@ -1,41 +1,13 @@ use nohash_hasher::IntSet; use re_data_store::{LatestAtQuery, RangeQuery}; -use re_query::{LatestAtResults, RangeResults}; +use re_query::LatestAtResults; use re_types_core::ComponentName; -use re_viewer_context::ViewerContext; +use re_viewer_context::{DataResult, ViewContext, ViewerContext}; -// --- - -#[derive(Debug)] -pub enum HybridResults { - LatestAt(LatestAtQuery, HybridLatestAtResults), - Range(RangeQuery, HybridRangeResults), -} - -impl From<(LatestAtQuery, HybridLatestAtResults)> for HybridResults { - #[inline] - fn from((query, results): (LatestAtQuery, HybridLatestAtResults)) -> Self { - Self::LatestAt(query, results) - } -} - -impl From<(RangeQuery, HybridRangeResults)> for HybridResults { - #[inline] - fn from((query, results): (RangeQuery, HybridRangeResults)) -> Self { - Self::Range(query, results) - } -} +use crate::results_ext::{HybridLatestAtResults, HybridRangeResults}; -/// Wrapper that contains the results of a range query with possible overrides. -/// -/// Although overrides are never temporal, when accessed via the [`crate::RangeResultsExt`] trait -/// they will be merged into the results appropriately. -#[derive(Debug)] -pub struct HybridRangeResults { - pub(crate) overrides: LatestAtResults, - pub(crate) results: RangeResults, -} +// --- /// Queries for the given `component_names` using range semantics with override support. /// @@ -43,7 +15,7 @@ pub struct HybridRangeResults { /// will be used instead of the range query. /// /// Data should be accessed via the [`crate::RangeResultsExt`] trait which is implemented for -/// [`HybridResults`]. +/// [`crate::HybridResults`]. pub fn range_with_overrides( ctx: &ViewerContext<'_>, _annotations: Option<&re_viewer_context::Annotations>, @@ -70,47 +42,44 @@ pub fn range_with_overrides( HybridRangeResults { overrides, results } } -/// Wrapper that contains the results of a latest-at query with possible overrides. -/// -/// Although overrides are never temporal, when accessed via the [`crate::RangeResultsExt`] trait -/// they will be merged into the results appropriately. -#[derive(Debug)] -pub struct HybridLatestAtResults { - pub(crate) overrides: LatestAtResults, - pub(crate) results: LatestAtResults, -} - /// Queries for the given `component_names` using latest-at semantics with override support. /// /// If the `DataResult` contains a specified override from the blueprint, that values /// will be used instead of the latest-at query. /// /// Data should be accessed via the [`crate::RangeResultsExt`] trait which is implemented for -/// [`HybridResults`]. -pub fn latest_at_with_overrides( - ctx: &ViewerContext<'_>, - _annotations: Option<&re_viewer_context::Annotations>, +/// [`crate::HybridResults`]. +pub fn latest_at_with_overrides<'a>( + ctx: &'a ViewContext<'a>, + _annotations: Option<&'a re_viewer_context::Annotations>, latest_at_query: &LatestAtQuery, - data_result: &re_viewer_context::DataResult, + data_result: &'a re_viewer_context::DataResult, component_names: impl IntoIterator, -) -> HybridLatestAtResults { +) -> HybridLatestAtResults<'a> { re_tracing::profile_function!(data_result.entity_path.to_string()); let mut component_set = component_names.into_iter().collect::>(); - let overrides = query_overrides(ctx, data_result, component_set.iter()); + let overrides = query_overrides(ctx.viewer_ctx, data_result, component_set.iter()); // No need to query for components that have overrides. component_set.retain(|component| !overrides.components.contains_key(component)); - let results = ctx.recording().query_caches().latest_at( - ctx.recording_store(), + let results = ctx.viewer_ctx.recording().query_caches().latest_at( + ctx.viewer_ctx.recording_store(), latest_at_query, &data_result.entity_path, component_set, ); - HybridLatestAtResults { overrides, results } + HybridLatestAtResults { + overrides, + results, + ctx, + query: latest_at_query.clone(), + data_result, + resolver: Default::default(), + } } fn query_overrides<'a>( @@ -166,3 +135,52 @@ fn query_overrides<'a>( } overrides } + +pub trait DataResultQuery { + fn latest_at_with_overrides<'a, A: re_types_core::Archetype>( + &'a self, + ctx: &'a ViewContext<'a>, + latest_at_query: &'a LatestAtQuery, + ) -> HybridLatestAtResults<'a>; + + fn best_fallback_for<'a>( + &self, + ctx: &'a ViewContext<'a>, + component: re_types_core::ComponentName, + ) -> Option<&'a dyn re_viewer_context::ComponentFallbackProvider>; +} + +impl DataResultQuery for DataResult { + fn latest_at_with_overrides<'a, A: re_types_core::Archetype>( + &'a self, + ctx: &'a ViewContext<'a>, + latest_at_query: &'a LatestAtQuery, + ) -> HybridLatestAtResults<'a> { + latest_at_with_overrides( + ctx, + None, + latest_at_query, + self, + A::all_components().iter().copied(), + ) + } + + fn best_fallback_for<'a>( + &self, + ctx: &'a ViewContext<'a>, + component: re_types_core::ComponentName, + ) -> Option<&'a dyn re_viewer_context::ComponentFallbackProvider> { + // TODO(jleibs): This should be cached somewhere + for vis in &self.visualizers { + let Ok(vis) = ctx.visualizer_collection.get_by_identifier(*vis) else { + continue; + }; + + if vis.visualizer_query_info().queried.contains(&component) { + return Some(vis.as_fallback_provider()); + } + } + + None + } +} diff --git a/crates/re_space_view/src/results_ext.rs b/crates/re_space_view/src/results_ext.rs index 109a96d2edf6..026bb5624b05 100644 --- a/crates/re_space_view/src/results_ext.rs +++ b/crates/re_space_view/src/results_ext.rs @@ -1,14 +1,162 @@ -use re_log_types::{RowId, TimeInt}; -use re_query::{LatestAtResults, PromiseResolver, PromiseResult, RangeData, RangeResults, Results}; -use re_types_core::Component; - -use crate::{ - query::{HybridLatestAtResults, HybridRangeResults}, - HybridResults, +use re_data_store::{LatestAtQuery, RangeQuery}; +use re_log_types::{external::arrow2, RowId, TimeInt}; +use re_query::{ + LatestAtComponentResults, LatestAtResults, PromiseResolver, PromiseResult, RangeData, + RangeResults, Results, }; +use re_types_core::{Component, ComponentName}; +use re_viewer_context::{DataResult, QueryContext, ViewContext}; + +use crate::DataResultQuery as _; // --- +/// Wrapper that contains the results of a latest-at query with possible overrides. +/// +/// Although overrides are never temporal, when accessed via the [`crate::RangeResultsExt`] trait +/// they will be merged into the results appropriately. +pub struct HybridLatestAtResults<'a> { + pub(crate) overrides: LatestAtResults, + pub(crate) results: LatestAtResults, + pub ctx: &'a ViewContext<'a>, + pub query: LatestAtQuery, + pub data_result: &'a DataResult, + pub resolver: PromiseResolver, +} + +/// Wrapper that contains the results of a range query with possible overrides. +/// +/// Although overrides are never temporal, when accessed via the [`crate::RangeResultsExt`] trait +/// they will be merged into the results appropriately. +#[derive(Debug)] +pub struct HybridRangeResults { + pub(crate) overrides: LatestAtResults, + pub(crate) results: RangeResults, +} + +impl<'a> HybridLatestAtResults<'a> { + /// Returns the [`LatestAtComponentResults`] for the specified [`Component`]. + #[inline] + pub fn get( + &self, + component_name: impl Into, + ) -> Option<&LatestAtComponentResults> { + let component_name = component_name.into(); + if self.overrides.contains(component_name) { + self.overrides.get(component_name) + } else { + self.results.get(component_name) + } + } + + /// Returns the [`LatestAtComponentResults`] for the specified [`Component`]. + /// + /// Returns an error if the component is not present. + #[inline] + pub fn get_required( + &self, + component_name: impl Into, + ) -> re_query::Result<&LatestAtComponentResults> { + let component_name = component_name.into(); + if self.overrides.contains(component_name) { + self.overrides.get_required(component_name) + } else { + self.results.get_required(component_name) + } + } + + /// Returns the [`LatestAtComponentResults`] for the specified [`Component`]. + /// + /// Returns empty results if the component is not present. + #[inline] + pub fn get_or_empty( + &self, + component_name: impl Into, + ) -> &LatestAtComponentResults { + let component_name = component_name.into(); + if self.overrides.contains(component_name) { + self.overrides.get_or_empty(component_name) + } else { + self.results.get_or_empty(component_name) + } + } + + pub fn try_fallback_raw( + &self, + component_name: ComponentName, + ) -> Option> { + let fallback_provider = self + .data_result + .best_fallback_for(self.ctx, component_name)?; + + let query_context = QueryContext { + viewer_ctx: self.ctx.viewer_ctx, + target_entity_path: &self.data_result.entity_path, + archetype_name: None, // TODO(jleibs): Do we need this? + query: &self.query, + view_state: self.ctx.view_state, + }; + + fallback_provider + .fallback_for(&query_context, component_name) + .ok() + } + + /// Utility for retrieving a single instance of a component. + #[inline] + pub fn get_instance(&self, index: usize) -> Option { + self.get(T::name()) + .and_then(|r| r.try_instance::(&self.resolver, index)) + } + + /// Utility for retrieving a single instance of a component. + #[inline] + pub fn get_mono(&self) -> Option { + self.get_instance(0) + } + + /// Utility for retrieving a single instance of a component with fallback + #[inline] + pub fn get_instance_with_fallback( + &self, + index: usize, + ) -> T { + self.get(T::name()) + .and_then(|r| r.try_instance::(&self.resolver, index)) + .or_else(|| { + self.try_fallback_raw(T::name()) + .and_then(|raw| T::from_arrow(raw.as_ref()).ok()) + .and_then(|r| r.first().cloned()) + }) + .unwrap_or_default() + } + + /// Utility for retrieving a single instance of a component. + #[inline] + pub fn get_mono_with_fallback(&self) -> T { + self.get_instance_with_fallback(0) + } +} + +pub enum HybridResults<'a> { + LatestAt(LatestAtQuery, HybridLatestAtResults<'a>), + Range(RangeQuery, HybridRangeResults), +} + +impl<'a> From<(LatestAtQuery, HybridLatestAtResults<'a>)> for HybridResults<'a> { + #[inline] + fn from((query, results): (LatestAtQuery, HybridLatestAtResults<'a>)) -> Self { + Self::LatestAt(query, results) + } +} + +impl<'a> From<(RangeQuery, HybridRangeResults)> for HybridResults<'a> { + #[inline] + fn from((query, results): (RangeQuery, HybridRangeResults)) -> Self { + Self::Range(query, results) + } +} + /// Extension traits to abstract query result handling for all spatial space views. /// /// Also turns all results into range results, so that views only have to worry about the ranged @@ -209,12 +357,12 @@ impl RangeResultsExt for HybridRangeResults { } } -impl RangeResultsExt for HybridLatestAtResults { +impl<'a> RangeResultsExt for HybridLatestAtResults<'a> { #[inline] - fn get_dense<'a, C: Component>( - &'a self, + fn get_dense<'b, C: Component>( + &'b self, resolver: &PromiseResolver, - ) -> Option>> { + ) -> Option>> { let component_name = C::name(); if self.overrides.contains(component_name) { @@ -245,10 +393,10 @@ impl RangeResultsExt for HybridLatestAtResults { } #[inline] - fn get_or_empty_dense<'a, C: Component>( - &'a self, + fn get_or_empty_dense<'b, C: Component>( + &'b self, resolver: &PromiseResolver, - ) -> re_query::Result> { + ) -> re_query::Result> { let component_name = C::name(); if self.overrides.contains(component_name) { @@ -275,21 +423,21 @@ impl RangeResultsExt for HybridLatestAtResults { } } -impl RangeResultsExt for HybridResults { - fn get_dense<'a, C: Component>( - &'a self, +impl<'a> RangeResultsExt for HybridResults<'a> { + fn get_dense<'b, C: Component>( + &'b self, resolver: &PromiseResolver, - ) -> Option>> { + ) -> Option>> { match self { Self::LatestAt(_, results) => results.get_dense(resolver), Self::Range(_, results) => results.get_dense(resolver), } } - fn get_or_empty_dense<'a, C: Component>( - &'a self, + fn get_or_empty_dense<'b, C: Component>( + &'b self, resolver: &PromiseResolver, - ) -> re_query::Result> { + ) -> re_query::Result> { match self { Self::LatestAt(_, results) => results.get_or_empty_dense(resolver), Self::Range(_, results) => results.get_or_empty_dense(resolver), diff --git a/crates/re_space_view_bar_chart/src/visualizer_system.rs b/crates/re_space_view_bar_chart/src/visualizer_system.rs index 4454cd87ea32..90d579c20afd 100644 --- a/crates/re_space_view_bar_chart/src/visualizer_system.rs +++ b/crates/re_space_view_bar_chart/src/visualizer_system.rs @@ -5,9 +5,8 @@ use re_entity_db::EntityPath; use re_space_view::diff_component_filter; use re_types::{archetypes::BarChart, components::Color, datatypes::TensorData}; use re_viewer_context::{ - IdentifiedViewSystem, SpaceViewState, SpaceViewSystemExecutionError, ViewContextCollection, - ViewQuery, ViewerContext, VisualizerAdditionalApplicabilityFilter, VisualizerQueryInfo, - VisualizerSystem, + IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, + ViewQuery, VisualizerAdditionalApplicabilityFilter, VisualizerQueryInfo, VisualizerSystem, }; /// A bar chart system, with everything needed to render it. @@ -43,10 +42,9 @@ impl VisualizerSystem for BarChartVisualizerSystem { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - _view_ctx: &ViewContextCollection, + _context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { re_tracing::profile_function!(); diff --git a/crates/re_space_view_dataframe/src/visualizer_system.rs b/crates/re_space_view_dataframe/src/visualizer_system.rs index e75c6279b330..b8177d0880d2 100644 --- a/crates/re_space_view_dataframe/src/visualizer_system.rs +++ b/crates/re_space_view_dataframe/src/visualizer_system.rs @@ -1,6 +1,6 @@ use re_viewer_context::{ - ComponentFallbackProvider, IdentifiedViewSystem, SpaceViewState, SpaceViewSystemExecutionError, - ViewContextCollection, ViewQuery, ViewerContext, VisualizerQueryInfo, VisualizerSystem, + ComponentFallbackProvider, IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, + ViewContextCollection, ViewQuery, VisualizerQueryInfo, VisualizerSystem, }; /// An empty system to accept all entities in the space view @@ -20,10 +20,9 @@ impl VisualizerSystem for EmptySystem { fn execute( &mut self, - _ctx: &ViewerContext<'_>, + _ctx: &ViewContext<'_>, _query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - _view_ctx: &ViewContextCollection, + _context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { Ok(vec![]) } diff --git a/crates/re_space_view_spatial/src/contexts/annotation_context.rs b/crates/re_space_view_spatial/src/contexts/annotation_context.rs index 3ff82b5fc952..f5328cb69f1a 100644 --- a/crates/re_space_view_spatial/src/contexts/annotation_context.rs +++ b/crates/re_space_view_spatial/src/contexts/annotation_context.rs @@ -24,14 +24,17 @@ impl ViewContextSystem for AnnotationSceneContext { fn execute( &mut self, - ctx: &re_viewer_context::ViewerContext<'_>, + ctx: &re_viewer_context::ViewContext<'_>, query: &re_viewer_context::ViewQuery<'_>, ) { re_tracing::profile_function!(); // We create a list of *all* entities here, do not only iterate over those with annotation context. // TODO(andreas): But knowing ahead of time where we have annotation contexts could be used for optimization. - self.0 - .load(ctx, &query.latest_at_query(), query.iter_all_entities()); + self.0.load( + ctx.viewer_ctx, + &query.latest_at_query(), + query.iter_all_entities(), + ); } fn as_any(&self) -> &dyn std::any::Any { diff --git a/crates/re_space_view_spatial/src/contexts/depth_offsets.rs b/crates/re_space_view_spatial/src/contexts/depth_offsets.rs index 258de2b3bacf..0725c5a729de 100644 --- a/crates/re_space_view_spatial/src/contexts/depth_offsets.rs +++ b/crates/re_space_view_spatial/src/contexts/depth_offsets.rs @@ -32,7 +32,7 @@ impl ViewContextSystem for EntityDepthOffsets { fn execute( &mut self, - ctx: &re_viewer_context::ViewerContext<'_>, + ctx: &re_viewer_context::ViewContext<'_>, query: &re_viewer_context::ViewQuery<'_>, ) { #[derive(PartialEq, PartialOrd, Eq, Ord)] @@ -49,14 +49,13 @@ impl ViewContextSystem for EntityDepthOffsets { for data_result in query.iter_all_data_results() { // Note that we can't use `query.iter_visible_data_results` here since `EntityDepthOffsets` isn't a visualizer // and thus not in the list of per system data results. - if !data_result.is_visible(ctx) { + if !data_result.is_visible(ctx.viewer_ctx) { continue; } // TODO(#5607): what should happen if the promise is still pending? if let Some(draw_order) = ctx - .store_context - .recording + .recording() .latest_at_component::(&data_result.entity_path, &ctx.current_query()) { entities_per_draw_order diff --git a/crates/re_space_view_spatial/src/contexts/mod.rs b/crates/re_space_view_spatial/src/contexts/mod.rs index 17185a15ebbc..823e0c3d1715 100644 --- a/crates/re_space_view_spatial/src/contexts/mod.rs +++ b/crates/re_space_view_spatial/src/contexts/mod.rs @@ -44,7 +44,7 @@ impl ViewContextSystem for PrimitiveCounter { fn execute( &mut self, - _ctx: &re_viewer_context::ViewerContext<'_>, + _ctx: &re_viewer_context::ViewContext<'_>, _query: &re_viewer_context::ViewQuery<'_>, ) { } diff --git a/crates/re_space_view_spatial/src/contexts/transform_context.rs b/crates/re_space_view_spatial/src/contexts/transform_context.rs index 37f31383f672..fe7ccededb49 100644 --- a/crates/re_space_view_spatial/src/contexts/transform_context.rs +++ b/crates/re_space_view_spatial/src/contexts/transform_context.rs @@ -1,14 +1,18 @@ use nohash_hasher::IntMap; use re_data_store::LatestAtQuery; -use re_entity_db::{EntityDb, EntityPath, EntityPropertyMap, EntityTree}; +use re_entity_db::{EntityDb, EntityPath, EntityTree}; +use re_space_view::DataResultQuery as _; use re_types::{ - components::{DisconnectedSpace, PinholeProjection, Transform3D, ViewCoordinates}, + archetypes::Pinhole, + components::{ + DisconnectedSpace, ImagePlaneDistance, PinholeProjection, Transform3D, ViewCoordinates, + }, ComponentNameSet, Loggable as _, }; -use re_viewer_context::{IdentifiedViewSystem, ViewContextSystem}; +use re_viewer_context::{IdentifiedViewSystem, ViewContext, ViewContextSystem}; -use crate::visualizers::{image_view_coordinates, CamerasVisualizer}; +use crate::visualizers::image_view_coordinates; #[derive(Clone)] struct TransformInfo { @@ -86,28 +90,13 @@ impl ViewContextSystem for TransformContext { /// entities are transformed relative to it. fn execute( &mut self, - ctx: &re_viewer_context::ViewerContext<'_>, + ctx: &re_viewer_context::ViewContext<'_>, query: &re_viewer_context::ViewQuery<'_>, ) { re_tracing::profile_function!(); let entity_tree = ctx.recording().tree(); - // TODO(jleibs): The need to do this hints at a problem with how we think about - // the interaction between properties and "context-systems". - // Build an entity_property_map for just the CamerasParts, where we would expect to find - // the image_depth_plane_distance property. - let entity_prop_map: EntityPropertyMap = query - .per_visualizer_data_results - .get(&CamerasVisualizer::identifier()) - .map(|results| { - results - .iter() - .map(|r| (r.entity_path.clone(), r.accumulated_properties().clone())) - .collect() - }) - .unwrap_or_default(); - self.space_origin = query.space_origin.clone(); // Find the entity path tree for the root. @@ -122,10 +111,11 @@ impl ViewContextSystem for TransformContext { // Child transforms of this space self.gather_descendants_transforms( + ctx, + query, current_tree, ctx.recording(), &time_query, - &entity_prop_map, glam::Affine3A::IDENTITY, &None, // Ignore potential pinhole camera at the root of the space view, since it regarded as being "above" this root. ); @@ -168,10 +158,11 @@ impl ViewContextSystem for TransformContext { // (skip over everything at and under `current_tree` automatically) self.gather_descendants_transforms( + ctx, + query, parent_tree, ctx.recording(), &time_query, - &entity_prop_map, reference_from_ancestor, &encountered_pinhole, ); @@ -189,10 +180,11 @@ impl TransformContext { #[allow(clippy::too_many_arguments)] fn gather_descendants_transforms( &mut self, + ctx: &ViewContext<'_>, + view_query: &re_viewer_context::ViewQuery<'_>, subtree: &EntityTree, entity_db: &EntityDb, query: &LatestAtQuery, - entity_properties: &EntityPropertyMap, reference_from_entity: glam::Affine3A, encountered_pinhole: &Option, ) { @@ -210,11 +202,28 @@ impl TransformContext { for child_tree in subtree.children.values() { let mut encountered_pinhole = encountered_pinhole.clone(); + + let lookup_image_plane = |p: &_| { + let query_result = ctx.viewer_ctx.lookup_query_result(view_query.space_view_id); + + query_result + .tree + .lookup_result_by_path(p) + .cloned() + .map(|data_result| { + let results = data_result.latest_at_with_overrides::(ctx, query); + + results.get_mono_with_fallback::() + }) + .unwrap_or_default() + .into() + }; + let reference_from_child = match transform_at( child_tree, entity_db, query, - |p| *entity_properties.get(p).pinhole_image_plane_distance, + lookup_image_plane, &mut encountered_pinhole, ) { Err(unreachable_reason) => { @@ -226,10 +235,11 @@ impl TransformContext { Ok(Some(child_from_parent)) => reference_from_entity * child_from_parent, }; self.gather_descendants_transforms( + ctx, + view_query, child_tree, entity_db, query, - entity_properties, reference_from_child, &encountered_pinhole, ); diff --git a/crates/re_space_view_spatial/src/heuristics.rs b/crates/re_space_view_spatial/src/heuristics.rs index ade356e8b3fb..0ab8490d1c13 100644 --- a/crates/re_space_view_spatial/src/heuristics.rs +++ b/crates/re_space_view_spatial/src/heuristics.rs @@ -14,11 +14,9 @@ use re_types::{ use re_viewer_context::{IdentifiedViewSystem, PerSystemEntities, ViewerContext}; use crate::{ - query_pinhole, + query_pinhole_legacy, view_kind::SpatialSpaceViewKind, - visualizers::{ - CamerasVisualizer, ImageVisualizer, SpatialViewVisualizerData, Transform3DArrowsVisualizer, - }, + visualizers::{ImageVisualizer, SpatialViewVisualizerData, Transform3DArrowsVisualizer}, }; pub fn generate_auto_legacy_properties( @@ -32,7 +30,6 @@ pub fn generate_auto_legacy_properties( let mut auto_properties = re_entity_db::EntityPropertyMap::default(); // Do pinhole properties before, since they may be used in transform3d heuristics. - update_pinhole_property_heuristics(per_system_entities, &mut auto_properties, scene_bbox_accum); update_depth_cloud_property_heuristics( ctx, per_system_entities, @@ -74,32 +71,6 @@ pub fn auto_size_world_heuristic( heuristic0.min(heuristic1) } -fn update_pinhole_property_heuristics( - per_system_entities: &PerSystemEntities, - auto_properties: &mut re_entity_db::EntityPropertyMap, - scene_bbox_accum: &macaw::BoundingBox, -) { - for ent_path in per_system_entities - .get(&CamerasVisualizer::identifier()) - .unwrap_or(&BTreeSet::new()) - { - let mut properties = auto_properties.get(ent_path); - - let scene_size = scene_bbox_accum.size().length(); - let default_image_plane_distance = if scene_size.is_finite() && scene_size > 0.0 { - scene_size * 0.02 // Works pretty well for `examples/python/open_photogrammetry_format/open_photogrammetry_format.py --no-frames` - } else { - // This value somewhat arbitrary. In almost all cases where the scene has defined bounds - // the heuristic will change it or it will be user edited. In the case of non-defined bounds - // this value works better with the default camera setup. - 0.3 - }; - properties.pinhole_image_plane_distance = - EditableAutoValue::Auto(default_image_plane_distance); - auto_properties.overwrite_properties(ent_path.clone(), properties); - } -} - fn update_depth_cloud_property_heuristics( ctx: &ViewerContext<'_>, per_system_entities: &PerSystemEntities, @@ -163,13 +134,13 @@ fn update_transform3d_lines_heuristics( ent_path: &'a EntityPath, ctx: &'a ViewerContext<'_>, ) -> Option<&'a EntityPath> { - if query_pinhole(ctx.recording(), &ctx.current_query(), ent_path).is_some() { + if query_pinhole_legacy(ctx.recording(), &ctx.current_query(), ent_path).is_some() { return Some(ent_path); } else { // Any direct child has a pinhole camera? if let Some(child_tree) = ctx.recording().tree().subtree(ent_path) { for child in child_tree.children.values() { - if query_pinhole(ctx.recording(), &ctx.current_query(), &child.path) + if query_pinhole_legacy(ctx.recording(), &ctx.current_query(), &child.path) .is_some() { return Some(&child.path); @@ -196,16 +167,18 @@ fn update_transform3d_lines_heuristics( only_has_transform_components || is_pinhole_extrinsics_of(ent_path, ctx).is_some(), ); - if let Some(pinhole_path) = is_pinhole_extrinsics_of(ent_path, ctx) { - // If there's a pinhole, we orient ourselves on its image plane distance - let pinhole_path_props = auto_properties.get(pinhole_path); - properties.transform_3d_size = - EditableAutoValue::Auto(*pinhole_path_props.pinhole_image_plane_distance * 0.25); - } else { - // Size should be proportional to the scene extent, here covered by its diagonal - let diagonal_length = (scene_bbox_accum.max - scene_bbox_accum.min).length(); - properties.transform_3d_size = EditableAutoValue::Auto(diagonal_length * 0.05); - } + // TODO(jleibs): This should be an independent heuristic. + /* + if let Some(pinhole_path) = is_pinhole_extrinsics_of(ent_path, ctx) { + // If there's a pinhole, we orient ourselves on its image plane distance + //let pinhole_path_props = auto_properties.get(pinhole_path); + //properties.transform_3d_size = + // EditableAutoValue::Auto(*pinhole_path_props.pinhole_image_plane_distance * 0.25); + } else { + */ + // Size should be proportional to the scene extent, here covered by its diagonal + let diagonal_length = (scene_bbox_accum.max - scene_bbox_accum.min).length(); + properties.transform_3d_size = EditableAutoValue::Auto(diagonal_length * 0.05); auto_properties.overwrite_properties(ent_path.clone(), properties); } diff --git a/crates/re_space_view_spatial/src/lib.rs b/crates/re_space_view_spatial/src/lib.rs index f75f9af74e13..0a9d0e500223 100644 --- a/crates/re_space_view_spatial/src/lib.rs +++ b/crates/re_space_view_spatial/src/lib.rs @@ -25,7 +25,8 @@ mod view_3d; mod view_3d_properties; mod visualizers; -use re_viewer_context::ViewerContext; +use re_space_view::DataResultQuery as _; +use re_viewer_context::{ViewContext, ViewerContext}; pub use view_2d::SpatialSpaceView2D; pub use view_3d::SpatialSpaceView3D; @@ -61,6 +62,36 @@ fn resolution_from_tensor( /// Utility for querying a pinhole archetype instance. fn query_pinhole( + ctx: &ViewContext<'_>, + query: &re_data_store::LatestAtQuery, + data_result: &re_viewer_context::DataResult, +) -> Option { + let results = data_result.latest_at_with_overrides::(ctx, query); + + let image_from_camera = results.get_mono()?; + + let resolution = results + .get_mono() + .or_else(|| resolution_from_tensor(ctx.recording(), query, &data_result.entity_path)); + + let camera_xyz = results.get_mono(); + + let image_plane_distance = Some(results.get_mono_with_fallback()); + + Some(re_types::archetypes::Pinhole { + image_from_camera, + resolution, + camera_xyz, + image_plane_distance, + }) +} + +/// Deprecated utility for querying a pinhole archetype instance. +/// +/// This function won't handle fallbacks correctly. +/// +// TODO(andreas): This is duplicated into `re_viewport` +fn query_pinhole_legacy( entity_db: &re_entity_db::EntityDb, query: &re_data_store::LatestAtQuery, entity_path: &re_log_types::EntityPath, @@ -77,6 +108,7 @@ fn query_pinhole( camera_xyz: entity_db .latest_at_component(entity_path, query) .map(|c| c.value), + image_plane_distance: None, }) } diff --git a/crates/re_space_view_spatial/src/ui_2d.rs b/crates/re_space_view_spatial/src/ui_2d.rs index a184f481a77a..e2ce1951941c 100644 --- a/crates/re_space_view_spatial/src/ui_2d.rs +++ b/crates/re_space_view_spatial/src/ui_2d.rs @@ -24,7 +24,7 @@ use super::{ ui::{create_labels, picking, screenshot_context_menu}, }; use crate::{ - query_pinhole, + query_pinhole_legacy, ui::{outline_config, SpatialSpaceViewState}, view_kind::SpatialSpaceViewKind, visualizers::collect_ui_labels, @@ -167,8 +167,12 @@ impl SpatialSpaceView2D { // Note that we can't rely on the camera being part of scene.space_cameras since that requires // the camera to be added to the scene! + // + // TODO(jleibs): Would be nice to use `query_pinhole` here, but we don't have a data-result or the other pieces + // necessary to properly handle overrides, defaults, or fallbacks. We don't actually use the image_plane_distance + // so it doesnt technically matter. state.pinhole_at_origin = - query_pinhole(ctx.recording(), &ctx.current_query(), query.space_origin); + query_pinhole_legacy(ctx.recording(), &ctx.current_query(), query.space_origin); let (mut response, painter) = ui.allocate_painter(ui.available_size(), egui::Sense::click_and_drag()); @@ -347,6 +351,7 @@ fn setup_target_config( .into(), resolution: Some([resolution.x, resolution.y].into()), camera_xyz: Some(ViewCoordinates::RDF), + image_plane_distance: None, }; } let pinhole_rect = Rect::from_min_size(Pos2::ZERO, egui::vec2(resolution.x, resolution.y)); diff --git a/crates/re_space_view_spatial/src/visualizers/arrows2d.rs b/crates/re_space_view_spatial/src/visualizers/arrows2d.rs index 4dc5ff402528..8da77bc90016 100644 --- a/crates/re_space_view_spatial/src/visualizers/arrows2d.rs +++ b/crates/re_space_view_spatial/src/visualizers/arrows2d.rs @@ -7,8 +7,8 @@ use re_types::{ components::{ClassId, Color, KeypointId, Position2D, Radius, Text, Vector2D}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -208,12 +208,11 @@ impl VisualizerSystem for Arrows2DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -223,8 +222,8 @@ impl VisualizerSystem for Arrows2DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/arrows3d.rs b/crates/re_space_view_spatial/src/visualizers/arrows3d.rs index 3fdb4ae7fd29..599f63468d9d 100644 --- a/crates/re_space_view_spatial/src/visualizers/arrows3d.rs +++ b/crates/re_space_view_spatial/src/visualizers/arrows3d.rs @@ -7,8 +7,8 @@ use re_types::{ components::{ClassId, Color, KeypointId, Position3D, Radius, Text, Vector3D}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -211,12 +211,11 @@ impl VisualizerSystem for Arrows3DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -226,8 +225,8 @@ impl VisualizerSystem for Arrows3DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/assets3d.rs b/crates/re_space_view_spatial/src/visualizers/assets3d.rs index 93c2f555eb5f..ad4c93d6c50a 100644 --- a/crates/re_space_view_spatial/src/visualizers/assets3d.rs +++ b/crates/re_space_view_spatial/src/visualizers/assets3d.rs @@ -8,9 +8,9 @@ use re_types::{ components::{Blob, MediaType, OutOfTreeTransform3D}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, SpaceViewState, SpaceViewSystemExecutionError, - ViewContextCollection, ViewQuery, ViewerContext, VisualizableEntities, - VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, + ApplicableEntities, IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, + ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, + VisualizerQueryInfo, VisualizerSystem, }; use super::{filter_visualizable_3d_entities, SpatialViewVisualizerData}; @@ -44,7 +44,7 @@ struct Asset3DComponentData<'a> { impl Asset3DVisualizer { fn process_data<'a>( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, render_ctx: &RenderContext, instances: &mut Vec, entity_path: &EntityPath, @@ -66,7 +66,7 @@ impl Asset3DVisualizer { // TODO(#5974): this is subtly wrong, the key should actually be a hash of everything that got // cached, which includes the media type… - let mesh = ctx.cache.entry(|c: &mut MeshCache| { + let mesh = ctx.viewer_ctx.cache.entry(|c: &mut MeshCache| { c.entry( &entity_path.to_string(), MeshCacheKey { @@ -131,12 +131,11 @@ impl VisualizerSystem for Asset3DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -145,8 +144,8 @@ impl VisualizerSystem for Asset3DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/boxes2d.rs b/crates/re_space_view_spatial/src/visualizers/boxes2d.rs index ffdb53689411..36cd923d2198 100644 --- a/crates/re_space_view_spatial/src/visualizers/boxes2d.rs +++ b/crates/re_space_view_spatial/src/visualizers/boxes2d.rs @@ -7,8 +7,8 @@ use re_types::{ components::{ClassId, Color, HalfSizes2D, KeypointId, Position2D, Radius, Text}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -204,12 +204,11 @@ impl VisualizerSystem for Boxes2DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -219,8 +218,8 @@ impl VisualizerSystem for Boxes2DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/boxes3d.rs b/crates/re_space_view_spatial/src/visualizers/boxes3d.rs index f2bd3b1a3047..0bd0460b9859 100644 --- a/crates/re_space_view_spatial/src/visualizers/boxes3d.rs +++ b/crates/re_space_view_spatial/src/visualizers/boxes3d.rs @@ -7,8 +7,8 @@ use re_types::{ components::{ClassId, Color, HalfSizes3D, KeypointId, Position3D, Radius, Rotation3D, Text}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -195,12 +195,11 @@ impl VisualizerSystem for Boxes3DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -210,8 +209,8 @@ impl VisualizerSystem for Boxes3DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/cameras.rs b/crates/re_space_view_spatial/src/visualizers/cameras.rs index 0cb839777962..ffc957a635eb 100644 --- a/crates/re_space_view_spatial/src/visualizers/cameras.rs +++ b/crates/re_space_view_spatial/src/visualizers/cameras.rs @@ -1,22 +1,23 @@ use glam::vec3; -use re_entity_db::{EntityPath, EntityProperties}; use re_log_types::Instance; use re_renderer::renderer::LineStripFlags; use re_types::{ archetypes::Pinhole, - components::{Transform3D, ViewCoordinates}, + components::{ImagePlaneDistance, Transform3D, ViewCoordinates}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, SpaceViewOutlineMasks, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, - VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, + ApplicableEntities, DataResult, IdentifiedViewSystem, QueryContext, SpaceViewOutlineMasks, + SpaceViewStateExt as _, SpaceViewSystemExecutionError, TypedComponentFallbackProvider, + ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, + VisualizerQueryInfo, VisualizerSystem, }; use super::{filter_visualizable_3d_entities, SpatialViewVisualizerData}; use crate::{ contexts::TransformContext, instance_hash_conversions::picking_layer_id_from_instance_path_hash, query_pinhole, - space_camera_3d::SpaceCamera3D, visualizers::SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES, + space_camera_3d::SpaceCamera3D, ui::SpatialSpaceViewState, + visualizers::SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES, }; const CAMERA_COLOR: re_renderer::Color32 = re_renderer::Color32::from_rgb(150, 150, 150); @@ -49,16 +50,17 @@ impl CamerasVisualizer { &mut self, line_builder: &mut re_renderer::LineDrawableBuilder<'_>, transforms: &TransformContext, - ent_path: &EntityPath, - props: &EntityProperties, + data_result: &DataResult, pinhole: &Pinhole, transform_at_entity: Option, pinhole_view_coordinates: ViewCoordinates, entity_highlight: &SpaceViewOutlineMasks, ) { let instance = Instance::from(0); + let ent_path = &data_result.entity_path; - let frustum_length = *props.pinhole_image_plane_distance; + // Assuming the fallback provider did the right thing, this value should always be set. + let frustum_length = pinhole.image_plane_distance.unwrap_or_default().into(); // If the camera is our reference, there is nothing for us to display. if transforms.reference_path() == ent_path { @@ -202,16 +204,15 @@ impl VisualizerSystem for CamerasVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; - let transforms = view_ctx.get::()?; + let transforms = context_systems.get::()?; // Counting all cameras ahead of time is a bit wasteful, but we also don't expect a huge amount, // so let re_renderer's allocator internally decide what buffer sizes to pick & grow them as we go. @@ -221,9 +222,7 @@ impl VisualizerSystem for CamerasVisualizer { for data_result in query.iter_visible_data_results(ctx, Self::identifier()) { let time_query = re_data_store::LatestAtQuery::new(query.timeline, query.latest_at); - if let Some(pinhole) = - query_pinhole(ctx.recording(), &time_query, &data_result.entity_path) - { + if let Some(pinhole) = query_pinhole(ctx, &time_query, data_result) { let entity_highlight = query .highlights .entity_outline_mask(data_result.entity_path.hash()); @@ -231,8 +230,7 @@ impl VisualizerSystem for CamerasVisualizer { self.visit_instance( &mut line_builder, transforms, - &data_result.entity_path, - data_result.accumulated_properties(), + data_result, &pinhole, // TODO(#5607): what should happen if the promise is still pending? ctx.recording() @@ -260,4 +258,25 @@ impl VisualizerSystem for CamerasVisualizer { } } -re_viewer_context::impl_component_fallback_provider!(CamerasVisualizer => []); +impl TypedComponentFallbackProvider for CamerasVisualizer { + fn fallback_for(&self, ctx: &QueryContext<'_>) -> ImagePlaneDistance { + let Ok(state) = ctx.view_state.downcast_ref::() else { + return Default::default(); + }; + + let scene_size = state.bounding_boxes.accumulated.size().length(); + + if scene_size.is_finite() && scene_size > 0.0 { + // Works pretty well for `examples/python/open_photogrammetry_format/open_photogrammetry_format.py --no-frames` + scene_size * 0.02 + } else { + // This value somewhat arbitrary. In almost all cases where the scene has defined bounds + // the heuristic will change it or it will be user edited. In the case of non-defined bounds + // this value works better with the default camera setup. + 0.3 + } + .into() + } +} + +re_viewer_context::impl_component_fallback_provider!(CamerasVisualizer => [ImagePlaneDistance]); diff --git a/crates/re_space_view_spatial/src/visualizers/entity_iterator.rs b/crates/re_space_view_spatial/src/visualizers/entity_iterator.rs index dfc291b6c277..0a2fdd057b70 100644 --- a/crates/re_space_view_spatial/src/visualizers/entity_iterator.rs +++ b/crates/re_space_view_spatial/src/visualizers/entity_iterator.rs @@ -6,8 +6,8 @@ use re_renderer::DepthOffset; use re_space_view::{latest_at_with_overrides, range_with_overrides, HybridResults}; use re_types::Archetype; use re_viewer_context::{ - IdentifiedViewSystem, QueryRange, SpaceViewClass, SpaceViewSystemExecutionError, - ViewContextCollection, ViewQuery, ViewerContext, + IdentifiedViewSystem, QueryRange, SpaceViewClass, SpaceViewSystemExecutionError, ViewContext, + ViewContextCollection, ViewQuery, }; use crate::{ @@ -39,13 +39,13 @@ pub fn clamped(values: &[T], clamped_len: usize) -> impl Iterator // --- Cached APIs --- -pub fn query_archetype_with_history( - ctx: &ViewerContext<'_>, +pub fn query_archetype_with_history<'a, A: Archetype>( + ctx: &'a ViewContext<'a>, timeline: &Timeline, timeline_cursor: TimeInt, query_range: &QueryRange, - data_result: &re_viewer_context::DataResult, -) -> HybridResults { + data_result: &'a re_viewer_context::DataResult, +) -> HybridResults<'a> { match query_range { QueryRange::TimeRange(time_range) => { let range_query = RangeQuery::new( @@ -56,7 +56,7 @@ pub fn query_archetype_with_history( ), ); let results = range_with_overrides( - ctx, + ctx.viewer_ctx, None, &range_query, data_result, @@ -83,7 +83,7 @@ pub fn query_archetype_with_history( /// The callback passed in gets passed along an [`SpatialSceneEntityContext`] which contains /// various useful information about an entity in the context of the current scene. pub fn process_archetype( - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, view_ctx: &ViewContextCollection, default_depth_offset: DepthOffset, @@ -92,11 +92,11 @@ pub fn process_archetype( where A: Archetype, F: FnMut( - &ViewerContext<'_>, + &ViewContext<'_>, &EntityPath, &EntityProperties, &SpatialSceneEntityContext<'_>, - &HybridResults, + &HybridResults<'_>, ) -> Result<(), SpaceViewSystemExecutionError>, { let transforms = view_ctx.get::()?; diff --git a/crates/re_space_view_spatial/src/visualizers/images.rs b/crates/re_space_view_spatial/src/visualizers/images.rs index c566be2a7154..360ea4a0226f 100644 --- a/crates/re_space_view_spatial/src/visualizers/images.rs +++ b/crates/re_space_view_spatial/src/visualizers/images.rs @@ -20,15 +20,14 @@ use re_types::{ }; use re_viewer_context::{ gpu_bridge, ApplicableEntities, DefaultColor, IdentifiedViewSystem, SpaceViewClass, - SpaceViewState, SpaceViewSystemExecutionError, TensorDecodeCache, TensorStatsCache, - ViewContextCollection, ViewQuery, ViewerContext, VisualizableEntities, - VisualizableFilterContext, VisualizerAdditionalApplicabilityFilter, VisualizerQueryInfo, - VisualizerSystem, + SpaceViewSystemExecutionError, TensorDecodeCache, TensorStatsCache, ViewContext, + ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, + VisualizerAdditionalApplicabilityFilter, VisualizerQueryInfo, VisualizerSystem, }; use crate::{ contexts::{EntityDepthOffsets, SpatialSceneEntityContext, TransformContext}, - query_pinhole, + query_pinhole_legacy, view_kind::SpatialSpaceViewKind, visualizers::{filter_visualizable_2d_entities, SIZE_BOOST_IN_POINTS_FOR_POINT_OUTLINES}, SpatialSpaceView2D, SpatialSpaceView3D, @@ -57,7 +56,7 @@ pub struct ViewerImage { #[allow(clippy::too_many_arguments)] fn to_textured_rect( - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, render_ctx: &RenderContext, ent_path: &EntityPath, ent_context: &SpatialSceneEntityContext<'_>, @@ -70,6 +69,7 @@ fn to_textured_rect( let debug_name = ent_path.to_string(); let tensor_stats = ctx + .viewer_ctx .cache .entry(|c: &mut TensorStatsCache| c.entry(tensor_data_row_id, tensor)); @@ -211,10 +211,9 @@ impl ImageVisualizer { #[allow(clippy::too_many_arguments)] fn process_image_data<'a>( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, render_ctx: &RenderContext, transforms: &TransformContext, - ent_props: &EntityProperties, entity_path: &EntityPath, ent_context: &SpatialSceneEntityContext<'_>, data: impl Iterator>, @@ -247,7 +246,7 @@ impl ImageVisualizer { } let tensor_data_row_id = data.index.1; - let tensor = match ctx.cache.entry(|c: &mut TensorDecodeCache| { + let tensor = match ctx.viewer_ctx.cache.entry(|c: &mut TensorDecodeCache| { c.entry(tensor_data_row_id, data.tensor.0.clone()) }) { Ok(tensor) => tensor, @@ -280,9 +279,7 @@ impl ImageVisualizer { // relationship where the image plane grows the bounds which in // turn influence the size of the image plane. // See: https://github.com/rerun-io/rerun/issues/3728 - if ent_context.space_view_class_identifier == SpatialSpaceView2D::identifier() - || !ent_props.pinhole_image_plane_distance.is_auto() - { + if ent_context.space_view_class_identifier == SpatialSpaceView2D::identifier() { self.data.add_bounding_box( entity_path.hash(), Self::compute_bounding_box(&textured_rect), @@ -305,10 +302,9 @@ impl ImageVisualizer { #[allow(clippy::too_many_arguments)] fn process_segmentation_image_data<'a>( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, render_ctx: &RenderContext, transforms: &TransformContext, - ent_props: &EntityProperties, entity_path: &EntityPath, ent_context: &SpatialSceneEntityContext<'_>, data: impl Iterator>, @@ -339,7 +335,7 @@ impl ImageVisualizer { } let tensor_data_row_id = data.index.1; - let tensor = match ctx.cache.entry(|c: &mut TensorDecodeCache| { + let tensor = match ctx.viewer_ctx.cache.entry(|c: &mut TensorDecodeCache| { c.entry(tensor_data_row_id, data.tensor.0.clone()) }) { Ok(tensor) => tensor, @@ -373,7 +369,8 @@ impl ImageVisualizer { // turn influence the size of the image plane. // See: https://github.com/rerun-io/rerun/issues/3728 if ent_context.space_view_class_identifier == SpatialSpaceView2D::identifier() - || !ent_props.pinhole_image_plane_distance.is_auto() + // TODO(jleibs): Is there an equivalent for this? + // || !ent_props.pinhole_image_plane_distance.is_auto() { self.data.add_bounding_box( entity_path.hash(), @@ -397,7 +394,7 @@ impl ImageVisualizer { #[allow(clippy::too_many_arguments)] fn process_depth_image_data<'a>( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, render_ctx: &RenderContext, depth_clouds: &mut Vec, transforms: &TransformContext, @@ -436,7 +433,7 @@ impl ImageVisualizer { } let tensor_data_row_id = data.index.1; - let tensor = match ctx.cache.entry(|c: &mut TensorDecodeCache| { + let tensor = match ctx.viewer_ctx.cache.entry(|c: &mut TensorDecodeCache| { c.entry(tensor_data_row_id, data.tensor.0.clone()) }) { Ok(tensor) => tensor, @@ -503,7 +500,8 @@ impl ImageVisualizer { // turn influence the size of the image plane. // See: https://github.com/rerun-io/rerun/issues/3728 if ent_context.space_view_class_identifier == SpatialSpaceView2D::identifier() - || !ent_props.pinhole_image_plane_distance.is_auto() + // TODO(jleibs): Is there an equivalent for this? + // || !ent_props.pinhole_image_plane_distance.is_auto() { self.data.add_bounding_box( entity_path.hash(), @@ -526,7 +524,7 @@ impl ImageVisualizer { #[allow(clippy::too_many_arguments)] fn process_entity_view_as_depth_cloud( - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, render_ctx: &RenderContext, transforms: &TransformContext, ent_context: &SpatialSceneEntityContext<'_>, @@ -539,7 +537,7 @@ impl ImageVisualizer { re_tracing::profile_function!(); let Some(intrinsics) = - query_pinhole(ctx.recording(), &ctx.current_query(), parent_pinhole_path) + query_pinhole_legacy(ctx.recording(), &ctx.current_query(), parent_pinhole_path) else { anyhow::bail!("Couldn't fetch pinhole intrinsics at {parent_pinhole_path:?}"); }; @@ -568,6 +566,7 @@ impl ImageVisualizer { let debug_name = ent_path.to_string(); let tensor_stats = ctx + .viewer_ctx .cache .entry(|c: &mut TensorStatsCache| c.entry(tensor_data_row_id, tensor)); let depth_texture = re_viewer_context::gpu_bridge::tensor_to_gpu( @@ -710,12 +709,11 @@ impl VisualizerSystem for ImageVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -724,13 +722,13 @@ impl VisualizerSystem for ImageVisualizer { self.process_image_archetype::( ctx, view_query, - view_ctx, + context_systems, &mut depth_clouds, |visualizer, ctx, _depth_clouds, transforms, - entity_props, + _entity_props, entity_path, spatial_ctx, data| { @@ -738,7 +736,6 @@ impl VisualizerSystem for ImageVisualizer { ctx, render_ctx, transforms, - entity_props, entity_path, spatial_ctx, data, @@ -749,13 +746,13 @@ impl VisualizerSystem for ImageVisualizer { self.process_image_archetype::( ctx, view_query, - view_ctx, + context_systems, &mut depth_clouds, |visualizer, ctx, _depth_clouds, transforms, - entity_props, + _entity_props, entity_path, spatial_ctx, data| { @@ -763,7 +760,6 @@ impl VisualizerSystem for ImageVisualizer { ctx, render_ctx, transforms, - entity_props, entity_path, spatial_ctx, data, @@ -774,7 +770,7 @@ impl VisualizerSystem for ImageVisualizer { self.process_image_archetype::( ctx, view_query, - view_ctx, + context_systems, &mut depth_clouds, |visualizer, ctx, @@ -851,7 +847,7 @@ impl VisualizerSystem for ImageVisualizer { impl ImageVisualizer { fn process_image_archetype( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, view_ctx: &ViewContextCollection, depth_clouds: &mut Vec, @@ -860,7 +856,7 @@ impl ImageVisualizer { where F: FnMut( &mut Self, - &ViewerContext<'_>, + &ViewContext<'_>, &mut Vec, &TransformContext, &EntityProperties, diff --git a/crates/re_space_view_spatial/src/visualizers/lines2d.rs b/crates/re_space_view_spatial/src/visualizers/lines2d.rs index 91fa8d3ea77b..2f080c1c80ba 100644 --- a/crates/re_space_view_spatial/src/visualizers/lines2d.rs +++ b/crates/re_space_view_spatial/src/visualizers/lines2d.rs @@ -7,8 +7,8 @@ use re_types::{ components::{ClassId, Color, KeypointId, LineStrip2D, Radius, Text}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -193,12 +193,11 @@ impl VisualizerSystem for Lines2DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -208,8 +207,8 @@ impl VisualizerSystem for Lines2DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/lines3d.rs b/crates/re_space_view_spatial/src/visualizers/lines3d.rs index 29c903891678..5f30cf004cec 100644 --- a/crates/re_space_view_spatial/src/visualizers/lines3d.rs +++ b/crates/re_space_view_spatial/src/visualizers/lines3d.rs @@ -7,8 +7,8 @@ use re_types::{ components::{ClassId, Color, KeypointId, LineStrip3D, Radius, Text}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -202,12 +202,11 @@ impl VisualizerSystem for Lines3DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -217,8 +216,8 @@ impl VisualizerSystem for Lines3DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/meshes.rs b/crates/re_space_view_spatial/src/visualizers/meshes.rs index 0dd4af9cd8cd..5075aec96bf2 100644 --- a/crates/re_space_view_spatial/src/visualizers/meshes.rs +++ b/crates/re_space_view_spatial/src/visualizers/meshes.rs @@ -11,9 +11,9 @@ use re_types::{ }, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, SpaceViewState, SpaceViewSystemExecutionError, - ViewContextCollection, ViewQuery, ViewerContext, VisualizableEntities, - VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, + ApplicableEntities, IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, + ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, + VisualizerQueryInfo, VisualizerSystem, }; use crate::{ @@ -57,7 +57,7 @@ struct Mesh3DComponentData<'a> { impl Mesh3DVisualizer { fn process_data<'a>( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, render_ctx: &RenderContext, instances: &mut Vec, entity_path: &EntityPath, @@ -76,7 +76,7 @@ impl Mesh3DVisualizer { continue; } - let mesh = ctx.cache.entry(|c: &mut MeshCache| { + let mesh = ctx.viewer_ctx.cache.entry(|c: &mut MeshCache| { let key = MeshCacheKey { versioned_instance_path_hash: picking_instance_hash.versioned(primary_row_id), media_type: None, @@ -162,12 +162,11 @@ impl VisualizerSystem for Mesh3DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -176,8 +175,8 @@ impl VisualizerSystem for Mesh3DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/points2d.rs b/crates/re_space_view_spatial/src/visualizers/points2d.rs index d1080198132a..20a267e6acd2 100644 --- a/crates/re_space_view_spatial/src/visualizers/points2d.rs +++ b/crates/re_space_view_spatial/src/visualizers/points2d.rs @@ -9,8 +9,8 @@ use re_types::{ components::{ClassId, Color, KeypointId, Position2D, Radius, Text}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -204,12 +204,11 @@ impl VisualizerSystem for Points2DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -226,8 +225,8 @@ impl VisualizerSystem for Points2DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/points3d.rs b/crates/re_space_view_spatial/src/visualizers/points3d.rs index 1fb4f2f74825..984869c586e0 100644 --- a/crates/re_space_view_spatial/src/visualizers/points3d.rs +++ b/crates/re_space_view_spatial/src/visualizers/points3d.rs @@ -9,8 +9,8 @@ use re_types::{ components::{ClassId, Color, KeypointId, Position3D, Radius, Text}, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -195,12 +195,11 @@ impl VisualizerSystem for Points3DVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; @@ -217,8 +216,8 @@ impl VisualizerSystem for Points3DVisualizer { super::entity_iterator::process_archetype::( ctx, view_query, - view_ctx, - view_ctx.get::()?.points, + context_systems, + context_systems.get::()?.points, |ctx, entity_path, _entity_props, spatial_ctx, results| { re_tracing::profile_scope!(format!("{entity_path}")); diff --git a/crates/re_space_view_spatial/src/visualizers/transform3d_arrows.rs b/crates/re_space_view_spatial/src/visualizers/transform3d_arrows.rs index 4f55752740c0..981fac556e53 100644 --- a/crates/re_space_view_spatial/src/visualizers/transform3d_arrows.rs +++ b/crates/re_space_view_spatial/src/visualizers/transform3d_arrows.rs @@ -2,9 +2,9 @@ use egui::Color32; use re_log_types::{EntityPath, Instance}; use re_types::components::Transform3D; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, SpaceViewState, SpaceViewSystemExecutionError, - ViewContextCollection, ViewQuery, ViewerContext, VisualizableEntities, - VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, + ApplicableEntities, IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, + ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, + VisualizerQueryInfo, VisualizerSystem, }; use crate::{ @@ -45,16 +45,15 @@ impl VisualizerSystem for Transform3DArrowsVisualizer { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let Some(render_ctx) = ctx.render_ctx else { + let Some(render_ctx) = ctx.viewer_ctx.render_ctx else { return Err(SpaceViewSystemExecutionError::NoRenderContextError); }; - let transforms = view_ctx.get::()?; + let transforms = context_systems.get::()?; let latest_at_query = re_data_store::LatestAtQuery::new(query.timeline, query.latest_at); diff --git a/crates/re_space_view_tensor/src/visualizer_system.rs b/crates/re_space_view_tensor/src/visualizer_system.rs index 26fbf4fab933..527d9fb69d87 100644 --- a/crates/re_space_view_tensor/src/visualizer_system.rs +++ b/crates/re_space_view_tensor/src/visualizer_system.rs @@ -3,7 +3,7 @@ use re_entity_db::{external::re_query::LatestAtMonoResult, EntityPath}; use re_log_types::RowId; use re_types::{archetypes::Tensor, components::TensorData, tensor_data::DecodedTensor}; use re_viewer_context::{ - IdentifiedViewSystem, SpaceViewState, SpaceViewSystemExecutionError, TensorDecodeCache, + IdentifiedViewSystem, SpaceViewSystemExecutionError, TensorDecodeCache, ViewContext, ViewContextCollection, ViewQuery, ViewerContext, VisualizerQueryInfo, VisualizerSystem, }; @@ -25,10 +25,9 @@ impl VisualizerSystem for TensorSystem { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - _view_ctx: &ViewContextCollection, + _context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { re_tracing::profile_function!(); @@ -40,7 +39,7 @@ impl VisualizerSystem for TensorSystem { .recording() .latest_at_component::(&data_result.entity_path, &timeline_query) { - self.load_tensor_entity(ctx, &data_result.entity_path, tensor); + self.load_tensor_entity(ctx.viewer_ctx, &data_result.entity_path, tensor); } } diff --git a/crates/re_space_view_text_document/src/visualizer_system.rs b/crates/re_space_view_text_document/src/visualizer_system.rs index 83985b0492a4..2986aeb3b50e 100644 --- a/crates/re_space_view_text_document/src/visualizer_system.rs +++ b/crates/re_space_view_text_document/src/visualizer_system.rs @@ -1,8 +1,8 @@ use re_data_store::LatestAtQuery; use re_types::{archetypes::TextDocument, components}; use re_viewer_context::{ - IdentifiedViewSystem, SpaceViewState, SpaceViewSystemExecutionError, ViewContextCollection, - ViewQuery, ViewerContext, VisualizerQueryInfo, VisualizerSystem, + IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, + ViewQuery, VisualizerQueryInfo, VisualizerSystem, }; // --- @@ -32,10 +32,9 @@ impl VisualizerSystem for TextDocumentSystem { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - _view_ctx: &ViewContextCollection, + _context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { let timeline_query = LatestAtQuery::new(view_query.timeline, view_query.latest_at); diff --git a/crates/re_space_view_text_log/src/visualizer_system.rs b/crates/re_space_view_text_log/src/visualizer_system.rs index 4d776c28095d..322290ed9bb4 100644 --- a/crates/re_space_view_text_log/src/visualizer_system.rs +++ b/crates/re_space_view_text_log/src/visualizer_system.rs @@ -8,8 +8,8 @@ use re_types::{ Component, Loggable as _, }; use re_viewer_context::{ - IdentifiedViewSystem, SpaceViewState, SpaceViewSystemExecutionError, ViewContextCollection, - ViewQuery, ViewerContext, VisualizerQueryInfo, VisualizerSystem, + IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, + ViewQuery, VisualizerQueryInfo, VisualizerSystem, }; #[derive(Debug, Clone)] @@ -47,10 +47,9 @@ impl VisualizerSystem for TextLogSystem { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _view_state: &dyn SpaceViewState, - _view_ctx: &ViewContextCollection, + _context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { let resolver = ctx.recording().resolver(); let query = diff --git a/crates/re_space_view_time_series/src/line_visualizer_system.rs b/crates/re_space_view_time_series/src/line_visualizer_system.rs index daef1dc51d36..43a5c5e3c609 100644 --- a/crates/re_space_view_time_series/src/line_visualizer_system.rs +++ b/crates/re_space_view_time_series/src/line_visualizer_system.rs @@ -8,9 +8,8 @@ use re_types::{ Archetype as _, ComponentNameSet, Loggable, }; use re_viewer_context::{ - IdentifiedViewSystem, QueryContext, SpaceViewState, SpaceViewSystemExecutionError, - TypedComponentFallbackProvider, ViewQuery, ViewerContext, VisualizerQueryInfo, - VisualizerSystem, + IdentifiedViewSystem, QueryContext, SpaceViewSystemExecutionError, + TypedComponentFallbackProvider, ViewContext, ViewQuery, VisualizerQueryInfo, VisualizerSystem, }; use crate::overrides::fallback_color; @@ -47,14 +46,13 @@ impl VisualizerSystem for SeriesLineSystem { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - view_state: &dyn SpaceViewState, _context: &re_viewer_context::ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { re_tracing::profile_function!(); - match self.load_scalars(ctx, query, view_state) { + match self.load_scalars(ctx, query) { Ok(_) | Err(QueryError::PrimaryNotFound(_)) => Ok(Vec::new()), Err(err) => Err(err.into()), } @@ -86,13 +84,13 @@ re_viewer_context::impl_component_fallback_provider!(SeriesLineSystem => [Color, impl SeriesLineSystem { fn load_scalars( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - view_state: &dyn SpaceViewState, ) -> Result<(), QueryError> { re_tracing::profile_function!(); - let (plot_bounds, time_per_pixel) = determine_plot_bounds_and_time_per_pixel(ctx, query); + let (plot_bounds, time_per_pixel) = + determine_plot_bounds_and_time_per_pixel(ctx.viewer_ctx, query); let data_results = query.iter_visible_data_results(ctx, Self::identifier()); @@ -112,7 +110,6 @@ impl SeriesLineSystem { time_per_pixel, data_result, &mut series, - view_state, )?; Ok(series) }) @@ -130,7 +127,6 @@ impl SeriesLineSystem { time_per_pixel, data_result, &mut series, - view_state, )?; } self.all_series = series; @@ -142,24 +138,23 @@ impl SeriesLineSystem { #[allow(clippy::too_many_arguments)] fn load_series( &self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, plot_bounds: Option, time_per_pixel: f64, data_result: &re_viewer_context::DataResult, all_series: &mut Vec, - view_state: &dyn SpaceViewState, ) -> Result<(), QueryError> { re_tracing::profile_function!(); let resolver = ctx.recording().resolver(); let query_ctx = QueryContext { - viewer_ctx: ctx, + viewer_ctx: ctx.viewer_ctx, archetype_name: Some(SeriesLine::name()), query: &ctx.current_query(), target_entity_path: &data_result.entity_path, - view_state, + view_state: ctx.view_state, }; let fallback_color = @@ -192,7 +187,7 @@ impl SeriesLineSystem { view_query.latest_at, data_result, plot_bounds, - ctx.app_options.experimental_plot_query_clamping, + ctx.viewer_ctx.app_options.experimental_plot_query_clamping, ); { use re_space_view::RangeResultsExt as _; @@ -203,7 +198,7 @@ impl SeriesLineSystem { let query = re_data_store::RangeQuery::new(view_query.timeline, time_range); let results = range_with_overrides( - ctx, + ctx.viewer_ctx, None, &query, data_result, diff --git a/crates/re_space_view_time_series/src/point_visualizer_system.rs b/crates/re_space_view_time_series/src/point_visualizer_system.rs index 33f9187e708c..81858f5fee21 100644 --- a/crates/re_space_view_time_series/src/point_visualizer_system.rs +++ b/crates/re_space_view_time_series/src/point_visualizer_system.rs @@ -8,9 +8,8 @@ use re_types::{ Archetype as _, ComponentNameSet, Loggable, }; use re_viewer_context::{ - IdentifiedViewSystem, QueryContext, SpaceViewState, SpaceViewSystemExecutionError, - TypedComponentFallbackProvider, ViewQuery, ViewerContext, VisualizerQueryInfo, - VisualizerSystem, + IdentifiedViewSystem, QueryContext, SpaceViewSystemExecutionError, + TypedComponentFallbackProvider, ViewContext, ViewQuery, VisualizerQueryInfo, VisualizerSystem, }; use crate::overrides::fallback_color; @@ -50,14 +49,13 @@ impl VisualizerSystem for SeriesPointSystem { fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - view_state: &dyn SpaceViewState, _context: &re_viewer_context::ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { re_tracing::profile_function!(); - match self.load_scalars(ctx, query, view_state) { + match self.load_scalars(ctx, query) { Ok(_) | Err(QueryError::PrimaryNotFound(_)) => Ok(Vec::new()), Err(err) => Err(err.into()), } @@ -89,25 +87,24 @@ re_viewer_context::impl_component_fallback_provider!(SeriesPointSystem => [Color impl SeriesPointSystem { fn load_scalars( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - view_state: &dyn SpaceViewState, ) -> Result<(), QueryError> { re_tracing::profile_function!(); let resolver = ctx.recording().resolver(); let (plot_bounds, time_per_pixel) = - determine_plot_bounds_and_time_per_pixel(ctx, view_query); + determine_plot_bounds_and_time_per_pixel(ctx.viewer_ctx, view_query); // TODO(cmc): this should be thread-pooled in case there are a gazillon series in the same plot… for data_result in view_query.iter_visible_data_results(ctx, Self::identifier()) { let query_ctx = QueryContext { - viewer_ctx: ctx, + viewer_ctx: ctx.viewer_ctx, archetype_name: Some(SeriesPoint::name()), query: &ctx.current_query(), target_entity_path: &data_result.entity_path, - view_state, + view_state: ctx.view_state, }; let fallback_color = @@ -144,7 +141,7 @@ impl SeriesPointSystem { view_query.latest_at, data_result, plot_bounds, - ctx.app_options.experimental_plot_query_clamping, + ctx.viewer_ctx.app_options.experimental_plot_query_clamping, ); { @@ -156,7 +153,7 @@ impl SeriesPointSystem { let query = re_data_store::RangeQuery::new(view_query.timeline, time_range); let results = range_with_overrides( - ctx, + ctx.viewer_ctx, None, &query, data_result, diff --git a/crates/re_types/definitions/rerun/archetypes/pinhole.fbs b/crates/re_types/definitions/rerun/archetypes/pinhole.fbs index 4bceb2315617..5828b8e0ac2d 100644 --- a/crates/re_types/definitions/rerun/archetypes/pinhole.fbs +++ b/crates/re_types/definitions/rerun/archetypes/pinhole.fbs @@ -34,6 +34,7 @@ table Pinhole ( // --- Optional --- + /// Sets the view coordinates for the camera. /// /// All common values are available as constants on the `components.ViewCoordinates` class. @@ -63,4 +64,9 @@ table Pinhole ( /// but will be re-oriented to project along the forward axis of the `camera_xyz` argument. // TODO(#2641): This should specify a default-value of `RDF` camera_xyz: rerun.components.ViewCoordinates ("attr.rerun.component_optional", nullable, order: 3000); + + /// The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + /// + /// This is only used for visualization purposes, and does not affect the projection itself. + image_plane_distance: rerun.components.ImagePlaneDistance ("attr.rerun.component_optional", nullable, order: 4000); } diff --git a/crates/re_types/definitions/rerun/components.fbs b/crates/re_types/definitions/rerun/components.fbs index d16de85f354f..f1b5a5374e78 100644 --- a/crates/re_types/definitions/rerun/components.fbs +++ b/crates/re_types/definitions/rerun/components.fbs @@ -8,6 +8,7 @@ include "./components/disconnected_space.fbs"; include "./components/draw_order.fbs"; include "./components/half_sizes2d.fbs"; include "./components/half_sizes3d.fbs"; +include "./components/image_plane_distance.fbs"; include "./components/keypoint_id.fbs"; include "./components/line_strip2d.fbs"; include "./components/line_strip3d.fbs"; diff --git a/crates/re_types/definitions/rerun/components/image_plane_distance.fbs b/crates/re_types/definitions/rerun/components/image_plane_distance.fbs new file mode 100644 index 000000000000..37dc1f3f6ae9 --- /dev/null +++ b/crates/re_types/definitions/rerun/components/image_plane_distance.fbs @@ -0,0 +1,18 @@ +include "rust/attributes.fbs"; +include "docs/attributes.fbs"; + +include "../datatypes/float32.fbs"; + +namespace rerun.components; + +// --- + + /// The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + /// + /// This is only used for visualization purposes, and does not affect the projection itself. +struct ImagePlaneDistance ( + "attr.rust.derive": "Copy, PartialEq, PartialOrd", + "attr.docs.unreleased" +) { + image_from_camera: rerun.datatypes.Float32 (order: 100); +} diff --git a/crates/re_types/src/archetypes/pinhole.rs b/crates/re_types/src/archetypes/pinhole.rs index 516b66bfc340..8456674e2bd8 100644 --- a/crates/re_types/src/archetypes/pinhole.rs +++ b/crates/re_types/src/archetypes/pinhole.rs @@ -128,6 +128,11 @@ pub struct Pinhole { /// The pinhole matrix (the `image_from_camera` argument) always project along the third (Z) axis, /// but will be re-oriented to project along the forward axis of the `camera_xyz` argument. pub camera_xyz: Option, + + /// The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + /// + /// This is only used for visualization purposes, and does not affect the projection itself. + pub image_plane_distance: Option, } impl ::re_types_core::SizeBytes for Pinhole { @@ -136,6 +141,7 @@ impl ::re_types_core::SizeBytes for Pinhole { self.image_from_camera.heap_size_bytes() + self.resolution.heap_size_bytes() + self.camera_xyz.heap_size_bytes() + + self.image_plane_distance.heap_size_bytes() } #[inline] @@ -143,6 +149,7 @@ impl ::re_types_core::SizeBytes for Pinhole { ::is_pod() && >::is_pod() && >::is_pod() + && >::is_pod() } } @@ -157,22 +164,28 @@ static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = ] }); -static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = - once_cell::sync::Lazy::new(|| ["rerun.components.ViewCoordinates".into()]); +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.components.ViewCoordinates".into(), + "rerun.components.ImagePlaneDistance".into(), + ] + }); -static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 4usize]> = +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 5usize]> = once_cell::sync::Lazy::new(|| { [ "rerun.components.PinholeProjection".into(), "rerun.components.Resolution".into(), "rerun.components.PinholeIndicator".into(), "rerun.components.ViewCoordinates".into(), + "rerun.components.ImagePlaneDistance".into(), ] }); impl Pinhole { - /// The total number of components in the archetype: 1 required, 2 recommended, 1 optional - pub const NUM_COMPONENTS: usize = 4usize; + /// The total number of components in the archetype: 1 required, 2 recommended, 2 optional + pub const NUM_COMPONENTS: usize = 5usize; } /// Indicator component for the [`Pinhole`] [`::re_types_core::Archetype`] @@ -259,10 +272,21 @@ impl ::re_types_core::Archetype for Pinhole { } else { None }; + let image_plane_distance = + if let Some(array) = arrays_by_name.get("rerun.components.ImagePlaneDistance") { + ::from_arrow_opt(&**array) + .with_context("rerun.archetypes.Pinhole#image_plane_distance")? + .into_iter() + .next() + .flatten() + } else { + None + }; Ok(Self { image_from_camera, resolution, camera_xyz, + image_plane_distance, }) } } @@ -280,6 +304,9 @@ impl ::re_types_core::AsComponents for Pinhole { self.camera_xyz .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), + self.image_plane_distance + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), ] .into_iter() .flatten() @@ -295,6 +322,7 @@ impl Pinhole { image_from_camera: image_from_camera.into(), resolution: None, camera_xyz: None, + image_plane_distance: None, } } @@ -347,4 +375,16 @@ impl Pinhole { self.camera_xyz = Some(camera_xyz.into()); self } + + /// The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + /// + /// This is only used for visualization purposes, and does not affect the projection itself. + #[inline] + pub fn with_image_plane_distance( + mut self, + image_plane_distance: impl Into, + ) -> Self { + self.image_plane_distance = Some(image_plane_distance.into()); + self + } } diff --git a/crates/re_types/src/components/.gitattributes b/crates/re_types/src/components/.gitattributes index 3275dfd96b81..fa15c2b5ca1d 100644 --- a/crates/re_types/src/components/.gitattributes +++ b/crates/re_types/src/components/.gitattributes @@ -10,6 +10,7 @@ disconnected_space.rs linguist-generated=true draw_order.rs linguist-generated=true half_sizes2d.rs linguist-generated=true half_sizes3d.rs linguist-generated=true +image_plane_distance.rs linguist-generated=true keypoint_id.rs linguist-generated=true line_strip2d.rs linguist-generated=true line_strip3d.rs linguist-generated=true diff --git a/crates/re_types/src/components/image_plane_distance.rs b/crates/re_types/src/components/image_plane_distance.rs new file mode 100644 index 000000000000..91f5c44326ef --- /dev/null +++ b/crates/re_types/src/components/image_plane_distance.rs @@ -0,0 +1,186 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/re_types/definitions/rerun/components/image_plane_distance.fbs". + +#![allow(trivial_numeric_casts)] +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::iter_on_single_items)] +#![allow(clippy::map_flatten)] +#![allow(clippy::match_wildcard_for_single_variants)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] +#![allow(clippy::unnecessary_cast)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Component**: The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. +/// +/// This is only used for visualization purposes, and does not affect the projection itself. +#[derive(Clone, Debug, Copy, PartialEq, PartialOrd)] +pub struct ImagePlaneDistance(pub crate::datatypes::Float32); + +impl ::re_types_core::SizeBytes for ImagePlaneDistance { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + } +} + +impl> From for ImagePlaneDistance { + fn from(v: T) -> Self { + Self(v.into()) + } +} + +impl std::borrow::Borrow for ImagePlaneDistance { + #[inline] + fn borrow(&self) -> &crate::datatypes::Float32 { + &self.0 + } +} + +impl std::ops::Deref for ImagePlaneDistance { + type Target = crate::datatypes::Float32; + + #[inline] + fn deref(&self) -> &crate::datatypes::Float32 { + &self.0 + } +} + +impl std::ops::DerefMut for ImagePlaneDistance { + #[inline] + fn deref_mut(&mut self) -> &mut crate::datatypes::Float32 { + &mut self.0 + } +} + +::re_types_core::macros::impl_into_cow!(ImagePlaneDistance); + +impl ::re_types_core::Loggable for ImagePlaneDistance { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.components.ImagePlaneDistance".into() + } + + #[allow(clippy::wildcard_imports)] + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + use arrow2::datatypes::*; + DataType::Float32 + } + + #[allow(clippy::wildcard_imports)] + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data0): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + let datum = datum.map(|datum| datum.into_owned().0); + (datum.is_some(), datum) + }) + .unzip(); + let data0_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + Self::arrow_datatype(), + data0 + .into_iter() + .map(|datum| datum.map(|datum| datum.0).unwrap_or_default()) + .collect(), + data0_bitmap, + ) + .boxed() + }) + } + + #[allow(clippy::wildcard_imports)] + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok(arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.components.ImagePlaneDistance#image_from_camera")? + .into_iter() + .map(|opt| opt.copied()) + .map(|res_or_opt| res_or_opt.map(|v| crate::datatypes::Float32(v))) + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .map(|res| res.map(|v| Some(Self(v)))) + .collect::>>>() + .with_context("rerun.components.ImagePlaneDistance#image_from_camera") + .with_context("rerun.components.ImagePlaneDistance")?) + } + + #[allow(clippy::wildcard_imports)] + #[inline] + fn from_arrow(arrow_data: &dyn arrow2::array::Array) -> DeserializationResult> + where + Self: Sized, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + if let Some(validity) = arrow_data.validity() { + if validity.unset_bits() != 0 { + return Err(DeserializationError::missing_data()); + } + } + Ok({ + let slice = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::Float32; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.components.ImagePlaneDistance#image_from_camera")? + .values() + .as_slice(); + { + slice + .iter() + .copied() + .map(|v| crate::datatypes::Float32(v)) + .map(|v| Self(v)) + .collect::>() + } + }) + } +} diff --git a/crates/re_types/src/components/image_plane_distance_ext.rs b/crates/re_types/src/components/image_plane_distance_ext.rs new file mode 100644 index 000000000000..ccc232b9952d --- /dev/null +++ b/crates/re_types/src/components/image_plane_distance_ext.rs @@ -0,0 +1,15 @@ +use super::ImagePlaneDistance; + +impl Default for ImagePlaneDistance { + #[inline] + fn default() -> Self { + 1.0.into() + } +} + +impl From for f32 { + #[inline] + fn from(val: ImagePlaneDistance) -> Self { + val.0.into() + } +} diff --git a/crates/re_types/src/components/mod.rs b/crates/re_types/src/components/mod.rs index bf970bcbcf8d..51ef9ca0fdc0 100644 --- a/crates/re_types/src/components/mod.rs +++ b/crates/re_types/src/components/mod.rs @@ -17,6 +17,8 @@ mod half_sizes2d; mod half_sizes2d_ext; mod half_sizes3d; mod half_sizes3d_ext; +mod image_plane_distance; +mod image_plane_distance_ext; mod keypoint_id; mod keypoint_id_ext; mod line_strip2d; @@ -79,6 +81,7 @@ pub use self::disconnected_space::DisconnectedSpace; pub use self::draw_order::DrawOrder; pub use self::half_sizes2d::HalfSizes2D; pub use self::half_sizes3d::HalfSizes3D; +pub use self::image_plane_distance::ImagePlaneDistance; pub use self::keypoint_id::KeypointId; pub use self::line_strip2d::LineStrip2D; pub use self::line_strip3d::LineStrip3D; diff --git a/crates/re_types/tests/pinhole.rs b/crates/re_types/tests/pinhole.rs index 88a91e535f4f..898a685fda75 100644 --- a/crates/re_types/tests/pinhole.rs +++ b/crates/re_types/tests/pinhole.rs @@ -12,6 +12,7 @@ fn roundtrip() { ), resolution: Some(components::Resolution([1.0, 2.0].into())), camera_xyz: Some(components::ViewCoordinates::RDF), + image_plane_distance: None, }; let arch = Pinhole::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]) diff --git a/crates/re_viewer/src/component_defaults/mod.rs b/crates/re_viewer/src/component_defaults/mod.rs index 63421e3350ec..9279b5a49c08 100644 --- a/crates/re_viewer/src/component_defaults/mod.rs +++ b/crates/re_viewer/src/component_defaults/mod.rs @@ -141,6 +141,10 @@ pub fn list_default_components( ::name(), HalfSizes3D::default().to_arrow()?, ), + ( + ::name(), + ImagePlaneDistance::default().to_arrow()?, + ), ( ::name(), KeypointId::default().to_arrow()?, diff --git a/crates/re_viewer_context/src/component_fallbacks.rs b/crates/re_viewer_context/src/component_fallbacks.rs index 097bbbf1fd1e..8c5ac1f305b7 100644 --- a/crates/re_viewer_context/src/component_fallbacks.rs +++ b/crates/re_viewer_context/src/component_fallbacks.rs @@ -112,12 +112,12 @@ macro_rules! impl_component_fallback_provider { impl $crate::ComponentFallbackProvider for $type { fn try_provide_fallback( &self, - ctx: &$crate::QueryContext<'_>, - component_name: re_types::ComponentName, + _ctx: &$crate::QueryContext<'_>, + _component_name: re_types::ComponentName, ) -> $crate::ComponentFallbackProviderResult { $( - if component_name == <$component as re_types::Loggable>::name() { - return $crate::TypedComponentFallbackProvider::<$component>::fallback_for(self, ctx).into(); + if _component_name == <$component as re_types::Loggable>::name() { + return $crate::TypedComponentFallbackProvider::<$component>::fallback_for(self, _ctx).into(); } )* $crate::ComponentFallbackProviderResult::ComponentNotHandled diff --git a/crates/re_viewer_context/src/lib.rs b/crates/re_viewer_context/src/lib.rs index 3ef3344c0b95..67473ca1c572 100644 --- a/crates/re_viewer_context/src/lib.rs +++ b/crates/re_viewer_context/src/lib.rs @@ -64,7 +64,7 @@ pub use space_view::{ SpaceViewClassExt, SpaceViewClassLayoutPriority, SpaceViewClassRegistry, SpaceViewClassRegistryError, SpaceViewEntityHighlight, SpaceViewHighlights, SpaceViewOutlineMasks, SpaceViewSpawnHeuristics, SpaceViewState, SpaceViewStateExt, - SpaceViewSystemExecutionError, SpaceViewSystemRegistrator, SystemExecutionOutput, + SpaceViewSystemExecutionError, SpaceViewSystemRegistrator, SystemExecutionOutput, ViewContext, ViewContextCollection, ViewContextSystem, ViewQuery, ViewStates, ViewSystemIdentifier, VisualizableFilterContext, VisualizerAdditionalApplicabilityFilter, VisualizerCollection, VisualizerQueryInfo, VisualizerSystem, diff --git a/crates/re_viewer_context/src/space_view/mod.rs b/crates/re_viewer_context/src/space_view/mod.rs index 7b1f1dd00adf..226fa719ac15 100644 --- a/crates/re_viewer_context/src/space_view/mod.rs +++ b/crates/re_viewer_context/src/space_view/mod.rs @@ -11,6 +11,7 @@ mod space_view_class_placeholder; mod space_view_class_registry; mod spawn_heuristics; mod system_execution_output; +mod view_context; mod view_context_system; mod view_query; mod view_states; @@ -28,6 +29,7 @@ pub use space_view_class_registry::{ }; pub use spawn_heuristics::{RecommendedSpaceView, SpaceViewSpawnHeuristics}; pub use system_execution_output::SystemExecutionOutput; +pub use view_context::ViewContext; pub use view_context_system::{ViewContextCollection, ViewContextSystem}; pub use view_query::{ DataResult, OverridePath, PerSystemDataResults, PropertyOverrides, SmallVisualizerSet, diff --git a/crates/re_viewer_context/src/space_view/space_view_class_placeholder.rs b/crates/re_viewer_context/src/space_view/space_view_class_placeholder.rs index e44f378405bc..19a37abaded3 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class_placeholder.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class_placeholder.rs @@ -59,3 +59,5 @@ impl SpaceViewClass for SpaceViewClassPlaceholder { Ok(()) } } + +crate::impl_component_fallback_provider!(SpaceViewClassPlaceholder => []); diff --git a/crates/re_viewer_context/src/space_view/view_context.rs b/crates/re_viewer_context/src/space_view/view_context.rs new file mode 100644 index 000000000000..1e79c556f18c --- /dev/null +++ b/crates/re_viewer_context/src/space_view/view_context.rs @@ -0,0 +1,72 @@ +use crate::{DataQueryResult, SpaceViewId}; + +/// The context associated with a view. +/// +/// This combines our [`crate::ViewerContext`] with [`crate::SpaceViewState`] +/// and other view-specific information. This is used as the interface for +/// execution of view systems and selection panel UI elements that happen +/// within the context of a view to simplify plumbing of the necessary +/// information to resolve a query with possible overrides and fallback values. +pub struct ViewContext<'a> { + pub viewer_ctx: &'a crate::ViewerContext<'a>, + pub view_state: &'a dyn crate::SpaceViewState, + pub visualizer_collection: &'a crate::VisualizerCollection, +} + +impl<'a> ViewContext<'a> { + /// The active recording. + #[inline] + pub fn recording(&self) -> &re_entity_db::EntityDb { + self.viewer_ctx.recording() + } + + /// The data store of the active recording. + #[inline] + pub fn recording_store(&self) -> &re_data_store::DataStore { + self.viewer_ctx.recording_store() + } + + /// The active blueprint. + #[inline] + pub fn blueprint_db(&self) -> &re_entity_db::EntityDb { + self.viewer_ctx.blueprint_db() + } + + /// The `StoreId` of the active recording. + #[inline] + pub fn recording_id(&self) -> &re_log_types::StoreId { + self.viewer_ctx.recording_id() + } + + /// Returns the current selection. + pub fn selection(&self) -> &crate::ItemCollection { + self.viewer_ctx.selection() + } + + /// Returns the currently hovered objects. + pub fn hovered(&self) -> &crate::ItemCollection { + self.viewer_ctx.hovered() + } + + pub fn selection_state(&self) -> &crate::ApplicationSelectionState { + self.viewer_ctx.selection_state() + } + + /// The current time query, based on the current time control. + pub fn current_query(&self) -> re_data_store::LatestAtQuery { + self.viewer_ctx.current_query() + } + + /// Set hover/select/focus for a given selection based on an egui response. + pub fn select_hovered_on_click( + &self, + response: &egui::Response, + selection: impl Into, + ) { + self.viewer_ctx.select_hovered_on_click(response, selection); + } + + pub fn lookup_query_result(&self, id: SpaceViewId) -> &DataQueryResult { + self.viewer_ctx.lookup_query_result(id) + } +} diff --git a/crates/re_viewer_context/src/space_view/view_context_system.rs b/crates/re_viewer_context/src/space_view/view_context_system.rs index c9a55b9a5775..f0e6f899b5d4 100644 --- a/crates/re_viewer_context/src/space_view/view_context_system.rs +++ b/crates/re_viewer_context/src/space_view/view_context_system.rs @@ -2,10 +2,9 @@ use ahash::HashMap; use re_types::{ComponentNameSet, SpaceViewClassIdentifier}; -use crate::{ - IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewQuery, ViewSystemIdentifier, - ViewerContext, -}; +use crate::{IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewQuery, ViewSystemIdentifier}; + +use super::view_context::ViewContext; /// View context that can be used by view parts and ui methods to retrieve information about the scene as a whole. /// @@ -23,7 +22,7 @@ pub trait ViewContextSystem: Send + Sync { fn compatible_component_sets(&self) -> Vec; /// Queries the data store and performs data conversions to make it ready for consumption by scene elements. - fn execute(&mut self, ctx: &ViewerContext<'_>, query: &ViewQuery<'_>); + fn execute(&mut self, ctx: &ViewContext<'_>, query: &ViewQuery<'_>); /// Converts itself to a reference of [`std::any::Any`], which enables downcasting to concrete types. fn as_any(&self) -> &dyn std::any::Any; diff --git a/crates/re_viewer_context/src/space_view/view_query.rs b/crates/re_viewer_context/src/space_view/view_query.rs index 30bc8568001d..69e97373716b 100644 --- a/crates/re_viewer_context/src/space_view/view_query.rs +++ b/crates/re_viewer_context/src/space_view/view_query.rs @@ -11,8 +11,8 @@ use re_log_types::StoreKind; use re_types::ComponentName; use crate::{ - DataResultTree, QueryRange, SpaceViewHighlights, SpaceViewId, ViewSystemIdentifier, - ViewerContext, + DataResultTree, QueryRange, SpaceViewHighlights, SpaceViewId, ViewContext, + ViewSystemIdentifier, ViewerContext, }; /// Path to a specific entity in a specific store used for overrides. @@ -196,6 +196,30 @@ impl DataResult { ctx.save_blueprint_component(recursive_override_path, desired_override); } + /// Saves a recursive override, does not take into current or default values. + /// + /// Ignores individual overrides and current value. + pub fn save_individual_override( + &self, + ctx: &ViewerContext<'_>, + desired_override: &C, + ) { + re_tracing::profile_function!(); + + // TODO(jleibs): Make it impossible for this to happen with different type structure + // This should never happen unless we're doing something with a partially processed + // query. + let Some(override_path) = self.individual_override_path() else { + re_log::warn!( + "Tried to save override for {:?} but it has no override path", + self.entity_path + ); + return; + }; + + ctx.save_blueprint_component(override_path, desired_override); + } + /// Clears the recursive override for a given component pub fn clear_recursive_override(&self, ctx: &ViewerContext<'_>) { // TODO(jleibs): Make it impossible for this to happen with different type structure @@ -428,7 +452,7 @@ impl<'s> ViewQuery<'s> { /// Iter over all of the currently visible [`DataResult`]s for a given `ViewSystem` pub fn iter_visible_data_results<'a>( &'a self, - ctx: &'a ViewerContext<'a>, + ctx: &'a ViewContext<'a>, visualizer: ViewSystemIdentifier, ) -> impl Iterator where @@ -440,7 +464,7 @@ impl<'s> ViewQuery<'s> { itertools::Either::Right( results .iter() - .filter(|result| result.is_visible(ctx)) + .filter(|result| result.is_visible(ctx.viewer_ctx)) .copied(), ) }, diff --git a/crates/re_viewer_context/src/space_view/visualizer_system.rs b/crates/re_viewer_context/src/space_view/visualizer_system.rs index 12be7d9cec25..6b450a401854 100644 --- a/crates/re_viewer_context/src/space_view/visualizer_system.rs +++ b/crates/re_viewer_context/src/space_view/visualizer_system.rs @@ -3,9 +3,9 @@ use ahash::HashMap; use re_types::{Archetype, ComponentNameSet}; use crate::{ - ApplicableEntities, ComponentFallbackProvider, IdentifiedViewSystem, SpaceViewState, - SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewSystemIdentifier, - ViewerContext, VisualizableEntities, VisualizableFilterContext, + ApplicableEntities, ComponentFallbackProvider, IdentifiedViewSystem, + SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, + ViewSystemIdentifier, VisualizableEntities, VisualizableFilterContext, VisualizerAdditionalApplicabilityFilter, }; @@ -82,10 +82,9 @@ pub trait VisualizerSystem: Send + Sync + ComponentFallbackProvider + 'static { /// Mustn't query any data outside of the archetype. fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - view_state: &dyn SpaceViewState, - view_ctx: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError>; /// Optionally retrieves a data store reference from the scene element. diff --git a/crates/re_viewport/src/system_execution.rs b/crates/re_viewport/src/system_execution.rs index 0e0d3334fd56..524cf911e74f 100644 --- a/crates/re_viewport/src/system_execution.rs +++ b/crates/re_viewport/src/system_execution.rs @@ -15,13 +15,24 @@ use re_viewport_blueprint::SpaceViewBlueprint; fn run_space_view_systems( ctx: &ViewerContext<'_>, - _space_view_class: SpaceViewClassIdentifier, + space_view_class: SpaceViewClassIdentifier, query: &ViewQuery<'_>, view_state: &dyn SpaceViewState, context_systems: &mut ViewContextCollection, view_systems: &mut VisualizerCollection, ) -> Vec { - re_tracing::profile_function!(_space_view_class.as_str()); + re_tracing::profile_function!(space_view_class.as_str()); + + // TODO(jleibs): This is weird. Most of the time we don't need this. + let visualizer_collection = ctx + .space_view_class_registry + .new_visualizer_collection(space_view_class); + + let view_ctx = re_viewer_context::ViewContext { + viewer_ctx: ctx, + view_state, + visualizer_collection: &visualizer_collection, + }; { re_tracing::profile_wait!("ViewContextSystem::execute"); @@ -30,7 +41,7 @@ fn run_space_view_systems( .par_iter_mut() .for_each(|(_name, system)| { re_tracing::profile_scope!("ViewContextSystem::execute", _name.as_str()); - system.execute(ctx, query); + system.execute(&view_ctx, query); }); }; @@ -40,7 +51,7 @@ fn run_space_view_systems( .par_iter_mut() .map(|(name, part)| { re_tracing::profile_scope!("VisualizerSystem::execute", name.as_str()); - match part.execute(ctx, query, view_state, context_systems) { + match part.execute(&view_ctx, query, context_systems) { Ok(part_draw_data) => part_draw_data, Err(err) => { re_log::error_once!("Error executing visualizer {name:?}: {err}"); diff --git a/docs/content/reference/types/archetypes/pinhole.md b/docs/content/reference/types/archetypes/pinhole.md index 924a93fc6ffe..342c43255e03 100644 --- a/docs/content/reference/types/archetypes/pinhole.md +++ b/docs/content/reference/types/archetypes/pinhole.md @@ -11,7 +11,7 @@ Camera perspective projection (a.k.a. intrinsics). **Recommended**: [`Resolution`](../components/resolution.md) -**Optional**: [`ViewCoordinates`](../components/view_coordinates.md) +**Optional**: [`ViewCoordinates`](../components/view_coordinates.md), [`ImagePlaneDistance`](../components/image_plane_distance.md) ## Shown in * [Spatial2DView](../views/spatial2d_view.md) diff --git a/docs/content/reference/types/components.md b/docs/content/reference/types/components.md index 60836ae770a1..41cb9de0d931 100644 --- a/docs/content/reference/types/components.md +++ b/docs/content/reference/types/components.md @@ -23,6 +23,7 @@ on [Entities and Components](../../concepts/entity-component.md). * [`DrawOrder`](components/draw_order.md): Draw order used for the display order of 2D elements. * [`HalfSizes2D`](components/half_sizes2d.md): Half-sizes (extents) of a 2D box along its local axis, starting at its local origin/center. * [`HalfSizes3D`](components/half_sizes3d.md): Half-sizes (extents) of a 3D box along its local axis, starting at its local origin/center. +* [`ImagePlaneDistance`](components/image_plane_distance.md): The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. * [`KeypointId`](components/keypoint_id.md): A 16-bit ID representing a type of semantic keypoint within a class. * [`LineStrip2D`](components/line_strip2d.md): A line strip in 2D space. * [`LineStrip3D`](components/line_strip3d.md): A line strip in 3D space. diff --git a/docs/content/reference/types/components/.gitattributes b/docs/content/reference/types/components/.gitattributes index 5b0baa0b1f8e..a9818981d6b9 100644 --- a/docs/content/reference/types/components/.gitattributes +++ b/docs/content/reference/types/components/.gitattributes @@ -11,6 +11,7 @@ disconnected_space.md linguist-generated=true draw_order.md linguist-generated=true half_sizes2d.md linguist-generated=true half_sizes3d.md linguist-generated=true +image_plane_distance.md linguist-generated=true keypoint_id.md linguist-generated=true line_strip2d.md linguist-generated=true line_strip3d.md linguist-generated=true diff --git a/docs/content/reference/types/components/image_plane_distance.md b/docs/content/reference/types/components/image_plane_distance.md new file mode 100644 index 000000000000..9136c5ad60a0 --- /dev/null +++ b/docs/content/reference/types/components/image_plane_distance.md @@ -0,0 +1,22 @@ +--- +title: "ImagePlaneDistance" +--- + + +The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + +This is only used for visualization purposes, and does not affect the projection itself. + +## Fields + +* image_from_camera: [`Float32`](../datatypes/float32.md) + +## API reference links + * 🌊 [C++ API docs for `ImagePlaneDistance`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1components_1_1ImagePlaneDistance.html?speculative-link) + * 🐍 [Python API docs for `ImagePlaneDistance`](https://ref.rerun.io/docs/python/stable/common/components?speculative-link#rerun.components.ImagePlaneDistance) + * 🦀 [Rust API docs for `ImagePlaneDistance`](https://docs.rs/rerun/latest/rerun/components/struct.ImagePlaneDistance.html?speculative-link) + + +## Used by + +* [`Pinhole`](../archetypes/pinhole.md) diff --git a/docs/content/reference/types/datatypes/float32.md b/docs/content/reference/types/datatypes/float32.md index e6e1c7b7228c..fbd8738f83e0 100644 --- a/docs/content/reference/types/datatypes/float32.md +++ b/docs/content/reference/types/datatypes/float32.md @@ -15,3 +15,6 @@ A single-precision 32-bit IEEE 754 floating point number. * 🦀 [Rust API docs for `Float32`](https://docs.rs/rerun/latest/rerun/datatypes/struct.Float32.html) +## Used by + +* [`ImagePlaneDistance`](../components/image_plane_distance.md?speculative-link) diff --git a/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs b/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs index 615ad1e039f7..e4d34f531a8f 100644 --- a/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs +++ b/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs @@ -4,8 +4,9 @@ use re_viewer::external::{ re_renderer, re_types::{self, components::Color, ComponentName, Loggable as _}, re_viewer_context::{ - self, IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContextCollection, - ViewQuery, ViewSystemIdentifier, ViewerContext, VisualizerQueryInfo, VisualizerSystem, + self, IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, + ViewContextCollection, ViewQuery, ViewSystemIdentifier, VisualizerQueryInfo, + VisualizerSystem, }, }; @@ -52,10 +53,9 @@ impl VisualizerSystem for InstanceColorSystem { /// Populates the scene part with data from the store. fn execute( &mut self, - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &ViewQuery<'_>, - _view_state: &dyn re_viewer_context::SpaceViewState, - _view_ctx: &ViewContextCollection, + _context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { // For each entity in the space view that should be displayed with the `InstanceColorSystem`… for data_result in query.iter_visible_data_results(ctx, Self::identifier()) { diff --git a/rerun_cpp/src/rerun/archetypes/pinhole.cpp b/rerun_cpp/src/rerun/archetypes/pinhole.cpp index 7d6d1c9d5add..f8e684b56c05 100644 --- a/rerun_cpp/src/rerun/archetypes/pinhole.cpp +++ b/rerun_cpp/src/rerun/archetypes/pinhole.cpp @@ -14,7 +14,7 @@ namespace rerun { ) { using namespace archetypes; std::vector cells; - cells.reserve(4); + cells.reserve(5); { auto result = DataCell::from_loggable(archetype.image_from_camera); @@ -31,6 +31,11 @@ namespace rerun { RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } + if (archetype.image_plane_distance.has_value()) { + auto result = DataCell::from_loggable(archetype.image_plane_distance.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } { auto indicator = Pinhole::IndicatorComponent(); auto result = DataCell::from_loggable(indicator); diff --git a/rerun_cpp/src/rerun/archetypes/pinhole.hpp b/rerun_cpp/src/rerun/archetypes/pinhole.hpp index 2fcc47bd9f7b..e2d07c239c02 100644 --- a/rerun_cpp/src/rerun/archetypes/pinhole.hpp +++ b/rerun_cpp/src/rerun/archetypes/pinhole.hpp @@ -5,6 +5,7 @@ #include "../collection.hpp" #include "../compiler_utils.hpp" +#include "../components/image_plane_distance.hpp" #include "../components/pinhole_projection.hpp" #include "../components/resolution.hpp" #include "../components/view_coordinates.hpp" @@ -116,6 +117,11 @@ namespace rerun::archetypes { /// but will be re-oriented to project along the forward axis of the `camera_xyz` argument. std::optional camera_xyz; + /// The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + /// + /// This is only used for visualization purposes, and does not affect the projection itself. + std::optional image_plane_distance; + public: static constexpr const char IndicatorComponentName[] = "rerun.components.PinholeIndicator"; @@ -230,6 +236,17 @@ namespace rerun::archetypes { // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } + + /// The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + /// + /// This is only used for visualization purposes, and does not affect the projection itself. + Pinhole with_image_plane_distance( + rerun::components::ImagePlaneDistance _image_plane_distance + ) && { + image_plane_distance = std::move(_image_plane_distance); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } }; } // namespace rerun::archetypes diff --git a/rerun_cpp/src/rerun/components.hpp b/rerun_cpp/src/rerun/components.hpp index 3f00d28e6321..d56a35af8ca7 100644 --- a/rerun_cpp/src/rerun/components.hpp +++ b/rerun_cpp/src/rerun/components.hpp @@ -12,6 +12,7 @@ #include "components/draw_order.hpp" #include "components/half_sizes2d.hpp" #include "components/half_sizes3d.hpp" +#include "components/image_plane_distance.hpp" #include "components/keypoint_id.hpp" #include "components/line_strip2d.hpp" #include "components/line_strip3d.hpp" diff --git a/rerun_cpp/src/rerun/components/.gitattributes b/rerun_cpp/src/rerun/components/.gitattributes index f40618f10505..d4f61adb5784 100644 --- a/rerun_cpp/src/rerun/components/.gitattributes +++ b/rerun_cpp/src/rerun/components/.gitattributes @@ -17,6 +17,7 @@ draw_order.cpp linguist-generated=true draw_order.hpp linguist-generated=true half_sizes2d.hpp linguist-generated=true half_sizes3d.hpp linguist-generated=true +image_plane_distance.hpp linguist-generated=true keypoint_id.hpp linguist-generated=true line_strip2d.cpp linguist-generated=true line_strip2d.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/components/image_plane_distance.hpp b/rerun_cpp/src/rerun/components/image_plane_distance.hpp new file mode 100644 index 000000000000..b16144fd4590 --- /dev/null +++ b/rerun_cpp/src/rerun/components/image_plane_distance.hpp @@ -0,0 +1,67 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/re_types/definitions/rerun/components/image_plane_distance.fbs". + +#pragma once + +#include "../datatypes/float32.hpp" +#include "../result.hpp" + +#include +#include + +namespace rerun::components { + /// **Component**: The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + /// + /// This is only used for visualization purposes, and does not affect the projection itself. + struct ImagePlaneDistance { + rerun::datatypes::Float32 image_from_camera; + + public: + ImagePlaneDistance() = default; + + ImagePlaneDistance(rerun::datatypes::Float32 image_from_camera_) + : image_from_camera(image_from_camera_) {} + + ImagePlaneDistance& operator=(rerun::datatypes::Float32 image_from_camera_) { + image_from_camera = image_from_camera_; + return *this; + } + + ImagePlaneDistance(float value_) : image_from_camera(value_) {} + + ImagePlaneDistance& operator=(float value_) { + image_from_camera = value_; + return *this; + } + + /// Cast to the underlying Float32 datatype + operator rerun::datatypes::Float32() const { + return image_from_camera; + } + }; +} // namespace rerun::components + +namespace rerun { + static_assert(sizeof(rerun::datatypes::Float32) == sizeof(components::ImagePlaneDistance)); + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.components.ImagePlaneDistance"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype() { + return Loggable::arrow_datatype(); + } + + /// Serializes an array of `rerun::components::ImagePlaneDistance` into an arrow array. + static Result> to_arrow( + const components::ImagePlaneDistance* instances, size_t num_instances + ) { + return Loggable::to_arrow( + &instances->image_from_camera, + num_instances + ); + } + }; +} // namespace rerun diff --git a/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py b/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py index 4ecb12f9b295..c66fac6298fb 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py @@ -73,6 +73,7 @@ def __attrs_clear__(self) -> None: image_from_camera=None, # type: ignore[arg-type] resolution=None, # type: ignore[arg-type] camera_xyz=None, # type: ignore[arg-type] + image_plane_distance=None, # type: ignore[arg-type] ) @classmethod @@ -141,5 +142,16 @@ def _clear(cls) -> Pinhole: # # (Docstring intentionally commented out to hide this field from the docs) + image_plane_distance: components.ImagePlaneDistanceBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=components.ImagePlaneDistanceBatch._optional, # type: ignore[misc] + ) + # The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + # + # This is only used for visualization purposes, and does not affect the projection itself. + # + # (Docstring intentionally commented out to hide this field from the docs) + __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py index 9ff59d7d7d5d..fd34431d3a99 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py @@ -26,6 +26,7 @@ def __init__( principal_point: npt.ArrayLike | None = None, fov_y: float | None = None, aspect_ratio: float | None = None, + image_plane_distance: float | None = None, ) -> None: """ Create a new instance of the Pinhole archetype. @@ -85,6 +86,9 @@ def __init__( Vertical field of view in radians. aspect_ratio Aspect ratio (width/height). + image_plane_distance: + The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + This is only used for visualization purposes, and does not affect the projection itself. """ @@ -148,7 +152,12 @@ def __init__( if fov_y is not None or aspect_ratio is not None: _send_warning_or_raise("Both image_from_camera and fov_y or aspect_ratio set", 1) - self.__attrs_init__(image_from_camera=image_from_camera, resolution=resolution, camera_xyz=camera_xyz) + self.__attrs_init__( + image_from_camera=image_from_camera, + resolution=resolution, + camera_xyz=camera_xyz, + image_plane_distance=image_plane_distance, + ) return self.__attrs_clear__() diff --git a/rerun_py/rerun_sdk/rerun/components/.gitattributes b/rerun_py/rerun_sdk/rerun/components/.gitattributes index 3df5fe24099f..370009cd9b0b 100644 --- a/rerun_py/rerun_sdk/rerun/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/components/.gitattributes @@ -12,6 +12,7 @@ disconnected_space.py linguist-generated=true draw_order.py linguist-generated=true half_sizes2d.py linguist-generated=true half_sizes3d.py linguist-generated=true +image_plane_distance.py linguist-generated=true keypoint_id.py linguist-generated=true line_strip2d.py linguist-generated=true line_strip3d.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/components/__init__.py b/rerun_py/rerun_sdk/rerun/components/__init__.py index fcf59159f53d..1788b743be0a 100644 --- a/rerun_py/rerun_sdk/rerun/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/components/__init__.py @@ -30,6 +30,7 @@ from .draw_order import DrawOrder, DrawOrderArrayLike, DrawOrderBatch, DrawOrderLike, DrawOrderType from .half_sizes2d import HalfSizes2D, HalfSizes2DBatch, HalfSizes2DType from .half_sizes3d import HalfSizes3D, HalfSizes3DBatch, HalfSizes3DType +from .image_plane_distance import ImagePlaneDistance, ImagePlaneDistanceBatch, ImagePlaneDistanceType from .keypoint_id import KeypointId, KeypointIdBatch, KeypointIdType from .line_strip2d import LineStrip2D, LineStrip2DArrayLike, LineStrip2DBatch, LineStrip2DLike, LineStrip2DType from .line_strip3d import LineStrip3D, LineStrip3DArrayLike, LineStrip3DBatch, LineStrip3DLike, LineStrip3DType @@ -114,6 +115,9 @@ "HalfSizes3D", "HalfSizes3DBatch", "HalfSizes3DType", + "ImagePlaneDistance", + "ImagePlaneDistanceBatch", + "ImagePlaneDistanceType", "KeypointId", "KeypointIdBatch", "KeypointIdType", diff --git a/rerun_py/rerun_sdk/rerun/components/image_plane_distance.py b/rerun_py/rerun_sdk/rerun/components/image_plane_distance.py new file mode 100644 index 000000000000..0ea89aa69cd5 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/components/image_plane_distance.py @@ -0,0 +1,32 @@ +# DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/re_types/definitions/rerun/components/image_plane_distance.fbs". + +# You can extend this class by creating a "ImagePlaneDistanceExt" class in "image_plane_distance_ext.py". + +from __future__ import annotations + +from .. import datatypes +from .._baseclasses import ComponentBatchMixin + +__all__ = ["ImagePlaneDistance", "ImagePlaneDistanceBatch", "ImagePlaneDistanceType"] + + +class ImagePlaneDistance(datatypes.Float32): + """ + **Component**: The distance from the camera origin to the image plane when the projection is shown in a 3D viewer. + + This is only used for visualization purposes, and does not affect the projection itself. + """ + + # You can define your own __init__ function as a member of ImagePlaneDistanceExt in image_plane_distance_ext.py + + # Note: there are no fields here because ImagePlaneDistance delegates to datatypes.Float32 + pass + + +class ImagePlaneDistanceType(datatypes.Float32Type): + _TYPE_NAME: str = "rerun.components.ImagePlaneDistance" + + +class ImagePlaneDistanceBatch(datatypes.Float32Batch, ComponentBatchMixin): + _ARROW_TYPE = ImagePlaneDistanceType() diff --git a/tests/python/release_checklist/check_all_components_ui.py b/tests/python/release_checklist/check_all_components_ui.py index b2d445b657e2..353d1c8fdf91 100644 --- a/tests/python/release_checklist/check_all_components_ui.py +++ b/tests/python/release_checklist/check_all_components_ui.py @@ -103,6 +103,7 @@ def alternatives(self) -> list[Any] | None: "DrawOrderBatch": TestCase(100.0), "HalfSizes2DBatch": TestCase(batch=[(5.0, 10.0), (50, 30), (23, 45)]), "HalfSizes3DBatch": TestCase(batch=[(5.0, 10.0, 20.0), (50, 30, 40), (23, 45, 67)]), + "ImagePlaneDistanceBatch": TestCase(batch=[100.0, 200.0, 300.0]), "KeypointIdBatch": TestCase(batch=[5, 6, 7]), "LineStrip2DBatch": TestCase(batch=[((0, 0), (1, 1), (2, 2)), ((3, 3), (4, 4), (5, 5)), ((6, 6), (7, 7), (8, 8))]), "LineStrip3DBatch": TestCase(