use crate::graph::{Graph, GraphOptions};
use crate::layout::types::{EdgeLabel, NodeLabel};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Relationship {
InEdges,
OutEdges,
}
pub(crate) fn build_layer_graph(
g: &Graph<NodeLabel, EdgeLabel>,
rank: i32,
relationship: Relationship,
nodes_with_rank: &[String],
) -> Graph<NodeLabel, EdgeLabel> {
let root = create_root_node(g);
let mut result = Graph::with_options(GraphOptions {
directed: true,
multigraph: false,
compound: true,
});
result.set_graph_label(root.clone());
for v in nodes_with_rank {
let node = match g.node(v) {
Some(n) => n,
None => continue,
};
let node_rank = node.rank;
let node_min_rank = node.min_rank;
let node_max_rank = node.max_rank;
let in_rank = node_rank == Some(rank)
|| (node_min_rank.is_some()
&& node_max_rank.is_some()
&& node_min_rank.unwrap() <= rank
&& rank <= node_max_rank.unwrap());
if !in_rank {
continue;
}
result.set_node(v.clone(), Some(node.clone()));
let parent = g.parent(v).unwrap_or(&root).to_string();
result.set_parent(v, Some(&parent));
let edges = match relationship {
Relationship::InEdges => g.in_edges(v, None).unwrap_or_default(),
Relationship::OutEdges => g.out_edges(v, None).unwrap_or_default(),
};
for e in &edges {
let u = if e.v == *v { &e.w } else { &e.v };
if !result.has_node(u) {
if let Some(u_label) = g.node(u) {
result.set_node(u.clone(), Some(u_label.clone()));
} else {
result.set_node(u.clone(), None);
}
}
let existing_weight = result.edge(u, v, None).map_or(0, |l: &EdgeLabel| l.weight);
let edge_weight = g.edge_by_obj(e).map_or(1, |l| l.weight);
let el = EdgeLabel {
weight: edge_weight + existing_weight,
..EdgeLabel::default()
};
result.set_edge(u.clone(), v.clone(), Some(el), None);
}
if node.min_rank.is_some() {
let r = rank as usize;
let bl = node.border_left.get(r).filter(|s| !s.is_empty()).cloned();
let br = node.border_right.get(r).filter(|s| !s.is_empty()).cloned();
let mut updated = NodeLabel::default();
if let Some(bl_val) = bl {
updated.border_left = vec![bl_val];
}
if let Some(br_val) = br {
updated.border_right = vec![br_val];
}
result.set_node(v.clone(), Some(updated));
}
}
result
}
pub(crate) fn get_root(lg: &Graph<NodeLabel, EdgeLabel>) -> String {
lg.graph_label::<String>().cloned().unwrap_or_default()
}
fn create_root_node(g: &Graph<NodeLabel, EdgeLabel>) -> String {
loop {
let v = crate::util::unique_id("_root");
if !g.has_node(&v) {
return v;
}
}
}