diff --git a/crates/re_space_view_spatial/src/visualizers/boxes2d.rs b/crates/re_space_view_spatial/src/visualizers/boxes2d.rs index 33b31ae53c8b..24296e5f725d 100644 --- a/crates/re_space_view_spatial/src/visualizers/boxes2d.rs +++ b/crates/re_space_view_spatial/src/visualizers/boxes2d.rs @@ -1,5 +1,6 @@ use re_entity_db::{EntityPath, InstancePathHash}; -use re_renderer::LineDrawableBuilder; +use re_query_cache2::{range_zip_1x6, CachedResults}; +use re_renderer::{LineDrawableBuilder, PickingLayerInstanceId}; use re_types::{ archetypes::Boxes2D, components::{ClassId, Color, HalfSizes2D, InstanceKey, KeypointId, Position2D, Radius, Text}, @@ -17,11 +18,13 @@ use crate::{ }; use super::{ - filter_visualizable_2d_entities, picking_id_from_instance_key, + entity_iterator::clamped, filter_visualizable_2d_entities, process_annotation_and_keypoint_slices, process_color_slice, process_radius_slice, SpatialViewVisualizerData, SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES, }; +// --- + pub struct Boxes2DVisualizer { /// If the number of points in the batch is > max_labels, don't render box labels. pub max_labels: usize, @@ -37,155 +40,143 @@ impl Default for Boxes2DVisualizer { } } +// NOTE: Do not put profile scopes in these methods. They are called for all entities and all +// timestamps within a time range -- it's _a lot_. impl Boxes2DVisualizer { fn process_labels<'a>( - labels: &'a [Option], + entity_path: &'a EntityPath, half_sizes: &'a [HalfSizes2D], - centers: impl Iterator + 'a, - instance_path_hashes: &'a [InstancePathHash], + centers: impl Iterator + 'a, + labels: &'a [Text], colors: &'a [egui::Color32], annotation_infos: &'a ResolvedAnnotationInfos, ) -> impl Iterator + 'a { - itertools::izip!( - annotation_infos.iter(), - half_sizes, - centers, - labels, - colors, - instance_path_hashes, - ) - .filter_map( - move |(annotation_info, half_size, center, label, color, labeled_instance)| { - let label = annotation_info.label(label.as_ref().map(|l| l.as_str())); - let min = half_size.box_min(center); - let max = half_size.box_max(center); - label.map(|label| UiLabel { - text: label, - color: *color, - target: UiLabelTarget::Rect(egui::Rect::from_min_max( - egui::pos2(min.x, min.y), - egui::pos2(max.x, max.y), - )), - labeled_instance: *labeled_instance, - }) - }, - ) + let labels = clamped(labels, half_sizes.len()); + let centers = centers.chain(std::iter::repeat(&Position2D::ZERO)); + itertools::izip!(annotation_infos.iter(), half_sizes, centers, labels, colors) + .enumerate() + .filter_map( + move |(i, (annotation_info, half_size, center, label, color))| { + let label = annotation_info.label(Some(label.as_str())); + match (half_size, label) { + (half_size, Some(label)) => { + let min = half_size.box_min(*center); + let max = half_size.box_max(*center); + Some(UiLabel { + text: label, + color: *color, + target: UiLabelTarget::Rect(egui::Rect::from_min_max( + egui::pos2(min.x, min.y), + egui::pos2(max.x, max.y), + )), + labeled_instance: InstancePathHash::instance( + entity_path, + InstanceKey(i as _), + ), + }) + } + _ => None, + } + }, + ) } - fn process_data( + fn process_data<'a>( &mut self, line_builder: &mut LineDrawableBuilder<'_>, - query: &ViewQuery<'_>, - data: &Boxes2DComponentData<'_>, - ent_path: &EntityPath, + view_query: &ViewQuery<'_>, + entity_path: &EntityPath, ent_context: &SpatialSceneEntityContext<'_>, + data: impl Iterator>, ) { - let (annotation_infos, _) = process_annotation_and_keypoint_slices( - query.latest_at, - data.instance_keys, - data.keypoint_ids, - data.class_ids, - data.half_sizes.iter().map(|_| glam::Vec3::ZERO), - &ent_context.annotations, - ); - - let centers = || { - data.centers - .as_ref() - .map_or( - itertools::Either::Left(std::iter::repeat(&None).take(data.half_sizes.len())), - |data| itertools::Either::Right(data.iter()), - ) - .map(|center| center.unwrap_or(Position2D::ZERO)) - }; - - let radii = process_radius_slice(data.radii, data.half_sizes.len(), ent_path); - let colors = process_color_slice(data.colors, ent_path, &annotation_infos); - - if data.instance_keys.len() <= self.max_labels { - re_tracing::profile_scope!("labels"); - - // Max labels is small enough that we can afford iterating on the colors again. - let colors = process_color_slice(data.colors, ent_path, &annotation_infos); - - let instance_path_hashes_for_picking = { - re_tracing::profile_scope!("instance_hashes"); - data.instance_keys - .iter() - .copied() - .map(|instance_key| InstancePathHash::instance(ent_path, instance_key)) - .collect::>() - }; - - if let Some(labels) = data.labels { + for data in data { + let num_instances = data.half_sizes.len(); + if num_instances == 0 { + continue; + } + + let (annotation_infos, _) = process_annotation_and_keypoint_slices( + view_query.latest_at, + num_instances, + data.half_sizes.iter().map(|_| glam::Vec3::ZERO), + data.keypoint_ids, + data.class_ids, + &ent_context.annotations, + ); + + let radii = process_radius_slice(entity_path, num_instances, data.radii); + let colors = + process_color_slice(entity_path, num_instances, &annotation_infos, data.colors); + + if num_instances <= self.max_labels { + let centers = clamped(data.centers, num_instances); self.data.ui_labels.extend(Self::process_labels( - labels, + entity_path, data.half_sizes, - centers(), - &instance_path_hashes_for_picking, + centers, + data.labels, &colors, &annotation_infos, )); } - } - let mut line_batch = line_builder - .batch("boxes2d") - .depth_offset(ent_context.depth_offset) - .world_from_obj(ent_context.world_from_entity) - .outline_mask_ids(ent_context.highlight.overall) - .picking_object_id(re_renderer::PickingLayerObjectId(ent_path.hash64())); - - let mut bounding_box = macaw::BoundingBox::nothing(); - - for (instance_key, half_size, center, radius, color) in itertools::izip!( - data.instance_keys, - data.half_sizes, - centers(), - radii, - colors - ) { - let instance_hash = re_entity_db::InstancePathHash::instance(ent_path, *instance_key); - - let min = half_size.box_min(center); - let max = half_size.box_max(center); - bounding_box.extend(min.extend(0.0)); - bounding_box.extend(max.extend(0.0)); - - let rectangle = line_batch - .add_rectangle_outline_2d( - min, - glam::vec2(half_size.width(), 0.0), - glam::vec2(0.0, half_size.height()), - ) - .color(color) - .radius(radius) - .picking_instance_id(picking_id_from_instance_key(*instance_key)); - if let Some(outline_mask_ids) = ent_context - .highlight - .instances - .get(&instance_hash.instance_key) + let mut line_batch = line_builder + .batch("boxes2d") + .depth_offset(ent_context.depth_offset) + .world_from_obj(ent_context.world_from_entity) + .outline_mask_ids(ent_context.highlight.overall) + .picking_object_id(re_renderer::PickingLayerObjectId(entity_path.hash64())); + + let mut bounding_box = macaw::BoundingBox::nothing(); + + let centers = + clamped(data.centers, num_instances).chain(std::iter::repeat(&Position2D::ZERO)); + for (i, (half_size, center, radius, color)) in + itertools::izip!(data.half_sizes, centers, radii, colors).enumerate() { - rectangle.outline_mask_ids(*outline_mask_ids); + let min = half_size.box_min(*center); + let max = half_size.box_max(*center); + bounding_box.extend(min.extend(0.0)); + bounding_box.extend(max.extend(0.0)); + + let rectangle = line_batch + .add_rectangle_outline_2d( + min, + glam::vec2(half_size.width(), 0.0), + glam::vec2(0.0, half_size.height()), + ) + .color(color) + .radius(radius) + .picking_instance_id(PickingLayerInstanceId(i as _)); + if let Some(outline_mask_ids) = + ent_context.highlight.instances.get(&InstanceKey(i as _)) + { + rectangle.outline_mask_ids(*outline_mask_ids); + } } - } - self.data - .add_bounding_box(ent_path.hash(), bounding_box, ent_context.world_from_entity); + self.data.add_bounding_box( + entity_path.hash(), + bounding_box, + ent_context.world_from_entity, + ); + } } } // --- struct Boxes2DComponentData<'a> { - pub instance_keys: &'a [InstanceKey], - pub half_sizes: &'a [HalfSizes2D], - pub centers: Option<&'a [Option]>, - pub colors: Option<&'a [Option]>, - pub radii: Option<&'a [Option]>, - pub labels: Option<&'a [Option]>, - pub keypoint_ids: Option<&'a [Option]>, - pub class_ids: Option<&'a [Option]>, + // Point of views + half_sizes: &'a [HalfSizes2D], + + // Clamped to edge + centers: &'a [Position2D], + colors: &'a [Color], + radii: &'a [Radius], + labels: &'a [Text], + keypoint_ids: &'a [KeypointId], + class_ids: &'a [ClassId], } impl IdentifiedViewSystem for Boxes2DVisualizer { @@ -211,66 +202,136 @@ impl VisualizerSystem for Boxes2DVisualizer { fn execute( &mut self, ctx: &ViewerContext<'_>, - query: &ViewQuery<'_>, + view_query: &ViewQuery<'_>, view_ctx: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let num_boxes = super::entity_iterator::count_instances_in_archetype_views::< - Boxes2DVisualizer, - Boxes2D, - 9, - >(ctx, query); - - if num_boxes == 0 { - return Ok(Vec::new()); - } - let mut line_builder = LineDrawableBuilder::new(ctx.render_ctx); line_builder.radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES); - // Each box consists of 4 independent lines of 2 vertices each. - line_builder.reserve_strips(num_boxes * 4)?; - line_builder.reserve_vertices(num_boxes * 4 * 2)?; - - super::entity_iterator::process_archetype_pov1_comp6::< - Boxes2DVisualizer, - Boxes2D, - HalfSizes2D, - Position2D, - Color, - Radius, - Text, - re_types::components::KeypointId, - re_types::components::ClassId, - _, - >( + super::entity_iterator::process_archetype::( ctx, - query, + view_query, view_ctx, view_ctx.get::()?.points, - |_ctx, - ent_path, - _ent_props, - ent_context, - (_time, _row_id), - instance_keys, - half_sizes, - centers, - colors, - radii, - labels, - keypoint_ids, - class_ids| { - let data = Boxes2DComponentData { - instance_keys, - half_sizes, - centers, - colors, - radii, - labels, - keypoint_ids, - class_ids, - }; - self.process_data(&mut line_builder, query, &data, ent_path, ent_context); + |ctx, entity_path, _entity_props, spatial_ctx, results| { + match results { + CachedResults::LatestAt(_query, results) => { + re_tracing::profile_scope!(format!("{entity_path} @ {_query:?}")); + + use crate::visualizers::CachedLatestAtResultsExt as _; + + let resolver = ctx.recording().resolver(); + + let half_sizes = match results.get_dense::(resolver) { + Some(Ok(vectors)) if !vectors.is_empty() => vectors, + Some(err @ Err(_)) => err?, + _ => return Ok(()), + }; + + // Each box consists of 4 independent lines of 2 vertices each. + line_builder.reserve_strips(half_sizes.len() * 4)?; + line_builder.reserve_vertices(half_sizes.len() * 4 * 2)?; + + let centers = results.get_or_empty_dense(resolver)?; + let colors = results.get_or_empty_dense(resolver)?; + let radii = results.get_or_empty_dense(resolver)?; + let labels = results.get_or_empty_dense(resolver)?; + let class_ids = results.get_or_empty_dense(resolver)?; + let keypoint_ids = results.get_or_empty_dense(resolver)?; + + let data = Boxes2DComponentData { + half_sizes, + centers, + colors, + radii, + labels, + keypoint_ids, + class_ids, + }; + + self.process_data( + &mut line_builder, + view_query, + entity_path, + spatial_ctx, + std::iter::once(data), + ); + } + + CachedResults::Range(_query, results) => { + re_tracing::profile_scope!(format!("{entity_path} @ {_query:?}")); + + use crate::visualizers::CachedRangeResultsExt as _; + + let resolver = ctx.recording().resolver(); + + let half_sizes = match results.get_dense::(resolver, _query) { + Some(Ok(vectors)) => vectors, + Some(err @ Err(_)) => err?, + _ => return Ok(()), + }; + + let num_boxes = half_sizes + .range_indexed(_query.range()) + .map(|(_, vectors)| vectors.len()) + .sum::(); + if num_boxes == 0 { + return Ok(()); + } + + // Each box consists of 4 independent lines of 2 vertices each. + line_builder.reserve_strips(num_boxes * 4)?; + line_builder.reserve_vertices(num_boxes * 4 * 2)?; + + let centers = results.get_or_empty_dense(resolver, _query)?; + let colors = results.get_or_empty_dense(resolver, _query)?; + let radii = results.get_or_empty_dense(resolver, _query)?; + let labels = results.get_or_empty_dense(resolver, _query)?; + let class_ids = results.get_or_empty_dense(resolver, _query)?; + let keypoint_ids = results.get_or_empty_dense(resolver, _query)?; + + let data = range_zip_1x6( + half_sizes.range_indexed(_query.range()), + centers.range_indexed(_query.range()), + colors.range_indexed(_query.range()), + radii.range_indexed(_query.range()), + labels.range_indexed(_query.range()), + class_ids.range_indexed(_query.range()), + keypoint_ids.range_indexed(_query.range()), + ) + .map( + |( + _index, + half_sizes, + centers, + colors, + radii, + labels, + class_ids, + keypoint_ids, + )| { + Boxes2DComponentData { + half_sizes, + centers: centers.unwrap_or_default(), + colors: colors.unwrap_or_default(), + radii: radii.unwrap_or_default(), + labels: labels.unwrap_or_default(), + class_ids: class_ids.unwrap_or_default(), + keypoint_ids: keypoint_ids.unwrap_or_default(), + } + }, + ); + + self.process_data( + &mut line_builder, + view_query, + entity_path, + spatial_ctx, + data, + ); + } + } + Ok(()) }, )?; diff --git a/crates/re_space_view_spatial/src/visualizers/boxes3d.rs b/crates/re_space_view_spatial/src/visualizers/boxes3d.rs index 1a5928331216..9b07651d3e0d 100644 --- a/crates/re_space_view_spatial/src/visualizers/boxes3d.rs +++ b/crates/re_space_view_spatial/src/visualizers/boxes3d.rs @@ -1,5 +1,6 @@ -use re_entity_db::EntityPath; -use re_renderer::LineDrawableBuilder; +use re_entity_db::{EntityPath, InstancePathHash}; +use re_query_cache2::{range_zip_1x7, CachedResults}; +use re_renderer::{LineDrawableBuilder, PickingLayerInstanceId}; use re_types::{ archetypes::Boxes3D, components::{ @@ -7,9 +8,9 @@ use re_types::{ }, }; use re_viewer_context::{ - ApplicableEntities, IdentifiedViewSystem, SpaceViewSystemExecutionError, ViewContextCollection, - ViewQuery, ViewerContext, VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, - VisualizerSystem, + ApplicableEntities, IdentifiedViewSystem, ResolvedAnnotationInfos, + SpaceViewSystemExecutionError, ViewContextCollection, ViewQuery, ViewerContext, + VisualizableEntities, VisualizableFilterContext, VisualizerQueryInfo, VisualizerSystem, }; use crate::{ @@ -19,11 +20,13 @@ use crate::{ }; use super::{ - filter_visualizable_3d_entities, picking_id_from_instance_key, - process_annotation_and_keypoint_slices, process_color_slice, process_label_slice, - process_radius_slice, SpatialViewVisualizerData, SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES, + entity_iterator::clamped, filter_visualizable_3d_entities, + process_annotation_and_keypoint_slices, process_color_slice, process_radius_slice, + SpatialViewVisualizerData, SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES, }; +// --- + pub struct Boxes3DVisualizer(SpatialViewVisualizerData); impl Default for Boxes3DVisualizer { @@ -34,118 +37,136 @@ impl Default for Boxes3DVisualizer { } } +// NOTE: Do not put profile scopes in these methods. They are called for all entities and all +// timestamps within a time range -- it's _a lot_. impl Boxes3DVisualizer { - fn process_data( + fn process_labels<'a>( + entity_path: &'a EntityPath, + half_sizes: &'a [HalfSizes3D], + centers: impl Iterator + 'a, + labels: &'a [Text], + colors: &'a [egui::Color32], + annotation_infos: &'a ResolvedAnnotationInfos, + world_from_entity: glam::Affine3A, + ) -> impl Iterator + 'a { + let labels = clamped(labels, half_sizes.len()); + let centers = centers.chain(std::iter::repeat(&Position3D::ZERO)); + itertools::izip!(annotation_infos.iter(), centers, labels, colors) + .enumerate() + .filter_map(move |(i, (annotation_info, center, label, color))| { + let label = annotation_info.label(Some(label.as_str())); + label.map(|label| UiLabel { + text: label, + color: *color, + target: UiLabelTarget::Position3D( + world_from_entity.transform_point3(center.0.into()), + ), + labeled_instance: InstancePathHash::instance(entity_path, InstanceKey(i as _)), + }) + }) + } + + fn process_data<'a>( &mut self, line_builder: &mut LineDrawableBuilder<'_>, query: &ViewQuery<'_>, - data: &Boxes3DComponentData<'_>, - ent_path: &EntityPath, + entity_path: &EntityPath, ent_context: &SpatialSceneEntityContext<'_>, + data: impl Iterator>, ) { - let (annotation_infos, _) = process_annotation_and_keypoint_slices( - query.latest_at, - data.instance_keys, - data.keypoint_ids, - data.class_ids, - data.half_sizes.iter().map(|_| glam::Vec3::ZERO), - &ent_context.annotations, - ); - - let centers = || { - data.centers - .as_ref() - .map_or( - itertools::Either::Left(std::iter::repeat(&None).take(data.half_sizes.len())), - |data| itertools::Either::Right(data.iter()), - ) - .map(|center| center.unwrap_or(Position3D::ZERO)) - }; - let rotations = || { - data.rotations - .as_ref() - .map_or( - itertools::Either::Left(std::iter::repeat(&None).take(data.half_sizes.len())), - |data| itertools::Either::Right(data.iter()), - ) - .map(|center| center.clone().unwrap_or(Rotation3D::IDENTITY)) - }; - - let radii = process_radius_slice(data.radii, data.half_sizes.len(), ent_path); - let colors = process_color_slice(data.colors, ent_path, &annotation_infos); - let labels = process_label_slice(data.labels, data.half_sizes.len(), &annotation_infos); - - let mut line_batch = line_builder - .batch("boxes3d") - .depth_offset(ent_context.depth_offset) - .world_from_obj(ent_context.world_from_entity) - .outline_mask_ids(ent_context.highlight.overall) - .picking_object_id(re_renderer::PickingLayerObjectId(ent_path.hash64())); - - let mut bounding_box = macaw::BoundingBox::nothing(); - - for (instance_key, half_size, center, rotation, radius, color, label) in itertools::izip!( - data.instance_keys, - data.half_sizes, - centers(), - rotations(), - radii, - colors, - labels, - ) { - let instance_hash = re_entity_db::InstancePathHash::instance(ent_path, *instance_key); - - bounding_box.extend(half_size.box_min(center)); - bounding_box.extend(half_size.box_max(center)); - - let center = center.into(); - - let box3d = line_batch - .add_box_outline_from_transform(glam::Affine3A::from_scale_rotation_translation( - glam::Vec3::from(*half_size) * 2.0, - rotation.into(), - center, - )) - .color(color) - .radius(radius) - .picking_instance_id(picking_id_from_instance_key(*instance_key)); - if let Some(outline_mask_ids) = ent_context - .highlight - .instances - .get(&instance_hash.instance_key) - { - box3d.outline_mask_ids(*outline_mask_ids); + for data in data { + let num_instances = data.half_sizes.len(); + if num_instances == 0 { + continue; } - if let Some(text) = label { - self.0.ui_labels.push(UiLabel { - text, - color, - target: UiLabelTarget::Position3D( - ent_context.world_from_entity.transform_point3(center), - ), - labeled_instance: instance_hash, - }); + let (annotation_infos, _) = process_annotation_and_keypoint_slices( + query.latest_at, + num_instances, + data.half_sizes.iter().map(|_| glam::Vec3::ZERO), + data.keypoint_ids, + data.class_ids, + &ent_context.annotations, + ); + + let radii = process_radius_slice(entity_path, num_instances, data.radii); + let colors = + process_color_slice(entity_path, num_instances, &annotation_infos, data.colors); + + let centers = clamped(data.centers, num_instances); + self.0.ui_labels.extend(Self::process_labels( + entity_path, + data.half_sizes, + centers, + data.labels, + &colors, + &annotation_infos, + ent_context.world_from_entity, + )); + + let mut line_batch = line_builder + .batch("boxes3d") + .depth_offset(ent_context.depth_offset) + .world_from_obj(ent_context.world_from_entity) + .outline_mask_ids(ent_context.highlight.overall) + .picking_object_id(re_renderer::PickingLayerObjectId(entity_path.hash64())); + + let mut bounding_box = macaw::BoundingBox::nothing(); + + let centers = + clamped(data.centers, num_instances).chain(std::iter::repeat(&Position3D::ZERO)); + let rotations = clamped(data.rotations, num_instances) + .chain(std::iter::repeat(&Rotation3D::IDENTITY)); + for (i, (half_size, ¢er, rotation, radius, color)) in + itertools::izip!(data.half_sizes, centers, rotations, radii, colors).enumerate() + { + bounding_box.extend(half_size.box_min(center)); + bounding_box.extend(half_size.box_max(center)); + + let center = center.into(); + + let box3d = line_batch + .add_box_outline_from_transform( + glam::Affine3A::from_scale_rotation_translation( + glam::Vec3::from(*half_size) * 2.0, + rotation.0.into(), + center, + ), + ) + .color(color) + .radius(radius) + .picking_instance_id(PickingLayerInstanceId(i as _)); + + if let Some(outline_mask_ids) = + ent_context.highlight.instances.get(&InstanceKey(i as _)) + { + box3d.outline_mask_ids(*outline_mask_ids); + } } - } - self.0 - .add_bounding_box(ent_path.hash(), bounding_box, ent_context.world_from_entity); + self.0.add_bounding_box( + entity_path.hash(), + bounding_box, + ent_context.world_from_entity, + ); + } } } // --- struct Boxes3DComponentData<'a> { - pub instance_keys: &'a [InstanceKey], - pub half_sizes: &'a [HalfSizes3D], - pub centers: Option<&'a [Option]>, - pub rotations: Option<&'a [Option]>, - pub colors: Option<&'a [Option]>, - pub radii: Option<&'a [Option]>, - pub labels: Option<&'a [Option]>, - pub keypoint_ids: Option<&'a [Option]>, - pub class_ids: Option<&'a [Option]>, + // Point of views + half_sizes: &'a [HalfSizes3D], + + // Clamped to edge + centers: &'a [Position3D], + rotations: &'a [Rotation3D], + colors: &'a [Color], + radii: &'a [Radius], + labels: &'a [Text], + keypoint_ids: &'a [KeypointId], + class_ids: &'a [ClassId], } impl IdentifiedViewSystem for Boxes3DVisualizer { @@ -171,69 +192,142 @@ impl VisualizerSystem for Boxes3DVisualizer { fn execute( &mut self, ctx: &ViewerContext<'_>, - query: &ViewQuery<'_>, + view_query: &ViewQuery<'_>, view_ctx: &ViewContextCollection, ) -> Result, SpaceViewSystemExecutionError> { - let num_boxes = super::entity_iterator::count_instances_in_archetype_views::< - Boxes3DVisualizer, - Boxes3D, - 9, - >(ctx, query); - - if num_boxes == 0 { - return Ok(Vec::new()); - } - let mut line_builder = LineDrawableBuilder::new(ctx.render_ctx); line_builder.radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES); - // Each box consists of 12 independent lines with 2 vertices each. - line_builder.reserve_strips(num_boxes * 12)?; - line_builder.reserve_vertices(num_boxes * 12 * 2)?; - - super::entity_iterator::process_archetype_pov1_comp7::< - Boxes3DVisualizer, - Boxes3D, - HalfSizes3D, - Position3D, - Rotation3D, - Color, - Radius, - Text, - re_types::components::KeypointId, - re_types::components::ClassId, - _, - >( + super::entity_iterator::process_archetype::( ctx, - query, + view_query, view_ctx, view_ctx.get::()?.points, - |_ctx, - ent_path, - _ent_props, - ent_context, - (_time, _row_id), - instance_keys, - half_sizes, - centers, - rotations, - colors, - radii, - labels, - keypoint_ids, - class_ids| { - let data = Boxes3DComponentData { - instance_keys, - half_sizes, - centers, - rotations, - colors, - radii, - labels, - keypoint_ids, - class_ids, - }; - self.process_data(&mut line_builder, query, &data, ent_path, ent_context); + |ctx, entity_path, _entity_props, spatial_ctx, results| { + match results { + CachedResults::LatestAt(_query, results) => { + re_tracing::profile_scope!(format!("{entity_path} @ {_query:?}")); + + use crate::visualizers::CachedLatestAtResultsExt as _; + + let resolver = ctx.recording().resolver(); + + let half_sizes = match results.get_dense::(resolver) { + Some(Ok(vectors)) if !vectors.is_empty() => vectors, + Some(err @ Err(_)) => err?, + _ => return Ok(()), + }; + + // Each box consists of 12 independent lines with 2 vertices each. + line_builder.reserve_strips(half_sizes.len() * 12)?; + line_builder.reserve_vertices(half_sizes.len() * 12 * 2)?; + + let centers = results.get_or_empty_dense(resolver)?; + let rotations = results.get_or_empty_dense(resolver)?; + let colors = results.get_or_empty_dense(resolver)?; + let radii = results.get_or_empty_dense(resolver)?; + let labels = results.get_or_empty_dense(resolver)?; + let class_ids = results.get_or_empty_dense(resolver)?; + let keypoint_ids = results.get_or_empty_dense(resolver)?; + + let data = Boxes3DComponentData { + half_sizes, + centers, + rotations, + colors, + radii, + labels, + keypoint_ids, + class_ids, + }; + + self.process_data( + &mut line_builder, + view_query, + entity_path, + spatial_ctx, + std::iter::once(data), + ); + } + + CachedResults::Range(_query, results) => { + re_tracing::profile_scope!(format!("{entity_path} @ {_query:?}")); + + use crate::visualizers::CachedRangeResultsExt as _; + + let resolver = ctx.recording().resolver(); + + let half_sizes = match results.get_dense::(resolver, _query) { + Some(Ok(vectors)) => vectors, + Some(err @ Err(_)) => err?, + _ => return Ok(()), + }; + + let num_boxes = half_sizes + .range_indexed(_query.range()) + .map(|(_, vectors)| vectors.len()) + .sum::(); + if num_boxes == 0 { + return Ok(()); + } + + // Each box consists of 12 independent lines with 2 vertices each. + line_builder.reserve_strips(num_boxes * 12)?; + line_builder.reserve_vertices(num_boxes * 12 * 2)?; + + let centers = results.get_or_empty_dense(resolver, _query)?; + let rotations = results.get_or_empty_dense(resolver, _query)?; + let colors = results.get_or_empty_dense(resolver, _query)?; + let radii = results.get_or_empty_dense(resolver, _query)?; + let labels = results.get_or_empty_dense(resolver, _query)?; + let class_ids = results.get_or_empty_dense(resolver, _query)?; + let keypoint_ids = results.get_or_empty_dense(resolver, _query)?; + + let data = range_zip_1x7( + half_sizes.range_indexed(_query.range()), + centers.range_indexed(_query.range()), + rotations.range_indexed(_query.range()), + colors.range_indexed(_query.range()), + radii.range_indexed(_query.range()), + labels.range_indexed(_query.range()), + class_ids.range_indexed(_query.range()), + keypoint_ids.range_indexed(_query.range()), + ) + .map( + |( + _index, + half_sizes, + centers, + rotations, + colors, + radii, + labels, + class_ids, + keypoint_ids, + )| { + Boxes3DComponentData { + half_sizes, + centers: centers.unwrap_or_default(), + rotations: rotations.unwrap_or_default(), + colors: colors.unwrap_or_default(), + radii: radii.unwrap_or_default(), + labels: labels.unwrap_or_default(), + class_ids: class_ids.unwrap_or_default(), + keypoint_ids: keypoint_ids.unwrap_or_default(), + } + }, + ); + + self.process_data( + &mut line_builder, + view_query, + entity_path, + spatial_ctx, + data, + ); + } + } + Ok(()) }, )?;