6 * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $
7 ***************************************************************/
10 * \brief Implements class PlanarStraightLayout
12 * \author Carsten Gutwenger
15 * This file is part of the Open Graph Drawing Framework (OGDF).
19 * See README.txt in the root directory of the OGDF installation for details.
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * Version 2 or 3 as published by the Free Software Foundation;
25 * see the file LICENSE.txt included in the packaging of this file
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
35 * You should have received a copy of the GNU General Public
36 * License along with this program; if not, write to the Free
37 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
38 * Boston, MA 02110-1301, USA.
40 * \see http://www.gnu.org/copyleft/gpl.html
41 ***************************************************************/
44 #include <ogdf/planarlayout/PlanarStraightLayout.h>
45 #include <ogdf/basic/GraphCopy.h>
46 #include <ogdf/basic/simple_graph_alg.h>
47 #include <ogdf/augmentation/PlanarAugmentation.h>
48 #include <ogdf/augmentation/PlanarAugmentationFix.h>
49 #include <ogdf/module/ShellingOrderModule.h>
50 #include <ogdf/planarlayout/BiconnectedShellingOrder.h>
51 #include <ogdf/planarity/SimpleEmbedder.h>
56 PlanarStraightLayout::PlanarStraightLayout()
58 m_sizeOptimization
= true;
61 m_augmenter
.set(new PlanarAugmentation
);
62 m_computeOrder
.set(new BiconnectedShellingOrder
);
63 m_embedder
.set(new SimpleEmbedder
);
67 void PlanarStraightLayout::doCall(
70 GridLayout
&gridLayout
,
74 // require to have a planar graph without multi-edges and self-loops;
75 // planarity is checked below
76 OGDF_ASSERT(isSimple(G
) && isLoopFree(G
));
78 // handle special case of graphs with less than 3 nodes
79 if(G
.numberOfNodes() < 3)
82 switch(G
.numberOfNodes())
85 boundingBox
= IPoint(0,0);
90 gridLayout
.x(v1
) = gridLayout
.y(v1
) = 0;
91 boundingBox
= IPoint(0,0);
97 gridLayout
.x(v1
) = gridLayout
.y(v1
) = gridLayout
.y(v2
) = 0;
99 boundingBox
= IPoint(1,0);
104 // we make a copy of G since we use planar biconnected augmentation
105 GraphCopySimple
GC(G
);
108 // determine adjacency entry on external face of GC (if required)
109 if(adjExternal
!= 0) {
110 edge eG
= adjExternal
->theEdge();
111 edge eGC
= GC
.copy(eG
);
112 adjExternal
= (adjExternal
== eG
->adjSource()) ? eGC
->adjSource() : eGC
->adjTarget();
115 PlanarAugmentationFix augmenter
;
121 // augment graph planar biconnected
122 m_augmenter
.get().call(GC
);
124 // embed augmented graph
125 m_embedder
.get().call(GC
,adjExternal
);
128 // compute shelling order with shelling order module
129 m_computeOrder
.get().baseRatio(m_baseRatio
);
132 m_computeOrder
.get().callLeftmost(GC
,order
,adjExternal
);
134 // compute grid coordinates for GC
135 NodeArray
<int> x(GC
), y(GC
);
136 computeCoordinates(GC
,order
,x
,y
);
138 boundingBox
.m_x
= x
[order(1,order
.len(1))];
142 if(y
[v
] > boundingBox
.m_y
) boundingBox
.m_y
= y
[v
];
144 // copy coordinates from GC to G
146 node vCopy
= GC
.copy(v
);
147 gridLayout
.x(v
) = x
[vCopy
];
148 gridLayout
.y(v
) = y
[vCopy
];
153 void PlanarStraightLayout::computeCoordinates(const Graph
&G
,
158 // let c_1,...,c_q be the the current contour, then
159 // next[c_i] = c_i+1, prev[c_i] = c_i-1
160 NodeArray
<node
> next(G
), prev(G
);
162 // upper[v] = w means x-coord. of v is relative to w
163 // (abs. x-coord. of v = x[v] + abs. x-coord of w)
164 NodeArray
<node
> upper(G
,0);
166 // initialize contour with base
167 const ShellingOrderSet
&V1
= lmc
[1];
169 node v2
= V1
[V1
.len()];
172 for (i
= 1; i
<= V1
.len(); ++i
)
175 x
[V1
[i
]] = (i
== 1) ? 0 : 2;
177 next
[V1
[i
]] = V1
[i
+1];
179 prev
[V1
[i
]] = V1
[i
-1];
181 prev
[v1
] = next
[v2
] = 0;
183 // process shelling order from bottom to top
184 const int n
= lmc
.length();
186 for (k
= 2; k
<= n
; ++k
)
188 const ShellingOrderSet
&Vk
= lmc
[k
]; // Vk = { z_1,...,z_l }
191 node cl
= Vk
.left(); // left vertex
192 node cr
= Vk
.right(); // right vertex
194 // compute relative x-distance from c_i to cl for i = l+1, ..., r
197 for (v
= next
[cl
]; v
!= cr
; v
= next
[v
])
202 x_cr
+= x
[cr
]; // x_cr = abs. x-coord(cr) - abs. x-coord(cl)
205 if (m_sizeOptimization
== true)
207 // optimization: compute minimal value offset by which cr must be
211 // if there is an edge from cl to right with slope +1, or from cr
212 // to left with slope -1, then offset must be at least 2
213 offset
= (y
[cl
] < y
[next
[cl
]] || y
[cr
] < y
[prev
[cr
]]) ? 2 : 0;
215 // y_max = max { y[c_i] | l <= i <= r }
216 for (v
= cl
; v
!= cr
; v
= next
[v
]) {
221 // offset must be at least so large, such that
222 // y[z_i] > y_max for all i
223 offset
= max (offset
, 2*(yMax
+l
) - x_cr
- y
[cl
] - y
[cr
]);
225 } else // no size optimization
230 // compute insert coordinates of z_i for 1 <= i <= l
231 x
[z1
] = (x_cr
+ y
[cr
] - y
[cl
]) / 2 - l
+ 1;
232 y
[z1
] = (x_cr
+ y
[cr
] + y
[cl
]) / 2 - l
+ 1;
234 for (i
= 2; i
<= l
; i
++) {
239 // Compute shift values for cl,...,cr and relative x-coord. to a node
240 // upper[v] for inner nodes
241 // Let l <= c_alpha <= c_beta <= r max. with
242 // y[cl] > ... > y[c_alpha] and y[c_beta] < ... < y[cr]
243 // Shift c_alpha,...,c_beta by offset/2 (c_alpha,c_beta only if != cl,
245 // Shift c_beta+1,...,cr by offset
246 // x-coord. of c_l+1, ...,c_alpha relative to cl
247 // -"- c_alpha+1,...,c_beta-1 relative to z1
248 // -"- c_beta, ...,cr relative to cr
249 node c_alpha
, c_beta
;
250 if (y
[cl
] <= y
[next
[cl
]]) {
254 for (c_alpha
= next
[cl
], v
= next
[c_alpha
];
255 c_alpha
!= cr
&& y
[v
] < y
[c_alpha
];
256 c_alpha
= v
, v
= next
[v
])
262 x
[c_alpha
] += (offset
/2);
267 if (y
[cr
] <= y
[prev
[cr
]]) {
271 for (c_beta
= prev
[cr
], v
= prev
[c_beta
];
272 c_beta
!= cl
&& y
[v
] < y
[c_beta
];
273 c_beta
= v
, v
= prev
[v
])
275 x
[c_beta
] += offset
- x_cr
;
278 if (c_beta
!= cl
&& c_beta
!= c_alpha
) {
279 x
[c_beta
] += (offset
/2) - x_cr
;
284 if (c_alpha
!= c_beta
)
285 for (v
= next
[c_alpha
]; v
!= c_beta
; v
= next
[v
]) {
286 x
[v
] += (offset
/2) - x
[z1
];
290 x
[cr
] = x_cr
- (x
[z1
] + 2*(l
-1));
292 // update contour after insertion of z_1,...,z_l
293 for (i
= 1; i
<= l
; i
++)
296 next
[Vk
[i
]] = Vk
[i
+1];
298 prev
[Vk
[i
]] = Vk
[i
-1];
306 // compute final x-coordinates for the nodes on the (final) contour
308 for (node v
= v1
; v
!= 0; v
= next
[v
]) {
309 x
[v
] = (sum
+= x
[v
]);
312 // compute final x-coordinates for the inner nodes
313 for (k
= n
-1; k
>= 1; k
--)
315 for (i
= 1; i
<= lmc
.len(k
); i
++)
318 if (upper
[zi
] != 0) // upper[zi] == 0 <=> z_i on contour
319 x
[zi
] += x
[upper
[zi
]];
324 } // end namespace ogdf