use ahash::HashSet;
use re_chunk_store::{LatestAtQuery, MissingChunkReporter};
use re_entity_db::EntityDb;
use re_log_types::{EntityPath, TimeInt};
use re_sdk_types::components::TransformFrameId;
use crate::TransformFrameIdHash;
use crate::frame_id_registry::FrameIdRegistry;
use super::cached_transforms_for_timeline::CachedTransformsForTimeline;
use super::parent_from_child_transform::ParentFromChildTransform;
use super::resolved_pinhole_projection::ResolvedPinholeProjection;
use super::tree_transforms_for_child_frame::TreeTransformsForChildFrame;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum EdgeFilter {
#[default]
All,
Static,
Temporal,
}
impl EdgeFilter {
#[inline]
pub fn includes(self, time: TimeInt) -> bool {
match self {
Self::All => true,
Self::Static => time.is_static(),
Self::Temporal => !time.is_static(),
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum FrameFilter {
#[default]
All,
EntityPath,
Named,
}
impl FrameFilter {
#[inline]
pub fn includes(self, kind: FrameKind) -> bool {
match self {
Self::All => true,
Self::EntityPath => kind == FrameKind::EntityPath,
Self::Named => kind == FrameKind::Named,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct SnapshotFilter {
pub frames: FrameFilter,
pub edges: EdgeFilter,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FrameKind {
EntityPath,
Named,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SubspaceKind {
TwoD,
ThreeD,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Frame {
pub id: TransformFrameIdHash,
pub label: TransformFrameId,
pub kind: FrameKind,
pub subspace_kind: SubspaceKind,
pub has_transform: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub enum EdgeSource {
ImplicitHierarchy,
Transform {
entity_path: EntityPath,
transform: ParentFromChildTransform,
},
Pinhole {
entity_path: EntityPath,
pinhole: ResolvedPinholeProjection,
},
}
#[derive(Clone, Debug, PartialEq)]
pub struct Edge {
pub parent: TransformFrameIdHash,
pub child: TransformFrameIdHash,
pub time: TimeInt,
pub source: EdgeSource,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Snapshot {
pub frames: Vec<Frame>,
pub edges: Vec<Edge>,
}
pub fn latest_at(
transforms: &CachedTransformsForTimeline,
frame_id_registry: &FrameIdRegistry,
entity_db: &EntityDb,
missing_chunk_reporter: &MissingChunkReporter,
query: &LatestAtQuery,
filter: SnapshotFilter,
) -> Snapshot {
let logged_edges =
latest_at_logged_transform_edges(transforms, entity_db, missing_chunk_reporter, query);
let children_with_logged_transforms = logged_edges
.iter()
.map(|edge| edge.child)
.collect::<HashSet<_>>();
let mut two_d_frames = HashSet::default();
let mut frames_with_transforms = HashSet::default();
let mut edges = Vec::new();
for edge in logged_edges {
frames_with_transforms.insert(edge.parent);
frames_with_transforms.insert(edge.child);
if matches!(edge.source, EdgeSource::Pinhole { .. }) {
two_d_frames.insert(edge.child);
}
if filter.edges.includes(edge.time) {
edges.push(edge);
}
}
for (parent, child) in frame_id_registry.iter_entity_path_hierarchy_edges() {
if children_with_logged_transforms.contains(&child) {
continue;
}
frames_with_transforms.insert(parent);
frames_with_transforms.insert(child);
if filter.edges.includes(TimeInt::STATIC) {
edges.push(Edge {
parent,
child,
time: TimeInt::STATIC,
source: EdgeSource::ImplicitHierarchy,
});
}
}
let mut returned_frames = HashSet::default();
let frames = frame_id_registry
.iter_frame_ids()
.filter_map(|(id, label)| {
let kind = if label.as_entity_path().is_some() {
FrameKind::EntityPath
} else {
FrameKind::Named
};
if !filter.frames.includes(kind) {
return None;
}
returned_frames.insert(*id);
Some(Frame {
id: *id,
label: label.clone(),
kind,
subspace_kind: if two_d_frames.contains(id) {
SubspaceKind::TwoD
} else {
SubspaceKind::ThreeD
},
has_transform: frames_with_transforms.contains(id),
})
})
.collect::<Vec<_>>();
edges.retain(|edge| {
returned_frames.contains(&edge.parent) && returned_frames.contains(&edge.child)
});
Snapshot { frames, edges }
}
fn latest_at_logged_transform_edges(
transforms: &CachedTransformsForTimeline,
entity_db: &EntityDb,
missing_chunk_reporter: &MissingChunkReporter,
query: &LatestAtQuery,
) -> Vec<Edge> {
let mut child_transforms = transforms
.per_child_frame_transforms
.iter()
.collect::<Vec<_>>();
child_transforms.sort_unstable_by_key(|(child, _)| **child);
child_transforms
.into_iter()
.flat_map(|(_, transforms)| {
[
latest_at_transform_edge(transforms, entity_db, missing_chunk_reporter, query),
latest_at_pinhole_edge(transforms, entity_db, missing_chunk_reporter, query),
]
.into_iter()
.flatten()
})
.collect()
}
fn latest_at_transform_edge(
transforms: &TreeTransformsForChildFrame,
entity_db: &EntityDb,
missing_chunk_reporter: &MissingChunkReporter,
query: &LatestAtQuery,
) -> Option<Edge> {
let (time, transform) =
transforms.latest_at_transform_with_metadata(entity_db, missing_chunk_reporter, query)?;
Some(Edge {
parent: transform.parent,
child: transforms.child_frame,
time,
source: EdgeSource::Transform {
entity_path: transforms.associated_entity_path(time).clone(),
transform,
},
})
}
fn latest_at_pinhole_edge(
transforms: &TreeTransformsForChildFrame,
entity_db: &EntityDb,
missing_chunk_reporter: &MissingChunkReporter,
query: &LatestAtQuery,
) -> Option<Edge> {
let (time, pinhole) =
transforms.latest_at_pinhole_with_metadata(entity_db, missing_chunk_reporter, query)?;
Some(Edge {
parent: pinhole.parent,
child: transforms.child_frame,
time,
source: EdgeSource::Pinhole {
entity_path: transforms.associated_entity_path(time).clone(),
pinhole,
},
})
}