use nohash_hasher::IntSet;
use re_log_types::EntityPath;
use re_sdk_types::ViewClassIdentifier;
use re_viewer_context::{ViewClass as _, ViewerContext};
use crate::{SpatialView2D, SpatialView3D};
pub struct IndicatedVisualizableEntities {
pub indicated_entities: IntSet<EntityPath>,
pub excluded_entities: Vec<EntityPath>,
}
impl IndicatedVisualizableEntities {
pub fn new(
ctx: &ViewerContext<'_>,
view_class_identifier: ViewClassIdentifier,
include_entity: &dyn Fn(&EntityPath) -> bool,
indicate_extra: impl FnOnce(&mut IntSet<EntityPath>),
) -> Self {
let mut indicated_entities = default_visualized_entities_for_visualizer_affinity(
ctx,
view_class_identifier,
include_entity,
);
indicate_extra(&mut indicated_entities);
let excluded_entities = default_excluded_entities_for_visualizer_affinity(
ctx,
view_class_identifier,
&indicated_entities,
);
Self {
indicated_entities,
excluded_entities,
}
}
}
fn default_visualized_entities_for_visualizer_affinity(
ctx: &ViewerContext<'_>,
view_class_identifier: ViewClassIdentifier,
include_entity: &dyn Fn(&EntityPath) -> bool,
) -> IntSet<EntityPath> {
re_tracing::profile_function!();
ctx.view_class_registry()
.new_visualizer_collection(view_class_identifier)
.iter_with_identifiers()
.filter_map(|(id, visualizer)| {
if visualizer.affinity()? == view_class_identifier {
let indicator_matching = ctx.indicated_entities_per_visualizer.get(&id)?;
let visualizable = ctx.visualizable_entities_per_visualizer.get(&id)?;
Some(
indicator_matching
.iter()
.filter(|e| visualizable.contains_key(e)),
)
} else {
None
}
})
.flatten()
.filter(|e| include_entity(e))
.cloned()
.collect()
}
fn opposite_spatial_view(
view_class_identifier: ViewClassIdentifier,
) -> Option<ViewClassIdentifier> {
if view_class_identifier == SpatialView2D::identifier() {
Some(SpatialView3D::identifier())
} else if view_class_identifier == SpatialView3D::identifier() {
Some(SpatialView2D::identifier())
} else {
None
}
}
fn default_excluded_entities_for_visualizer_affinity(
ctx: &ViewerContext<'_>,
view_class_identifier: ViewClassIdentifier,
included_entities: &IntSet<EntityPath>,
) -> Vec<EntityPath> {
let Some(opposite_view) = opposite_spatial_view(view_class_identifier) else {
return Vec::new();
};
let included_ancestors = included_entities
.iter()
.flat_map(|e| {
let mut e = Some(e.clone());
std::iter::from_fn(move || {
let item = e.take();
e = item.as_ref().and_then(|e| e.parent());
item
})
})
.collect::<IntSet<_>>();
ctx.view_class_registry()
.new_visualizer_collection(opposite_view)
.iter_with_identifiers()
.filter_map(|(id, visualizer)| {
if visualizer.affinity()? == view_class_identifier {
None
} else {
let indicator_matching = ctx.indicated_entities_per_visualizer.get(&id)?;
Some(indicator_matching.iter())
}
})
.flatten()
.filter(|e| !included_ancestors.contains(e))
.filter_map(|e| {
let mut highest = None;
let mut current = e.clone();
loop {
let Some(p) = current.parent() else {
if highest.is_none() {
highest = Some(current.clone());
}
break;
};
if included_entities.contains(&p) {
return None;
}
if highest.is_none() && included_ancestors.contains(&p) {
highest = Some(current.clone());
}
current = p.clone();
}
highest
})
.collect()
}