///|
pub fn order_build_layer_graph(
g : Graph,
rank : Int,
relationship : String,
) -> Graph {
let root = order_create_root_node(g)
let result = Graph::new(compound=true)
let graph_label = empty_attrs()
graph_label.set_string("root", root)
result.set_graph(graph_label)
for v in g.nodes() {
let node = g.node(v)
let node_rank = node.get_int("rank")
let min_rank = node.get_int("minRank")
let max_rank = node.get_int("maxRank")
let in_layer = if node_rank is Some(node_rank) {
node_rank == rank
} else if min_rank is Some(min_rank) && max_rank is Some(max_rank) {
min_rank <= rank && rank <= max_rank
} else {
false
}
if in_layer {
result.set_node(v, label=node)
let parent = if g.parent(v) is Some(parent) { parent } else { root }
result.set_parent(v, parent~)
let incident = order_incident_edges(g, relationship, v)
for e in incident {
let u = if e.v == v { e.w } else { e.v }
if !result.has_node(u) {
if g.node_opt(u) is Some(u_node) {
result.set_node(u, label=u_node)
} else {
result.set_node(u)
}
}
let existing = order_edge_weight(result.edge(u, v))
let w = existing + order_edge_weight(g.edge_obj(e))
let edge = empty_attrs()
edge.set_float("weight", w)
result.set_edge(u, v, label=attrs_value(edge))
}
if node.get_int("minRank") is Some(_) {
let cluster_label = empty_attrs()
if node.get_strings("borderLeft") is Some(border_lefts) {
if rank >= 0 && rank < border_lefts.length() {
cluster_label.set_string("borderLeft", border_lefts[rank])
}
}
if node.get_strings("borderRight") is Some(border_rights) {
if rank >= 0 && rank < border_rights.length() {
cluster_label.set_string("borderRight", border_rights[rank])
}
}
result.set_node(v, label=cluster_label)
}
}
}
result
}
///|
fn order_create_root_node(g : Graph) -> String {
let mut v = unique_id("_root")
while g.has_node(v) {
v = unique_id("_root")
}
v
}
///|
fn order_incident_edges(
g : Graph,
relationship : String,
v : String,
) -> Array[EdgeObj] {
if relationship == "inEdges" || relationship == "in_edges" {
g.in_edges(v)
} else {
g.out_edges(v)
}
}
///|
fn order_edge_weight(label : Value?) -> Double {
if value_as_attrs(label) is Some(attrs) {
attrs.get_float_or("weight", 0.0)
} else if value_as_int(label) is Some(v) {
v.to_double()
} else if value_as_float(label) is Some(v) {
v
} else {
0.0
}
}