6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
10 * \brief implementation of the wrapper class of the Boyer-Myrvold planarity test
12 * \author Jens Schmidt
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/planarity/BoyerMyrvold.h>
45 #include <ogdf/planarity/ExtractKuratowskis.h>
51 // returns true, if g is planar, false otherwise. this is the
52 // routine, which avoids the overhead of copying the input graph.
53 // it is therefore not suitable, if your graph must not be changed.
54 bool BoyerMyrvold::isPlanarDestructive(Graph
& g
)
59 // less than 9 edges are always planar
60 if (g
.numberOfEdges() < 9) return true;
62 SListPure
<KuratowskiStructure
> dummy
;
63 pBMP
= new BoyerMyrvoldPlanar(g
,false,BoyerMyrvoldPlanar::doNotEmbed
,false,
69 // returns true, if g is planar, false otherwise.
70 // use this slower routine, if your graph must not be changed.
71 bool BoyerMyrvold::isPlanar(const Graph
& g
)
76 // less than 9 edges are always planar
77 if (g
.numberOfEdges() < 9) return true;
80 SListPure
<KuratowskiStructure
> dummy
;
81 pBMP
= new BoyerMyrvoldPlanar(h
,false,BoyerMyrvoldPlanar::doNotEmbed
,false,
87 // Transforms KuratowskiWrapper in KuratowskiSubdivision
88 void BoyerMyrvold::transform(
89 const KuratowskiWrapper
& source
,
90 KuratowskiSubdivision
& target
,
91 NodeArray
<int>& count
,
92 EdgeArray
<int>& countEdge
)
94 // init linear counting structure
97 SListConstIterator
<edge
> itE
;
98 for (itE
= source
.edgeList
.begin(); itE
.valid(); ++itE
) {
100 OGDF_ASSERT(!countEdge
[e
]);
102 if (++count
[e
->source()] == 3) kn
[k
++] = e
->source();
103 if (++count
[e
->target()] == 3) kn
[k
++] = e
->target();
106 // transform edgelist of KuratowskiSubdivision to KuratowskiWrapper
107 OGDF_ASSERT(k
==5 || k
==6);
114 for (int k
= 0; k
<5; k
++) {
115 forall_adj_edges(e
,kn
[k
]) {
116 if (!countEdge
[e
]) continue;
119 // traverse degree-2-path
120 while (count
[n
= f
->opposite(n
)] == 2) {
122 forall_adj_edges(h
,n
) {
123 if (countEdge
[h
] && h
!= f
) {
131 while (kn
[i
] != n
) i
++;
142 int touched
[6] = { -1, -1, -1, -1, -1, -1}, t
=0, i
=0;
143 for (int k
= 0; k
<6; k
++) {
144 if (touched
[k
] != -1) continue;
145 forall_adj_edges(e
,kn
[k
]) {
146 if (!countEdge
[e
]) continue;
149 while(count
[n
= f
->opposite(n
)] == 2) {
151 forall_adj_edges(h
,n
) {
152 if (countEdge
[h
] && h
!= f
) {
160 while (kn
[j
] != n
) j
++;
161 if (touched
[j
] == -1)
163 target
[i
*3 + touched
[j
]].conc(L
);
169 // destruct linear counting structure
170 for (itE
= source
.edgeList
.begin(); itE
.valid(); ++itE
) {
173 count
[e
->source()] = 0;
174 count
[e
->target()] = 0;
178 // Transforms KuratowskiWrapper-List in KuratowskiSubdivision-List with respect to sieving constraints
179 void BoyerMyrvold::transform(
180 const SList
<KuratowskiWrapper
>& sourceList
,
181 SList
<KuratowskiSubdivision
>& targetList
,
183 const bool onlyDifferent
)
185 if (sourceList
.empty()) return;
187 NodeArray
<int> count(g
,0);
188 EdgeArray
<int> countEdge(g
,0);
189 SListConstIterator
<KuratowskiWrapper
> it
;
190 node lastEmbeddedVertex
= NULL
;
192 // transform each KuratowskiWrapper into KuratowskiSubdivision
193 for (it
= sourceList
.begin(); it
.valid(); ++it
) {
194 if (!onlyDifferent
|| (*it
).V
!= lastEmbeddedVertex
) {
195 lastEmbeddedVertex
= (*it
).V
;
196 KuratowskiSubdivision s
;
197 transform(*it
,s
,count
,countEdge
);
199 targetList
.pushBack(s
);
204 // returns true, if g is planar, false otherwise. in addition,
205 // g contains a planar embedding, if planar. if not planar,
206 // kuratowski subdivisions are added to output.
207 // use this function, if g may be changed.
208 // use embeddingGrade to bound the overall number of extracted kuratowski subdivisions;
209 // use the value 0 to extract no kuratowski subdivision and the value -1 to find as much
210 // as possible. value -2 doesn't even invoke the FIND-procedure.
211 bool BoyerMyrvold::planarEmbedDestructive(
213 SList
<KuratowskiWrapper
>& output
,
216 bool limitStructures
,
220 OGDF_ASSERT(embeddingGrade
!= BoyerMyrvoldPlanar::doNotEmbed
);
223 SListPure
<KuratowskiStructure
> dummy
;
224 pBMP
= new BoyerMyrvoldPlanar(g
,bundles
,embeddingGrade
,limitStructures
,dummy
,
225 randomDFSTree
,avoidE2Minors
);
226 bool planar
= pBMP
->start();
227 OGDF_ASSERT(!planar
|| g
.genus()==0);
229 nOfStructures
= dummy
.size();
231 // Kuratowski extraction
232 if (embeddingGrade
> BoyerMyrvoldPlanar::doFindZero
||
233 embeddingGrade
== BoyerMyrvoldPlanar::doFindUnlimited
) {
234 ExtractKuratowskis
extract(*pBMP
);
236 extract
.extractBundles(dummy
,output
);
238 extract
.extract(dummy
,output
);
240 OGDF_ASSERT(planar
|| !output
.empty());
245 // returns true, if g is planar, false otherwise. in addition,
246 // h contains a planar embedding, if planar. if not planar, list
247 // contains a kuratowski subdivision.
248 // use this slower function, if g must not be changed.
249 // use embeddingGrade to bound the overall number of extracted kuratowski subdivisions;
250 // use the value 0 to extract no kuratowski subdivision and the value -1 to find as much
251 // as possible. value -2 doesn't even invoke the FIND-procedure.
252 bool BoyerMyrvold::planarEmbed(
254 SList
<KuratowskiWrapper
>& output
,
257 bool limitStructures
,
261 OGDF_ASSERT(embeddingGrade
!= BoyerMyrvoldPlanar::doNotEmbed
);
264 GraphCopySimple
h(g
);
265 SListPure
<KuratowskiStructure
> dummy
;
266 pBMP
= new BoyerMyrvoldPlanar(h
,bundles
,embeddingGrade
,limitStructures
,dummy
,
267 randomDFSTree
,avoidE2Minors
);
268 bool planar
= pBMP
->start();
269 OGDF_ASSERT(!planar
|| h
.genus()==0);
271 nOfStructures
= dummy
.size();
273 // Kuratowski extraction
274 if (embeddingGrade
> BoyerMyrvoldPlanar::doFindZero
||
275 embeddingGrade
== BoyerMyrvoldPlanar::doFindUnlimited
) {
276 ExtractKuratowskis
extract(*pBMP
);
278 extract
.extractBundles(dummy
,output
);
280 extract
.extract(dummy
,output
);
282 OGDF_ASSERT(planar
|| !output
.empty());
284 // convert kuratowski edges in original graph edges
285 if (!output
.empty()) {
286 SListIterator
<KuratowskiWrapper
> it
;
287 SListIterator
<edge
> itE
;
288 for (it
= output
.begin(); it
.valid(); ++it
) {
289 for (itE
= (*it
).edgeList
.begin(); itE
.valid(); ++itE
)
290 (*itE
) = h
.original(*itE
);
295 // copy adjacency lists, if planar
299 SListPure
<adjEntry
> entries
;
302 forall_adj(adj
,h
.copy(v
)) {
303 OGDF_ASSERT(adj
->theNode() == h
.copy(v
));
304 edge e
= h
.original(adj
->theEdge());
305 OGDF_ASSERT(e
->graphOf() == &g
);
306 //if (e->source() == v) {
307 if(adj
== adj
->theEdge()->adjSource()) {
308 entries
.pushBack(e
->adjSource());
309 OGDF_ASSERT(e
->adjSource()->theNode() == v
);
311 entries
.pushBack(e
->adjTarget());
312 OGDF_ASSERT(e
->adjTarget()->theNode() == v
);
322 // returns true, if graph copy h is planar, false otherwise. in addition,
323 // h contains a planar embedding, if planar. if not planar, list
324 // contains a kuratowski subdivision.
325 // use this slower function, if g must not be changed.
326 // use embeddingGrade to bound the overall number of extracted kuratowski subdivisions;
327 // use the value 0 to extract no kuratowski subdivision and the value -1 to find as much
328 // as possible. value -2 doesn't even invoke the FIND-procedure.
329 bool BoyerMyrvold::planarEmbed(
332 SList
<KuratowskiWrapper
>& output
,
335 bool limitStructures
,
339 OGDF_ASSERT(embeddingGrade
!= BoyerMyrvoldPlanar::doNotEmbed
);
342 //OGDF_ASSERT(&h.original() == &g);
343 SListPure
<KuratowskiStructure
> dummy
;
344 pBMP
= new BoyerMyrvoldPlanar(h
,bundles
,embeddingGrade
,limitStructures
,dummy
,
345 randomDFSTree
,avoidE2Minors
);
346 bool planar
= pBMP
->start();
347 OGDF_ASSERT(!planar
|| h
.genus()==0);
349 nOfStructures
= dummy
.size();
351 // Kuratowski extraction
352 if (embeddingGrade
> BoyerMyrvoldPlanar::doFindZero
||
353 embeddingGrade
== BoyerMyrvoldPlanar::doFindUnlimited
) {
354 ExtractKuratowskis
extract(*pBMP
);
356 extract
.extractBundles(dummy
,output
);
358 extract
.extract(dummy
,output
);
360 OGDF_ASSERT(planar
|| !output
.empty());
362 // convert kuratowski edges in original graph edges
363 if (!output
.empty()) {
364 SListIterator
<KuratowskiWrapper
> it
;
365 SListIterator
<edge
> itE
;
366 for (it
= output
.begin(); it
.valid(); ++it
) {
367 for (itE
= (*it
).edgeList
.begin(); itE
.valid(); ++itE
)
368 (*itE
) = h
.original(*itE
);