Skip to content

Commit

Permalink
Convert to DrawableNode
Browse files Browse the repository at this point in the history
  • Loading branch information
grtlr committed Nov 27, 2024
1 parent 145a1a4 commit 45a2dc7
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 158 deletions.
10 changes: 6 additions & 4 deletions crates/viewer/re_space_view_graph/src/canvas.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use egui::{
emath::TSTransform, Area, Color32, Id, Order, Pos2, Rect, Response, Sense, Stroke, Ui, UiBuilder, UiKind, Vec2
emath::TSTransform, style::Interaction, Area, Color32, Id, Order, Pos2, Rect, Response, Sense, Stroke, Ui, UiBuilder, UiKind, Vec2
};
use re_viewer_context::InteractionHighlight;

use crate::ui::draw::DrawableNode;
use crate::ui::draw::DrawableLabel;

fn register_pan_and_zoom(ui: &Ui, resp: Response, transform: &mut TSTransform) -> Response {
if resp.dragged() {
Expand Down Expand Up @@ -51,12 +52,13 @@ pub fn draw_node(
ui: &mut Ui,
center: Pos2,
world_to_view: &mut TSTransform,
node: DrawableNode,
node: &DrawableLabel,
highlight: InteractionHighlight,
) -> Response {
let resp = {
let builder = UiBuilder::new().max_rect(Rect::from_center_size(center, node.size()));
let mut node_ui = ui.new_child(builder);
node.draw(&mut node_ui)
node.draw(&mut node_ui, highlight)
};
register_pan_and_zoom(ui, resp, world_to_view)
}
Expand Down
1 change: 1 addition & 0 deletions crates/viewer/re_space_view_graph/src/graph/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use re_types::components;

use super::GraphNodeHash;

// TODO(grtlr): Rename this to `NodeId`.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct NodeIndex {
pub entity_hash: EntityPathHash,
Expand Down
125 changes: 83 additions & 42 deletions crates/viewer/re_space_view_graph/src/graph/mod.rs
Original file line number Diff line number Diff line change
@@ -1,84 +1,125 @@
mod hash;
use egui::Pos2;
pub(crate) use hash::GraphNodeHash;
mod index;
pub(crate) use index::NodeIndex;

use re_types::components::{GraphNode, GraphType};
use re_log_types::Instance;
use re_types::{blueprint::components, components::GraphType, ArrowString};

use crate::visualizers::{EdgeData, EdgeInstance, NodeData, NodeInstance};
use crate::{
ui::draw::DrawableLabel,
visualizers::{EdgeData, EdgeInstance, NodeData, NodeInstance},
};

pub struct NodeInstanceImplicit {
pub node: GraphNode,
pub index: NodeIndex,
pub enum Node {
Explicit {
id: NodeIndex,
instance: Instance,
node: ArrowString,
position: Option<Pos2>,
label: DrawableLabel,
},
Implicit {
id: NodeIndex,
node: ArrowString,
label: DrawableLabel,
},
}

impl std::hash::Hash for NodeInstanceImplicit {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.index.hash(state);
impl Node {
pub fn id(&self) -> NodeIndex {
match self {
Node::Explicit { id, .. } => *id,
Node::Implicit { id, .. } => *id,
}
}

pub fn label(&self) -> &DrawableLabel {
match self {
Node::Explicit { label, .. } => label,
Node::Implicit { label, .. } => label,
}
}
}

#[derive(Hash)]
pub struct Graph<'a> {
explicit: &'a [NodeInstance],
implicit: Vec<NodeInstanceImplicit>,
edges: &'a [EdgeInstance],
pub struct Edge {
pub from: NodeIndex,
pub to: NodeIndex,
marker: bool,
}

pub struct Graph {
nodes: Vec<Node>,
edges: Vec<Edge>,
kind: GraphType,
}

impl<'a> Graph<'a> {
pub fn new(node_data: Option<&'a NodeData>, edge_data: Option<&'a EdgeData>) -> Self {
impl Graph {
pub fn new<'a>(
ui: &egui::Ui,
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 explicit = if let Some(data) = node_data {
let mut nodes: Vec<Node> = if let Some(data) = node_data {
seen.extend(data.nodes.iter().map(|n| n.index));
data.nodes.as_slice()
data.nodes
.iter()
.map(|n| Node::Explicit {
id: n.index,
instance: n.instance,
node: n.node.0 .0.clone(),
position: n.position,
label: DrawableLabel::from_label(ui, &n.label),
})
.collect()
} else {
&[][..]
Vec::new()
};

let (edges, implicit, kind) = if let Some(data) = edge_data {
let mut implicit = Vec::new();
let (edges, kind) = if let Some(data) = edge_data {
for edge in &data.edges {
if !seen.contains(&edge.source_index) {
implicit.push(NodeInstanceImplicit {
node: edge.source.clone(),
index: edge.source_index,
nodes.push(Node::Implicit {
id: edge.source_index,
node: edge.source.0 .0.clone(),
label: DrawableLabel::implicit_circle(),
});
seen.insert(edge.source_index);
}
if !seen.contains(&edge.target_index) {
implicit.push(NodeInstanceImplicit {
node: edge.target.clone(),
index: edge.target_index,
nodes.push(Node::Implicit {
id: edge.target_index,
node: edge.target.0 .0.clone(),
label: DrawableLabel::implicit_circle(),
});
seen.insert(edge.target_index);
}
}
(data.edges.as_slice(), implicit, Some(data.graph_type))

let es = data.edges.iter().map(|e| Edge {
from: e.source_index,
to: e.target_index,
marker: data.graph_type == GraphType::Directed,
});

(es.collect(), data.graph_type)
} else {
(&[][..], Vec::new(), None)
(Vec::new(), GraphType::default())
};

Self {
explicit,
implicit,
edges,
kind: kind.unwrap_or_default(),
}
}

pub fn nodes_explicit(&self) -> impl Iterator<Item = &NodeInstance> {
self.explicit.iter()
Self { nodes, edges, kind }
}

pub fn nodes_implicit(&self) -> impl Iterator<Item = &NodeInstanceImplicit> + '_ {
self.implicit.iter()
pub fn nodes(&self) -> &[Node] {
&self.nodes
}

pub fn edges(&self) -> impl Iterator<Item = &EdgeInstance> {
self.edges.iter()
pub fn edges(&self) -> &[Edge] {
&self.edges
}

pub fn kind(&self) -> GraphType {
Expand Down
36 changes: 17 additions & 19 deletions crates/viewer/re_space_view_graph/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use egui::{Pos2, Rect, Vec2};
use fjadra as fj;

use crate::{
graph::{Graph, NodeIndex},
graph::{Graph, Node, NodeIndex},
ui::bounding_rect_from_iter,
visualizers::NodeInstance,
};

#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -38,13 +37,15 @@ impl Layout {
}
}

impl<'a> From<&'a NodeInstance> for fj::Node {
fn from(instance: &'a NodeInstance) -> Self {
let mut node = Self::default();
if let Some(pos) = instance.position {
node = node.fixed_position(pos.x as f64, pos.y as f64);
impl<'a> From<&'a Node> for fj::Node {
fn from(node: &'a Node) -> Self {
match node {
Node::Explicit {
position: Some(pos),
..
} => Self::default().fixed_position(pos.x as f64, pos.y as f64),
_ => Self::default(),
}
node
}
}

Expand All @@ -54,27 +55,24 @@ pub struct ForceLayout {
}

impl ForceLayout {
pub fn new<'a>(graphs: impl Iterator<Item = &'a Graph<'a>> + Clone) -> Self {
let explicit = graphs
.clone()
.flat_map(|g| g.nodes_explicit().map(|n| (n.index, fj::Node::from(n))));
let implicit = graphs
.clone()
.flat_map(|g| g.nodes_implicit().map(|n| (n.index, fj::Node::default())));
pub fn new(graphs: &[Graph]) -> Self {
let nodes = graphs
.iter()
.flat_map(|g| g.nodes().iter().map(|n| (n.id(), fj::Node::from(n))));

let mut node_index = ahash::HashMap::default();
let all_nodes: Vec<fj::Node> = explicit
.chain(implicit)
let all_nodes: Vec<fj::Node> = nodes
.enumerate()
.map(|(i, n)| {
node_index.insert(n.0, i);
n.1
})
.collect();

let all_edges = graphs.flat_map(|g| {
let all_edges = graphs.iter().flat_map(|g| {
g.edges()
.map(|e| (node_index[&e.source_index], node_index[&e.target_index]))
.iter()
.map(|e| (node_index[&e.from], node_index[&e.to]))
});

// TODO(grtlr): Currently we guesstimate good forces. Eventually these should be exposed as blueprints.
Expand Down
2 changes: 1 addition & 1 deletion crates/viewer/re_space_view_graph/src/ui/draw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ mod node;

pub use edge::draw_edge;
pub use entity::draw_entity;
pub use node::{DrawableNode};
pub use node::{DrawableLabel};
Loading

0 comments on commit 45a2dc7

Please sign in to comment.