From 1c88985d58587b548b7bda9937ee8e65dae34967 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 13 Nov 2024 16:35:09 +0100 Subject: [PATCH] move parts of annotation context machinery to re_space_view, remove unnecessary keypoint queries from many visualizers, add colors from annotations to map view --- Cargo.lock | 4 + .../rerun/archetypes/geo_points.fbs | 5 + .../re_types/src/archetypes/geo_points.rs | 47 +++++- crates/viewer/re_space_view/Cargo.toml | 3 + .../src/annotation_context_utils.rs | 137 ++++++++++++++++++ .../src/annotation_scene_context.rs} | 0 crates/viewer/re_space_view/src/lib.rs | 23 +++ crates/viewer/re_space_view_map/Cargo.toml | 1 + .../re_space_view_map/src/map_space_view.rs | 7 +- .../src/visualizers/geo_points.rs | 46 ++++-- .../re_space_view_spatial/src/contexts/mod.rs | 3 +- .../re_space_view_spatial/src/picking_ui.rs | 2 +- .../src/picking_ui_pixel.rs | 5 +- .../src/visualizers/arrows2d.rs | 3 +- .../src/visualizers/arrows3d.rs | 30 +--- .../src/visualizers/boxes2d.rs | 20 +-- .../src/visualizers/boxes3d.rs | 21 +-- .../src/visualizers/capsules3d.rs | 3 +- .../src/visualizers/ellipsoids.rs | 11 +- .../src/visualizers/lines2d.rs | 28 +--- .../src/visualizers/lines3d.rs | 30 +--- .../src/visualizers/mod.rs | 121 +--------------- .../src/visualizers/points2d.rs | 6 +- .../src/visualizers/points3d.rs | 6 +- .../visualizers/utilities/entity_iterator.rs | 25 +--- .../visualizers/utilities/proc_mesh_vis.rs | 11 +- crates/viewer/re_viewer/src/reflection/mod.rs | 6 +- .../reference/types/archetypes/geo_points.md | 2 + .../reference/types/components/class_id.md | 1 + rerun_cpp/src/rerun/archetypes/geo_points.cpp | 7 +- rerun_cpp/src/rerun/archetypes/geo_points.hpp | 15 ++ .../rerun_sdk/rerun/archetypes/geo_points.py | 12 ++ 32 files changed, 346 insertions(+), 295 deletions(-) create mode 100644 crates/viewer/re_space_view/src/annotation_context_utils.rs rename crates/viewer/{re_space_view_spatial/src/contexts/annotation_context.rs => re_space_view/src/annotation_scene_context.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index dea4885f2ad4..52d432c7be13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6083,8 +6083,10 @@ dependencies = [ name = "re_space_view" version = "0.20.0-alpha.4+dev" dependencies = [ + "ahash", "bytemuck", "egui", + "glam", "itertools 0.13.0", "nohash-hasher", "re_chunk_store", @@ -6094,6 +6096,7 @@ dependencies = [ "re_query", "re_renderer", "re_tracing", + "re_types", "re_types_core", "re_ui", "re_viewer_context", @@ -6145,6 +6148,7 @@ dependencies = [ name = "re_space_view_map" version = "0.20.0-alpha.4+dev" dependencies = [ + "bytemuck", "egui", "glam", "itertools 0.13.0", diff --git a/crates/store/re_types/definitions/rerun/archetypes/geo_points.fbs b/crates/store/re_types/definitions/rerun/archetypes/geo_points.fbs index a21581427e17..9ce923e86e1c 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/geo_points.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/geo_points.fbs @@ -30,6 +30,11 @@ table GeoPoints ( /// \py As either 0-1 floats or 0-255 integers, with separate alpha. colors: [rerun.components.Color] ("attr.rerun.component_recommended", nullable, order: 2100); + /// Optional class Ids for the points. + /// + /// The [components.ClassId] provides colors if not specified explicitly. + class_ids: [rerun.components.ClassId] ("attr.rerun.component_optional", nullable, order: 3200); + //TODO(ab): add `Label` and `ShowLabels` components //TODO(ab): add `Altitude` component } diff --git a/crates/store/re_types/src/archetypes/geo_points.rs b/crates/store/re_types/src/archetypes/geo_points.rs index aaa32d63a97e..c6585ad66e66 100644 --- a/crates/store/re_types/src/archetypes/geo_points.rs +++ b/crates/store/re_types/src/archetypes/geo_points.rs @@ -60,6 +60,11 @@ pub struct GeoPoints { /// Optional colors for the points. pub colors: Option>, + + /// Optional class Ids for the points. + /// + /// The [`components::ClassId`][crate::components::ClassId] provides colors if not specified explicitly. + pub class_ids: Option>, } impl ::re_types_core::SizeBytes for GeoPoints { @@ -68,6 +73,7 @@ impl ::re_types_core::SizeBytes for GeoPoints { self.positions.heap_size_bytes() + self.radii.heap_size_bytes() + self.colors.heap_size_bytes() + + self.class_ids.heap_size_bytes() } #[inline] @@ -75,6 +81,7 @@ impl ::re_types_core::SizeBytes for GeoPoints { >::is_pod() && >>::is_pod() && >>::is_pod() + && >>::is_pod() } } @@ -90,22 +97,23 @@ static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = ] }); -static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 0usize]> = - once_cell::sync::Lazy::new(|| []); +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.components.ClassId".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.LatLon".into(), "rerun.components.Radius".into(), "rerun.components.Color".into(), "rerun.components.GeoPointsIndicator".into(), + "rerun.components.ClassId".into(), ] }); impl GeoPoints { - /// The total number of components in the archetype: 1 required, 3 recommended, 0 optional - pub const NUM_COMPONENTS: usize = 4usize; + /// The total number of components in the archetype: 1 required, 3 recommended, 1 optional + pub const NUM_COMPONENTS: usize = 5usize; } /// Indicator component for the [`GeoPoints`] [`::re_types_core::Archetype`] @@ -196,10 +204,23 @@ impl ::re_types_core::Archetype for GeoPoints { } else { None }; + let class_ids = if let Some(array) = arrays_by_name.get("rerun.components.ClassId") { + Some({ + ::from_arrow_opt(&**array) + .with_context("rerun.archetypes.GeoPoints#class_ids")? + .into_iter() + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .collect::>>() + .with_context("rerun.archetypes.GeoPoints#class_ids")? + }) + } else { + None + }; Ok(Self { positions, radii, colors, + class_ids, }) } } @@ -217,6 +238,9 @@ impl ::re_types_core::AsComponents for GeoPoints { self.colors .as_ref() .map(|comp_batch| (comp_batch as &dyn ComponentBatch).into()), + self.class_ids + .as_ref() + .map(|comp_batch| (comp_batch as &dyn ComponentBatch).into()), ] .into_iter() .flatten() @@ -236,6 +260,7 @@ impl GeoPoints { positions: positions.into_iter().map(Into::into).collect(), radii: None, colors: None, + class_ids: None, } } @@ -260,4 +285,16 @@ impl GeoPoints { self.colors = Some(colors.into_iter().map(Into::into).collect()); self } + + /// Optional class Ids for the points. + /// + /// The [`components::ClassId`][crate::components::ClassId] provides colors if not specified explicitly. + #[inline] + pub fn with_class_ids( + mut self, + class_ids: impl IntoIterator>, + ) -> Self { + self.class_ids = Some(class_ids.into_iter().map(Into::into).collect()); + self + } } diff --git a/crates/viewer/re_space_view/Cargo.toml b/crates/viewer/re_space_view/Cargo.toml index f6662e724fef..c7d72ab2d0cc 100644 --- a/crates/viewer/re_space_view/Cargo.toml +++ b/crates/viewer/re_space_view/Cargo.toml @@ -30,11 +30,14 @@ re_query.workspace = true re_renderer.workspace = true re_tracing.workspace = true re_types_core.workspace = true +re_types.workspace = true re_ui.workspace = true re_viewer_context.workspace = true re_viewport_blueprint.workspace = true +ahash.workspace = true bytemuck.workspace = true egui.workspace = true +glam.workspace = true itertools.workspace = true nohash-hasher.workspace = true diff --git a/crates/viewer/re_space_view/src/annotation_context_utils.rs b/crates/viewer/re_space_view/src/annotation_context_utils.rs new file mode 100644 index 000000000000..239a08f0cce8 --- /dev/null +++ b/crates/viewer/re_space_view/src/annotation_context_utils.rs @@ -0,0 +1,137 @@ +use ahash::HashMap; + +use re_types::components::Color; +use re_viewer_context::{Annotations, QueryContext, ResolvedAnnotationInfos}; + +use crate::clamped_or_nothing; + +#[inline] +fn to_egui_color(color: &Color) -> egui::Color32 { + let [r, g, b, a] = color.to_array(); + egui::Color32::from_rgba_unmultiplied(r, g, b, a) +} + +/// Process [`Color`] components using annotations and default colors. +pub fn process_color_slice<'a>( + ctx: &QueryContext<'_>, + fallback_provider: &'a dyn re_viewer_context::TypedComponentFallbackProvider, + num_instances: usize, + annotation_infos: &'a ResolvedAnnotationInfos, + colors: &'a [Color], +) -> Vec { + // NOTE: Do not put tracing scopes here, this is called for every entity/timestamp in a frame. + + if let Some(last_color) = colors.last() { + // If we have colors we can ignore the annotation infos/contexts. + + if colors.len() == num_instances { + // Common happy path + colors.iter().map(to_egui_color).collect() + } else if colors.len() == 1 { + // Common happy path + vec![to_egui_color(last_color); num_instances] + } else { + let colors = clamped_or_nothing(colors, num_instances); + colors.map(to_egui_color).collect() + } + } else { + match annotation_infos { + ResolvedAnnotationInfos::Same(count, annotation_info) => { + re_tracing::profile_scope!("no colors, same annotation"); + let color = annotation_info + .color() + .unwrap_or_else(|| fallback_provider.fallback_for(ctx).into()); + vec![color; *count] + } + ResolvedAnnotationInfos::Many(annotation_info) => { + re_tracing::profile_scope!("no-colors, many annotations"); + let fallback = fallback_provider.fallback_for(ctx).into(); + annotation_info + .iter() + .map(|annotation_info| annotation_info.color().unwrap_or(fallback)) + .collect() + } + } + } +} + +pub type Keypoints = HashMap< + (re_types::components::ClassId, i64), + HashMap, +>; + +/// Resolves all annotations and keypoints for the given entity view. +pub fn process_annotation_and_keypoint_slices( + latest_at: re_log_types::TimeInt, + num_instances: usize, + positions: impl Iterator, + keypoint_ids: &[re_types::components::KeypointId], + class_ids: &[re_types::components::ClassId], + annotations: &Annotations, +) -> (ResolvedAnnotationInfos, Keypoints) { + re_tracing::profile_function!(); + + let mut keypoints: Keypoints = HashMap::default(); + + // No need to process annotations if we don't have class-ids + if class_ids.is_empty() { + let resolved_annotation = annotations + .resolved_class_description(None) + .annotation_info(); + + return ( + ResolvedAnnotationInfos::Same(num_instances, resolved_annotation), + keypoints, + ); + }; + + let class_ids = clamped_or_nothing(class_ids, num_instances); + + if keypoint_ids.is_empty() { + let annotation_info = class_ids + .map(|&class_id| { + let class_description = annotations.resolved_class_description(Some(class_id)); + class_description.annotation_info() + }) + .collect(); + + ( + ResolvedAnnotationInfos::Many(annotation_info), + Default::default(), + ) + } else { + let keypoint_ids = clamped_or_nothing(keypoint_ids, num_instances); + let annotation_info = itertools::izip!(positions, keypoint_ids, class_ids) + .map(|(position, keypoint_id, &class_id)| { + let class_description = annotations.resolved_class_description(Some(class_id)); + + keypoints + .entry((class_id, latest_at.as_i64())) + .or_default() + .insert(keypoint_id.0, position); + class_description.annotation_info_with_keypoint(keypoint_id.0) + }) + .collect(); + + (ResolvedAnnotationInfos::Many(annotation_info), keypoints) + } +} + +/// Resolves all annotations for the given entity view. +pub fn process_annotation_slices( + latest_at: re_log_types::TimeInt, + num_instances: usize, + class_ids: &[re_types::components::ClassId], + annotations: &Annotations, +) -> ResolvedAnnotationInfos { + let (annotations, _keypoints) = process_annotation_and_keypoint_slices( + latest_at, + num_instances, + std::iter::empty(), // positions are only needed for keypoint lookup + &[], + class_ids, + annotations, + ); + + annotations +} diff --git a/crates/viewer/re_space_view_spatial/src/contexts/annotation_context.rs b/crates/viewer/re_space_view/src/annotation_scene_context.rs similarity index 100% rename from crates/viewer/re_space_view_spatial/src/contexts/annotation_context.rs rename to crates/viewer/re_space_view/src/annotation_scene_context.rs diff --git a/crates/viewer/re_space_view/src/lib.rs b/crates/viewer/re_space_view/src/lib.rs index 52804f8833e5..2d311a0a21a6 100644 --- a/crates/viewer/re_space_view/src/lib.rs +++ b/crates/viewer/re_space_view/src/lib.rs @@ -4,6 +4,8 @@ pub mod controls; +mod annotation_context_utils; +mod annotation_scene_context; mod heuristics; mod instance_hash_conversions; mod outlines; @@ -12,6 +14,10 @@ mod results_ext; mod screenshot; mod view_property_ui; +pub use annotation_context_utils::{ + process_annotation_and_keypoint_slices, process_annotation_slices, process_color_slice, +}; +pub use annotation_scene_context::AnnotationSceneContext; pub use heuristics::suggest_space_view_for_each_entity; pub use instance_hash_conversions::{ instance_path_hash_from_picking_layer_id, picking_layer_id_from_instance_path_hash, @@ -53,3 +59,20 @@ pub fn diff_component_filter( .any(|instances| instances.iter().any(filter)) }) } + +/// Clamp the last value in `values` in order to reach a length of `clamped_len`. +/// +/// Returns an empty iterator if values is empty. +#[inline] +pub fn clamped_or_nothing(values: &[T], clamped_len: usize) -> impl Iterator + Clone { + let Some(last) = values.last() else { + return itertools::Either::Left(std::iter::empty()); + }; + + itertools::Either::Right( + values + .iter() + .chain(std::iter::repeat(last)) + .take(clamped_len), + ) +} diff --git a/crates/viewer/re_space_view_map/Cargo.toml b/crates/viewer/re_space_view_map/Cargo.toml index dc3726afb309..2afeb72446e1 100644 --- a/crates/viewer/re_space_view_map/Cargo.toml +++ b/crates/viewer/re_space_view_map/Cargo.toml @@ -33,6 +33,7 @@ re_ui.workspace = true re_viewer_context.workspace = true re_viewport_blueprint.workspace = true +bytemuck.workspace = true egui.workspace = true glam.workspace = true itertools.workspace = true diff --git a/crates/viewer/re_space_view_map/src/map_space_view.rs b/crates/viewer/re_space_view_map/src/map_space_view.rs index d571cff601e1..fd4934f14079 100644 --- a/crates/viewer/re_space_view_map/src/map_space_view.rs +++ b/crates/viewer/re_space_view_map/src/map_space_view.rs @@ -1,4 +1,5 @@ use egui::{Context, NumExt as _, Rect, Response}; +use re_space_view::AnnotationSceneContext; use walkers::{HttpTiles, Map, MapMemory, Tiles}; use re_data_ui::{item_ui, DataUi}; @@ -119,7 +120,11 @@ Displays geospatial primitives on a map. system_registry: &mut SpaceViewSystemRegistrator<'_>, ) -> Result<(), SpaceViewClassRegistryError> { system_registry.register_visualizer::()?; - system_registry.register_visualizer::() + system_registry.register_visualizer::()?; + + system_registry.register_context_system::()?; + + Ok(()) } fn new_state(&self) -> Box { diff --git a/crates/viewer/re_space_view_map/src/visualizers/geo_points.rs b/crates/viewer/re_space_view_map/src/visualizers/geo_points.rs index b4f17dfe099f..a5f16427c278 100644 --- a/crates/viewer/re_space_view_map/src/visualizers/geo_points.rs +++ b/crates/viewer/re_space_view_map/src/visualizers/geo_points.rs @@ -1,9 +1,12 @@ use re_log_types::EntityPath; use re_renderer::{renderer::PointCloudDrawDataError, PickingLayerInstanceId}; -use re_space_view::{DataResultQuery as _, RangeResultsExt as _}; +use re_space_view::{ + process_annotation_slices, process_color_slice, AnnotationSceneContext, DataResultQuery as _, + RangeResultsExt as _, +}; use re_types::{ archetypes::GeoPoints, - components::{Color, LatLon, Radius}, + components::{ClassId, Color, LatLon, Radius}, Loggable as _, }; use re_viewer_context::{ @@ -41,10 +44,14 @@ impl VisualizerSystem for GeoPointsVisualizer { &mut self, ctx: &ViewContext<'_>, view_query: &ViewQuery<'_>, - _context_systems: &ViewContextCollection, + context_systems: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { + let annotation_scene_context = context_systems.get::()?; + let latest_at_query = view_query.latest_at_query(); + for data_result in view_query.iter_visible_data_results(ctx, Self::identifier()) { let results = data_result.query_archetype_with_history::(ctx, view_query); + let annotation_context = annotation_scene_context.0.find(&data_result.entity_path); let mut batch_data = GeoPointBatch::default(); @@ -53,34 +60,49 @@ impl VisualizerSystem for GeoPointsVisualizer { let all_positions = results.iter_as(timeline, LatLon::name()); let all_colors = results.iter_as(timeline, Color::name()); let all_radii = results.iter_as(timeline, Radius::name()); + let all_class_ids = results.iter_as(timeline, ClassId::name()); // fallback component values - let fallback_color: Color = - self.fallback_for(&ctx.query_context(data_result, &view_query.latest_at_query())); + let query_context = ctx.query_context(data_result, &latest_at_query); let fallback_radius: Radius = - self.fallback_for(&ctx.query_context(data_result, &view_query.latest_at_query())); + self.fallback_for(&ctx.query_context(data_result, &latest_at_query)); // iterate over each chunk and find all relevant component slices - for (_index, positions, colors, radii) in re_query::range_zip_1x2( + for (_index, positions, colors, radii, class_ids) in re_query::range_zip_1x3( all_positions.component::(), - all_colors.component::(), + all_colors.primitive::(), all_radii.component::(), + all_class_ids.primitive::(), ) { // required component let positions = positions.as_slice(); + let num_instances = positions.len(); + + // Resolve annotation info (if needed). + let annotation_infos = process_annotation_slices( + view_query.latest_at, + num_instances, + class_ids.map_or(&[], |class_ids| bytemuck::cast_slice(class_ids)), + &annotation_context, + ); // optional components - let colors = colors.as_ref().map(|c| c.as_slice()).unwrap_or(&[]); + let colors = process_color_slice( + &query_context, + self, + num_instances, + &annotation_infos, + colors.map_or(&[], |colors| bytemuck::cast_slice(colors)), + ); let radii = radii.as_ref().map(|r| r.as_slice()).unwrap_or(&[]); // optional components values to be used for instance clamping semantics - let last_color = colors.last().copied().unwrap_or(fallback_color); let last_radii = radii.last().copied().unwrap_or(fallback_radius); // iterate over all instances for (instance_index, (position, color, radius)) in itertools::izip!( positions, - colors.iter().chain(std::iter::repeat(&last_color)), + colors.iter(), radii.iter().chain(std::iter::repeat(&last_radii)), ) .enumerate() @@ -90,7 +112,7 @@ impl VisualizerSystem for GeoPointsVisualizer { position.longitude(), )); batch_data.radii.push(*radius); - batch_data.colors.push(color.0.into()); + batch_data.colors.push(*color); batch_data .instance_id .push(re_renderer::PickingLayerInstanceId(instance_index as _)); diff --git a/crates/viewer/re_space_view_spatial/src/contexts/mod.rs b/crates/viewer/re_space_view_spatial/src/contexts/mod.rs index d7a425f20ccc..5956680d872b 100644 --- a/crates/viewer/re_space_view_spatial/src/contexts/mod.rs +++ b/crates/viewer/re_space_view_spatial/src/contexts/mod.rs @@ -1,9 +1,8 @@ -mod annotation_context; mod depth_offsets; mod transform_context; -pub use annotation_context::AnnotationSceneContext; pub use depth_offsets::EntityDepthOffsets; +use re_space_view::AnnotationSceneContext; use re_types::SpaceViewClassIdentifier; pub use transform_context::{TransformContext, TransformInfo, TwoDInThreeDTransformInfo}; diff --git a/crates/viewer/re_space_view_spatial/src/picking_ui.rs b/crates/viewer/re_space_view_spatial/src/picking_ui.rs index 8aa10dde8581..bfd8e096fb88 100644 --- a/crates/viewer/re_space_view_spatial/src/picking_ui.rs +++ b/crates/viewer/re_space_view_spatial/src/picking_ui.rs @@ -2,6 +2,7 @@ use egui::NumExt as _; use re_data_ui::{item_ui, DataUi as _}; use re_log_types::Instance; +use re_space_view::AnnotationSceneContext; use re_ui::{ list_item::{list_item_scope, PropertyContent}, UiExt as _, @@ -12,7 +13,6 @@ use re_viewer_context::{ }; use crate::{ - contexts::AnnotationSceneContext, picking::{PickableUiRect, PickingContext, PickingHitType}, picking_ui_pixel::{textured_rect_hover_ui, PickedPixelInfo}, ui::SpatialSpaceViewState, diff --git a/crates/viewer/re_space_view_spatial/src/picking_ui_pixel.rs b/crates/viewer/re_space_view_spatial/src/picking_ui_pixel.rs index 1ddba8d86373..c28242717b0c 100644 --- a/crates/viewer/re_space_view_spatial/src/picking_ui_pixel.rs +++ b/crates/viewer/re_space_view_spatial/src/picking_ui_pixel.rs @@ -1,12 +1,11 @@ use re_data_ui::item_ui; use re_renderer::{external::wgpu, renderer::ColormappedTexture, resource_managers::GpuTexture2D}; +use re_space_view::AnnotationSceneContext; use re_types::{datatypes::ColorModel, image::ImageKind, tensor_data::TensorElement}; use re_ui::UiExt as _; use re_viewer_context::{gpu_bridge, Annotations, ImageInfo, ViewQuery, ViewerContext}; -use crate::{ - contexts::AnnotationSceneContext, view_kind::SpatialSpaceViewKind, PickableRectSourceData, -}; +use crate::{view_kind::SpatialSpaceViewKind, PickableRectSourceData}; pub struct PickedPixelInfo { pub source_data: PickableRectSourceData, diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/arrows2d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/arrows2d.rs index acd58a4899f6..d001f8ca7291 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/arrows2d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/arrows2d.rs @@ -1,5 +1,6 @@ use re_log_types::Instance; use re_renderer::{renderer::LineStripFlags, LineDrawableBuilder, PickingLayerInstanceId}; +use re_space_view::{process_annotation_and_keypoint_slices, process_color_slice}; use re_types::{ archetypes::Arrows2D, components::{ @@ -21,7 +22,7 @@ use crate::{ use super::{ entity_iterator::clamped_or, - process_annotation_and_keypoint_slices, process_color_slice, process_radius_slice, + process_radius_slice, utilities::{process_labels_2d, LabeledBatch}, SpatialViewVisualizerData, }; diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/arrows3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/arrows3d.rs index 6d430f8e4a56..3107ddb4df63 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/arrows3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/arrows3d.rs @@ -1,8 +1,9 @@ use re_log_types::Instance; use re_renderer::{renderer::LineStripFlags, LineDrawableBuilder, PickingLayerInstanceId}; +use re_space_view::{process_annotation_slices, process_color_slice}; use re_types::{ archetypes::Arrows3D, - components::{ClassId, Color, KeypointId, Position3D, Radius, ShowLabels, Text, Vector3D}, + components::{ClassId, Color, Position3D, Radius, ShowLabels, Text, Vector3D}, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -18,8 +19,8 @@ use crate::{ }; use super::{ - entity_iterator::clamped_or, process_annotation_and_keypoint_slices, process_color_slice, - process_labels_3d, process_radius_slice, utilities::LabeledBatch, SpatialViewVisualizerData, + entity_iterator::clamped_or, process_labels_3d, process_radius_slice, utilities::LabeledBatch, + SpatialViewVisualizerData, }; // --- @@ -55,11 +56,9 @@ impl Arrows3DVisualizer { continue; } - let (annotation_infos, _) = process_annotation_and_keypoint_slices( + let annotation_infos = process_annotation_slices( query.latest_at, num_instances, - data.vectors.iter().map(|_| glam::Vec3::ZERO), - data.keypoint_ids, data.class_ids, &ent_context.annotations, ); @@ -159,7 +158,6 @@ struct Arrows3DComponentData<'a> { colors: &'a [Color], radii: &'a [Radius], labels: Vec, - keypoint_ids: &'a [KeypointId], class_ids: &'a [ClassId], // Non-repeated @@ -234,31 +232,19 @@ impl VisualizerSystem for Arrows3DVisualizer { let all_radii = results.iter_as(timeline, Radius::name()); let all_labels = results.iter_as(timeline, Text::name()); let all_class_ids = results.iter_as(timeline, ClassId::name()); - let all_keypoint_ids = results.iter_as(timeline, KeypointId::name()); let all_show_labels = results.iter_as(timeline, ShowLabels::name()); - let data = re_query::range_zip_1x7( + let data = re_query::range_zip_1x6( all_vectors_indexed, all_origins.primitive_array::<3, f32>(), all_colors.primitive::(), all_radii.primitive::(), all_labels.string(), all_class_ids.primitive::(), - all_keypoint_ids.primitive::(), all_show_labels.component::(), ) .map( - |( - _index, - vectors, - origins, - colors, - radii, - labels, - class_ids, - keypoint_ids, - show_labels, - )| { + |(_index, vectors, origins, colors, radii, labels, class_ids, show_labels)| { Arrows3DComponentData { vectors: bytemuck::cast_slice(vectors), origins: origins.map_or(&[], |origins| bytemuck::cast_slice(origins)), @@ -267,8 +253,6 @@ impl VisualizerSystem for Arrows3DVisualizer { labels: labels.unwrap_or_default(), class_ids: class_ids .map_or(&[], |class_ids| bytemuck::cast_slice(class_ids)), - keypoint_ids: keypoint_ids - .map_or(&[], |keypoint_ids| bytemuck::cast_slice(keypoint_ids)), show_labels: show_labels.unwrap_or_default().first().copied(), } }, diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/boxes2d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/boxes2d.rs index dff98f6d0962..d4a15e14eb3c 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/boxes2d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/boxes2d.rs @@ -1,10 +1,9 @@ use re_log_types::Instance; use re_renderer::{LineDrawableBuilder, PickingLayerInstanceId}; +use re_space_view::{process_annotation_slices, process_color_slice}; use re_types::{ archetypes::Boxes2D, - components::{ - ClassId, Color, DrawOrder, HalfSize2D, KeypointId, Position2D, Radius, ShowLabels, Text, - }, + components::{ClassId, Color, DrawOrder, HalfSize2D, Position2D, Radius, ShowLabels, Text}, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -21,8 +20,7 @@ use crate::{ }; use super::{ - filter_visualizable_2d_entities, process_annotation_and_keypoint_slices, process_color_slice, - process_radius_slice, + filter_visualizable_2d_entities, process_radius_slice, utilities::{process_labels, LabeledBatch}, SpatialViewVisualizerData, }; @@ -60,11 +58,9 @@ impl Boxes2DVisualizer { continue; } - let (annotation_infos, _) = process_annotation_and_keypoint_slices( + let annotation_infos = process_annotation_slices( view_query.latest_at, num_instances, - data.half_sizes.iter().map(|_| glam::Vec3::ZERO), - data.keypoint_ids, data.class_ids, &ent_context.annotations, ); @@ -162,7 +158,6 @@ struct Boxes2DComponentData<'a> { colors: &'a [Color], radii: &'a [Radius], labels: Vec, - keypoint_ids: &'a [KeypointId], class_ids: &'a [ClassId], // Non-repeated @@ -241,17 +236,15 @@ impl VisualizerSystem for Boxes2DVisualizer { let all_radii = results.iter_as(timeline, Radius::name()); let all_labels = results.iter_as(timeline, Text::name()); let all_class_ids = results.iter_as(timeline, ClassId::name()); - let all_keypoint_ids = results.iter_as(timeline, KeypointId::name()); let all_show_labels = results.iter_as(timeline, ShowLabels::name()); - let data = re_query::range_zip_1x7( + let data = re_query::range_zip_1x6( all_half_sizes_indexed, all_centers.primitive_array::<2, f32>(), all_colors.primitive::(), all_radii.primitive::(), all_labels.string(), all_class_ids.primitive::(), - all_keypoint_ids.primitive::(), all_show_labels.component::(), ) .map( @@ -263,7 +256,6 @@ impl VisualizerSystem for Boxes2DVisualizer { radii, labels, class_ids, - keypoint_ids, show_labels, )| { Boxes2DComponentData { @@ -274,8 +266,6 @@ impl VisualizerSystem for Boxes2DVisualizer { labels: labels.unwrap_or_default(), class_ids: class_ids .map_or(&[], |class_ids| bytemuck::cast_slice(class_ids)), - keypoint_ids: keypoint_ids - .map_or(&[], |keypoint_ids| bytemuck::cast_slice(keypoint_ids)), show_labels: show_labels.unwrap_or_default().first().copied(), } }, diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/boxes3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/boxes3d.rs index afb768b15844..343e0387fd09 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/boxes3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/boxes3d.rs @@ -2,7 +2,7 @@ use std::iter; use re_types::{ archetypes::Boxes3D, - components::{ClassId, Color, FillMode, HalfSize3D, KeypointId, Radius, ShowLabels, Text}, + components::{ClassId, Color, FillMode, HalfSize3D, Radius, ShowLabels, Text}, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -62,7 +62,6 @@ impl Boxes3DVisualizer { colors: batch.colors, labels: &batch.labels, show_labels: batch.show_labels, - keypoint_ids: batch.keypoint_ids, class_ids: batch.class_ids, }, )?; @@ -82,7 +81,6 @@ struct Boxes3DComponentData<'a> { colors: &'a [Color], radii: &'a [Radius], labels: Vec, - keypoint_ids: &'a [KeypointId], class_ids: &'a [ClassId], // Non-repeated @@ -155,7 +153,6 @@ impl VisualizerSystem for Boxes3DVisualizer { let all_radii = results.iter_as(timeline, Radius::name()); let all_labels = results.iter_as(timeline, Text::name()); let all_class_ids = results.iter_as(timeline, ClassId::name()); - let all_keypoint_ids = results.iter_as(timeline, KeypointId::name()); let all_show_labels = results.iter_as(timeline, ShowLabels::name()); // Deserialized because it's a union. @@ -178,26 +175,16 @@ impl VisualizerSystem for Boxes3DVisualizer { } } - let data = re_query::range_zip_1x6( + let data = re_query::range_zip_1x5( all_half_sizes_indexed, all_colors.primitive::(), all_radii.primitive::(), all_labels.string(), all_class_ids.primitive::(), - all_keypoint_ids.primitive::(), all_show_labels.component::(), ) .map( - |( - _index, - half_sizes, - colors, - radii, - labels, - class_ids, - keypoint_ids, - show_labels, - )| { + |(_index, half_sizes, colors, radii, labels, class_ids, show_labels)| { Boxes3DComponentData { half_sizes: bytemuck::cast_slice(half_sizes), colors: colors.map_or(&[], |colors| bytemuck::cast_slice(colors)), @@ -207,8 +194,6 @@ impl VisualizerSystem for Boxes3DVisualizer { labels: labels.unwrap_or_default(), class_ids: class_ids .map_or(&[], |class_ids| bytemuck::cast_slice(class_ids)), - keypoint_ids: keypoint_ids - .map_or(&[], |keypoint_ids| bytemuck::cast_slice(keypoint_ids)), show_labels: show_labels.unwrap_or_default().first().copied(), } }, diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/capsules3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/capsules3d.rs index cb649d69c42f..64ad8f99b9eb 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/capsules3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/capsules3d.rs @@ -1,6 +1,7 @@ use std::iter; use ordered_float::NotNan; +use re_space_view::clamped_or_nothing; use re_types::{ archetypes::Capsules3D, components::{self, ClassId, Color, FillMode, HalfSize3D, Length, Radius, ShowLabels, Text}, @@ -16,7 +17,6 @@ use re_viewer_context::{ use crate::{contexts::SpatialSceneEntityContext, proc_mesh, view_kind::SpatialSpaceViewKind}; use super::{ - entity_iterator::clamped_or_nothing, filter_visualizable_3d_entities, utilities::{ProcMeshBatch, ProcMeshDrawableBuilder}, SpatialViewVisualizerData, @@ -85,7 +85,6 @@ impl Capsules3DVisualizer { colors: batch.colors, labels: &batch.labels, show_labels: batch.show_labels, - keypoint_ids: &[], class_ids: batch.class_ids, }, )?; diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/ellipsoids.rs b/crates/viewer/re_space_view_spatial/src/visualizers/ellipsoids.rs index 3c842cff14f3..4dd5dc3074a8 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/ellipsoids.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/ellipsoids.rs @@ -2,7 +2,7 @@ use std::iter; use re_types::{ archetypes::Ellipsoids3D, - components::{ClassId, Color, FillMode, HalfSize3D, KeypointId, Radius, ShowLabels, Text}, + components::{ClassId, Color, FillMode, HalfSize3D, Radius, ShowLabels, Text}, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -69,7 +69,6 @@ impl Ellipsoids3DVisualizer { colors: batch.colors, labels: &batch.labels, show_labels: batch.show_labels, - keypoint_ids: batch.keypoint_ids, class_ids: batch.class_ids, }, )?; @@ -89,7 +88,6 @@ struct Ellipsoids3DComponentData<'a> { colors: &'a [Color], line_radii: &'a [Radius], labels: Vec, - keypoint_ids: &'a [KeypointId], class_ids: &'a [ClassId], // Non-repeated @@ -174,17 +172,15 @@ impl VisualizerSystem for Ellipsoids3DVisualizer { let all_fill_modes = results.iter_as(timeline, FillMode::name()); let all_labels = results.iter_as(timeline, Text::name()); let all_class_ids = results.iter_as(timeline, ClassId::name()); - let all_keypoint_ids = results.iter_as(timeline, KeypointId::name()); let all_show_labels = results.iter_as(timeline, ShowLabels::name()); - let data = re_query::range_zip_1x7( + let data = re_query::range_zip_1x6( all_half_sizes_indexed, all_colors.primitive::(), all_line_radii.primitive::(), all_fill_modes.component::(), all_labels.string(), all_class_ids.primitive::(), - all_keypoint_ids.primitive::(), all_show_labels.component::(), ) .map( @@ -196,7 +192,6 @@ impl VisualizerSystem for Ellipsoids3DVisualizer { fill_modes, labels, class_ids, - keypoint_ids, show_labels, )| { Ellipsoids3DComponentData { @@ -213,8 +208,6 @@ impl VisualizerSystem for Ellipsoids3DVisualizer { labels: labels.unwrap_or_default(), class_ids: class_ids .map_or(&[], |class_ids| bytemuck::cast_slice(class_ids)), - keypoint_ids: keypoint_ids - .map_or(&[], |keypoint_ids| bytemuck::cast_slice(keypoint_ids)), show_labels: show_labels.unwrap_or_default().first().copied(), } }, diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/lines2d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/lines2d.rs index 5a868ea4045d..b6c2779bb1fa 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/lines2d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/lines2d.rs @@ -1,8 +1,9 @@ use re_log_types::Instance; use re_renderer::{renderer::LineStripFlags, LineDrawableBuilder, PickingLayerInstanceId}; +use re_space_view::{process_annotation_slices, process_color_slice}; use re_types::{ archetypes::LineStrips2D, - components::{ClassId, Color, DrawOrder, KeypointId, LineStrip2D, Radius, ShowLabels, Text}, + components::{ClassId, Color, DrawOrder, LineStrip2D, Radius, ShowLabels, Text}, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -15,8 +16,7 @@ use re_viewer_context::{ use crate::{contexts::SpatialSceneEntityContext, view_kind::SpatialSpaceViewKind}; use super::{ - filter_visualizable_2d_entities, process_annotation_and_keypoint_slices, process_color_slice, - process_radius_slice, + filter_visualizable_2d_entities, process_radius_slice, utilities::{process_labels_2d, LabeledBatch}, SpatialViewVisualizerData, }; @@ -54,11 +54,9 @@ impl Lines2DVisualizer { continue; } - let (annotation_infos, _) = process_annotation_and_keypoint_slices( + let annotation_infos = process_annotation_slices( query.latest_at, num_instances, - data.strips.iter().map(|_| glam::Vec3::ZERO), - data.keypoint_ids, data.class_ids, &ent_context.annotations, ); @@ -143,7 +141,6 @@ struct Lines2DComponentData<'a> { colors: &'a [Color], radii: &'a [Radius], labels: Vec, - keypoint_ids: &'a [KeypointId], class_ids: &'a [ClassId], // Non-repeated @@ -227,29 +224,18 @@ impl VisualizerSystem for Lines2DVisualizer { let all_radii = results.iter_as(timeline, Radius::name()); let all_labels = results.iter_as(timeline, Text::name()); let all_class_ids = results.iter_as(timeline, ClassId::name()); - let all_keypoint_ids = results.iter_as(timeline, KeypointId::name()); let all_show_labels = results.iter_as(timeline, ShowLabels::name()); - let data = re_query::range_zip_1x6( + let data = re_query::range_zip_1x5( all_strips_indexed, all_colors.primitive::(), all_radii.primitive::(), all_labels.string(), all_class_ids.primitive::(), - all_keypoint_ids.primitive::(), all_show_labels.component::(), ) .map( - |( - _index, - strips, - colors, - radii, - labels, - class_ids, - keypoint_ids, - show_labels, - )| { + |(_index, strips, colors, radii, labels, class_ids, show_labels)| { Lines2DComponentData { strips, colors: colors.map_or(&[], |colors| bytemuck::cast_slice(colors)), @@ -257,8 +243,6 @@ impl VisualizerSystem for Lines2DVisualizer { labels: labels.unwrap_or_default(), class_ids: class_ids .map_or(&[], |class_ids| bytemuck::cast_slice(class_ids)), - keypoint_ids: keypoint_ids - .map_or(&[], |keypoint_ids| bytemuck::cast_slice(keypoint_ids)), show_labels: show_labels.unwrap_or_default().first().copied(), } }, diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/lines3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/lines3d.rs index 754cf13ef3ba..8145491e14b4 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/lines3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/lines3d.rs @@ -1,8 +1,9 @@ use re_log_types::Instance; use re_renderer::{renderer::LineStripFlags, PickingLayerInstanceId}; +use re_space_view::{process_annotation_slices, process_color_slice}; use re_types::{ archetypes::LineStrips3D, - components::{ClassId, Color, KeypointId, LineStrip3D, Radius, ShowLabels, Text}, + components::{ClassId, Color, LineStrip3D, Radius, ShowLabels, Text}, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -18,10 +19,7 @@ use crate::{ visualizers::utilities::{process_labels_3d, LabeledBatch}, }; -use super::{ - filter_visualizable_3d_entities, process_annotation_and_keypoint_slices, process_color_slice, - process_radius_slice, SpatialViewVisualizerData, -}; +use super::{filter_visualizable_3d_entities, process_radius_slice, SpatialViewVisualizerData}; // --- @@ -56,11 +54,9 @@ impl Lines3DVisualizer { continue; } - let (annotation_infos, _) = process_annotation_and_keypoint_slices( + let annotation_infos = process_annotation_slices( query.latest_at, num_instances, - data.strips.iter().map(|_| glam::Vec3::ZERO), - data.keypoint_ids, data.class_ids, &ent_context.annotations, ); @@ -150,7 +146,6 @@ struct Lines3DComponentData<'a> { colors: &'a [Color], radii: &'a [Radius], labels: Vec, - keypoint_ids: &'a [KeypointId], class_ids: &'a [ClassId], // Non-repeated @@ -233,29 +228,18 @@ impl VisualizerSystem for Lines3DVisualizer { let all_radii = results.iter_as(timeline, Radius::name()); let all_labels = results.iter_as(timeline, Text::name()); let all_class_ids = results.iter_as(timeline, ClassId::name()); - let all_keypoint_ids = results.iter_as(timeline, KeypointId::name()); let all_show_labels = results.iter_as(timeline, ShowLabels::name()); - let data = re_query::range_zip_1x6( + let data = re_query::range_zip_1x5( all_strips_indexed, all_colors.primitive::(), all_radii.primitive::(), all_labels.string(), all_class_ids.primitive::(), - all_keypoint_ids.primitive::(), all_show_labels.component::(), ) .map( - |( - _index, - strips, - colors, - radii, - labels, - class_ids, - keypoint_ids, - show_labels, - )| { + |(_index, strips, colors, radii, labels, class_ids, show_labels)| { Lines3DComponentData { strips, colors: colors.map_or(&[], |colors| bytemuck::cast_slice(colors)), @@ -263,8 +247,6 @@ impl VisualizerSystem for Lines3DVisualizer { labels: labels.unwrap_or_default(), class_ids: class_ids .map_or(&[], |class_ids| bytemuck::cast_slice(class_ids)), - keypoint_ids: keypoint_ids - .map_or(&[], |keypoint_ids| bytemuck::cast_slice(keypoint_ids)), show_labels: show_labels.unwrap_or_default().first().copied(), } }, diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/mod.rs b/crates/viewer/re_space_view_spatial/src/visualizers/mod.rs index 91a0c3679e3b..f7e0f69be848 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/mod.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/mod.rs @@ -48,18 +48,14 @@ pub struct LoadingSpinner { use ahash::HashMap; use re_entity_db::EntityPath; -use re_types::{ - components::Color, - datatypes::{KeypointId, KeypointPair}, -}; +use re_types::datatypes::{KeypointId, KeypointPair}; use re_viewer_context::{ - auto_color_egui, Annotations, ApplicableEntities, IdentifiedViewSystem, QueryContext, - ResolvedAnnotationInfos, SpaceViewClassRegistryError, SpaceViewSystemExecutionError, - SpaceViewSystemRegistrator, ViewSystemIdentifier, VisualizableEntities, - VisualizableFilterContext, VisualizerCollection, + auto_color_egui, ApplicableEntities, IdentifiedViewSystem, SpaceViewClassRegistryError, + SpaceViewSystemExecutionError, SpaceViewSystemRegistrator, ViewSystemIdentifier, + VisualizableEntities, VisualizableFilterContext, VisualizerCollection, }; -use utilities::entity_iterator::clamped_or_nothing; +use re_space_view::clamped_or_nothing; use crate::view_2d::VisualizableFilterContext2D; use crate::view_3d::VisualizableFilterContext3D; @@ -143,56 +139,6 @@ pub fn collect_ui_labels(visualizers: &VisualizerCollection) -> Vec { .collect() } -/// Process [`Color`] components using annotations and default colors. -pub fn process_color_slice<'a>( - ctx: &QueryContext<'_>, - fallback_provider: &'a dyn re_viewer_context::TypedComponentFallbackProvider, - num_instances: usize, - annotation_infos: &'a ResolvedAnnotationInfos, - colors: &'a [Color], -) -> Vec { - // NOTE: Do not put tracing scopes here, this is called for every entity/timestamp in a frame. - - if let Some(last_color) = colors.last() { - // If we have colors we can ignore the annotation infos/contexts. - - if colors.len() == num_instances { - // Common happy path - colors.iter().map(to_egui_color).collect() - } else if colors.len() == 1 { - // Common happy path - vec![to_egui_color(last_color); num_instances] - } else { - let colors = clamped_or_nothing(colors, num_instances); - colors.map(to_egui_color).collect() - } - } else { - match annotation_infos { - ResolvedAnnotationInfos::Same(count, annotation_info) => { - re_tracing::profile_scope!("no colors, same annotation"); - let color = annotation_info - .color() - .unwrap_or_else(|| fallback_provider.fallback_for(ctx).into()); - vec![color; *count] - } - ResolvedAnnotationInfos::Many(annotation_info) => { - re_tracing::profile_scope!("no-colors, many annotations"); - let fallback = fallback_provider.fallback_for(ctx).into(); - annotation_info - .iter() - .map(|annotation_info| annotation_info.color().unwrap_or(fallback)) - .collect() - } - } - } -} - -#[inline] -fn to_egui_color(color: &Color) -> egui::Color32 { - let [r, g, b, a] = color.to_array(); - egui::Color32::from_rgba_unmultiplied(r, g, b, a) -} - /// Process [`re_types::components::Radius`] components to [`re_renderer::Size`] using auto size /// where no radius is specified. pub fn process_radius_slice( @@ -237,63 +183,6 @@ fn process_radius( re_renderer::Size(*radius.0) } -/// Resolves all annotations and keypoints for the given entity view. -fn process_annotation_and_keypoint_slices( - latest_at: re_log_types::TimeInt, - num_instances: usize, - positions: impl Iterator, - keypoint_ids: &[re_types::components::KeypointId], - class_ids: &[re_types::components::ClassId], - annotations: &Annotations, -) -> (ResolvedAnnotationInfos, Keypoints) { - re_tracing::profile_function!(); - - let mut keypoints: Keypoints = HashMap::default(); - - // No need to process annotations if we don't have class-ids - if class_ids.is_empty() { - let resolved_annotation = annotations - .resolved_class_description(None) - .annotation_info(); - - return ( - ResolvedAnnotationInfos::Same(num_instances, resolved_annotation), - keypoints, - ); - }; - - let class_ids = clamped_or_nothing(class_ids, num_instances); - - if keypoint_ids.is_empty() { - let annotation_info = class_ids - .map(|&class_id| { - let class_description = annotations.resolved_class_description(Some(class_id)); - class_description.annotation_info() - }) - .collect(); - - ( - ResolvedAnnotationInfos::Many(annotation_info), - Default::default(), - ) - } else { - let keypoint_ids = clamped_or_nothing(keypoint_ids, num_instances); - let annotation_info = itertools::izip!(positions, keypoint_ids, class_ids) - .map(|(position, keypoint_id, &class_id)| { - let class_description = annotations.resolved_class_description(Some(class_id)); - - keypoints - .entry((class_id, latest_at.as_i64())) - .or_default() - .insert(keypoint_id.0, position); - class_description.annotation_info_with_keypoint(keypoint_id.0) - }) - .collect(); - - (ResolvedAnnotationInfos::Many(annotation_info), keypoints) - } -} - pub fn load_keypoint_connections( line_builder: &mut re_renderer::LineDrawableBuilder<'_>, ent_context: &SpatialSceneEntityContext<'_>, diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/points2d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/points2d.rs index 894171528ff5..0d277b31d615 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/points2d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/points2d.rs @@ -1,6 +1,7 @@ use itertools::Itertools as _; use re_renderer::{LineDrawableBuilder, PickingLayerInstanceId, PointCloudBuilder}; +use re_space_view::{process_annotation_and_keypoint_slices, process_color_slice}; use re_types::{ archetypes::Points2D, components::{ClassId, Color, DrawOrder, KeypointId, Position2D, Radius, ShowLabels, Text}, @@ -16,10 +17,7 @@ use re_viewer_context::{ use crate::{ contexts::SpatialSceneEntityContext, view_kind::SpatialSpaceViewKind, - visualizers::{ - load_keypoint_connections, process_annotation_and_keypoint_slices, process_color_slice, - process_radius_slice, - }, + visualizers::{load_keypoint_connections, process_radius_slice}, }; use super::{ diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/points3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/points3d.rs index 1c212fcf3060..813df98bbd92 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/points3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/points3d.rs @@ -1,6 +1,7 @@ use itertools::Itertools; use re_renderer::{LineDrawableBuilder, PickingLayerInstanceId, PointCloudBuilder}; +use re_space_view::{process_annotation_and_keypoint_slices, process_color_slice}; use re_types::{ archetypes::Points3D, components::{ClassId, Color, KeypointId, Position3D, Radius, ShowLabels, Text}, @@ -16,10 +17,7 @@ use re_viewer_context::{ use crate::{ contexts::SpatialSceneEntityContext, view_kind::SpatialSpaceViewKind, - visualizers::{ - load_keypoint_connections, process_annotation_and_keypoint_slices, process_color_slice, - process_radius_slice, - }, + visualizers::{load_keypoint_connections, process_radius_slice}, }; use super::{ diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/utilities/entity_iterator.rs b/crates/viewer/re_space_view_spatial/src/visualizers/utilities/entity_iterator.rs index fd71c14e1636..f0b7e04fc351 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/utilities/entity_iterator.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/utilities/entity_iterator.rs @@ -1,16 +1,12 @@ -use itertools::Either; - use re_log_types::{TimeInt, Timeline}; -use re_space_view::{DataResultQuery as _, HybridResults}; +use re_space_view::{AnnotationSceneContext, DataResultQuery as _, HybridResults}; use re_types::Archetype; use re_viewer_context::{ IdentifiedViewSystem, QueryContext, SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery, }; -use crate::contexts::{ - AnnotationSceneContext, EntityDepthOffsets, SpatialSceneEntityContext, TransformContext, -}; +use crate::contexts::{EntityDepthOffsets, SpatialSceneEntityContext, TransformContext}; // --- @@ -23,23 +19,6 @@ pub fn clamped_or<'a, T>(values: &'a [T], if_empty: &'a T) -> impl Iterator(values: &[T], clamped_len: usize) -> impl Iterator + Clone { - let Some(last) = values.last() else { - return Either::Left(std::iter::empty()); - }; - - Either::Right( - values - .iter() - .chain(std::iter::repeat(last)) - .take(clamped_len), - ) -} - /// Clamp the last value in `values` in order to reach a length of `clamped_len`. /// /// Returns an empty vctor if values is empty. diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/utilities/proc_mesh_vis.rs b/crates/viewer/re_space_view_spatial/src/visualizers/utilities/proc_mesh_vis.rs index 0f4a57402d3e..62c500151d09 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/utilities/proc_mesh_vis.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/utilities/proc_mesh_vis.rs @@ -2,6 +2,7 @@ use re_entity_db::InstancePathHash; use re_log_types::Instance; use re_renderer::renderer::{GpuMeshInstance, LineStripFlags}; use re_renderer::{LineDrawableBuilder, PickingLayerInstanceId, RenderContext}; +use re_space_view::{clamped_or_nothing, process_annotation_slices, process_color_slice}; use re_types::components::{self, FillMode}; use re_viewer_context::{ QueryContext, SpaceViewSystemExecutionError, TypedComponentFallbackProvider, ViewQuery, @@ -10,10 +11,7 @@ use re_viewer_context::{ use crate::contexts::SpatialSceneEntityContext; use crate::proc_mesh::{self, ProcMeshKey}; use crate::visualizers::{ - process_annotation_and_keypoint_slices, process_color_slice, process_labels_3d, - process_radius_slice, - utilities::{entity_iterator::clamped_or_nothing, LabeledBatch}, - SpatialViewVisualizerData, + process_labels_3d, process_radius_slice, utilities::LabeledBatch, SpatialViewVisualizerData, }; #[cfg(doc)] @@ -58,7 +56,6 @@ pub struct ProcMeshBatch<'a, IMesh, IFill> { pub colors: &'a [components::Color], pub labels: &'a [re_types::ArrowString], pub show_labels: Option, - pub keypoint_ids: &'a [components::KeypointId], pub class_ids: &'a [components::ClassId], } @@ -112,11 +109,9 @@ where .max(ent_context.transform_info.reference_from_instances.len()); let half_sizes = clamped_or_nothing(batch.half_sizes, num_instances); - let (annotation_infos, _) = process_annotation_and_keypoint_slices( + let annotation_infos = process_annotation_slices( self.query.latest_at, num_instances, - std::iter::repeat(glam::Vec3::ZERO).take(num_instances), - batch.keypoint_ids, batch.class_ids, &ent_context.annotations, ); diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 374d996ab1cd..3b4ac9c58512 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -1295,7 +1295,11 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { is_required : false, }, ArchetypeFieldReflection { component_name : "rerun.components.Color".into(), display_name : "Colors", docstring_md : "Optional colors for the points.", is_required : - false, }, + false, }, ArchetypeFieldReflection { component_name : + "rerun.components.ClassId".into(), display_name : "Class ids", + docstring_md : + "Optional class Ids for the points.\n\nThe [`components.ClassId`](https://rerun.io/docs/reference/types/components/class_id) provides colors if not specified explicitly.", + is_required : false, }, ], }, ), diff --git a/docs/content/reference/types/archetypes/geo_points.md b/docs/content/reference/types/archetypes/geo_points.md index 1d83565979fc..990934a6a296 100644 --- a/docs/content/reference/types/archetypes/geo_points.md +++ b/docs/content/reference/types/archetypes/geo_points.md @@ -13,6 +13,8 @@ Geospatial points with positions expressed in [EPSG:4326](https://epsg.io/4326) **Recommended**: [`Radius`](../components/radius.md), [`Color`](../components/color.md) +**Optional**: [`ClassId`](../components/class_id.md) + ## Shown in * [MapView](../views/map_view.md) * [DataframeView](../views/dataframe_view.md) diff --git a/docs/content/reference/types/components/class_id.md b/docs/content/reference/types/components/class_id.md index a4bb3669ddd6..952fe87a578d 100644 --- a/docs/content/reference/types/components/class_id.md +++ b/docs/content/reference/types/components/class_id.md @@ -28,6 +28,7 @@ uint16 * [`Boxes3D`](../archetypes/boxes3d.md) * [`Capsules3D`](../archetypes/capsules3d.md?speculative-link) * [`Ellipsoids3D`](../archetypes/ellipsoids3d.md) +* [`GeoPoints`](../archetypes/geo_points.md?speculative-link) * [`LineStrips2D`](../archetypes/line_strips2d.md) * [`LineStrips3D`](../archetypes/line_strips3d.md) * [`Mesh3D`](../archetypes/mesh3d.md) diff --git a/rerun_cpp/src/rerun/archetypes/geo_points.cpp b/rerun_cpp/src/rerun/archetypes/geo_points.cpp index dfd990f5e8a8..a1615bed11b0 100644 --- a/rerun_cpp/src/rerun/archetypes/geo_points.cpp +++ b/rerun_cpp/src/rerun/archetypes/geo_points.cpp @@ -14,7 +14,7 @@ namespace rerun { ) { using namespace archetypes; std::vector cells; - cells.reserve(4); + cells.reserve(5); { auto result = ComponentBatch::from_loggable(archetype.positions); @@ -31,6 +31,11 @@ namespace rerun { RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } + if (archetype.class_ids.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.class_ids.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } { auto indicator = GeoPoints::IndicatorComponent(); auto result = ComponentBatch::from_loggable(indicator); diff --git a/rerun_cpp/src/rerun/archetypes/geo_points.hpp b/rerun_cpp/src/rerun/archetypes/geo_points.hpp index 2246b45c2eb4..6bd0ca7d38bb 100644 --- a/rerun_cpp/src/rerun/archetypes/geo_points.hpp +++ b/rerun_cpp/src/rerun/archetypes/geo_points.hpp @@ -6,6 +6,7 @@ #include "../collection.hpp" #include "../compiler_utils.hpp" #include "../component_batch.hpp" +#include "../components/class_id.hpp" #include "../components/color.hpp" #include "../components/lat_lon.hpp" #include "../components/radius.hpp" @@ -54,6 +55,11 @@ namespace rerun::archetypes { /// Optional colors for the points. std::optional> colors; + /// Optional class Ids for the points. + /// + /// The `components::ClassId` provides colors if not specified explicitly. + std::optional> class_ids; + public: static constexpr const char IndicatorComponentName[] = "rerun.components.GeoPointsIndicator"; @@ -93,6 +99,15 @@ namespace rerun::archetypes { // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } + + /// Optional class Ids for the points. + /// + /// The `components::ClassId` provides colors if not specified explicitly. + GeoPoints with_class_ids(Collection _class_ids) && { + class_ids = std::move(_class_ids); + // 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_py/rerun_sdk/rerun/archetypes/geo_points.py b/rerun_py/rerun_sdk/rerun/archetypes/geo_points.py index 92aa58553d59..b7f3e6f5e8e9 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/geo_points.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/geo_points.py @@ -60,6 +60,7 @@ def __attrs_clear__(self) -> None: positions=None, # type: ignore[arg-type] radii=None, # type: ignore[arg-type] colors=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] ) @classmethod @@ -100,5 +101,16 @@ def _clear(cls) -> GeoPoints: # # (Docstring intentionally commented out to hide this field from the docs) + class_ids: components.ClassIdBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=components.ClassIdBatch._optional, # type: ignore[misc] + ) + # Optional class Ids for the points. + # + # The [`components.ClassId`][rerun.components.ClassId] provides colors if not specified explicitly. + # + # (Docstring intentionally commented out to hide this field from the docs) + __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ # type: ignore[assignment]