Skip to content

Instantly share code, notes, and snippets.

@matthewjberger
Last active October 29, 2019 21:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewjberger/eea3a9d855bd548f3e3f1de2349aca07 to your computer and use it in GitHub Desktop.
Save matthewjberger/eea3a9d855bd548f3e3f1de2349aca07 to your computer and use it in GitHub Desktop.
Using petgraph to create a scene graph and traverse it non-recursively with DFS, keeping track of transformations via indices
[package]
name = "dfs"
version = "0.1.0"
authors = ["Matthew J. Berger <matthewberger@nevada.unr.edu>"]
edition = "2018"
[dependencies]
petgraph = "0.4.13"
use petgraph::{
prelude::*,
Graph,
visit::Dfs
};
struct Node {
transform: i32, // This would be some other data type depending on the transform
}
impl Node {
fn new(transform: i32) -> Self { Node { transform } }
}
fn main() {
// Tree:
// 0
// / \
// 1 2
// / \ /
// 3 4 8
// / \
// 5 6
// /
// 7
let mut graph: Graph<Node, ()> = Graph::new();
let a = graph.add_node(Node::new(0));
let b = graph.add_node(Node::new(1));
let c = graph.add_node(Node::new(2));
let d = graph.add_node(Node::new(3));
let e = graph.add_node(Node::new(4));
let f = graph.add_node(Node::new(5));
let g = graph.add_node(Node::new(6));
let h = graph.add_node(Node::new(7));
let i = graph.add_node(Node::new(8));
graph.add_edge(a, b, ());
graph.add_edge(a, c, ());
graph.add_edge(b, d, ());
graph.add_edge(b, e, ());
graph.add_edge(d, f, ());
graph.add_edge(d, g, ());
graph.add_edge(f, h, ());
graph.add_edge(c, i, ());
let mut transform_indices: Vec<NodeIndex> = Vec::new();
// The dfs does not keep a borrow to the graph, so the graph is still mutable after this
let mut dfs = Dfs::new(&graph, a);
while let Some(nx) = dfs.next(&graph) {
let mut incoming_walker = graph.neighbors_directed(nx, Incoming).detach();
let mut outgoing_walker = graph.neighbors_directed(nx, Outgoing).detach();
if let Some(parent) = incoming_walker.next_node(&graph) {
while let Some(last_index) = transform_indices.last() {
if *last_index == parent {
break;
}
// Discard indices for transforms that are no longer needed
transform_indices.pop();
}
}
println!("{:?}: Transform_indices: {:#?}", nx, transform_indices);
let current_transform = transform_indices.iter().fold(1, |transform, index| transform * graph[*index].transform);
let transform = current_transform * graph[nx].transform;
// If the node has children, store the index for children to use
if outgoing_walker.next(&graph).is_some() {
transform_indices.push(nx);
}
// Render with the given transform
println!("");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment