layout/topo/
layout.rs

1//! This module the implementation of VisualGraph, which is the data-structure
2//! that we use for assigning (x,y) locations to all of the shapes and edges.
3//! The VisualGraph uses a DAG to represent the relationships between the nodes
4//! and the Ranks data-structure to represent rows of shapes that have the same
5//! x coordinate.
6
7#[cfg(feature = "log")]
8extern crate log;
9
10use crate::adt::dag::*;
11use crate::core::base::Orientation;
12use crate::core::format::RenderBackend;
13use crate::core::format::Renderable;
14use crate::core::format::Visible;
15use crate::core::geometry::Position;
16use crate::std_shapes::render::*;
17use crate::std_shapes::shapes::*;
18use crate::topo::optimizer::EdgeCrossOptimizer;
19use crate::topo::optimizer::RankOptimizer;
20use std::mem::swap;
21use std::vec;
22
23use super::placer::Placer;
24
25#[derive(Debug)]
26pub struct VisualGraph {
27    // Holds all of the elements in the graph.
28    nodes: Vec<Element>,
29    // The arrows and the list of elements that they visits.
30    edges: Vec<(Arrow, Vec<NodeHandle>)>,
31    // Contains a list of self-edges. We use this as a temporary storage during
32    // lowering. This list should be removes by the time we start the layout
33    // process.
34    self_edges: Vec<(Arrow, NodeHandle)>,
35    // Representing the connections between the nodes. Used to keep the graph
36    // a dag by detecting reverse edges. Used to create 'levels', and decide
37    // which node moves/controls which node. After lowering, the graph should
38    // only contain edges that skip zero or one levels.
39    pub dag: DAG,
40    // Sets the graph orientation (L-to-R, or T-to-B).
41    orientation: Orientation,
42}
43
44impl VisualGraph {
45    pub fn new(orientation: Orientation) -> Self {
46        VisualGraph {
47            nodes: Vec::new(),
48            edges: Vec::new(),
49            self_edges: Vec::new(),
50            dag: DAG::new(),
51            orientation,
52        }
53    }
54
55    pub fn orientation(&self) -> Orientation {
56        self.orientation
57    }
58
59    pub fn num_nodes(&self) -> usize {
60        self.dag.len()
61    }
62
63    pub fn iter_nodes(&self) -> NodeIterator {
64        self.dag.iter()
65    }
66
67    pub fn succ(&self, node: NodeHandle) -> &Vec<NodeHandle> {
68        self.dag.successors(node)
69    }
70
71    pub fn preds(&self, node: NodeHandle) -> &Vec<NodeHandle> {
72        self.dag.predecessors(node)
73    }
74
75    pub fn pos(&self, n: NodeHandle) -> Position {
76        self.element(n).position()
77    }
78
79    pub fn pos_mut(&mut self, n: NodeHandle) -> &mut Position {
80        self.element_mut(n).position_mut()
81    }
82
83    pub fn is_connector(&self, n: NodeHandle) -> bool {
84        return self.element(n).is_connector();
85    }
86
87    pub fn transpose(&mut self) {
88        for node in self.dag.iter() {
89            self.element_mut(node).transpose();
90        }
91    }
92
93    pub fn element(&self, node: NodeHandle) -> &Element {
94        &self.nodes[node.get_index()]
95    }
96
97    pub fn element_mut(&mut self, node: NodeHandle) -> &mut Element {
98        &mut self.nodes[node.get_index()]
99    }
100
101    /// Add a node to the graph.
102    /// \returns a handle to the node.
103    pub fn add_node(&mut self, elem: Element) -> NodeHandle {
104        let res = self.dag.new_node();
105        assert!(res.get_index() == self.nodes.len());
106        self.nodes.push(elem);
107        res
108    }
109
110    /// Add an edge to the graph.
111    pub fn add_edge(&mut self, arrow: Arrow, from: NodeHandle, to: NodeHandle) {
112        assert!(from.get_index() < self.nodes.len(), "Invalid handle");
113        assert!(to.get_index() < self.nodes.len(), "Invalid handle");
114        let lst = vec![from, to];
115        self.edges.push((arrow, lst));
116    }
117}
118
119// Render.
120impl VisualGraph {
121    fn render(&self, debug: bool, rb: &mut dyn RenderBackend) {
122        // Draw the nodes.
123        for node in &self.nodes {
124            node.render(debug, rb);
125        }
126
127        // Draw the arrows:
128        for arrow in &self.edges {
129            let mut elements = Vec::new();
130            for h in &arrow.1 {
131                elements.push(self.nodes[h.get_index()].clone());
132            }
133            render_arrow(rb, debug, &elements[..], &arrow.0);
134        }
135    }
136}
137
138impl VisualGraph {
139    pub fn do_it(
140        &mut self,
141        debug_mode: bool,
142        disable_opt: bool,
143        disable_layout: bool,
144        rb: &mut dyn RenderBackend,
145    ) {
146        self.lower(disable_opt);
147        Placer::new(self).layout(disable_layout);
148        self.render(debug_mode, rb);
149    }
150
151    fn lower(&mut self, disable_optimizations: bool) {
152        #[cfg(feature = "log")]
153        log::info!("Lowering a graph with {} nodes.", self.num_nodes());
154        self.to_valid_dag();
155        self.split_text_edges();
156        self.split_long_edges(disable_optimizations);
157
158        for elem in self.dag.iter() {
159            self.element_mut(elem).resize();
160        }
161    }
162
163    /// Flip the edges in the graph to create a valid dag.
164    /// This is the first step of graph canonicalization.
165    pub fn to_valid_dag(&mut self) {
166        let edges = self.edges.clone();
167        self.edges.clear();
168
169        // At this point the DAG should have all of the nodes, but none of the
170        // edges. In here we construct the edges.
171        assert_eq!(self.nodes.len(), self.dag.len(), "bad number of nodes");
172
173        // For each edge.
174        for edge in edges {
175            let mut arrow = edge.0;
176            let lst = edge.1;
177            assert_eq!(lst.len(), 2);
178            let mut from = lst[0];
179            let mut to = lst[1];
180
181            if from == to {
182                self.self_edges.push((arrow, from));
183                continue;
184            }
185
186            // Reverse back edges.
187            if self.dag.is_reachable(to, from) {
188                swap(&mut from, &mut to);
189                arrow = arrow.reverse();
190            }
191
192            self.dag.add_edge(from, to);
193            self.add_edge(arrow, from, to);
194
195            self.dag.verify();
196        }
197    }
198
199    /// Convert all of the edges that contain text labels to edges that go
200    /// through connectors.
201    /// This is the second step of graph canonicalization.
202    pub fn split_text_edges(&mut self) {
203        let mut edges = self.edges.clone();
204        //self.edge_list.clear();
205
206        for edge in edges.iter_mut() {
207            let lst = &edge.1;
208            assert_eq!(lst.len(), 2);
209            let arrow = &edge.0;
210            let from = lst[0];
211            let to = lst[1];
212
213            // If the edge is empty then there is nothing to do.
214            if edge.0.text.is_empty() {
215                continue;
216            }
217
218            let text = arrow.text.clone();
219
220            // Create a new connection block.
221            let dir = self.element(from).orientation;
222            let conn = Element::create_connector(&text, &arrow.look, dir);
223            let conn = self.add_node(conn);
224
225            // Update the edge node list, and remove the text.
226            edge.1 = vec![from, conn, to];
227            edge.0.text = String::new();
228
229            // Add the edge to dag.
230            let res = self.dag.remove_edge(from, to);
231            assert!(res, "Expected the edge to be in the graph!");
232            self.dag.add_edge(from, conn);
233            self.dag.add_edge(conn, to);
234        }
235
236        self.edges = edges;
237    }
238
239    pub fn split_long_edges(&mut self, disable_optimizations: bool) {
240        // Assign optimal rank to nodes in the graph.
241        self.dag.recompute_node_ranks();
242        self.dag.verify();
243        if !disable_optimizations {
244            RankOptimizer::new(&mut self.dag).optimize();
245        }
246
247        let mut edges = self.edges.clone();
248        self.edges.clear();
249
250        for edge in edges.iter_mut() {
251            let mut lst = edge.1.clone();
252
253            // Points the 'to' edge in each pair in the graph. We start with
254            // node '1', and compare to the previous node.
255            let mut i = 1;
256            while i < lst.len() {
257                let prev = lst[i - 1];
258                let curr = lst[i];
259
260                let prev_level = self.dag.level(prev);
261                let curr_level = self.dag.level(curr);
262
263                // If the edges point to a lower rank then move on.
264                assert!(prev_level < curr_level, "Invalid edge");
265                if prev_level + 1 == curr_level {
266                    i += 1;
267                    continue;
268                }
269
270                // We need to add a new connector node.
271                let dir = self.element(prev).orientation;
272                let conn = Element::empty_connector(dir);
273                let conn = self.add_node(conn);
274                lst.insert(i, conn);
275
276                // Update the dag connections.
277                self.dag.remove_edge(prev, curr);
278                self.dag.add_edge(prev, conn);
279                self.dag.add_edge(conn, curr);
280
281                // Place the new connection node at the right level.
282                self.dag.update_node_rank_level(conn, prev_level + 1, None);
283            }
284
285            edge.1 = lst;
286        }
287        self.edges = edges;
288
289        if !disable_optimizations {
290            EdgeCrossOptimizer::new(&mut self.dag).optimize();
291        }
292        self.expand_self_edges()
293    }
294
295    /// Convert all of the saved self edges into proper edges in the graph.
296    pub fn expand_self_edges(&mut self) {
297        for se in self.self_edges.clone().iter() {
298            let mut arrow = se.0.clone();
299            let node = se.1;
300            let level = self.dag.level(node);
301            let text = arrow.text.to_string();
302            arrow.text = String::new();
303            let dir = self.element(node).orientation;
304            let conn = Element::create_connector(&text, &arrow.look, dir);
305            let conn = self.add_node(conn);
306            self.dag.update_node_rank_level(conn, level, Some(node));
307            self.edges.push((arrow, vec![node, conn, node]));
308        }
309
310        // Wipe out the self edges.
311        self.self_edges.clear();
312    }
313}