use graphlib_rust::{Graph, GraphOption};
use ordered_hashmap::OrderedHashMap;
use crate::GraphEdgePoint;
use crate::layout::{GraphConfig, GraphEdge, GraphNode};
static mut UNIQUE_STARTER: usize = 0;
pub fn unique_id() -> usize {
unsafe {
UNIQUE_STARTER += 1;
return UNIQUE_STARTER;
}
}
pub fn add_dummy_node(graph: &mut Graph<GraphConfig, GraphNode, GraphEdge>, node_type: String, data: GraphNode, name: String) -> String {
let mut node_id = format!("{}{}", name, unique_id());
while graph.has_node(&node_id) {
node_id = format!("{}{}", name, unique_id());
}
let mut node_data = data.clone();
node_data.dummy = Some(node_type);
graph.set_node(node_id.clone(), Some(node_data));
return node_id;
}
pub fn simplify(g: &Graph<GraphConfig, GraphNode, GraphEdge>) -> Graph<GraphConfig, GraphNode, GraphEdge> {
let mut simplified: Graph<GraphConfig, GraphNode, GraphEdge> = Graph::new(Some(GraphOption {
directed: Some(true),
multigraph: None,
compound: None,
}));
let nodes = g.nodes();
let edges = g.edges();
for node_id in nodes.into_iter() {
simplified.set_node(node_id.clone(), g.node(&node_id).cloned());
}
for edge_obj in edges.into_iter() {
let edge_label_ = g.edge_with_obj(&edge_obj);
let mut simple_label = simplified.edge(&edge_obj.v, &edge_obj.w, None).cloned().unwrap_or(GraphEdge::default());
if let Some(edge_label) = edge_label_ {
if let Some(minlen) = edge_label.minlen {
simple_label.minlen = Some(std::cmp::max(simple_label.minlen.unwrap_or(1.0) as i32, minlen as i32) as f32);
}
if let Some(weight) = edge_label.weight {
simple_label.weight = Some(simple_label.weight.unwrap_or(0.0) + weight);
}
}
let _ = simplified.set_edge(
&edge_obj.v,
&edge_obj.w,
Some(simple_label),
None
);
}
simplified
}
pub fn simplify_ref(g: &mut Graph<GraphConfig, GraphNode, GraphEdge>) {
let edges = g.edges();
for edge_obj in edges.into_iter() {
let edge_label_ = g.edge_mut_with_obj(&edge_obj);
if let Some(edge_label) = edge_label_ {
if edge_label.weight.is_none() {
edge_label.weight = Some(0.0);
}
if edge_label.minlen.is_none() {
edge_label.minlen = Some(1.0);
}
}
}
}
pub fn as_non_compound_graph(g: &mut Graph<GraphConfig, GraphNode, GraphEdge>) -> Graph<GraphConfig, GraphNode, GraphEdge> {
let mut simplified: Graph<GraphConfig, GraphNode, GraphEdge> = Graph::new(Some(GraphOption {
directed: Some(true),
multigraph: Some(true),
compound: Some(false),
}));
simplified.set_graph(g.graph().clone());
let nodes = g.nodes();
for v in nodes.into_iter() {
if g.children(&v).len() == 0 {
simplified.set_node(v.clone(), Some(g.node(&v).cloned().unwrap_or(GraphNode::default())));
}
}
let edge_objs = g.edges();
for e in edge_objs.into_iter() {
let _ = simplified.set_edge_with_obj(&e, g.edge_with_obj(&e).cloned());
}
return simplified;
}
pub fn transfer_node_edge_labels(source: &Graph<GraphConfig, GraphNode, GraphEdge>, destination: &mut Graph<GraphConfig, GraphNode, GraphEdge>) {
let nodes = source.nodes();
for v in nodes.into_iter() {
if source.children(&v).len() == 0 {
destination.set_node(v.clone(), Some(source.node(&v).cloned().unwrap_or(GraphNode::default())));
}
}
let edge_objs = source.edges();
for e in edge_objs.into_iter() {
let _ = destination.set_edge_with_obj(&e, source.edge_with_obj(&e).cloned());
}
}
pub struct Rect {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
pub fn intersect_rect(rect: &Rect, point: &GraphEdgePoint) -> GraphEdgePoint {
let x = rect.x;
let y = rect.y;
let dx = point.x - x;
let dy = point.y - y;
let w = rect.width / 2.0;
let h = rect.height / 2.0;
if dx == 0.0 && dy == 0.0 {
panic!("Not possible to find intersection inside of the rectangle");
}
let (sx, sy) = if (dy.abs() * w) > (dx.abs() * h) {
if dy < 0.0 {
(-h * dx / dy, -h)
} else {
(h * dx / dy, h)
}
} else {
if dx < 0.0 {
(-w, -w * dy / dx)
} else {
(w, w * dy / dx)
}
};
GraphEdgePoint { x: x + sx, y: y + sy }
}
pub fn build_layer_matrix(g: &Graph<GraphConfig, GraphNode, GraphEdge>) -> Vec<Vec<String>> {
let mut layering: Vec<OrderedHashMap<usize, String>> = (0..=max_rank(g)).map(|_| OrderedHashMap::new()).collect();
g.nodes().iter().for_each(|v| {
let node = g.node(v).unwrap();
let rank = node.rank.unwrap_or(0) as usize;
let layer: &mut OrderedHashMap<usize, String> = layering.get_mut(rank).unwrap();
layer.insert(node.order.unwrap_or(0), v.clone());
});
return layering.into_iter().map(|layer| -> Vec<String> {
let mut keys: Vec<usize> = layer.keys().cloned().collect();
keys.sort();
keys.iter().map(|key| -> String {
layer.get(key).cloned().unwrap()
}).collect()
}).collect();
}
pub fn normalize_ranks(graph: &mut Graph<GraphConfig, GraphNode, GraphEdge>) {
let node_ids = graph.nodes();
let node_ranks: Vec<i32> = node_ids.iter().map(|v| {
graph.node(v).unwrap_or(&GraphNode::default()).rank.clone().unwrap_or(0)
}).collect();
let min = node_ranks.iter().min().cloned().unwrap_or(0);
node_ids.iter().for_each(|node_id| {
let node_ = graph.node_mut(node_id);
if let Some(node) = node_ {
if node.rank.is_some() {
node.rank = Some(node.rank.unwrap() - min);
}
}
})
}
pub fn remove_empty_ranks(graph: &mut Graph<GraphConfig, GraphNode, GraphEdge>) {
let nodes: Vec<String> = graph.nodes();
let node_ranks: Vec<i32> = nodes.iter()
.map(|v| -> i32 {
graph.node(v).cloned().unwrap_or(GraphNode::default()).rank.unwrap_or(0)
})
.collect();
let offset: i32 = node_ranks.iter().min().cloned().unwrap_or(0);
let mut layers: OrderedHashMap<i32, Vec<String>> = OrderedHashMap::new();
for v in nodes.iter() {
let rank = graph.node(v).unwrap_or(&GraphNode::default()).rank.clone().unwrap_or(0) - offset;
layers.entry(rank.clone()).or_insert(vec![]).push(v.clone());
}
let mut delta = 0;
let node_rank_factor = graph.graph().node_rank_factor.clone().unwrap_or(0.0) as i32;
for (i, vs) in layers.iter() {
if vs.len() == 0 && i.clone() % node_rank_factor != 0 {
delta -= 1;
} else if delta != 0 {
for v in vs.iter() {
let node_ = graph.node_mut(v);
if let Some(node) = node_ {
node.rank = Some(node.rank.unwrap_or(0) + delta.clone())
}
}
}
}
}
pub fn add_border_node(
graph: &mut Graph<GraphConfig, GraphNode, GraphEdge>,
prefix: &str,
rank: Option<&usize>,
order: Option<&usize>
) -> String {
let mut node = GraphNode::default();
if rank.is_some() {
node.rank = Some(rank.cloned().unwrap_or(0) as i32);
}
if order.is_some() {
node.order = Some(order.cloned().unwrap_or(0));
}
return add_dummy_node(graph, "border".to_string(), node, prefix.clone().to_string());
}
pub fn max_rank(g: &Graph<GraphConfig, GraphNode, GraphEdge>) -> i32 {
g.nodes().iter().map(|v| {
g.node(v).as_ref().unwrap().rank.clone().unwrap()
}).max().unwrap_or(0)
}
#[derive(Debug, Clone)]
pub struct PartitionResponse<V> {
pub lhs: Vec<V>,
pub rhs: Vec<V>
}
pub fn partition<V: Clone>(collection: &Vec<V>, fn_: Box<dyn Fn(&V) -> bool>) -> PartitionResponse<V> {
let mut result: PartitionResponse<V> = PartitionResponse {
lhs: vec![],
rhs: vec![]
};
collection.iter().for_each(|val| {
if fn_(val) {
result.lhs.push(val.clone());
} else {
result.rhs.push(val.clone());
}
});
return result;
}