Node graph improvements (#855)

* Selecting multiple nodes

* Improve logs

* Log bad types in dyn any

* Add (broken) node links

* New topological sort

* Fix reorder ids function

* Input and output node

* Add nodes that operate on images

* Fixups

* Show node parameters together with layer properties

* New nodes don't crash editor

* Fix tests

* Node positions backend

* Generate node graph on value change

* Add expose input message

* Fix tests

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2022-11-17 15:36:23 -08:00
committed by GitHub
co-authored by Keavon Chambers
parent 5fe7aba85d
commit 6cd0dbdcd0
23 changed files with 734 additions and 331 deletions
+53 -12
View File
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use crate::document::value;
use crate::document::NodeId;
@@ -165,7 +165,37 @@ impl ProtoNetwork {
edges
}
// Based on https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
// Based on https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search
// This approach excludes nodes that are not connected
pub fn topological_sort(&self) -> Vec<NodeId> {
let mut sorted = Vec::new();
let inwards_edges = self.collect_inwards_edges();
fn visit(node_id: NodeId, temp_marks: &mut HashSet<NodeId>, sorted: &mut Vec<NodeId>, inwards_edges: &HashMap<NodeId, Vec<NodeId>>) {
if sorted.contains(&node_id) {
return;
};
if temp_marks.contains(&node_id) {
panic!("Cycle detected");
}
info!("Visiting {node_id}");
if let Some(dependencies) = inwards_edges.get(&node_id) {
temp_marks.insert(node_id);
for &dependant in dependencies {
visit(dependant, temp_marks, sorted, inwards_edges);
}
temp_marks.remove(&node_id);
}
sorted.push(node_id);
}
assert!(self.nodes.iter().any(|(id, _)| *id == self.output), "Output id {} does not exist", self.output);
visit(self.output, &mut HashSet::new(), &mut sorted, &inwards_edges);
info!("Sorted order {sorted:?}");
sorted
}
/*// Based on https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
pub fn topological_sort(&self) -> Vec<NodeId> {
let mut sorted = Vec::new();
let outwards_edges = self.collect_outwards_edges();
@@ -187,21 +217,24 @@ impl ProtoNetwork {
}
}
}
info!("Sorted order {sorted:?}");
sorted
}
}*/
pub fn reorder_ids(&mut self) {
let order = self.topological_sort();
let lookup = self
.nodes
// Map of node ids to indexes (which become the node ids as they are inserted into the borrow stack)
let lookup: HashMap<_, _> = order.iter().enumerate().map(|(pos, id)| (*id, pos as NodeId)).collect();
info!("Order {order:?}");
self.nodes = order
.iter()
.map(|(id, _)| (*id, order.iter().position(|x| x == id).unwrap() as u64))
.collect::<HashMap<u64, u64>>();
self.nodes.sort_by_key(|(id, _)| lookup.get(id).unwrap());
self.nodes.iter_mut().for_each(|(id, node)| {
node.map_ids(|id| *lookup.get(&id).unwrap());
*id = *lookup.get(id).unwrap()
});
.map(|id| {
let mut node = self.nodes.swap_remove(self.nodes.iter().position(|(test_id, _)| test_id == id).unwrap()).1;
node.map_ids(|id| *lookup.get(&id).unwrap());
(*lookup.get(id).unwrap(), node)
})
.collect();
assert_eq!(order.len(), self.nodes.len());
}
}
@@ -217,6 +250,14 @@ mod test {
inputs: vec![10],
output: 1,
nodes: [
(
7,
ProtoNode {
identifier: "id".into(),
input: ProtoNodeInput::Node(11),
construction_args: ConstructionArgs::Nodes(vec![]),
},
),
(
1,
ProtoNode {