1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
//! Provides a basic abstraction over a graph that was logged to an entity.
// For now this is pretty basic, but in the future we might replace this with
// something like `petgraph`, which will unlock more user interactions, such as
// highlighting of neighboring nodes and edges.
mod hash;
use egui::{Pos2, Vec2};
pub(crate) use hash::GraphNodeHash;
mod ids;
pub(crate) use ids::{EdgeId, NodeId};
use re_chunk::EntityPath;
use re_types::components::{self, GraphType};
use crate::{
layout::EdgeTemplate,
ui::DrawableLabel,
visualizers::{EdgeData, NodeData, NodeInstance},
};
/// Describes the different kind of nodes that we can have in a graph.
pub enum Node {
/// An explicit node is a node that was provided via [`re_types::archetypes::GraphNodes`].
///
/// It therefore has an instance, as well as all properties that can be added via that archetype.
Explicit {
instance: NodeInstance,
label: DrawableLabel,
},
/// An implicit node is a node that was provided via [`re_types::archetypes::GraphEdges`], but does not have a corresponding [`re_types::components::GraphNode`] in an [`re_types::archetypes::GraphNodes`] archetype.
///
/// Because it was never specified directly, it also does not have many of the properties that an [`Node::Explicit`] has.
Implicit {
id: NodeId,
graph_node: components::GraphNode,
label: DrawableLabel,
},
}
impl Node {
pub fn id(&self) -> NodeId {
match self {
Self::Explicit { instance, .. } => instance.id,
Self::Implicit { id, .. } => *id,
}
}
/// The original [`components::GraphNode`] id that was logged by the user.
pub fn graph_node(&self) -> &components::GraphNode {
match self {
Self::Explicit { instance, .. } => &instance.graph_node,
Self::Implicit { graph_node, .. } => graph_node,
}
}
pub fn label(&self) -> &DrawableLabel {
match self {
Self::Explicit { label, .. } | Self::Implicit { label, .. } => label,
}
}
pub fn size(&self) -> Vec2 {
self.label().size()
}
pub fn position(&self) -> Option<Pos2> {
match self {
Self::Explicit {
instance: NodeInstance { position, .. },
..
} => *position,
Self::Implicit { .. } => None,
}
}
}
pub struct Graph {
entity: EntityPath,
nodes: Vec<Node>,
edges: Vec<EdgeTemplate>,
kind: GraphType,
}
impl Graph {
pub fn new<'a>(
ui: &egui::Ui,
entity: EntityPath,
node_data: Option<&'a NodeData>,
edge_data: Option<&'a EdgeData>,
) -> Self {
// We keep track of the nodes to find implicit nodes.
let mut seen = ahash::HashSet::default();
let mut nodes: Vec<Node> = if let Some(data) = node_data {
seen.extend(data.nodes.iter().map(|n| n.id));
// TODO(grtlr): We should see if we can get rid of some of the cloning here.
data.nodes
.iter()
.map(|n| Node::Explicit {
instance: n.clone(),
label: DrawableLabel::from_label(ui, &n.label),
})
.collect()
} else {
Vec::new()
};
let (edges, kind) = if let Some(data) = edge_data {
for edge in &data.edges {
if !seen.contains(&edge.source_index) {
nodes.push(Node::Implicit {
id: edge.source_index,
graph_node: edge.source.clone(),
label: DrawableLabel::implicit_circle(ui),
});
seen.insert(edge.source_index);
}
if !seen.contains(&edge.target_index) {
nodes.push(Node::Implicit {
id: edge.target_index,
graph_node: edge.target.clone(),
label: DrawableLabel::implicit_circle(ui),
});
seen.insert(edge.target_index);
}
}
let es = data.edges.iter().map(|e| EdgeTemplate {
source: e.source_index,
target: e.target_index,
target_arrow: data.graph_type == GraphType::Directed,
});
(es.collect(), data.graph_type)
} else {
(Vec::new(), GraphType::default())
};
Self {
entity,
nodes,
edges,
kind,
}
}
pub fn nodes(&self) -> &[Node] {
&self.nodes
}
pub fn edges(&self) -> &[EdgeTemplate] {
&self.edges
}
pub fn kind(&self) -> GraphType {
self.kind
}
pub fn entity(&self) -> &EntityPath {
&self.entity
}
}