Don't import ogdf namespace
[TortoiseGit.git] / ext / OGDF / src / orthogonal / CompactionConstraintGraph.cpp
blob1042034cbb77bbe071784273e4a11157fa3b03a2
1 /*
2 * $Revision: 2599 $
4 * last checkin:
5 * $Author: chimani $
6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
9 /** \file
10 * \brief Implementation of class CompactionConstraintGraphBase.
12 * Represents base class for CompactionConstraintGraph<ATYPE>
14 * \author Carsten Gutwenger
16 * \par License:
17 * This file is part of the Open Graph Drawing Framework (OGDF).
19 * \par
20 * Copyright (C)<br>
21 * See README.txt in the root directory of the OGDF installation for details.
23 * \par
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * Version 2 or 3 as published by the Free Software Foundation;
27 * see the file LICENSE.txt included in the packaging of this file
28 * for details.
30 * \par
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
36 * \par
37 * You should have received a copy of the GNU General Public
38 * License along with this program; if not, write to the Free
39 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
40 * Boston, MA 02110-1301, USA.
42 * \see http://www.gnu.org/copyleft/gpl.html
43 ***************************************************************/
46 #include <ogdf/orthogonal/CompactionConstraintGraph.h>
47 #include <ogdf/planarity/PlanRep.h>
48 #include <ogdf/basic/simple_graph_alg.h>
49 #include <ogdf/basic/extended_graph_alg.h>
51 //#define foutput
53 namespace ogdf {
56 // constructor for orthogonal representation
57 // builds constraint graph with basic arcs
58 CompactionConstraintGraphBase::CompactionConstraintGraphBase(
59 const OrthoRep &OR,
60 const PlanRep &PG,
61 OrthoDir arcDir,
62 int costGen,
63 int costAssoc,
64 bool align
65 ) :
66 m_pathNode(OR),
67 m_edgeToBasicArc(OR,0)
69 OGDF_ASSERT(&PG == &(const Graph &)OR);
71 m_path .init(*this);
72 m_cost .init(*this,costAssoc);
73 m_type .init(*this,cetBasicArc);
74 m_verticalGen .init(PG, false);
75 m_verticalArc .init(*this, false);
76 m_border .init(*this, false);
77 m_alignmentArc.init(*this, false);
78 m_pathToEdge .init(*this, 0);
79 m_originalEdge.init(*this, 0);
81 m_pPR = &PG;//only used in detecting cage visibility arcs
82 m_pOR = &OR;
83 m_align = align;
84 m_arcDir = arcDir;
85 m_oppArcDir = OR.oppDir(arcDir);
86 m_edgeCost[Graph::generalization] = costGen;
87 m_edgeCost[Graph::association ] = costAssoc;
89 edge e;
90 forall_edges(e, PG)
92 if ((PG.typeOf(e) == Graph::generalization) && (!PG.isExpansionEdge(e)))
93 m_verticalGen[e] = true;
94 }//for
96 insertPathVertices(PG);
97 insertBasicArcs(PG);
101 // insert vertex for each segment
102 void CompactionConstraintGraphBase::insertPathVertices(const PlanRep &PG)
104 NodeArray<node> genOpposite(PG,0);
106 node v;
107 forall_nodes(v,PG)
109 const OrthoRep::VertexInfoUML *vi = m_pOR->cageInfo(v);
110 if (vi == 0 || PG.typeOf(v) == Graph::generalizationMerger) continue;
112 adjEntry adjGen = vi->m_side[m_arcDir ].m_adjGen;
113 adjEntry adjOpp = vi->m_side[m_oppArcDir].m_adjGen;
114 if (adjGen != 0 && adjOpp != 0)
116 node v1 = adjGen->theNode();
117 node v2 = adjOpp->theNode();
118 genOpposite[genOpposite[v1] = v2] = v1;
122 //TODO: hier abfragen, ob Kantensegment einer Originalkante
123 //und diese hat Multikantenstatus => man muss sich die Abstaende am Rand merken
124 //und auf alle Segmente anwenden
126 NodeArray<bool> visited(PG,false);
128 forall_nodes(v,PG)
130 if (!visited[v]) {
131 node pathVertex = newNode();
133 dfsInsertPathVertex(v, pathVertex, visited, genOpposite);
135 //test for multi sep
136 //if exact two nodes in path, edge between is original edge segment,
137 //save this to recall the minsep for all segments later over original
138 //muss man hier originaledge als rueckgabe reintun???
139 if ((m_path[pathVertex].size() == 2) && m_pathToEdge[pathVertex])
142 }//if original segment
143 else m_pathToEdge[pathVertex] = 0;
149 // insert all graph vertices into segment pathVertex
150 void CompactionConstraintGraphBase::dfsInsertPathVertex(
151 node v,
152 node pathVertex,
153 NodeArray<bool> &visited,
154 const NodeArray<node> &genOpposite)
156 visited[v] = true;
157 m_path[pathVertex].pushFront(v);
158 m_pathNode[v] = pathVertex;
160 adjEntry adj;
161 forall_adj(adj,v)
163 OrthoDir dirAdj = m_pOR->direction(adj);
164 OGDF_ASSERT(dirAdj != odUndefined);
166 if (dirAdj != m_arcDir && dirAdj != m_oppArcDir) {
167 //for multiedges, only useful if only one edge considered on path
168 //maybe zero if no original edge exists
169 if (!m_pathToEdge[pathVertex])
171 //only reset later for multi edge segments
172 m_pathToEdge[pathVertex] = m_pPR->original(adj->theEdge());
173 //used for all vertices
177 node w = adj->theEdge()->opposite(v);
178 if (!visited[w])
179 dfsInsertPathVertex(w, pathVertex, visited, genOpposite);
183 node w = genOpposite[v];
184 if (w != 0 && !visited[w])
185 dfsInsertPathVertex(w, pathVertex, visited, genOpposite);
191 // insert an arc for each edge with direction m_arcDir
192 void CompactionConstraintGraphBase::insertBasicArcs(const PlanRep &PG)
194 const Graph &G = *m_pOR;
196 node v;
197 forall_nodes(v,G)
199 node start = m_pathNode[v];
201 adjEntry adj;
202 forall_adj(adj,v) {
203 if (m_pOR->direction(adj) == m_arcDir) {
204 edge e = newEdge(start, m_pathNode[adj->theEdge()->opposite(v)]);
205 m_edgeToBasicArc[adj] = e;
207 m_cost[e] = m_edgeCost[PG.typeOf(adj->theEdge())];
209 //try to pull nodes up in hierarchies
210 if ( (PG.typeOf(adj->theEdge()) == Graph::generalization) &&
211 (PG.typeOf(adj->theEdge()->target()) == Graph::generalizationExpander) &&
212 !(PG.isExpansionEdge(adj->theEdge()))
215 if (m_align)
217 //got to be higher than vertexarccost*doublebendfactor
218 m_cost[e] = 4000*m_cost[e]; //use parameter later corresponding
219 m_alignmentArc[e] = true;
220 }//if align
221 //to compconsgraph::doublebendfactor
222 else m_cost[e] = 2*m_cost[e];
225 //set generalization type
226 if (verticalGen(adj->theEdge())) m_verticalArc[e] = true;
227 //set onborder
228 if (PG.isDegreeExpansionEdge(adj->theEdge()))
230 edge borderE = adj->theEdge();
231 node v1 = borderE->source();
232 node v2 = borderE->target();
233 m_border[e] = ((v1->degree()>2) && (v2->degree()>2) ? 2 : 1);
242 // embeds constraint graph such that all sources and sinks lie in a common
243 // face
244 void CompactionConstraintGraphBase::embed()
246 NodeArray<bool> onExternal(*this,false);
247 const CombinatorialEmbedding &E = *m_pOR;
248 face fExternal = E.externalFace();
250 adjEntry adj;
251 forall_face_adj(adj,fExternal)
252 onExternal[m_pathNode[adj->theNode()]] = true;
254 // compute lists of sources and sinks
255 SList<node> sources, sinks;
257 node v;
258 forall_nodes(v,*this) {
259 if (onExternal[v]) {
260 if (v->indeg() == 0)
261 sources.pushBack(v);
262 if (v->outdeg() == 0)
263 sinks.pushBack(v);
267 #ifdef foutput
268 writeGML("c:\\temp\\CCgraphbefore.gml", onExternal);
269 #endif
271 // determine super source and super sink
272 node s,t;
273 if (sources.size() > 1)
275 s = newNode();
276 SListIterator<node> it;
277 for (it = sources.begin(); it.valid(); it++)
278 newEdge(s,*it);
280 else
281 s = sources.front();
283 if (sinks.size() > 1)
285 t = newNode();
286 SListIterator<node> it;
287 for (it = sinks.begin(); it.valid(); it++)
288 newEdge(*it,t);
290 else
291 t = sinks.front();
293 edge st = newEdge(s,t);
295 #ifdef foutput
296 writeGML(String("c:\\temp\\CCgraph%d.gml"));//,randomNumber(0,20)));
297 writeGML("c:\\temp\\CClastgraph.gml");
298 #endif
300 bool isPlanar = planarEmbed(*this);
301 if (!isPlanar) OGDF_THROW(AlgorithmFailureException);
304 delEdge(st);
305 if (sources.size() > 1)
306 delNode(s);
307 if (sinks.size() > 1)
308 delNode(t);
312 // computes topological numbering on the segments of the constraint graph.
313 // Usage: If used on the basic (and vertex size) arcs, the numbering can be
314 // used in order to serve as sorting criteria for respecting the given
315 // embedding, e.g., when computing visibility arcs and allowing edges
316 // with length 0.
317 void CompactionConstraintGraphBase::computeTopologicalSegmentNum(
318 NodeArray<int> &topNum)
320 NodeArray<int> indeg(*this);
321 StackPure<node> sources;
323 node v;
324 forall_nodes(v,*this) {
325 topNum[v] = 0;
326 indeg[v] = v->indeg();
327 if(indeg[v] == 0)
328 sources.push(v);
331 while(!sources.empty())
333 node v = sources.pop();
335 edge e;
336 forall_adj_edges(e,v) {
337 if(e->source() != v) continue;
339 node w = e->target();
341 if (topNum[w] < topNum[v] + 1)
342 topNum[w] = topNum[v] + 1;
344 if (--indeg[w] == 0)
345 sources.push(w);
352 class BucketFirstIndex : public BucketFunc<Tuple2<node,node> >
354 public:
355 int getBucket(const Tuple2<node,node> &t) {
356 return t.x1()->index();
360 class BucketSecondIndex : public BucketFunc<Tuple2<node,node> >
362 public:
363 int getBucket(const Tuple2<node,node> &t) {
364 return t.x2()->index();
369 // remove "arcs" from visibArcs which we already have in the constraint graph
370 // (as basic arcs)
371 void CompactionConstraintGraphBase::removeRedundantVisibArcs(
372 SListPure<Tuple2<node,node> > &visibArcs)
374 // bucket sort list of all edges
375 SListPure<edge> all;
376 allEdges(all);
377 parallelFreeSort(*this,all);
379 // bucket sort visibArcs
380 BucketFirstIndex bucketSrc;
381 visibArcs.bucketSort(0,maxNodeIndex(),bucketSrc);
383 BucketSecondIndex bucketTgt;
384 visibArcs.bucketSort(0,maxNodeIndex(),bucketTgt);
386 // now, in both lists, arcs are sorted by increasing target index,
387 // and arcs with the same target index by increasing source index.
388 SListConstIterator<edge> itAll = all.begin();
389 SListIterator<Tuple2<node,node> > it, itNext, itPrev;
391 // for each arc in visibArcs, we check if it is also contained in list all
392 for(it = visibArcs.begin(); it.valid(); it = itNext)
394 // required since we delete from the list we traverse
395 itNext = it.succ();
396 int i = (*it).x1()->index();
397 int j = (*it).x2()->index();
399 // skip all arcs with smaller target index
400 while(itAll.valid() && (*itAll)->target()->index() < j)
401 ++itAll;
403 // no more arcs => no more duplicates, so return
404 if (!itAll.valid()) break;
406 // if target index is j, we also skip all arcs with target index i
407 // and source index smaller than i
408 while(itAll.valid() && (*itAll)->target()->index() == j && (*itAll)->source()->index() < i)
409 ++itAll;
411 // no more arcs => no more duplicates, so return
412 if (!itAll.valid()) break;
414 // if (i,j) is already present, we delete it from visibArcs
415 if ((*itAll)->source()->index() == i &&
416 (*itAll)->target()->index() == j)
418 //visibArcs.del(it);
419 if (itPrev.valid())
420 visibArcs.delSucc(itPrev);
421 else
422 visibArcs.popFront();
423 } else
424 itPrev = it;
425 }//for visibArcs
427 //****************************CHECK for
428 //special treatment for cage visibility
429 //two cases: input node cage: just compare arbitrary node
430 // merger cage: check first if there are mergers
431 itPrev = 0;
432 for(it = visibArcs.begin(); it.valid(); it = itNext)
435 itNext = it.succ();
437 OGDF_ASSERT(!(m_path[(*it).x1()].empty()) && !(m_path[(*it).x1()].empty()));
439 node boundRepresentant1 = m_path[(*it).x1()].front();
440 node boundRepresentant2 = m_path[(*it).x2()].front();
441 node en1 = m_pPR->expandedNode(boundRepresentant1);
442 node en2 = m_pPR->expandedNode(boundRepresentant2);
443 //do not allow visibility constraints in fixed cages
444 //due to non-planarity with middle position constraints
446 if ( ( en1 && en2 ) && ( en1 == en2) )
448 if (itPrev.valid()) visibArcs.delSucc(itPrev);
449 else visibArcs.popFront();
451 else
453 //check if its a genmergerspanning vis arc, merge cases later
454 node firstn = 0, secondn = 0;
455 SListIterator< node > itn;
456 for (itn = m_path[(*it).x1()].begin(); itn.valid(); itn++)
458 node en = m_pPR->expandedNode(*itn);
459 if (!en) continue;
460 if (!(m_pPR->typeOf(*itn) == Graph::generalizationExpander)) continue;
461 else {firstn = en; break;}
462 }//for
463 for (itn = m_path[(*it).x2()].begin(); itn.valid(); itn++)
465 node en = m_pPR->expandedNode(*itn);
466 if (!en) continue;
467 if (!(m_pPR->typeOf(*itn) == Graph::generalizationExpander)) continue;
468 else {secondn = en; break;}
469 }//for
470 if ((firstn && secondn) && (firstn == secondn))
472 if (itPrev.valid()) visibArcs.delSucc(itPrev);
473 else visibArcs.popFront();
475 else itPrev = it;
477 }//for visibArcs
483 // output in gml-format with special edge colouring
484 // arcs with cost 0 are green, other arcs red
485 void CompactionConstraintGraphBase::writeGML(const char *filename) const
487 ofstream os(filename);
488 writeGML(os);
490 void CompactionConstraintGraphBase::writeGML(const char *filename, NodeArray<bool> one) const
492 ofstream os(filename);
493 writeGML(os, one);
496 void CompactionConstraintGraphBase::writeGML(ostream &os) const
498 const Graph &G = *this;
500 NodeArray<int> id(*this);
501 int nextId = 0;
503 os.setf(ios::showpoint);
504 os.precision(10);
506 os << "Creator \"ogdf::CompactionConstraintGraphBase::writeGML\"\n";
507 os << "graph [\n";
508 os << " directed 1\n";
510 node v;
511 forall_nodes(v,G) {
512 os << " node [\n";
514 os << " id " << (id[v] = nextId++) << "\n";
516 os << " graphics [\n";
517 os << " x 0.0\n";
518 os << " y 0.0\n";
519 os << " w 30.0\n";
520 os << " h 30.0\n";
522 os << " fill \"#FFFF00\"\n";
523 os << " ]\n"; // graphics
525 os << " ]\n"; // node
529 edge e;
530 forall_edges(e,G) {
531 os << " edge [\n";
533 os << " source " << id[e->source()] << "\n";
534 os << " target " << id[e->target()] << "\n";
536 // nice idea to use the edge length as edge labels, but Graphwin-
537 // garbage is not able to show the graph (thinks it has to set
538 // the y-coordinates of all nodes to NAN)
539 #if 0
540 os << " label \"";
541 writeLength(os,e);
542 os << "\"\n";
543 #endif
545 os << " graphics [\n";
547 os << " type \"line\"\n";
548 os << " arrow \"last\"\n";
549 switch(m_type[e])
551 case cetBasicArc: // red
552 os << " fill \"#FF0000\"\n";
553 break;
554 case cetVertexSizeArc: // blue
555 os << " fill \"#0000FF\"\n";
556 break;
557 case cetVisibilityArc: // green
558 os << " fill \"#00FF00\"\n";
559 break;
560 case cetReducibleArc: // rose
561 os << " fill \"#FF00FF\"\n";
562 break;
563 case cetFixToZeroArc: //violett
564 os << " fill \"#3F00FF\"\n";
565 break;
566 OGDF_NODEFAULT
569 os << " ]\n"; // graphics
571 #if 0
572 os << " LabelGraphics [\n";
573 os << " type \"text\"\n";
574 os << " fill \"#000000\"\n";
575 os << " anchor \"w\"\n";
576 os << " ]\n";
577 #endif
579 os << " ]\n"; // edge
582 os << "]\n"; // graph
583 }//writegml
585 void CompactionConstraintGraphBase::writeGML(ostream &os, NodeArray<bool> one) const
587 const Graph &G = *this;
589 NodeArray<int> id(*this);
590 int nextId = 0;
592 os.setf(ios::showpoint);
593 os.precision(10);
595 os << "Creator \"ogdf::CompactionConstraintGraphBase::writeGML\"\n";
596 os << "graph [\n";
597 os << " directed 1\n";
599 node v;
600 forall_nodes(v,G) {
601 os << " node [\n";
603 os << " id " << (id[v] = nextId++) << "\n";
605 os << " graphics [\n";
606 os << " x 0.0\n";
607 os << " y 0.0\n";
608 os << " w 30.0\n";
609 os << " h 30.0\n";
610 if ((one[v])) {
611 os << " fill \"#FF0F0F\"\n";
612 } else {
613 os << " fill \"#FFFF00\"\n";
615 os << " ]\n"; // graphics
617 os << " ]\n"; // node
621 edge e;
622 forall_edges(e,G) {
623 os << " edge [\n";
625 os << " source " << id[e->source()] << "\n";
626 os << " target " << id[e->target()] << "\n";
628 // nice idea to use the edge length as edge labels, but Graphwin-
629 // garbage is not able to show the graph (thinks it has to set
630 // the y-coordinates of all nodes to NAN)
631 #if 0
632 os << " label \"";
633 writeLength(os,e);
634 os << "\"\n";
635 #endif
637 os << " graphics [\n";
639 os << " type \"line\"\n";
640 os << " arrow \"last\"\n";
641 switch(m_type[e])
643 case cetBasicArc: // red
644 os << " fill \"#FF0000\"\n";
645 break;
646 case cetVertexSizeArc: // blue
647 os << " fill \"#0000FF\"\n";
648 break;
649 case cetVisibilityArc: // green
650 os << "fill \"#00FF00\"\n";
651 break;
652 case cetReducibleArc: // rose
653 os << " fill \"#FF00FF\"\n";
654 break;
655 case cetFixToZeroArc: //violett
656 os << " fill \"#3F00FF\"\n";
657 break;
658 OGDF_NODEFAULT
661 os << " ]\n"; // graphics
663 #if 0
664 os << " LabelGraphics [\n";
665 os << " type \"text\"\n";
666 os << " fill \"#000000\"\n";
667 os << " anchor \"w\"\n";
668 os << " ]\n";
669 #endif
671 os << " ]\n"; // edge
674 os << "]\n"; // graph
678 } // end namespace ogdf