1 /** \file
2  * \brief declaration of the FastSimpleHierarchyLayout
3  * (third phase of sugiyama)
4  *
5  * \author Till Schäfer, Carsten Gutwenger
6  *
7  * \par License:
8  * This file is part of the Open Graph Drawing Framework (OGDF).
9  *
10  * \par
11  * Copyright (C)<br>
12  * See README.md in the OGDF root directory for details.
13  *
14  * \par
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * Version 2 or 3 as published by the Free Software Foundation;
18  * see the file LICENSE.txt included in the packaging of this file
19  * for details.
20  *
21  * \par
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * \par
28  * You should have received a copy of the GNU General Public
29  * License along with this program; if not, see
30  * http://www.gnu.org/copyleft/gpl.html
31  */
32 
33 #pragma once
34 
35 #include <ogdf/layered/HierarchyLayoutModule.h>
36 #include <ogdf/layered/Hierarchy.h>
37 #include <ogdf/basic/NodeArray.h>
38 
39 namespace ogdf {
40 
41 /**
42  * \brief Coordinate assignment phase for the Sugiyama algorithm by Ulrik Brandes and Boris Köpf
43  *
44  * @ingroup gd-hlm
45  *
46  * This class implements a hierarchy layout algorithm, i.e., it layouts
47  * hierarchies with a given order of nodes on each layer. It is used as a third
48  * phase of the Sugiyama algorithm.
49  *
50  * The Algorithm runs in three phases.<br>
51  * - Alignment (4x)<br>
52  * - Horizontal Compactation (4x)<br>
53  * - Balancing
54  *
55  * The <i>Alignment</i> and <i>Horzontal Compactation</i> phase are calculated downward, upward,
56  * left-to-right and right-to-left. The four resulting layouts are combined in a balancing step.
57  *
58  * The implementation is based on:
59  *
60  * Ulrik Brandes, Boris Köpf: <i>Fast and Simple Horizontal Coordinate Assignment</i>.
61  * LNCS 2002, Volume 2265/2002, pp. 33-36
62  *
63  * <h3>Optional Parameters</h3>
64  *
65  * <table>
66  *   <tr>
67  *     <th>Option</th><th>Type</th><th>Default</th><th>Description</th>
68  *   </tr><tr>
69  *     <td><i>node distance</i></td><td>int</td><td>150</td>
70  *     <td>the minimal horizontal distance between two nodes on the same layer</td>
71  *   </tr><tr>
72  *     <td><i>layer distance</i></td><td>int</td><td>75</td>
73  *     <td>the minimal vertical distance between two nodes on adjacent layers</td>
74  *   </tr><tr>
75  *     <td><i>balanced</i></td><td>bool</td><td>true</td>
76  *     <td>determines whether balancing is used</td>
77  *   </tr><tr>
78  *     <td><i>left-to-right</i></td><td>bool</td><td>true</td>
79  *     <td>determines whether block alignment is computed by a left-to-right (true) or right-to-left traversal</td>
80  *   </tr><tr>
81  *     <td><i>downward</i></td><td>bool</td><td>true</td>
82  *     <td>determines whether block alignment is computed by a downward (true) or upward traversal</td>
83  *   </tr>
84  * </table>
85  */
86 class OGDF_EXPORT FastSimpleHierarchyLayout : public HierarchyLayoutModule
87 {
88 private:
89 	double m_minXSep;	//!< stores the option <i>node distance</i>.
90 	double m_ySep;		//!< stores the option <i>layer distance</i>.
91 	bool   m_balanced;	//!< stores the option <i>balanced</i>.
92 	bool   m_downward;	//!< stores the option <i>downward</i>.
93 	bool   m_leftToRight;	//!< stores the option <i>left-to-right</i>.
94 
95 protected:
96 	virtual void doCall(const HierarchyLevelsBase &levels, GraphAttributes &AGC) override;
97 
98 public:
99 	//! Creates an instance of fast simple hierarchy layout.
100 	/**
101 	 * Sets the options to default values, i.e., use balanced layout with left-to-right node
102 	 * direction on each layer, node distance as given by LayoutStandards, and layer distance as
103 	 * 1.5 times node distance.
104 	 */
105 	FastSimpleHierarchyLayout();
106 
107 
108 	//! Copy constructor.
109 	FastSimpleHierarchyLayout(const FastSimpleHierarchyLayout &);
110 
111 	// destructor
~FastSimpleHierarchyLayout()112 	virtual ~FastSimpleHierarchyLayout() { }
113 
114 
115 	//! Assignment operator
116 	FastSimpleHierarchyLayout &operator=(const FastSimpleHierarchyLayout &);
117 
118 
119 	//! Returns the option <i>node distance</i>.
nodeDistance()120 	double nodeDistance() const {
121 		return m_minXSep;
122 	}
123 
124 	//! Sets the option node distance to \p dist.
nodeDistance(double dist)125 	void nodeDistance(double dist) {
126 		m_minXSep = dist;
127 	}
128 
129 	//! Returns the option <i>layer distance</i>.
layerDistance()130 	double layerDistance() const {
131 		return m_ySep;
132 	}
133 
134 	//! Sets the option <i>layer distance</i> to \p dist.
layerDistance(double dist)135 	void layerDistance(double dist) {
136 		m_ySep = dist;
137 	}
138 
139 	//! Returns the option <i>downward</i>.
downward()140 	bool downward() const {
141 		return m_downward;
142 	}
143 
144 	//! Sets the option <i>downward</i> to \p d.
downward(bool d)145 	void downward(bool d) {
146 		m_downward = d;
147 	}
148 
149 	//! Returns the option <i>left-to-right</i>.
leftToRight()150 	bool leftToRight() const {
151 		return m_leftToRight;
152 	}
153 
154 	//! Sets the option <i>left-to-right</i> to \p b.
leftToRight(bool b)155 	void leftToRight(bool b) {
156 		m_leftToRight = b;
157 	}
158 
159 	//! Returns the option <i>balanced</i>.
balanced()160 	bool balanced() const {
161 		return m_balanced;
162 	}
163 
164 	//! Sets the option <i>balanced</i> to \p b.
balanced(bool b)165 	void balanced(bool b) {
166 		m_balanced = b;
167 	}
168 
169 
170 private:
171 	/**
172 	 * Preprocessing step to find all type1 conflicts.
173 	 * A type1 conflict is a crossing of a inner segment with a non-inner segment.
174 	 *
175 	 * This is for preferring straight inner segments.
176 	 *
177 	 * @param levels The Hierarchy
178 	 * @param downward The level direction
179 	 * @param type1Conflicts is assigned the conflicts, (type1Conflicts[v])[u]=true means (u,v) is marked, u is the upper node
180 	 */
181 	void markType1Conflicts(const HierarchyLevelsBase &levels, bool downward, NodeArray<NodeArray<bool> > &type1Conflicts);
182 
183 	/**
184 	 * Align each node to a node on the next higher level. The result is a blockgraph where each
185 	 * node is in a block whith a nother node when they have the same root.
186 	 *
187 	 * @param levels The Hierarchy
188 	 * @param root The root for each node (calculated by this method)
189 	 * @param align The alignment to the next level node (align(v)=u <=> u is aligned to v) (calculated by this method)
190 	 * @param type1Conflicts Type1 conflicts to prefer straight inner segments
191 	 * @param downward The level direction
192 	 * @param leftToRight The node direction on each level
193 	 */
194 	void verticalAlignment(
195 		const HierarchyLevelsBase &levels,
196 		NodeArray<node> &root,
197 		NodeArray<node> &align,
198 		const NodeArray<NodeArray<bool> > &type1Conflicts,
199 		const bool downward,
200 		const bool leftToRight);
201 
202 	/**
203 	 * Computes the width of each block, i.e., the maximal width of a node in the block, and
204 	 * stores it in blockWidth for the root of the block.
205 	 *
206 	 * @param GC The input graph copy
207 	 * @param GCA The input graph copies (gives in particular the widths of nodes)
208 	 * @param root The root for each node (calculated by this method)
209 	 * @param blockWidth Is assigned the width of each block (stored for the root)
210 	 */
211 	void computeBlockWidths(
212 		const GraphCopy &GC,
213 		const GraphAttributes &GCA,
214 		NodeArray<node> &root,
215 		NodeArray<double> &blockWidth);
216 
217 	/**
218 	 * Calculate the coordinates for each node
219 	 *
220 	 * @param align The alignment to the next level node (align(v)=u <=> u is aligned to v)
221 	 * @param levels The Hierarchy
222 	 * @param root The root for each node
223 	 * @param blockWidth The width of each block
224 	 * @param x The x-coordinates for each node (calculated by this method)
225 	 * @param leftToRight The node direction on each level
226 	 * @param downward The level direction
227 	 */
228 	void horizontalCompactation(
229 		const NodeArray<node> &align,
230 		const HierarchyLevelsBase &levels,
231 		const NodeArray<node> &root,
232 		const NodeArray<double> &blockWidth,
233 		NodeArray<double> &x,
234 		const bool leftToRight,
235 		bool downward);
236 
237 	/**
238 	 * Calculate the coordinate for root nodes (placing)
239 	 *
240 	 * @param v The root node to place
241 	 * @param sink The Sink for each node. A sink identifies each block class (calculated by this method)
242 	 * @param shift The shift for each class (calculated by this method)
243 	 * @param x The class relative x-coordinate for each node (calculated by this method)
244 	 * @param align The alignment to the next level node (align(v)=u <=> u is aligned to v)
245 	 * @param levels The Hierarchy
246 	 * @param blockWidth The width of each block
247 	 * @param root The root for each node
248 	 * @param leftToRight The node direction on each level
249 	 */
250 	void placeBlock(
251 		node v,
252 		NodeArray<node> &sink,
253 		NodeArray<double> &shift,
254 		NodeArray<double> &x,
255 		const NodeArray<node> &align,
256 		const HierarchyLevelsBase &levels,
257 		const NodeArray<double> &blockWidth,
258 		const NodeArray<node> &root,
259 		const bool leftToRight);
260 
261 	/**
262 	 * The twin of an inner Segment
263 	 *
264 	 * @return Parent node which is connected by an inner segment.
265 	 * nullptr if there is no parent segment or if the segment is not an inner segment.
266 	 */
267 	node virtualTwinNode(const HierarchyLevelsBase &levels, const node v, const HierarchyLevelsBase::TraversingDir dir) const;
268 
269 	/**
270 	 * Predecessor of v on the same level,
271 	 *
272 	 * @param v The node for which the predecessor should be calculated.
273 	 * @param levels The Hierarchy
274 	 * @param leftToRight If true the left predecessor is choosen. Otherwise the right predecessor.
275 	 * @return Predescessor on the same level. nullptr if there is no predecessor.
276 	 */
277 	node pred(const node v, const HierarchyLevelsBase &levels, const bool leftToRight);
278 };
279 
280 }
281