diff --git a/crates/re_edit_ui/src/datatype_editors/float_drag.rs b/crates/re_edit_ui/src/datatype_editors/float_drag.rs index a0712b8d4dc2..0c60c5d06c55 100644 --- a/crates/re_edit_ui/src/datatype_editors/float_drag.rs +++ b/crates/re_edit_ui/src/datatype_editors/float_drag.rs @@ -1,7 +1,17 @@ use egui::NumExt as _; +use re_types::datatypes; -/// Generic editor for a f32 value from zero to infinity. +/// Generic editor for a [`re_types::datatypes::Float32`] value from zero to infinity. pub fn edit_f32_zero_to_inf( + _ctx: &re_viewer_context::ViewerContext<'_>, + ui: &mut egui::Ui, + value: &mut impl std::ops::DerefMut, +) -> egui::Response { + edit_f32_zero_to_inf_impl(ui, &mut value.deref_mut().0) +} + +/// Generic editor for a raw f32 value from zero to infinity. +pub fn edit_f32_zero_to_inf_raw( _ctx: &re_viewer_context::ViewerContext<'_>, ui: &mut egui::Ui, value: &mut impl std::ops::DerefMut, diff --git a/crates/re_edit_ui/src/datatype_editors/mod.rs b/crates/re_edit_ui/src/datatype_editors/mod.rs index 07adc2c2e153..efe0bee01306 100644 --- a/crates/re_edit_ui/src/datatype_editors/mod.rs +++ b/crates/re_edit_ui/src/datatype_editors/mod.rs @@ -5,5 +5,5 @@ mod singleline_string; pub use bool_toggle::{edit_bool, edit_bool_raw}; pub use enum_combobox::edit_enum; -pub use float_drag::edit_f32_zero_to_inf; +pub use float_drag::{edit_f32_zero_to_inf, edit_f32_zero_to_inf_raw}; pub use singleline_string::edit_singleline_string; diff --git a/crates/re_edit_ui/src/lib.rs b/crates/re_edit_ui/src/lib.rs index fe0414ce2220..778442b10a69 100644 --- a/crates/re_edit_ui/src/lib.rs +++ b/crates/re_edit_ui/src/lib.rs @@ -12,7 +12,9 @@ mod visual_bounds2d; use datatype_editors::edit_enum; use re_types::{ blueprint::components::{BackgroundKind, Corner2D, LockRangeDuringZoom, Visible}, - components::{Color, MarkerSize, Name, Radius, StrokeWidth, Text}, + components::{ + AxisLength, Color, ImagePlaneDistance, MarkerSize, Name, Radius, StrokeWidth, Text, + }, }; use re_viewer_context::ViewerContext; @@ -42,15 +44,18 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { registry.add_singleline_editor_ui(marker_shape::edit_marker_shape_ui); registry.add_singleline_editor_ui(range1d::edit_range1d); + registry.add_singleline_editor_ui::(datatype_editors::edit_f32_zero_to_inf); + registry.add_singleline_editor_ui::(datatype_editors::edit_f32_zero_to_inf); + registry.add_singleline_editor_ui::(datatype_editors::edit_bool_raw); registry.add_singleline_editor_ui::(datatype_editors::edit_bool); registry.add_singleline_editor_ui::(datatype_editors::edit_singleline_string); registry.add_singleline_editor_ui::(datatype_editors::edit_singleline_string); - registry.add_singleline_editor_ui::(datatype_editors::edit_f32_zero_to_inf); - registry.add_singleline_editor_ui::(datatype_editors::edit_f32_zero_to_inf); - registry.add_singleline_editor_ui::(datatype_editors::edit_f32_zero_to_inf); + registry.add_singleline_editor_ui::(datatype_editors::edit_f32_zero_to_inf_raw); + registry.add_singleline_editor_ui::(datatype_editors::edit_f32_zero_to_inf_raw); + registry.add_singleline_editor_ui::(datatype_editors::edit_f32_zero_to_inf_raw); registry.add_singleline_editor_ui(|_ctx, ui, value| { edit_enum(ui, "corner2d", value, &Corner2D::ALL) diff --git a/crates/re_entity_db/src/entity_properties.rs b/crates/re_entity_db/src/entity_properties.rs index 9518682af83e..63fb8d54501a 100644 --- a/crates/re_entity_db/src/entity_properties.rs +++ b/crates/re_entity_db/src/entity_properties.rs @@ -114,17 +114,6 @@ pub struct EntityProperties { /// Used to scale the radii of the points in the resulting point cloud. pub backproject_radius_scale: EditableAutoValue, // TODO(andreas): should be a component on the DepthImage archetype. - /// Whether to show the 3D transform visualization at all. - // TODO(andreas): should go away once we can disable visualizer. Revisit how to collectively enable/disable these on an entire view. - // To consider: Make a TransformAxis archetype whose indicator is what enables the visualizer - // -> size etc. are now part of this archetype, not the `Transform` archetype - // -> `TransformAxis` itself doesn't have a required component, but the visualizer has. Just like in SeriesLines & Scalar. - // TODO(andreas)/TODO(jleibs): There's a pattern here that we should capture & formalize in the API / codegen / definitions. - pub transform_3d_visible: EditableAutoValue, - - /// The length of the arrows in the entity's own coordinate system (space). - pub transform_3d_size: EditableAutoValue, // TODO(andreas): should be a component on the Transform3D/TransformAxis archetype. - /// Should the legend be shown (for plot space views). pub show_legend: EditableAutoValue, // TODO(andreas): BarChart is still using it, we already have the legend archteype! @@ -147,8 +136,6 @@ impl Default for EntityProperties { backproject_depth: EditableAutoValue::Auto(true), depth_from_world_scale: EditableAutoValue::Auto(1.0), backproject_radius_scale: EditableAutoValue::Auto(1.0), - transform_3d_visible: EditableAutoValue::Auto(false), - transform_3d_size: EditableAutoValue::Auto(1.0), show_legend: EditableAutoValue::Auto(true), legend_location: None, time_series_aggregator: EditableAutoValue::Auto(TimeSeriesAggregator::default()), @@ -175,12 +162,6 @@ impl EntityProperties { .or(&child.backproject_radius_scale) .clone(), - transform_3d_visible: self - .transform_3d_visible - .or(&child.transform_3d_visible) - .clone(), - transform_3d_size: self.transform_3d_size.or(&child.transform_3d_size).clone(), - show_legend: self.show_legend.or(&child.show_legend).clone(), legend_location: self.legend_location.or(child.legend_location), time_series_aggregator: self @@ -213,12 +194,6 @@ impl EntityProperties { .or(&self.backproject_radius_scale) .clone(), - transform_3d_visible: other - .transform_3d_visible - .or(&self.transform_3d_visible) - .clone(), - transform_3d_size: self.transform_3d_size.or(&other.transform_3d_size).clone(), - show_legend: other.show_legend.or(&self.show_legend).clone(), legend_location: other.legend_location.or(self.legend_location), time_series_aggregator: other @@ -236,8 +211,6 @@ impl EntityProperties { backproject_depth, depth_from_world_scale, backproject_radius_scale, - transform_3d_visible, - transform_3d_size, show_legend, legend_location, time_series_aggregator, @@ -248,8 +221,6 @@ impl EntityProperties { || 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) - || transform_3d_visible.has_edits(&other.transform_3d_visible) - || transform_3d_size.has_edits(&other.transform_3d_size) || show_legend.has_edits(&other.show_legend) || *legend_location != other.legend_location || time_series_aggregator.has_edits(&other.time_series_aggregator) diff --git a/crates/re_selection_panel/src/override_ui.rs b/crates/re_selection_panel/src/override_ui.rs index a1d5c0e665c4..7b385c49b44e 100644 --- a/crates/re_selection_panel/src/override_ui.rs +++ b/crates/re_selection_panel/src/override_ui.rs @@ -8,15 +8,14 @@ use re_log_types::{DataCell, DataRow, RowId, StoreKind}; use re_types_core::{components::VisualizerOverrides, ComponentName}; use re_ui::{ContextExt as _, UiExt as _}; use re_viewer_context::{ - ComponentUiTypes, DataResult, OverridePath, QueryContext, SpaceViewClassExt as _, - SystemCommand, SystemCommandSender as _, ViewSystemIdentifier, ViewerContext, + ComponentUiTypes, DataResult, OverridePath, SpaceViewClassExt as _, SystemCommand, + SystemCommandSender as _, ViewContext, ViewSystemIdentifier, ViewerContext, }; use re_viewport_blueprint::SpaceViewBlueprint; pub fn override_ui( - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, space_view: &SpaceViewBlueprint, - view_state: &dyn re_viewer_context::SpaceViewState, instance_path: &InstancePath, ui: &mut egui::Ui, ) { @@ -47,10 +46,6 @@ pub fn override_ui( .map(|props| props.resolved_component_overrides.keys().copied().collect()) .unwrap_or_default(); - let view_systems = ctx - .space_view_class_registry - .new_visualizer_collection(space_view.class_identifier()); - let mut component_to_vis: BTreeMap = Default::default(); // Accumulate the components across all visualizers and track which visualizer @@ -60,7 +55,8 @@ pub fn override_ui( // TODO(jleibs): We can do something fancier in the future such as presenting both // options once we have a motivating use-case. for vis in &data_result.visualizers { - let Some(queried) = view_systems + let Some(queried) = ctx + .visualizer_collection .get_by_identifier(*vis) .ok() .map(|vis| vis.visualizer_query_info().queried) @@ -78,14 +74,14 @@ pub fn override_ui( &query, ctx.recording(), ui, - &view_systems, &component_to_vis, &active_overrides, &data_result, - view_state, ); - let Some(overrides) = data_result.property_overrides else { + // TODO(jleibs): This clone is annoying, but required because QueryContext wants + // a reference to the EntityPath. We could probably refactor this to avoid the clone. + let Some(overrides) = data_result.property_overrides.clone() else { return; }; @@ -94,6 +90,8 @@ pub fn override_ui( .into_iter() .sorted_by_key(|(c, _)| *c); + let query_context = ctx.query_context(&data_result, &query); + re_ui::list_item::list_item_scope(ui, "overrides", |ui| { ui.spacing_mut().item_spacing.y = 0.0; for ( @@ -107,7 +105,10 @@ pub fn override_ui( let Some(visualizer_identifier) = component_to_vis.get(component_name) else { continue; }; - let Ok(visualizer) = view_systems.get_by_identifier(*visualizer_identifier) else { + let Ok(visualizer) = ctx + .visualizer_collection + .get_by_identifier(*visualizer_identifier) + else { re_log::warn!( "Failed to resolve visualizer identifier {visualizer_identifier}, to a visualizer implementation" ); @@ -117,7 +118,7 @@ pub fn override_ui( let value_fn = |ui: &mut egui::Ui| { let (origin_db, query) = match store_kind { StoreKind::Blueprint => { - (ctx.store_context.blueprint, ctx.blueprint_query.clone()) + (ctx.blueprint_db(), ctx.viewer_ctx.blueprint_query.clone()) } StoreKind::Recording => (ctx.recording(), ctx.current_query()), }; @@ -134,14 +135,8 @@ pub fn override_ui( .cloned(); /* arc */ if let Some(results) = component_data { - ctx.component_ui_registry.singleline_edit_ui( - &QueryContext { - viewer_ctx: ctx, - target_entity_path: &instance_path.entity_path, - archetype_name: None, - query: &query, - view_state, - }, + ctx.viewer_ctx.component_ui_registry.singleline_edit_ui( + &query_context, ui, origin_db, entity_path_overridden, @@ -177,15 +172,13 @@ pub fn override_ui( #[allow(clippy::too_many_arguments)] pub fn add_new_override( - ctx: &ViewerContext<'_>, + ctx: &ViewContext<'_>, query: &LatestAtQuery, db: &EntityDb, ui: &mut egui::Ui, - view_systems: &re_viewer_context::VisualizerCollection, component_to_vis: &BTreeMap, active_overrides: &BTreeSet, data_result: &DataResult, - view_state: &dyn re_viewer_context::SpaceViewState, ) { let remaining_components = component_to_vis .keys() @@ -201,13 +194,7 @@ pub fn add_new_override( opened = true; ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend); - let query_context = QueryContext { - viewer_ctx: ctx, - target_entity_path: &data_result.entity_path, - archetype_name: None, - query, - view_state, - }; + let query_context = ctx.query_context(data_result, query); // Present the option to add new components for each component that doesn't // already have an active override. @@ -227,6 +214,7 @@ pub fn add_new_override( // If there is no registered editor, don't let the user create an override // TODO(andreas): Can only handle single line editors right now. if !ctx + .viewer_ctx .component_ui_registry .registered_ui_types(*component) .contains(ComponentUiTypes::SingleLineEditor) @@ -247,11 +235,16 @@ pub fn add_new_override( .latest_at(query, &data_result.entity_path, *component, &components) .and_then(|result| result.2[0].clone()) .or_else(|| { - view_systems.get_by_identifier(*viz).ok().and_then(|sys| { - sys.fallback_for(&query_context, *component) - .map(|fallback| DataCell::from_arrow(*component, fallback)) - .ok() - }) + ctx.visualizer_collection + .get_by_identifier(*viz) + .ok() + .and_then(|sys| { + sys.fallback_for(&query_context, *component) + .map(|fallback| { + DataCell::from_arrow(*component, fallback) + }) + .ok() + }) }) else { re_log::warn!("Could not identify an initial value for: {}", component); @@ -262,16 +255,17 @@ pub fn add_new_override( match DataRow::from_cells( RowId::new(), - ctx.store_context.blueprint_timepoint_for_writes(), + ctx.blueprint_timepoint_for_writes(), override_path.clone(), [initial_data], ) { Ok(row) => { - ctx.command_sender - .send_system(SystemCommand::UpdateBlueprint( - ctx.store_context.blueprint.store_id().clone(), + ctx.viewer_ctx.command_sender.send_system( + SystemCommand::UpdateBlueprint( + ctx.blueprint_db().store_id().clone(), vec![row], - )); + ), + ); } Err(err) => { re_log::warn!( diff --git a/crates/re_selection_panel/src/selection_panel.rs b/crates/re_selection_panel/src/selection_panel.rs index 009c786d32a4..e39169908605 100644 --- a/crates/re_selection_panel/src/selection_panel.rs +++ b/crates/re_selection_panel/src/selection_panel.rs @@ -14,8 +14,10 @@ use re_log_types::EntityPathFilter; use re_space_view::DataResultQuery as _; use re_space_view_time_series::TimeSeriesSpaceView; use re_types::{ - archetypes::Pinhole, - components::{ImagePlaneDistance, PinholeProjection, Transform3D}, + archetypes::{Axes3D, Pinhole}, + components::{ + AxisLength, ImagePlaneDistance, PinholeProjection, Transform3D, VisualizerOverrides, + }, tensor_data::TensorDataMeaning, }; use re_ui::{icons, list_item, ContextExt as _, DesignTokens, SyntaxHighlighting as _, UiExt as _}; @@ -173,17 +175,10 @@ impl SelectionPanel { override_visualizer_ui(ctx, view, instance_path, ui); }); - let view_state = view_states - .get_mut( - ctx.space_view_class_registry, - *view_id, - view.class_identifier(), - ) - .view_state - .as_ref(); + let view_ctx = view.bundle_context_with_states(ctx, view_states); ui.large_collapsing_header("Component Overrides", true, |ui| { - override_ui(ctx, view, view_state, instance_path, ui); + override_ui(&view_ctx, view, instance_path, ui); }); } } @@ -225,34 +220,13 @@ impl SelectionPanel { } Item::DataResult(space_view_id, instance_path) => { - let Some(space_view) = blueprint.space_view(space_view_id) else { + let Some(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 view_ctx = view.bundle_context_with_states(ctx, view_states); - 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, - ); + blueprint_ui_for_data_result(&view_ctx, view, ui, *space_view_id, instance_path); } } } @@ -1247,7 +1221,7 @@ fn entity_props_ui( // if *view_state.state_spatial.nav_mode.get() == SpatialNavigationMode::ThreeD { 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); + transform3d_visualization_ui(ctx, ui, data_result); }); } @@ -1314,6 +1288,84 @@ fn pinhole_props_ui(ctx: &ViewContext<'_>, ui: &mut egui::Ui, data_result: &Data } } +fn transform3d_visualization_ui( + ctx: &ViewContext<'_>, + ui: &mut egui::Ui, + data_result: &DataResult, +) { + re_tracing::profile_function!(); + + let (query, store) = + guess_query_and_db_for_selected_entity(ctx.viewer_ctx, &data_result.entity_path); + + if store + .latest_at_component::(&data_result.entity_path, &query) + .is_none() + { + return; + } + + let arrow_viz = "Transform3DArrows".into(); + + let mut show_arrows = data_result.visualizers.contains(&arrow_viz); + + let results = data_result.latest_at_with_overrides::(ctx, &query); + + let mut arrow_length: f32 = results.get_mono_with_fallback::().into(); + + { + let response = ui.re_checkbox( &mut show_arrows, "Show transform").on_hover_text( + "Enables/disables the display of three arrows to visualize the (accumulated) transform at this entity. Red/green/blue show the x/y/z axis respectively."); + if response.changed() { + let component = if show_arrows { + VisualizerOverrides::from( + data_result + .visualizers + .iter() + .chain(std::iter::once(&arrow_viz)) + .map(|v| re_types_core::ArrowString::from(v.as_str())) + .collect::>(), + ) + } else { + VisualizerOverrides::from( + data_result + .visualizers + .iter() + .filter(|v| **v != arrow_viz) + .map(|v| re_types_core::ArrowString::from(v.as_str())) + .collect::>(), + ) + }; + + data_result.save_individual_override(ctx.viewer_ctx, &component); + } + } + + if show_arrows { + ui.end_row(); + ui.label("Transform-arrow length"); + let speed = (arrow_length * 0.05).at_least(0.001); + let response = ui + .add( + egui::DragValue::new(&mut arrow_length) + .clamp_range(0.0..=1.0e8) + .speed(speed), + ) + .on_hover_text( + "How long the arrows should be in the entity's own coordinate system. Double-click to reset to auto.", + ); + if response.double_clicked() { + data_result.clear_individual_override::(ctx.viewer_ctx); + response.surrender_focus(); + } else if response.changed() { + data_result + .save_individual_override::(ctx.viewer_ctx, &arrow_length.into()); + } + } + + ui.end_row(); +} + fn depth_props_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, @@ -1413,61 +1465,3 @@ fn backproject_radius_scale_ui(ui: &mut egui::Ui, property: &mut EditableAutoVal } ui.end_row(); } - -fn transform3d_visualization_ui( - ctx: &ViewerContext<'_>, - ui: &mut egui::Ui, - entity_path: &EntityPath, - entity_props: &mut EntityProperties, -) { - re_tracing::profile_function!(); - - let (query, store) = guess_query_and_db_for_selected_entity(ctx, entity_path); - - if store - .latest_at_component::(entity_path, &query) - .is_none() - { - return; - } - - let show_arrows = &mut entity_props.transform_3d_visible; - let arrow_length = &mut entity_props.transform_3d_size; - - { - let mut checked = *show_arrows.get(); - let response = ui.re_checkbox( &mut checked, "Show transform").on_hover_text( - "Enables/disables the display of three arrows to visualize the (accumulated) transform at this entity. Red/green/blue show the x/y/z axis respectively."); - if response.changed() { - *show_arrows = EditableAutoValue::UserEdited(checked); - } - if response.double_clicked() { - *show_arrows = EditableAutoValue::Auto(checked); - } - } - - if *show_arrows.get() { - ui.end_row(); - ui.label("Transform-arrow length"); - let mut value = *arrow_length.get(); - let speed = (value * 0.05).at_least(0.001); - let response = ui - .add( - egui::DragValue::new(&mut value) - .clamp_range(0.0..=1.0e8) - .speed(speed), - ) - .on_hover_text( - "How long the arrows should be in the entity's own coordinate system. Double-click to reset to auto.", - ); - if response.double_clicked() { - // reset to auto - the exact value will be restored somewhere else - *arrow_length = EditableAutoValue::Auto(value); - response.surrender_focus(); - } else if response.changed() { - *arrow_length = EditableAutoValue::UserEdited(value); - } - } - - ui.end_row(); -} diff --git a/crates/re_space_view/src/results_ext.rs b/crates/re_space_view/src/results_ext.rs index 026bb5624b05..fa7302b45c6b 100644 --- a/crates/re_space_view/src/results_ext.rs +++ b/crates/re_space_view/src/results_ext.rs @@ -95,6 +95,7 @@ impl<'a> HybridLatestAtResults<'a> { archetype_name: None, // TODO(jleibs): Do we need this? query: &self.query, view_state: self.ctx.view_state, + view_ctx: Some(self.ctx), }; fallback_provider diff --git a/crates/re_space_view/src/view_property_ui.rs b/crates/re_space_view/src/view_property_ui.rs index 124bd5ec4384..9fb83ba619d4 100644 --- a/crates/re_space_view/src/view_property_ui.rs +++ b/crates/re_space_view/src/view_property_ui.rs @@ -36,6 +36,7 @@ fn view_property_ui_impl( archetype_name: Some(archetype.name), query: ctx.blueprint_query, view_state, + view_ctx: None, }; let component_results = ctx.blueprint_db().latest_at( diff --git a/crates/re_space_view_spatial/src/heuristics.rs b/crates/re_space_view_spatial/src/heuristics.rs index 0ab8490d1c13..f14cf394d23e 100644 --- a/crates/re_space_view_spatial/src/heuristics.rs +++ b/crates/re_space_view_spatial/src/heuristics.rs @@ -9,20 +9,18 @@ use re_log_types::EntityPath; use re_types::{ components::{DepthMeter, TensorData}, tensor_data::TensorDataMeaning, - Archetype as _, SpaceViewClassIdentifier, + SpaceViewClassIdentifier, }; use re_viewer_context::{IdentifiedViewSystem, PerSystemEntities, ViewerContext}; use crate::{ - query_pinhole_legacy, view_kind::SpatialSpaceViewKind, - visualizers::{ImageVisualizer, SpatialViewVisualizerData, Transform3DArrowsVisualizer}, + visualizers::{ImageVisualizer, SpatialViewVisualizerData}, }; pub fn generate_auto_legacy_properties( ctx: &ViewerContext<'_>, per_system_entities: &PerSystemEntities, - scene_bbox_accum: &macaw::BoundingBox, spatial_kind: SpatialSpaceViewKind, ) -> re_entity_db::EntityPropertyMap { re_tracing::profile_function!(); @@ -36,12 +34,6 @@ pub fn generate_auto_legacy_properties( &mut auto_properties, spatial_kind, ); - update_transform3d_lines_heuristics( - ctx, - per_system_entities, - &mut auto_properties, - scene_bbox_accum, - ); auto_properties } @@ -120,70 +112,6 @@ fn update_depth_cloud_property_heuristics( } } -fn update_transform3d_lines_heuristics( - ctx: &ViewerContext<'_>, - per_system_entities: &PerSystemEntities, - auto_properties: &mut re_entity_db::EntityPropertyMap, - scene_bbox_accum: &macaw::BoundingBox, -) { - for ent_path in per_system_entities - .get(&Transform3DArrowsVisualizer::identifier()) - .unwrap_or(&BTreeSet::new()) - { - fn is_pinhole_extrinsics_of<'a>( - ent_path: &'a EntityPath, - ctx: &'a ViewerContext<'_>, - ) -> Option<&'a EntityPath> { - 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_legacy(ctx.recording(), &ctx.current_query(), &child.path) - .is_some() - { - return Some(&child.path); - } - } - } - } - - None - } - - let mut properties = auto_properties.get(ent_path); - - // By default show the transform if it is a camera extrinsic, - // or if this entity only contains Transform3D components. - let only_has_transform_components = ctx - .recording_store() - .all_components(&ctx.current_query().timeline(), ent_path) - .map_or(false, |c| { - c.iter() - .all(|c| re_types::archetypes::Transform3D::all_components().contains(c)) - }); - properties.transform_3d_visible = EditableAutoValue::Auto( - only_has_transform_components || is_pinhole_extrinsics_of(ent_path, ctx).is_some(), - ); - - // 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); - } -} - /// Returns all entities for which a visualizer of the given kind would be picked. /// /// I.e. all entities for which at least one visualizer of the specified kind is applicable diff --git a/crates/re_space_view_spatial/src/view_2d.rs b/crates/re_space_view_spatial/src/view_2d.rs index f1ea7ca96225..76ece67ef3ae 100644 --- a/crates/re_space_view_spatial/src/view_2d.rs +++ b/crates/re_space_view_spatial/src/view_2d.rs @@ -159,15 +159,11 @@ impl SpaceViewClass for SpatialSpaceView2D { ent_paths: &PerSystemEntities, auto_properties: &mut re_entity_db::EntityPropertyMap, ) { - let Ok(state) = state.downcast_mut::() else { + let Ok(_state) = state.downcast_mut::() else { return; }; - *auto_properties = generate_auto_legacy_properties( - ctx, - ent_paths, - &state.bounding_boxes.accumulated, - SpatialSpaceViewKind::TwoD, - ); + *auto_properties = + generate_auto_legacy_properties(ctx, ent_paths, SpatialSpaceViewKind::TwoD); } fn spawn_heuristics( diff --git a/crates/re_space_view_spatial/src/view_3d.rs b/crates/re_space_view_spatial/src/view_3d.rs index 005df589caeb..4c3b7c84c545 100644 --- a/crates/re_space_view_spatial/src/view_3d.rs +++ b/crates/re_space_view_spatial/src/view_3d.rs @@ -1,3 +1,4 @@ +use ahash::HashSet; use itertools::Itertools; use nohash_hasher::IntSet; @@ -11,11 +12,14 @@ use re_types::{ }; use re_ui::UiExt as _; use re_viewer_context::{ - PerSystemEntities, RecommendedSpaceView, SpaceViewClass, SpaceViewClassRegistryError, + IdentifiedViewSystem, IndicatedEntities, PerSystemEntities, PerVisualizer, + RecommendedSpaceView, SmallVisualizerSet, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewSpawnHeuristics, SpaceViewState, SpaceViewStateExt as _, - SpaceViewSystemExecutionError, ViewQuery, ViewerContext, VisualizableFilterContext, + SpaceViewSystemExecutionError, ViewQuery, ViewSystemIdentifier, ViewerContext, + VisualizableEntities, VisualizableFilterContext, }; +use crate::visualizers::{CamerasVisualizer, Transform3DArrowsVisualizer, Transform3DDetector}; use crate::{ contexts::{register_spatial_contexts, PrimitiveCounter}, heuristics::{ @@ -184,6 +188,56 @@ impl SpaceViewClass for SpatialSpaceView3D { Box::new(context.unwrap_or_default()) } + /// Choose the default visualizers to enable for this entity. + fn choose_default_visualizers( + &self, + entity_path: &EntityPath, + visualizable_entities_per_visualizer: &PerVisualizer, + indicated_entities_per_visualizer: &PerVisualizer, + ) -> SmallVisualizerSet { + let available_visualizers: HashSet<&ViewSystemIdentifier> = + visualizable_entities_per_visualizer + .iter() + .filter_map(|(visualizer, ents)| { + if ents.contains(entity_path) { + Some(visualizer) + } else { + None + } + }) + .collect(); + + let mut visualizers: SmallVisualizerSet = available_visualizers + .iter() + .filter_map(|visualizer| { + if indicated_entities_per_visualizer + .get(*visualizer) + .map_or(false, |matching_list| matching_list.contains(entity_path)) + { + Some(**visualizer) + } else { + None + } + }) + .collect(); + + if available_visualizers.contains(&Transform3DArrowsVisualizer::identifier()) { + // There are two cases where we want to activate the [`Transform3DArrowVisualizer`]: + // - If we have no visualizers, but [`Transform3DDetector`] indicates there is a transform here. + // - If we have the [`CamerasVisualizer`] active. + if (visualizers.is_empty() + && available_visualizers.contains(&Transform3DDetector::identifier())) + || visualizers.contains(&CamerasVisualizer::identifier()) + { + visualizers.push(Transform3DArrowsVisualizer::identifier()); + } + } + + // If there were no other visualizers, or this is a camera, then we will include axes. + + visualizers + } + fn spawn_heuristics( &self, ctx: &ViewerContext<'_>, @@ -285,15 +339,11 @@ impl SpaceViewClass for SpatialSpaceView3D { ent_paths: &PerSystemEntities, auto_properties: &mut re_entity_db::EntityPropertyMap, ) { - let Ok(state) = state.downcast_mut::() else { + let Ok(_state) = state.downcast_mut::() else { return; }; - *auto_properties = generate_auto_legacy_properties( - ctx, - ent_paths, - &state.bounding_boxes.accumulated, - SpatialSpaceViewKind::ThreeD, - ); + *auto_properties = + generate_auto_legacy_properties(ctx, ent_paths, SpatialSpaceViewKind::ThreeD); } fn selection_ui( diff --git a/crates/re_space_view_spatial/src/visualizers/mod.rs b/crates/re_space_view_spatial/src/visualizers/mod.rs index 16e39d243e55..71607564b50c 100644 --- a/crates/re_space_view_spatial/src/visualizers/mod.rs +++ b/crates/re_space_view_spatial/src/visualizers/mod.rs @@ -19,7 +19,7 @@ mod transform3d_arrows; pub use cameras::CamerasVisualizer; pub use images::{ImageVisualizer, ViewerImage}; pub use spatial_view_visualizer::SpatialViewVisualizerData; -pub use transform3d_arrows::{add_axis_arrows, Transform3DArrowsVisualizer}; +pub use transform3d_arrows::{add_axis_arrows, Transform3DArrowsVisualizer, Transform3DDetector}; // --- @@ -65,6 +65,7 @@ pub fn register_2d_spatial_visualizers( system_registry.register_visualizer::()?; system_registry.register_visualizer::()?; system_registry.register_visualizer::()?; + system_registry.register_visualizer::()?; Ok(()) } @@ -84,6 +85,7 @@ pub fn register_3d_spatial_visualizers( system_registry.register_visualizer::()?; system_registry.register_visualizer::()?; system_registry.register_visualizer::()?; + system_registry.register_visualizer::()?; Ok(()) } 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 981fac556e53..ab2a7e2e4e77 100644 --- a/crates/re_space_view_spatial/src/visualizers/transform3d_arrows.rs +++ b/crates/re_space_view_spatial/src/visualizers/transform3d_arrows.rs @@ -1,18 +1,23 @@ use egui::Color32; use re_log_types::{EntityPath, Instance}; -use re_types::components::Transform3D; +use re_space_view::DataResultQuery; +use re_types::{ + archetypes::{Axes3D, Pinhole, Transform3D}, + components::{AxisLength, ImagePlaneDistance}, +}; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContext, + ApplicableEntities, IdentifiedViewSystem, QueryContext, SpaceViewStateExt, + SpaceViewSystemExecutionError, TypedComponentFallbackProvider, ViewContext, ViewContextCollection, ViewQuery, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; use crate::{ - contexts::TransformContext, view_kind::SpatialSpaceViewKind, + contexts::TransformContext, ui::SpatialSpaceViewState, view_kind::SpatialSpaceViewKind, visualizers::SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES, }; -use super::{filter_visualizable_3d_entities, SpatialViewVisualizerData}; +use super::{filter_visualizable_3d_entities, CamerasVisualizer, SpatialViewVisualizerData}; pub struct Transform3DArrowsVisualizer(SpatialViewVisualizerData); @@ -32,7 +37,7 @@ impl IdentifiedViewSystem for Transform3DArrowsVisualizer { impl VisualizerSystem for Transform3DArrowsVisualizer { fn visualizer_query_info(&self) -> VisualizerQueryInfo { - VisualizerQueryInfo::from_archetype::() + VisualizerQueryInfo::from_archetype::() } fn filter_visualizable_entities( @@ -63,18 +68,6 @@ impl VisualizerSystem for Transform3DArrowsVisualizer { line_builder.radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES); for data_result in query.iter_visible_data_results(ctx, Self::identifier()) { - if !*data_result.accumulated_properties().transform_3d_visible { - continue; - } - - if ctx - .recording() - .latest_at_component::(&data_result.entity_path, &latest_at_query) - .is_none() - { - continue; - } - // Use transform without potential pinhole, since we don't want to visualize image-space coordinates. let Some(world_from_obj) = transforms.reference_from_entity_ignoring_pinhole( &data_result.entity_path, @@ -91,11 +84,14 @@ impl VisualizerSystem for Transform3DArrowsVisualizer { world_from_obj, ); + let results = data_result.latest_at_with_overrides::(ctx, &latest_at_query); + let axis_length = results.get_mono_with_fallback::().into(); + add_axis_arrows( &mut line_builder, world_from_obj, Some(&data_result.entity_path), - *data_result.accumulated_properties().transform_3d_size, + axis_length, query .highlights .entity_outline_mask(data_result.entity_path.hash()) @@ -167,4 +163,99 @@ pub fn add_axis_arrows( .picking_instance_id(picking_instance_id); } -re_viewer_context::impl_component_fallback_provider!(Transform3DArrowsVisualizer => []); +impl TypedComponentFallbackProvider for Transform3DArrowsVisualizer { + fn fallback_for(&self, ctx: &QueryContext<'_>) -> AxisLength { + if let Some(view_ctx) = ctx.view_ctx { + let query_result = ctx.viewer_ctx.lookup_query_result(view_ctx.view_id); + + // If there is a camera in the scene and it has a pinhole, use the image plane distance to determine the axis length. + if let Some(length) = query_result + .tree + .lookup_result_by_path(ctx.target_entity_path) + .cloned() + .and_then(|data_result| { + if data_result + .visualizers + .contains(&CamerasVisualizer::identifier()) + { + let results = + data_result.latest_at_with_overrides::(view_ctx, ctx.query); + + Some(results.get_mono_with_fallback::()) + } else { + None + } + }) + { + let length: f32 = length.into(); + return (length * 0.5).into(); + } + } + + // If there is a finite bounding box, use the scene size to determine the axis length. + if let Ok(state) = ctx.view_state.downcast_ref::() { + let scene_size = state.bounding_boxes.accumulated.size().length(); + + if scene_size.is_finite() && scene_size > 0.0 { + return (scene_size * 0.05).into(); + }; + } + + // Otherwise 0.3 is a reasonable default. + + // 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!(Transform3DArrowsVisualizer => [AxisLength]); + +/// The `Transform3DDetector` doesn't actually visualize anything, but it allows us to detect +/// when a transform should otherwise be visualized. +/// +/// See the logic in [`crate::SpatialSpaceView3D`]`::choose_default_visualizers`. +#[derive(Default)] +pub struct Transform3DDetector(); + +impl IdentifiedViewSystem for Transform3DDetector { + fn identifier() -> re_viewer_context::ViewSystemIdentifier { + "Transform3DDetector".into() + } +} + +impl VisualizerSystem for Transform3DDetector { + fn visualizer_query_info(&self) -> VisualizerQueryInfo { + VisualizerQueryInfo::from_archetype::() + } + + fn execute( + &mut self, + _ctx: &ViewContext<'_>, + _query: &ViewQuery<'_>, + _context_systems: &ViewContextCollection, + ) -> Result, SpaceViewSystemExecutionError> { + Ok(vec![]) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn as_fallback_provider(&self) -> &dyn re_viewer_context::ComponentFallbackProvider { + self + } + + #[inline] + fn filter_visualizable_entities( + &self, + _entities: ApplicableEntities, + _context: &dyn VisualizableFilterContext, + ) -> VisualizableEntities { + // Never actually visualize this detector + Default::default() + } +} + +re_viewer_context::impl_component_fallback_provider!(Transform3DDetector => []); diff --git a/crates/re_space_view_text_log/src/space_view_class.rs b/crates/re_space_view_text_log/src/space_view_class.rs index c189705ba400..1b5ffe282105 100644 --- a/crates/re_space_view_text_log/src/space_view_class.rs +++ b/crates/re_space_view_text_log/src/space_view_class.rs @@ -108,6 +108,7 @@ impl SpaceViewClass for TextSpaceView { _root_entity_properties: &mut EntityProperties, ) -> Result<(), SpaceViewSystemExecutionError> { let state = state.downcast_mut::()?; + let ViewTextFilters { col_timelines, col_entity_path, 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 43a5c5e3c609..b70d0ee96b3b 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 @@ -149,13 +149,8 @@ impl SeriesLineSystem { let resolver = ctx.recording().resolver(); - let query_ctx = QueryContext { - viewer_ctx: ctx.viewer_ctx, - archetype_name: Some(SeriesLine::name()), - query: &ctx.current_query(), - target_entity_path: &data_result.entity_path, - view_state: ctx.view_state, - }; + let current_query = ctx.current_query(); + let query_ctx = ctx.query_context(data_result, ¤t_query); let fallback_color = re_viewer_context::TypedComponentFallbackProvider::::fallback_for( 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 81858f5fee21..c6060f797559 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 @@ -99,13 +99,8 @@ impl SeriesPointSystem { // 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, - archetype_name: Some(SeriesPoint::name()), - query: &ctx.current_query(), - target_entity_path: &data_result.entity_path, - view_state: ctx.view_state, - }; + let current_query = ctx.current_query(); + let query_ctx = ctx.query_context(data_result, ¤t_query); let fallback_color = re_viewer_context::TypedComponentFallbackProvider::::fallback_for( diff --git a/crates/re_types/definitions/rerun/archetypes.fbs b/crates/re_types/definitions/rerun/archetypes.fbs index 4ddccbed02f3..35a533031f6d 100644 --- a/crates/re_types/definitions/rerun/archetypes.fbs +++ b/crates/re_types/definitions/rerun/archetypes.fbs @@ -2,6 +2,7 @@ include "./archetypes/annotation_context.fbs"; include "./archetypes/arrows2d.fbs"; include "./archetypes/arrows3d.fbs"; include "./archetypes/asset3d.fbs"; +include "./archetypes/axes3d.fbs"; include "./archetypes/bar_chart.fbs"; include "./archetypes/boxes2d.fbs"; include "./archetypes/boxes3d.fbs"; diff --git a/crates/re_types/definitions/rerun/archetypes/axes3d.fbs b/crates/re_types/definitions/rerun/archetypes/axes3d.fbs new file mode 100644 index 000000000000..693cc7ceca42 --- /dev/null +++ b/crates/re_types/definitions/rerun/archetypes/axes3d.fbs @@ -0,0 +1,30 @@ +include "fbs/attributes.fbs"; +include "rust/attributes.fbs"; + +include "rerun/components.fbs"; + +namespace rerun.archetypes; + +// --- + +/// This archetype shows a set of orthogonal coordinate axes such as for representing a transform. +/// +/// \py See [`Transform3D`][rerun.archetypes.Transform3D] +/// \rs See [`Transform3D`][crate::archetypes.ScTransform3Dalar] +/// \cpp See `rerun::archetypes::Transform3D` +/// +/// \example archetypes/transform3d_axes title="Transform with axes" image="https://static.rerun.io/transform3d_axes/35cd6a68cce0cd582231984be4e2628d1627540b/1200w.png" +table Axes3D ( + "attr.docs.category": "Plotting", + "attr.docs.view_types": "Spatial3DView, Spatial2DView: if logged above active projection", + "attr.docs.unreleased" +) { + // --- Required --- + + // --- Optional --- + + /// Length of the 3 axes. + length: rerun.components.AxisLength ("attr.rerun.component_optional", nullable, order: 1000); + + /// TODO(jleibs): Abillity to set color for the axes. +} diff --git a/crates/re_types/definitions/rerun/components.fbs b/crates/re_types/definitions/rerun/components.fbs index f1b5a5374e78..0a2c4a77c198 100644 --- a/crates/re_types/definitions/rerun/components.fbs +++ b/crates/re_types/definitions/rerun/components.fbs @@ -1,4 +1,5 @@ include "./components/annotation_context.fbs"; +include "./components/axis_length.fbs"; include "./components/blob.fbs"; include "./components/class_id.fbs"; include "./components/clear_is_recursive.fbs"; diff --git a/crates/re_types/definitions/rerun/components/axis_length.fbs b/crates/re_types/definitions/rerun/components/axis_length.fbs new file mode 100644 index 000000000000..7ee6e026299d --- /dev/null +++ b/crates/re_types/definitions/rerun/components/axis_length.fbs @@ -0,0 +1,21 @@ +include "arrow/attributes.fbs"; +include "python/attributes.fbs"; +include "rust/attributes.fbs"; + +include "rerun/datatypes.fbs"; +include "rerun/attributes.fbs"; + +namespace rerun.components; + +// --- + +/// The length of an axis in local units of the space. +struct AxisLength ( + "attr.python.aliases": "float", + "attr.python.array_aliases": "float, npt.ArrayLike", + "attr.rust.derive": "Copy, PartialEq, PartialOrd", + "attr.rust.repr": "transparent", + "attr.docs.unreleased" +) { + length: rerun.datatypes.Float32 (order: 100); +} diff --git a/crates/re_types/src/archetypes/.gitattributes b/crates/re_types/src/archetypes/.gitattributes index cc96164742f4..4f5061652788 100644 --- a/crates/re_types/src/archetypes/.gitattributes +++ b/crates/re_types/src/archetypes/.gitattributes @@ -5,6 +5,7 @@ annotation_context.rs linguist-generated=true arrows2d.rs linguist-generated=true arrows3d.rs linguist-generated=true asset3d.rs linguist-generated=true +axes3d.rs linguist-generated=true bar_chart.rs linguist-generated=true boxes2d.rs linguist-generated=true boxes3d.rs linguist-generated=true diff --git a/crates/re_types/src/archetypes/axes3d.rs b/crates/re_types/src/archetypes/axes3d.rs new file mode 100644 index 000000000000..080aba86f25d --- /dev/null +++ b/crates/re_types/src/archetypes/axes3d.rs @@ -0,0 +1,204 @@ +// 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/archetypes/axes3d.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}; + +/// **Archetype**: This archetype shows a set of orthogonal coordinate axes such as for representing a transform. +/// +/// See [`Transform3D`][crate::archetypes.ScTransform3Dalar] +/// +/// ## Example +/// +/// ### Transform with axes +/// ```ignore +/// fn main() -> Result<(), Box> { +/// let rec = rerun::RecordingStreamBuilder::new("rerun_example_transform3d_axes").spawn()?; +/// +/// let base_axes = rerun::Axes3D::new().with_length(1.0); +/// let other_axes = rerun::Axes3D::new().with_length(0.5); +/// +/// rec.log_static("base", &base_axes)?; +/// rec.log_static("base/rotated", &other_axes)?; +/// rec.log_static("base/rotated/translated", &other_axes)?; +/// +/// for deg in 0..360 { +/// rec.set_time_sequence("step", deg); +/// rec.log( +/// "base/rotated", +/// &rerun::Transform3D::from_rotation(rerun::RotationAxisAngle::new( +/// [1.0, 1.0, 1.0], +/// rerun::Angle::Degrees(deg as f32), +/// )), +/// )?; +/// rec.log( +/// "base/rotated/translated", +/// &rerun::Transform3D::from_translation([2.0, 0.0, 0.0]), +/// )?; +/// } +/// +/// Ok(()) +/// } +/// ``` +///
+/// +/// +/// +/// +/// +/// +/// +///
+#[derive(Clone, Debug)] +pub struct Axes3D { + /// Length of the 3 axes. + pub length: Option, +} + +impl ::re_types_core::SizeBytes for Axes3D { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.length.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + >::is_pod() + } +} + +static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 0usize]> = + once_cell::sync::Lazy::new(|| []); + +static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.components.Axes3DIndicator".into()]); + +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.components.AxisLength".into()]); + +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.components.Axes3DIndicator".into(), + "rerun.components.AxisLength".into(), + ] + }); + +impl Axes3D { + /// The total number of components in the archetype: 0 required, 1 recommended, 1 optional + pub const NUM_COMPONENTS: usize = 2usize; +} + +/// Indicator component for the [`Axes3D`] [`::re_types_core::Archetype`] +pub type Axes3DIndicator = ::re_types_core::GenericIndicatorComponent; + +impl ::re_types_core::Archetype for Axes3D { + type Indicator = Axes3DIndicator; + + #[inline] + fn name() -> ::re_types_core::ArchetypeName { + "rerun.archetypes.Axes3D".into() + } + + #[inline] + fn display_name() -> &'static str { + "Axes 3D" + } + + #[inline] + fn indicator() -> MaybeOwnedComponentBatch<'static> { + static INDICATOR: Axes3DIndicator = Axes3DIndicator::DEFAULT; + MaybeOwnedComponentBatch::Ref(&INDICATOR) + } + + #[inline] + fn required_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + REQUIRED_COMPONENTS.as_slice().into() + } + + #[inline] + fn recommended_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + RECOMMENDED_COMPONENTS.as_slice().into() + } + + #[inline] + fn optional_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + OPTIONAL_COMPONENTS.as_slice().into() + } + + #[inline] + fn all_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + ALL_COMPONENTS.as_slice().into() + } + + #[inline] + fn from_arrow_components( + arrow_data: impl IntoIterator)>, + ) -> DeserializationResult { + re_tracing::profile_function!(); + use ::re_types_core::{Loggable as _, ResultExt as _}; + let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data + .into_iter() + .map(|(name, array)| (name.full_name(), array)) + .collect(); + let length = if let Some(array) = arrays_by_name.get("rerun.components.AxisLength") { + ::from_arrow_opt(&**array) + .with_context("rerun.archetypes.Axes3D#length")? + .into_iter() + .next() + .flatten() + } else { + None + }; + Ok(Self { length }) + } +} + +impl ::re_types_core::AsComponents for Axes3D { + fn as_component_batches(&self) -> Vec> { + re_tracing::profile_function!(); + use ::re_types_core::Archetype as _; + [ + Some(Self::indicator()), + self.length + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + ] + .into_iter() + .flatten() + .collect() + } +} + +impl Axes3D { + /// Create a new `Axes3D`. + #[inline] + pub fn new() -> Self { + Self { length: None } + } + + /// Length of the 3 axes. + #[inline] + pub fn with_length(mut self, length: impl Into) -> Self { + self.length = Some(length.into()); + self + } +} diff --git a/crates/re_types/src/archetypes/mod.rs b/crates/re_types/src/archetypes/mod.rs index 6ce5a6ebc872..b34937d09375 100644 --- a/crates/re_types/src/archetypes/mod.rs +++ b/crates/re_types/src/archetypes/mod.rs @@ -7,6 +7,7 @@ mod arrows3d; mod arrows3d_ext; mod asset3d; mod asset3d_ext; +mod axes3d; mod bar_chart; mod boxes2d; mod boxes2d_ext; @@ -45,6 +46,7 @@ pub use self::annotation_context::AnnotationContext; pub use self::arrows2d::Arrows2D; pub use self::arrows3d::Arrows3D; pub use self::asset3d::Asset3D; +pub use self::axes3d::Axes3D; pub use self::bar_chart::BarChart; pub use self::boxes2d::Boxes2D; pub use self::boxes3d::Boxes3D; diff --git a/crates/re_types/src/components/.gitattributes b/crates/re_types/src/components/.gitattributes index fa15c2b5ca1d..6d4308f5d00e 100644 --- a/crates/re_types/src/components/.gitattributes +++ b/crates/re_types/src/components/.gitattributes @@ -2,6 +2,7 @@ .gitattributes linguist-generated=true annotation_context.rs linguist-generated=true +axis_length.rs linguist-generated=true blob.rs linguist-generated=true class_id.rs linguist-generated=true color.rs linguist-generated=true diff --git a/crates/re_types/src/components/axis_length.rs b/crates/re_types/src/components/axis_length.rs new file mode 100644 index 000000000000..5c4eb7358ee7 --- /dev/null +++ b/crates/re_types/src/components/axis_length.rs @@ -0,0 +1,185 @@ +// 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/axis_length.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 length of an axis in local units of the space. +#[derive(Clone, Debug, Copy, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct AxisLength(pub crate::datatypes::Float32); + +impl ::re_types_core::SizeBytes for AxisLength { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + } +} + +impl> From for AxisLength { + fn from(v: T) -> Self { + Self(v.into()) + } +} + +impl std::borrow::Borrow for AxisLength { + #[inline] + fn borrow(&self) -> &crate::datatypes::Float32 { + &self.0 + } +} + +impl std::ops::Deref for AxisLength { + type Target = crate::datatypes::Float32; + + #[inline] + fn deref(&self) -> &crate::datatypes::Float32 { + &self.0 + } +} + +impl std::ops::DerefMut for AxisLength { + #[inline] + fn deref_mut(&mut self) -> &mut crate::datatypes::Float32 { + &mut self.0 + } +} + +::re_types_core::macros::impl_into_cow!(AxisLength); + +impl ::re_types_core::Loggable for AxisLength { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.components.AxisLength".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.AxisLength#length")? + .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.AxisLength#length") + .with_context("rerun.components.AxisLength")?) + } + + #[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.AxisLength#length")? + .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/axis_length_ext.rs b/crates/re_types/src/components/axis_length_ext.rs new file mode 100644 index 000000000000..6c1ceba9c0e8 --- /dev/null +++ b/crates/re_types/src/components/axis_length_ext.rs @@ -0,0 +1,15 @@ +use super::AxisLength; + +impl Default for AxisLength { + #[inline] + fn default() -> Self { + 1.0.into() + } +} + +impl From for f32 { + #[inline] + fn from(val: AxisLength) -> Self { + val.0.into() + } +} diff --git a/crates/re_types/src/components/mod.rs b/crates/re_types/src/components/mod.rs index 51ef9ca0fdc0..9e94543a0a9a 100644 --- a/crates/re_types/src/components/mod.rs +++ b/crates/re_types/src/components/mod.rs @@ -1,6 +1,8 @@ // DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs mod annotation_context; +mod axis_length; +mod axis_length_ext; mod blob; mod blob_ext; mod class_id; @@ -73,6 +75,7 @@ mod view_coordinates; mod view_coordinates_ext; pub use self::annotation_context::AnnotationContext; +pub use self::axis_length::AxisLength; pub use self::blob::Blob; pub use self::class_id::ClassId; pub use self::color::Color; diff --git a/crates/re_viewer/src/component_defaults/mod.rs b/crates/re_viewer/src/component_defaults/mod.rs index 9279b5a49c08..e73c7045b887 100644 --- a/crates/re_viewer/src/component_defaults/mod.rs +++ b/crates/re_viewer/src/component_defaults/mod.rs @@ -111,6 +111,10 @@ pub fn list_default_components( ::name(), AnnotationContext::default().to_arrow()?, ), + ( + ::name(), + AxisLength::default().to_arrow()?, + ), (::name(), Blob::default().to_arrow()?), ( ::name(), diff --git a/crates/re_viewer_context/src/query_context.rs b/crates/re_viewer_context/src/query_context.rs index 556069562e2f..c692901d9401 100644 --- a/crates/re_viewer_context/src/query_context.rs +++ b/crates/re_viewer_context/src/query_context.rs @@ -5,7 +5,7 @@ use smallvec::SmallVec; use re_log_types::{EntityPath, EntityPathHash}; -use crate::{DataResult, SpaceViewId, SpaceViewState, ViewerContext}; +use crate::{DataResult, SpaceViewId, SpaceViewState, ViewContext, ViewerContext}; slotmap::new_key_type! { /// Identifier for a [`DataResultNode`] @@ -35,6 +35,10 @@ pub struct QueryContext<'a> { /// The view state of the view in which the query is executed. pub view_state: &'a dyn SpaceViewState, + + /// The view context, if available. + // TODO(jleibs): Make this non-optional. + pub view_ctx: Option<&'a ViewContext<'a>>, } /// The result of executing a single data query diff --git a/crates/re_viewer_context/src/space_view/view_context.rs b/crates/re_viewer_context/src/space_view/view_context.rs index 1e79c556f18c..0b99118c5915 100644 --- a/crates/re_viewer_context/src/space_view/view_context.rs +++ b/crates/re_viewer_context/src/space_view/view_context.rs @@ -1,4 +1,10 @@ -use crate::{DataQueryResult, SpaceViewId}; +use std::sync::Arc; + +use re_data_store::LatestAtQuery; +use re_log_types::{DataCell, EntityPath, TimePoint}; +use re_types::{AsComponents, ComponentBatch, ComponentName}; + +use crate::{DataQueryResult, DataResult, QueryContext, SpaceViewId}; /// The context associated with a view. /// @@ -9,11 +15,28 @@ use crate::{DataQueryResult, SpaceViewId}; /// information to resolve a query with possible overrides and fallback values. pub struct ViewContext<'a> { pub viewer_ctx: &'a crate::ViewerContext<'a>, + pub view_id: SpaceViewId, pub view_state: &'a dyn crate::SpaceViewState, - pub visualizer_collection: &'a crate::VisualizerCollection, + pub visualizer_collection: Arc, } impl<'a> ViewContext<'a> { + #[inline] + pub fn query_context( + &'a self, + data_result: &'a DataResult, + query: &'a LatestAtQuery, + ) -> QueryContext<'a> { + QueryContext { + viewer_ctx: self.viewer_ctx, + target_entity_path: &data_result.entity_path, + archetype_name: None, + query, + view_state: self.view_state, + view_ctx: Some(self), + } + } + /// The active recording. #[inline] pub fn recording(&self) -> &re_entity_db::EntityDb { @@ -39,25 +62,30 @@ impl<'a> ViewContext<'a> { } /// Returns the current selection. + #[inline] pub fn selection(&self) -> &crate::ItemCollection { self.viewer_ctx.selection() } /// Returns the currently hovered objects. + #[inline] pub fn hovered(&self) -> &crate::ItemCollection { self.viewer_ctx.hovered() } + #[inline] pub fn selection_state(&self) -> &crate::ApplicationSelectionState { self.viewer_ctx.selection_state() } /// The current time query, based on the current time control. + #[inline] 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. + #[inline] pub fn select_hovered_on_click( &self, response: &egui::Response, @@ -66,7 +94,66 @@ impl<'a> ViewContext<'a> { self.viewer_ctx.select_hovered_on_click(response, selection); } + #[inline] pub fn lookup_query_result(&self, id: SpaceViewId) -> &DataQueryResult { self.viewer_ctx.lookup_query_result(id) } + + #[inline] + pub fn save_blueprint_archetype(&self, entity_path: EntityPath, components: &dyn AsComponents) { + self.viewer_ctx + .save_blueprint_archetype(entity_path, components); + } + + #[inline] + pub fn save_blueprint_component( + &self, + entity_path: &EntityPath, + components: &dyn ComponentBatch, + ) { + self.viewer_ctx + .save_blueprint_component(entity_path, components); + } + + #[inline] + pub fn save_blueprint_data_cell(&self, entity_path: &EntityPath, data_cell: DataCell) { + self.viewer_ctx + .save_blueprint_data_cell(entity_path, data_cell); + } + + #[inline] + pub fn save_empty_blueprint_component(&self, entity_path: &EntityPath) + where + C: re_types::Component + 'a, + { + self.viewer_ctx + .save_empty_blueprint_component::(entity_path); + } + + #[inline] + pub fn reset_blueprint_component_by_name( + &self, + entity_path: &EntityPath, + component_name: ComponentName, + ) { + self.viewer_ctx + .reset_blueprint_component_by_name(entity_path, component_name); + } + + #[inline] + pub fn save_empty_blueprint_component_by_name( + &self, + entity_path: &EntityPath, + component_name: ComponentName, + ) { + self.viewer_ctx + .save_empty_blueprint_component_by_name(entity_path, component_name); + } + + #[inline] + pub fn blueprint_timepoint_for_writes(&self) -> TimePoint { + self.viewer_ctx + .store_context + .blueprint_timepoint_for_writes() + } } 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 69e97373716b..ea1914c32111 100644 --- a/crates/re_viewer_context/src/space_view/view_query.rs +++ b/crates/re_viewer_context/src/space_view/view_query.rs @@ -236,6 +236,22 @@ impl DataResult { ctx.save_empty_blueprint_component::(recursive_override_path); } + /// Clears the recursive override for a given component + pub fn clear_individual_override(&self, ctx: &ViewerContext<'_>) { + // 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(individual_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_empty_blueprint_component::(individual_override_path); + } + /// Write the [`EntityProperties`] for this result back to the Blueprint store on the recursive override. /// /// Setting `new_recursive_props` to `None` will always clear the override. diff --git a/crates/re_viewport/src/system_execution.rs b/crates/re_viewport/src/system_execution.rs index 524cf911e74f..0bbdc0469078 100644 --- a/crates/re_viewport/src/system_execution.rs +++ b/crates/re_viewport/src/system_execution.rs @@ -4,7 +4,6 @@ use ahash::HashMap; use rayon::prelude::*; use re_log_types::TimeInt; -use re_types::SpaceViewClassIdentifier; use re_viewer_context::{ PerSystemDataResults, SpaceViewId, SpaceViewState, SystemExecutionOutput, ViewContextCollection, ViewQuery, ViewStates, ViewerContext, VisualizerCollection, @@ -15,24 +14,15 @@ use re_viewport_blueprint::SpaceViewBlueprint; fn run_space_view_systems( ctx: &ViewerContext<'_>, - space_view_class: SpaceViewClassIdentifier, + view: &SpaceViewBlueprint, query: &ViewQuery<'_>, view_state: &dyn SpaceViewState, context_systems: &mut ViewContextCollection, view_systems: &mut VisualizerCollection, ) -> Vec { - 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); + re_tracing::profile_function!(view.class_identifier().as_str()); - let view_ctx = re_viewer_context::ViewContext { - viewer_ctx: ctx, - view_state, - visualizer_collection: &visualizer_collection, - }; + let view_ctx = view.bundle_context_with_state(ctx, view_state); { re_tracing::profile_wait!("ViewContextSystem::execute"); @@ -109,7 +99,7 @@ pub fn execute_systems_for_space_view<'a>( let draw_data = if let Some(view_state) = view_states.get(view.id) { run_space_view_systems( ctx, - view.class_identifier(), + view, &query, view_state.view_state.as_ref(), &mut context_systems, diff --git a/crates/re_viewport_blueprint/src/space_view.rs b/crates/re_viewport_blueprint/src/space_view.rs index b81c7b480b07..7650009c6ddd 100644 --- a/crates/re_viewport_blueprint/src/space_view.rs +++ b/crates/re_viewport_blueprint/src/space_view.rs @@ -1,4 +1,8 @@ +use std::sync::Arc; + +use ahash::HashMap; use itertools::{FoldWhile, Itertools}; +use parking_lot::Mutex; use re_entity_db::EntityProperties; use re_types::SpaceViewClassIdentifier; @@ -18,7 +22,8 @@ use re_types_core::Archetype as _; use re_viewer_context::{ ContentsName, DataResult, PerSystemEntities, QueryRange, RecommendedSpaceView, SpaceViewClass, SpaceViewClassRegistry, SpaceViewId, SpaceViewState, StoreContext, SystemCommand, - SystemCommandSender as _, SystemExecutionOutput, ViewQuery, ViewerContext, + SystemCommandSender as _, SystemExecutionOutput, ViewContext, ViewQuery, ViewStates, + ViewerContext, VisualizerCollection, }; /// A view of a space. @@ -462,6 +467,58 @@ impl SpaceViewBlueprint { |time_range| QueryRange::TimeRange(time_range.clone()), ) } + + pub fn bundle_context_with_states<'a>( + &self, + ctx: &'a ViewerContext<'a>, + view_states: &'a mut ViewStates, + ) -> ViewContext<'a> { + let view_state = view_states + .get_mut( + ctx.space_view_class_registry, + self.id, + self.class_identifier(), + ) + .view_state + .as_ref(); + + ViewContext { + viewer_ctx: ctx, + view_id: self.id, + view_state, + visualizer_collection: self.visualizer_collection(ctx), + } + } + + pub fn bundle_context_with_state<'a>( + &self, + ctx: &'a ViewerContext<'a>, + view_state: &'a dyn SpaceViewState, + ) -> ViewContext<'a> { + ViewContext { + viewer_ctx: ctx, + view_id: self.id, + view_state, + visualizer_collection: self.visualizer_collection(ctx), + } + } + + fn visualizer_collection(&self, ctx: &ViewerContext<'_>) -> Arc { + static VISUALIZER_FOR_CONTEXT: once_cell::sync::Lazy< + Mutex>>, + > = once_cell::sync::Lazy::new(Default::default); + + VISUALIZER_FOR_CONTEXT + .lock() + .entry(self.class_identifier()) + .or_insert_with(|| { + Arc::new( + ctx.space_view_class_registry + .new_visualizer_collection(self.class_identifier()), + ) + }) + .clone() + } } #[cfg(test)] diff --git a/crates/re_viewport_blueprint/src/view_properties.rs b/crates/re_viewport_blueprint/src/view_properties.rs index 2eb79f2186c7..48111a3378a0 100644 --- a/crates/re_viewport_blueprint/src/view_properties.rs +++ b/crates/re_viewport_blueprint/src/view_properties.rs @@ -162,6 +162,7 @@ impl<'a> ViewProperty<'a> { archetype_name: Some(self.archetype_name), query: self.blueprint_query, view_state, + view_ctx: None, } } } diff --git a/docs/content/reference/types/archetypes.md b/docs/content/reference/types/archetypes.md index 01feee9e3455..f01751fccc19 100644 --- a/docs/content/reference/types/archetypes.md +++ b/docs/content/reference/types/archetypes.md @@ -15,6 +15,7 @@ Archetypes are bundles of components. This page lists all built-in components. ## Plotting +* [`Axes3D`](archetypes/axes3d.md): This archetype shows a set of orthogonal coordinate axes such as for representing a transform. * [`BarChart`](archetypes/bar_chart.md): A bar chart. * [`Scalar`](archetypes/scalar.md): Log a double-precision scalar. * [`SeriesLine`](archetypes/series_line.md): Define the style properties for a line series in a chart. diff --git a/docs/content/reference/types/archetypes/.gitattributes b/docs/content/reference/types/archetypes/.gitattributes index 5035912305cd..7dd234417708 100644 --- a/docs/content/reference/types/archetypes/.gitattributes +++ b/docs/content/reference/types/archetypes/.gitattributes @@ -5,6 +5,7 @@ annotation_context.md linguist-generated=true arrows2d.md linguist-generated=true arrows3d.md linguist-generated=true asset3d.md linguist-generated=true +axes3d.md linguist-generated=true bar_chart.md linguist-generated=true boxes2d.md linguist-generated=true boxes3d.md linguist-generated=true diff --git a/docs/content/reference/types/archetypes/axes3d.md b/docs/content/reference/types/archetypes/axes3d.md new file mode 100644 index 000000000000..aa0935e1446e --- /dev/null +++ b/docs/content/reference/types/archetypes/axes3d.md @@ -0,0 +1,34 @@ +--- +title: "Axes3D" +--- + + +This archetype shows a set of orthogonal coordinate axes such as for representing a transform. + +## Components + +**Optional**: [`AxisLength`](../components/axis_length.md) + +## Shown in +* [Spatial3DView](../views/spatial3d_view.md) +* [Spatial2DView](../views/spatial2d_view.md) (if logged above active projection) + +## API reference links + * 🌊 [C++ API docs for `Axes3D`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1archetypes_1_1Axes3D.html?speculative-link) + * 🐍 [Python API docs for `Axes3D`](https://ref.rerun.io/docs/python/stable/common/archetypes?speculative-link#rerun.archetypes.Axes3D) + * 🦀 [Rust API docs for `Axes3D`](https://docs.rs/rerun/latest/rerun/archetypes/struct.Axes3D.html?speculative-link) + +## Example + +### Transform with axes + +snippet: archetypes/transform3d_axes + + + + + + + + + diff --git a/docs/content/reference/types/components.md b/docs/content/reference/types/components.md index 41cb9de0d931..7c2547c2a381 100644 --- a/docs/content/reference/types/components.md +++ b/docs/content/reference/types/components.md @@ -14,6 +14,7 @@ on [Entities and Components](../../concepts/entity-component.md). * [`AnnotationContext`](components/annotation_context.md): The `AnnotationContext` provides additional information on how to display entities. +* [`AxisLength`](components/axis_length.md): The length of an axis in local units of the space. * [`Blob`](components/blob.md): A binary blob of data. * [`ClassId`](components/class_id.md): A 16-bit ID representing a type of semantic class. * [`ClearIsRecursive`](components/clear_is_recursive.md): Configures how a clear operation should behave - recursive or not. diff --git a/docs/content/reference/types/components/.gitattributes b/docs/content/reference/types/components/.gitattributes index a9818981d6b9..0dea75b762ce 100644 --- a/docs/content/reference/types/components/.gitattributes +++ b/docs/content/reference/types/components/.gitattributes @@ -2,6 +2,7 @@ .gitattributes linguist-generated=true annotation_context.md linguist-generated=true +axis_length.md linguist-generated=true blob.md linguist-generated=true class_id.md linguist-generated=true clear_is_recursive.md linguist-generated=true diff --git a/docs/content/reference/types/components/axis_length.md b/docs/content/reference/types/components/axis_length.md new file mode 100644 index 000000000000..eb7807c2afcb --- /dev/null +++ b/docs/content/reference/types/components/axis_length.md @@ -0,0 +1,20 @@ +--- +title: "AxisLength" +--- + + +The length of an axis in local units of the space. + +## Fields + +* length: [`Float32`](../datatypes/float32.md) + +## API reference links + * 🌊 [C++ API docs for `AxisLength`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1components_1_1AxisLength.html?speculative-link) + * 🐍 [Python API docs for `AxisLength`](https://ref.rerun.io/docs/python/stable/common/components?speculative-link#rerun.components.AxisLength) + * 🦀 [Rust API docs for `AxisLength`](https://docs.rs/rerun/latest/rerun/components/struct.AxisLength.html?speculative-link) + + +## Used by + +* [`Axes3D`](../archetypes/axes3d.md?speculative-link) diff --git a/docs/content/reference/types/datatypes/float32.md b/docs/content/reference/types/datatypes/float32.md index fbd8738f83e0..6bfe194b9012 100644 --- a/docs/content/reference/types/datatypes/float32.md +++ b/docs/content/reference/types/datatypes/float32.md @@ -17,4 +17,5 @@ A single-precision 32-bit IEEE 754 floating point number. ## Used by +* [`AxisLength`](../components/axis_length.md?speculative-link) * [`ImagePlaneDistance`](../components/image_plane_distance.md?speculative-link) diff --git a/docs/content/reference/types/views/spatial2d_view.md b/docs/content/reference/types/views/spatial2d_view.md index f496568cfab6..1c793966c01f 100644 --- a/docs/content/reference/types/views/spatial2d_view.md +++ b/docs/content/reference/types/views/spatial2d_view.md @@ -57,6 +57,7 @@ snippet: views/spatial2d * [`SegmentationImage`](../archetypes/segmentation_image.md) * [`Arrows3D`](../archetypes/arrows3d.md) (if logged above active projection) * [`Asset3D`](../archetypes/asset3d.md) (if logged above active projection) +* [`Axes3D`](../archetypes/axes3d.md) (if logged above active projection) * [`Boxes3D`](../archetypes/boxes3d.md) (if logged above active projection) * [`LineStrips3D`](../archetypes/line_strips3d.md) (if logged above active projection) * [`Mesh3D`](../archetypes/mesh3d.md) (if logged above active projection) diff --git a/docs/content/reference/types/views/spatial3d_view.md b/docs/content/reference/types/views/spatial3d_view.md index 0d28a2be43db..5a6662d85483 100644 --- a/docs/content/reference/types/views/spatial3d_view.md +++ b/docs/content/reference/types/views/spatial3d_view.md @@ -41,6 +41,7 @@ snippet: views/spatial3d * [`AnnotationContext`](../archetypes/annotation_context.md) * [`Arrows3D`](../archetypes/arrows3d.md) * [`Asset3D`](../archetypes/asset3d.md) +* [`Axes3D`](../archetypes/axes3d.md) * [`Boxes3D`](../archetypes/boxes3d.md) * [`Clear`](../archetypes/clear.md) * [`DisconnectedSpace`](../archetypes/disconnected_space.md) diff --git a/docs/snippets/all/archetypes/transform3d_axes.cpp b/docs/snippets/all/archetypes/transform3d_axes.cpp new file mode 100644 index 000000000000..9cd9543ff5a5 --- /dev/null +++ b/docs/snippets/all/archetypes/transform3d_axes.cpp @@ -0,0 +1,29 @@ +// Log different transforms with visualized coordinates axes. + +#include + +int main() { + const auto rec = rerun::RecordingStream("rerun_example_transform3d_axes"); + rec.spawn().exit_on_failure(); + + auto base_axes = rerun::Axes3D().with_length(1.0); + auto other_axes = rerun::Axes3D().with_length(0.5); + + rec.log_static("base", base_axes); + rec.log_static("base/rotated", other_axes); + rec.log_static("base/rotated/translated", other_axes); + + for (int deg = 0; deg < 360; deg++) { + rec.set_time_sequence("step", deg); + + rec.log( + "base/rotated", + rerun::Transform3D(rerun::RotationAxisAngle( + {1.0f, 1.0f, 1.0f}, + rerun::Angle::degrees(static_cast(deg)) + )) + ); + + rec.log("base/rotated/translated", rerun::Transform3D({2.0f, 0.0f, 0.0f})); + } +} diff --git a/docs/snippets/all/archetypes/transform3d_axes.py b/docs/snippets/all/archetypes/transform3d_axes.py new file mode 100644 index 000000000000..df55c0d5c4a4 --- /dev/null +++ b/docs/snippets/all/archetypes/transform3d_axes.py @@ -0,0 +1,30 @@ +"""Log different transforms with visualized coordinates axes.""" + +import rerun as rr + +rr.init("rerun_example_transform3d_axes", spawn=True) + +# Make the base axes longer +# Log all axes markers as static first +rr.log("base", rr.Axes3D(length=1), static=True) +rr.log("base/rotated", rr.Axes3D(length=0.5), static=True) +rr.log("base/rotated/translated", rr.Axes3D(length=0.5), static=True) + +# Now sweep out a rotation relative to the base +for deg in range(360): + rr.set_time_sequence("step", deg) + rr.log( + "base/rotated", + rr.Transform3D( + rotation=rr.RotationAxisAngle( + axis=[1.0, 1.0, 1.0], + degrees=deg, + ) + ), + ) + rr.log( + "base/rotated/translated", + rr.Transform3D( + translation=[2.0, 0, 0], + ), + ) diff --git a/docs/snippets/all/archetypes/transform3d_axes.rs b/docs/snippets/all/archetypes/transform3d_axes.rs new file mode 100644 index 000000000000..e1198186eda6 --- /dev/null +++ b/docs/snippets/all/archetypes/transform3d_axes.rs @@ -0,0 +1,29 @@ +//! Log different transforms with visualized coordinates axes. + +fn main() -> Result<(), Box> { + let rec = rerun::RecordingStreamBuilder::new("rerun_example_transform3d_axes").spawn()?; + + let base_axes = rerun::Axes3D::new().with_length(1.0); + let other_axes = rerun::Axes3D::new().with_length(0.5); + + rec.log_static("base", &base_axes)?; + rec.log_static("base/rotated", &other_axes)?; + rec.log_static("base/rotated/translated", &other_axes)?; + + for deg in 0..360 { + rec.set_time_sequence("step", deg); + rec.log( + "base/rotated", + &rerun::Transform3D::from_rotation(rerun::RotationAxisAngle::new( + [1.0, 1.0, 1.0], + rerun::Angle::Degrees(deg as f32), + )), + )?; + rec.log( + "base/rotated/translated", + &rerun::Transform3D::from_translation([2.0, 0.0, 0.0]), + )?; + } + + Ok(()) +} diff --git a/rerun_cpp/src/rerun/archetypes.hpp b/rerun_cpp/src/rerun/archetypes.hpp index f001bdc6d371..5e0f02b47dd6 100644 --- a/rerun_cpp/src/rerun/archetypes.hpp +++ b/rerun_cpp/src/rerun/archetypes.hpp @@ -6,6 +6,7 @@ #include "archetypes/arrows2d.hpp" #include "archetypes/arrows3d.hpp" #include "archetypes/asset3d.hpp" +#include "archetypes/axes3d.hpp" #include "archetypes/bar_chart.hpp" #include "archetypes/boxes2d.hpp" #include "archetypes/boxes3d.hpp" diff --git a/rerun_cpp/src/rerun/archetypes/.gitattributes b/rerun_cpp/src/rerun/archetypes/.gitattributes index 395fe533c718..549d638dca58 100644 --- a/rerun_cpp/src/rerun/archetypes/.gitattributes +++ b/rerun_cpp/src/rerun/archetypes/.gitattributes @@ -9,6 +9,8 @@ arrows3d.cpp linguist-generated=true arrows3d.hpp linguist-generated=true asset3d.cpp linguist-generated=true asset3d.hpp linguist-generated=true +axes3d.cpp linguist-generated=true +axes3d.hpp linguist-generated=true bar_chart.cpp linguist-generated=true bar_chart.hpp linguist-generated=true boxes2d.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/archetypes/axes3d.cpp b/rerun_cpp/src/rerun/archetypes/axes3d.cpp new file mode 100644 index 000000000000..335c211eac74 --- /dev/null +++ b/rerun_cpp/src/rerun/archetypes/axes3d.cpp @@ -0,0 +1,33 @@ +// 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/archetypes/axes3d.fbs". + +#include "axes3d.hpp" + +#include "../collection_adapter_builtins.hpp" + +namespace rerun::archetypes {} + +namespace rerun { + + Result> AsComponents::serialize( + const archetypes::Axes3D& archetype + ) { + using namespace archetypes; + std::vector cells; + cells.reserve(2); + + if (archetype.length.has_value()) { + auto result = DataCell::from_loggable(archetype.length.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + { + auto indicator = Axes3D::IndicatorComponent(); + auto result = DataCell::from_loggable(indicator); + RR_RETURN_NOT_OK(result.error); + cells.emplace_back(std::move(result.value)); + } + + return cells; + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/archetypes/axes3d.hpp b/rerun_cpp/src/rerun/archetypes/axes3d.hpp new file mode 100644 index 000000000000..521f223bd9fd --- /dev/null +++ b/rerun_cpp/src/rerun/archetypes/axes3d.hpp @@ -0,0 +1,92 @@ +// 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/archetypes/axes3d.fbs". + +#pragma once + +#include "../collection.hpp" +#include "../compiler_utils.hpp" +#include "../components/axis_length.hpp" +#include "../data_cell.hpp" +#include "../indicator_component.hpp" +#include "../result.hpp" + +#include +#include +#include +#include + +namespace rerun::archetypes { + /// **Archetype**: This archetype shows a set of orthogonal coordinate axes such as for representing a transform. + /// + /// See `rerun::archetypes::Transform3D` + /// + /// ## Example + /// + /// ### Transform with axes + /// ![image](https://static.rerun.io/transform3d_axes/35cd6a68cce0cd582231984be4e2628d1627540b/full.png) + /// + /// ```cpp + /// #include + /// + /// int main() { + /// const auto rec = rerun::RecordingStream("rerun_example_transform3d_axes"); + /// rec.spawn().exit_on_failure(); + /// + /// auto base_axes = rerun::Axes3D().with_length(1.0); + /// auto other_axes = rerun::Axes3D().with_length(0.5); + /// + /// rec.log_static("base", base_axes); + /// rec.log_static("base/rotated", other_axes); + /// rec.log_static("base/rotated/translated", other_axes); + /// + /// for (int deg = 0; deg <360; deg++) { + /// rec.set_time_sequence("step", deg); + /// + /// rec.log( + /// "base/rotated", + /// rerun::Transform3D(rerun::RotationAxisAngle( + /// {1.0f, 1.0f, 1.0f}, + /// rerun::Angle::degrees(static_cast(deg)) + /// )) + /// ); + /// + /// rec.log("base/rotated/translated", rerun::Transform3D({2.0f, 0.0f, 0.0f})); + /// } + /// } + /// ``` + struct Axes3D { + /// Length of the 3 axes. + std::optional length; + + public: + static constexpr const char IndicatorComponentName[] = "rerun.components.Axes3DIndicator"; + + /// Indicator component, used to identify the archetype when converting to a list of components. + using IndicatorComponent = rerun::components::IndicatorComponent; + + public: + Axes3D() = default; + Axes3D(Axes3D&& other) = default; + + /// Length of the 3 axes. + Axes3D with_length(rerun::components::AxisLength _length) && { + length = std::move(_length); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + }; + +} // namespace rerun::archetypes + +namespace rerun { + /// \private + template + struct AsComponents; + + /// \private + template <> + struct AsComponents { + /// Serialize all set component batches. + static Result> serialize(const archetypes::Axes3D& archetype); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/c/rerun.h b/rerun_cpp/src/rerun/c/rerun.h index 992799ff024c..06e6303c50cd 100644 --- a/rerun_cpp/src/rerun/c/rerun.h +++ b/rerun_cpp/src/rerun/c/rerun.h @@ -266,7 +266,7 @@ typedef struct rr_error { /// /// This should match the string returned by `rr_version_string`. /// If not, the SDK's binary and the C header are out of sync. -#define RERUN_SDK_HEADER_VERSION "0.17.0-alpha.2" +#define RERUN_SDK_HEADER_VERSION "0.17.0-alpha.3" /// Returns a human-readable version string of the Rerun C SDK. /// diff --git a/rerun_cpp/src/rerun/components.hpp b/rerun_cpp/src/rerun/components.hpp index d56a35af8ca7..cc69ede2b29a 100644 --- a/rerun_cpp/src/rerun/components.hpp +++ b/rerun_cpp/src/rerun/components.hpp @@ -3,6 +3,7 @@ #pragma once #include "components/annotation_context.hpp" +#include "components/axis_length.hpp" #include "components/blob.hpp" #include "components/class_id.hpp" #include "components/clear_is_recursive.hpp" diff --git a/rerun_cpp/src/rerun/components/.gitattributes b/rerun_cpp/src/rerun/components/.gitattributes index d4f61adb5784..9b7176bee6fd 100644 --- a/rerun_cpp/src/rerun/components/.gitattributes +++ b/rerun_cpp/src/rerun/components/.gitattributes @@ -3,6 +3,7 @@ .gitattributes linguist-generated=true annotation_context.cpp linguist-generated=true annotation_context.hpp linguist-generated=true +axis_length.hpp linguist-generated=true blob.cpp linguist-generated=true blob.hpp linguist-generated=true class_id.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/components/axis_length.hpp b/rerun_cpp/src/rerun/components/axis_length.hpp new file mode 100644 index 000000000000..558f93188caa --- /dev/null +++ b/rerun_cpp/src/rerun/components/axis_length.hpp @@ -0,0 +1,61 @@ +// 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/axis_length.fbs". + +#pragma once + +#include "../datatypes/float32.hpp" +#include "../result.hpp" + +#include +#include + +namespace rerun::components { + /// **Component**: The length of an axis in local units of the space. + struct AxisLength { + rerun::datatypes::Float32 length; + + public: + AxisLength() = default; + + AxisLength(rerun::datatypes::Float32 length_) : length(length_) {} + + AxisLength& operator=(rerun::datatypes::Float32 length_) { + length = length_; + return *this; + } + + AxisLength(float value_) : length(value_) {} + + AxisLength& operator=(float value_) { + length = value_; + return *this; + } + + /// Cast to the underlying Float32 datatype + operator rerun::datatypes::Float32() const { + return length; + } + }; +} // namespace rerun::components + +namespace rerun { + static_assert(sizeof(rerun::datatypes::Float32) == sizeof(components::AxisLength)); + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.components.AxisLength"; + + /// 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::AxisLength` into an arrow array. + static Result> to_arrow( + const components::AxisLength* instances, size_t num_instances + ) { + return Loggable::to_arrow(&instances->length, num_instances); + } + }; +} // namespace rerun diff --git a/rerun_py/docs/gen_common_index.py b/rerun_py/docs/gen_common_index.py index 819f8093cea2..1773519b4ebb 100755 --- a/rerun_py/docs/gen_common_index.py +++ b/rerun_py/docs/gen_common_index.py @@ -181,6 +181,7 @@ class Section: "archetypes.Arrows3D", "archetypes.Arrows2D", "archetypes.Asset3D", + "archetypes.Axes3D", "archetypes.Boxes2D", "archetypes.Boxes3D", "archetypes.LineStrips2D", diff --git a/rerun_py/rerun_sdk/rerun/__init__.py b/rerun_py/rerun_sdk/rerun/__init__.py index eb8ceb495603..088c6bb7e0ab 100644 --- a/rerun_py/rerun_sdk/rerun/__init__.py +++ b/rerun_py/rerun_sdk/rerun/__init__.py @@ -41,6 +41,7 @@ Arrows2D as Arrows2D, Arrows3D as Arrows3D, Asset3D as Asset3D, + Axes3D as Axes3D, BarChart as BarChart, Boxes2D as Boxes2D, Boxes3D as Boxes3D, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/.gitattributes b/rerun_py/rerun_sdk/rerun/archetypes/.gitattributes index d249edf2df81..fe89b89524b3 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/archetypes/.gitattributes @@ -6,6 +6,7 @@ annotation_context.py linguist-generated=true arrows2d.py linguist-generated=true arrows3d.py linguist-generated=true asset3d.py linguist-generated=true +axes3d.py linguist-generated=true bar_chart.py linguist-generated=true boxes2d.py linguist-generated=true boxes3d.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/archetypes/__init__.py b/rerun_py/rerun_sdk/rerun/archetypes/__init__.py index 6b6b4e518c5f..147860ee7670 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/__init__.py @@ -6,6 +6,7 @@ from .arrows2d import Arrows2D from .arrows3d import Arrows3D from .asset3d import Asset3D +from .axes3d import Axes3D from .bar_chart import BarChart from .boxes2d import Boxes2D from .boxes3d import Boxes3D @@ -34,6 +35,7 @@ "Arrows2D", "Arrows3D", "Asset3D", + "Axes3D", "BarChart", "Boxes2D", "Boxes3D", diff --git a/rerun_py/rerun_sdk/rerun/archetypes/axes3d.py b/rerun_py/rerun_sdk/rerun/archetypes/axes3d.py new file mode 100644 index 000000000000..e4c1d13ffb5a --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/archetypes/axes3d.py @@ -0,0 +1,111 @@ +# 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/archetypes/axes3d.fbs". + +# You can extend this class by creating a "Axes3DExt" class in "axes3d_ext.py". + +from __future__ import annotations + +from typing import Any + +from attrs import define, field + +from .. import components, datatypes +from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions + +__all__ = ["Axes3D"] + + +@define(str=False, repr=False, init=False) +class Axes3D(Archetype): + """ + **Archetype**: This archetype shows a set of orthogonal coordinate axes such as for representing a transform. + + See [`Transform3D`][rerun.archetypes.Transform3D] + + Example + ------- + ### Transform with axes: + ```python + import rerun as rr + + rr.init("rerun_example_transform3d_axes", spawn=True) + + # Make the base axes longer + # Log all axes markers as static first + rr.log("base", rr.Axes3D(length=1), static=True) + rr.log("base/rotated", rr.Axes3D(length=0.5), static=True) + rr.log("base/rotated/translated", rr.Axes3D(length=0.5), static=True) + + # Now sweep out a rotation relative to the base + for deg in range(360): + rr.set_time_sequence("step", deg) + rr.log( + "base/rotated", + rr.Transform3D( + rotation=rr.RotationAxisAngle( + axis=[1.0, 1.0, 1.0], + degrees=deg, + ) + ), + ) + rr.log( + "base/rotated/translated", + rr.Transform3D( + translation=[2.0, 0, 0], + ), + ) + ``` +
+ + + + + + + +
+ + """ + + def __init__(self: Any, *, length: datatypes.Float32Like | None = None): + """ + Create a new instance of the Axes3D archetype. + + Parameters + ---------- + length: + Length of the 3 axes. + + """ + + # You can define your own __init__ function as a member of Axes3DExt in axes3d_ext.py + with catch_and_log_exceptions(context=self.__class__.__name__): + self.__attrs_init__(length=length) + return + self.__attrs_clear__() + + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( + length=None, # type: ignore[arg-type] + ) + + @classmethod + def _clear(cls) -> Axes3D: + """Produce an empty Axes3D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + + length: components.AxisLengthBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=components.AxisLengthBatch._optional, # type: ignore[misc] + ) + # Length of the 3 axes. + # + # (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/components/.gitattributes b/rerun_py/rerun_sdk/rerun/components/.gitattributes index 370009cd9b0b..ca3b0f59b8d8 100644 --- a/rerun_py/rerun_sdk/rerun/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/components/.gitattributes @@ -3,6 +3,7 @@ .gitattributes linguist-generated=true __init__.py linguist-generated=true annotation_context.py linguist-generated=true +axis_length.py linguist-generated=true blob.py linguist-generated=true class_id.py linguist-generated=true clear_is_recursive.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 1788b743be0a..e36042969005 100644 --- a/rerun_py/rerun_sdk/rerun/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/components/__init__.py @@ -9,6 +9,7 @@ AnnotationContextLike, AnnotationContextType, ) +from .axis_length import AxisLength, AxisLengthBatch, AxisLengthType from .blob import Blob, BlobArrayLike, BlobBatch, BlobLike, BlobType from .class_id import ClassId, ClassIdBatch, ClassIdType from .clear_is_recursive import ( @@ -78,6 +79,9 @@ "AnnotationContextBatch", "AnnotationContextLike", "AnnotationContextType", + "AxisLength", + "AxisLengthBatch", + "AxisLengthType", "Blob", "BlobArrayLike", "BlobBatch", diff --git a/rerun_py/rerun_sdk/rerun/components/axis_length.py b/rerun_py/rerun_sdk/rerun/components/axis_length.py new file mode 100644 index 000000000000..9e652f949aff --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/components/axis_length.py @@ -0,0 +1,28 @@ +# 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/axis_length.fbs". + +# You can extend this class by creating a "AxisLengthExt" class in "axis_length_ext.py". + +from __future__ import annotations + +from .. import datatypes +from .._baseclasses import ComponentBatchMixin + +__all__ = ["AxisLength", "AxisLengthBatch", "AxisLengthType"] + + +class AxisLength(datatypes.Float32): + """**Component**: The length of an axis in local units of the space.""" + + # You can define your own __init__ function as a member of AxisLengthExt in axis_length_ext.py + + # Note: there are no fields here because AxisLength delegates to datatypes.Float32 + pass + + +class AxisLengthType(datatypes.Float32Type): + _TYPE_NAME: str = "rerun.components.AxisLength" + + +class AxisLengthBatch(datatypes.Float32Batch, ComponentBatchMixin): + _ARROW_TYPE = AxisLengthType() diff --git a/tests/python/release_checklist/check_all_components_ui.py b/tests/python/release_checklist/check_all_components_ui.py index 353d1c8fdf91..887568a125a2 100644 --- a/tests/python/release_checklist/check_all_components_ui.py +++ b/tests/python/release_checklist/check_all_components_ui.py @@ -89,6 +89,7 @@ def alternatives(self) -> list[Any] | None: ), ) ]), + "AxisLengthBatch": TestCase(batch=[100.0, 200.0, 300.0]), "BlobBatch": TestCase( alternatives=[ b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09",