#[cfg(feature = "log")]
extern crate log;
use crate::adt::dag::*;
use crate::core::base::Orientation;
use crate::core::format::RenderBackend;
use crate::core::format::Renderable;
use crate::core::format::Visible;
use crate::core::geometry::Position;
use crate::std_shapes::render::*;
use crate::std_shapes::shapes::*;
use crate::topo::optimizer::EdgeCrossOptimizer;
use crate::topo::optimizer::RankOptimizer;
use std::mem::swap;
use std::vec;
use super::placer::Placer;
#[derive(Debug)]
pub struct VisualGraph {
nodes: Vec<Element>,
edges: Vec<(Arrow, Vec<NodeHandle>)>,
self_edges: Vec<(Arrow, NodeHandle)>,
pub dag: DAG,
orientation: Orientation,
}
impl VisualGraph {
pub fn new(orientation: Orientation) -> Self {
VisualGraph {
nodes: Vec::new(),
edges: Vec::new(),
self_edges: Vec::new(),
dag: DAG::new(),
orientation,
}
}
pub fn orientation(&self) -> Orientation {
self.orientation
}
pub fn num_nodes(&self) -> usize {
self.dag.len()
}
pub fn iter_nodes(&self) -> NodeIterator {
self.dag.iter()
}
pub fn succ(&self, node: NodeHandle) -> &Vec<NodeHandle> {
self.dag.successors(node)
}
pub fn preds(&self, node: NodeHandle) -> &Vec<NodeHandle> {
self.dag.predecessors(node)
}
pub fn pos(&self, n: NodeHandle) -> Position {
self.element(n).position()
}
pub fn pos_mut(&mut self, n: NodeHandle) -> &mut Position {
self.element_mut(n).position_mut()
}
pub fn is_connector(&self, n: NodeHandle) -> bool {
return self.element(n).is_connector();
}
pub fn transpose(&mut self) {
for node in self.dag.iter() {
self.element_mut(node).transpose();
}
}
pub fn element(&self, node: NodeHandle) -> &Element {
&self.nodes[node.get_index()]
}
pub fn element_mut(&mut self, node: NodeHandle) -> &mut Element {
&mut self.nodes[node.get_index()]
}
pub fn add_node(&mut self, elem: Element) -> NodeHandle {
let res = self.dag.new_node();
assert!(res.get_index() == self.nodes.len());
self.nodes.push(elem);
res
}
pub fn add_edge(&mut self, arrow: Arrow, from: NodeHandle, to: NodeHandle) {
assert!(from.get_index() < self.nodes.len(), "Invalid handle");
assert!(to.get_index() < self.nodes.len(), "Invalid handle");
let lst = vec![from, to];
self.edges.push((arrow, lst));
}
}
impl VisualGraph {
fn render(&self, debug: bool, rb: &mut dyn RenderBackend) {
for node in &self.nodes {
node.render(debug, rb);
}
for arrow in &self.edges {
let mut elements = Vec::new();
for h in &arrow.1 {
elements.push(self.nodes[h.get_index()].clone());
}
render_arrow(rb, debug, &elements[..], &arrow.0);
}
}
}
impl VisualGraph {
pub fn do_it(
&mut self,
debug_mode: bool,
disable_opt: bool,
disable_layout: bool,
rb: &mut dyn RenderBackend,
) {
self.lower(disable_opt);
Placer::new(self).layout(disable_layout);
self.render(debug_mode, rb);
}
fn lower(&mut self, disable_optimizations: bool) {
#[cfg(feature = "log")]
log::info!("Lowering a graph with {} nodes.", self.num_nodes());
self.to_valid_dag();
self.split_text_edges();
self.split_long_edges(disable_optimizations);
for elem in self.dag.iter() {
self.element_mut(elem).resize();
}
}
pub fn to_valid_dag(&mut self) {
let edges = self.edges.clone();
self.edges.clear();
assert_eq!(self.nodes.len(), self.dag.len(), "bad number of nodes");
for edge in edges {
let mut arrow = edge.0;
let lst = edge.1;
assert_eq!(lst.len(), 2);
let mut from = lst[0];
let mut to = lst[1];
if from == to {
self.self_edges.push((arrow, from));
continue;
}
if self.dag.is_reachable(to, from) {
swap(&mut from, &mut to);
arrow = arrow.reverse();
}
self.dag.add_edge(from, to);
self.add_edge(arrow, from, to);
self.dag.verify();
}
}
pub fn split_text_edges(&mut self) {
let mut edges = self.edges.clone();
for edge in edges.iter_mut() {
let lst = &edge.1;
assert_eq!(lst.len(), 2);
let arrow = &edge.0;
let from = lst[0];
let to = lst[1];
if edge.0.text.is_empty() {
continue;
}
let text = arrow.text.clone();
let dir = self.element(from).orientation;
let conn = Element::create_connector(&text, &arrow.look, dir);
let conn = self.add_node(conn);
edge.1 = vec![from, conn, to];
edge.0.text = String::new();
let res = self.dag.remove_edge(from, to);
assert!(res, "Expected the edge to be in the graph!");
self.dag.add_edge(from, conn);
self.dag.add_edge(conn, to);
}
self.edges = edges;
}
pub fn split_long_edges(&mut self, disable_optimizations: bool) {
self.dag.recompute_node_ranks();
self.dag.verify();
if !disable_optimizations {
RankOptimizer::new(&mut self.dag).optimize();
}
let mut edges = self.edges.clone();
self.edges.clear();
for edge in edges.iter_mut() {
let mut lst = edge.1.clone();
let mut i = 1;
while i < lst.len() {
let prev = lst[i - 1];
let curr = lst[i];
let prev_level = self.dag.level(prev);
let curr_level = self.dag.level(curr);
assert!(prev_level < curr_level, "Invalid edge");
if prev_level + 1 == curr_level {
i += 1;
continue;
}
let dir = self.element(prev).orientation;
let conn = Element::empty_connector(dir);
let conn = self.add_node(conn);
lst.insert(i, conn);
self.dag.remove_edge(prev, curr);
self.dag.add_edge(prev, conn);
self.dag.add_edge(conn, curr);
self.dag.update_node_rank_level(conn, prev_level + 1, None);
}
edge.1 = lst;
}
self.edges = edges;
if !disable_optimizations {
EdgeCrossOptimizer::new(&mut self.dag).optimize();
}
self.expand_self_edges()
}
pub fn expand_self_edges(&mut self) {
for se in self.self_edges.clone().iter() {
let mut arrow = se.0.clone();
let node = se.1;
let level = self.dag.level(node);
let text = arrow.text.to_string();
arrow.text = String::new();
let dir = self.element(node).orientation;
let conn = Element::create_connector(&text, &arrow.look, dir);
let conn = self.add_node(conn);
self.dag.update_node_rank_level(conn, level, Some(node));
self.edges.push((arrow, vec![node, conn, node]));
}
self.self_edges.clear();
}
}