Prefer to use VS2013 for compiling and testing on AppVeyor
[TortoiseGit.git] / ext / OGDF / src / planarity / PlanRep.cpp
blob8c6b8b7b51618bcc1423197624b624314f983689
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 PlanRep base class for planar rep.
12 * \author Karsten Klein
14 * \par License:
15 * This file is part of the Open Graph Drawing Framework (OGDF).
17 * \par
18 * Copyright (C)<br>
19 * See README.txt in the root directory of the OGDF installation for details.
21 * \par
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
26 * for details.
28 * \par
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.
34 * \par
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/basic/simple_graph_alg.h>
46 #include <ogdf/basic/extended_graph_alg.h>
48 #include <ogdf/planarity/PlanRep.h>
51 namespace ogdf {
53 PlanRep::PlanRep(const Graph& AG) :
54 GraphCopy(),
55 m_pGraphAttributes(NULL),
56 m_boundaryAdj(AG, 0),//*this, 0),
57 m_oriEdgeTypes(AG, 0),
58 m_eAuxCopy(AG)
60 m_vType .init(*this, Graph::dummy);
61 m_nodeTypes .init(*this, 0); //the new node type info
62 m_expandedNode .init(*this, 0);
63 m_expandAdj .init(*this, 0);
64 m_expansionEdge.init(*this, 0);
65 m_eType .init(*this, Graph::association); //should be dummy or standard, but isnt checked correctly,
66 m_edgeTypes .init(*this, 0); //the new edge type info
68 const Graph &G = AG;
70 // special way of initializing GraphCopy; we start with an empty copy
71 // and add components by need
72 GraphCopy::createEmpty(G);
74 // compute connected component of G
75 NodeArray<int> component(G);
76 m_numCC = connectedComponents(G,component);
78 // intialize the array of lists of nodes contained in a CC
79 m_nodesInCC.init(m_numCC);
81 node v;
82 forall_nodes(v,G)
83 m_nodesInCC[component[v]].pushBack(v);
85 m_currentCC = -1; // not yet initialized
89 PlanRep::PlanRep(const GraphAttributes& AG) :
90 GraphCopy(),
91 m_pGraphAttributes(&AG),
92 m_boundaryAdj(AG.constGraph(), 0),
93 m_oriEdgeTypes(AG.constGraph(), 0),
94 m_eAuxCopy(AG.constGraph())
96 m_vType .init(*this,Graph::dummy);
97 m_nodeTypes .init(*this, 0); //the new node type info
98 m_expandedNode .init(*this,0);
99 m_expandAdj .init(*this,0);
100 m_expansionEdge.init(*this, 0);
101 m_eType .init(*this, Graph::association); //should be dummy or standard, but isnt checked correctly,
102 m_edgeTypes .init(*this, 0); //the new edge type info
104 const Graph &G = AG.constGraph();
106 // special way of initializing GraphCopy; we start with an empty copy
107 // and add components by need
108 GraphCopy::createEmpty(G);
110 // compute connected component of G
111 NodeArray<int> component(G);
112 m_numCC = connectedComponents(G,component);
114 // intialize the array of lists of nodes contained in a CC
115 m_nodesInCC.init(m_numCC);
117 node v;
118 forall_nodes(v,G)
119 m_nodesInCC[component[v]].pushBack(v);
121 m_currentCC = -1; // not yet initialized
122 }//PlanRep
125 void PlanRep::initCC(int i)
127 // delete copy / chain fields for originals of nodes in current cc
128 // (since we remove all these copies in initByNodes(...)
129 if (m_currentCC >= 0)
131 const List<node> &origInCC = nodesInCC(i);
132 ListConstIterator<node> itV;
134 for(itV = origInCC.begin(); itV.valid(); ++itV) {
135 node vG = *itV;
137 m_vCopy[vG] = 0;
139 adjEntry adj;
140 forall_adj(adj,vG) {
141 if ((adj->index() & 1) == 0) continue;
142 edge eG = adj->theEdge();
144 m_eCopy[eG].clear();
149 m_currentCC = i;
150 GraphCopy::initByNodes(m_nodesInCC[i], m_eAuxCopy);
152 // set type of edges (gen. or assoc.) in the current CC
153 edge e;
154 forall_edges(e,*this)
155 setCopyType(e, original(e));
157 if(m_pGraphAttributes == 0)
158 return;
160 // The following part is only relevant with given graph attributes!
162 node v;
163 forall_nodes(v,*this)
165 m_vType[v] = m_pGraphAttributes->type(original(v));
166 if (m_pGraphAttributes->isAssociationClass(original(v))) {
167 OGDF_ASSERT(v->degree() == 1)
168 edge e = v->firstAdj()->theEdge();
169 setAssClass(e);
172 }//initCC
175 //inserts Boundary for a given group of nodes
176 //can e.g. be used to split clique replacements from the rest of the graph
177 //precondition: is only applicable for planar embedded subgraphs
179 //void PlanRep::insertBoundary(List<node> &group)
181 //TODO
182 //Difficulty: efficiently find the outgoing edges
184 //special version for stars
185 //works on copy nodes
186 //precondition: center is the center of a star-like subgraph
187 //induced by the neighbours of center, subgraph has connection
188 //to the rest of the graph
189 //keeps the given embedding
190 void PlanRep::insertBoundary(node centerOrig, adjEntry& adjExternal)//, CombinatorialEmbedding &E)
192 //we insert edges to represent the boundary
193 //by splitting the outgoing edges and connecting the
194 //split nodes
195 node center = copy(centerOrig);
196 OGDF_ASSERT(center)
198 if (center->degree() < 1) return;
200 OGDF_ASSERT(original(center))
202 //---------------------------
203 //retrieve the outgoing edges
204 //we run over all nodes adjacent to center and add their
205 //adjacent edges
206 SList<adjEntry> outAdj;
208 adjEntry adj;
209 forall_adj(adj, center)
211 //--------------------------------------------------------------
212 //check if external face was saved over adjEntry on center edges
214 //we want to stay in the same (external) face, next adjEntry
215 //may get split later on, succ(succ) can never be within this clique
216 //(and split) because all clique node - clique node connections are deleted
217 //IFF the target node is connnected to some non-clique part of the graph
218 //the search in this case would loop if there is no connection to the rest of
219 //the graph
220 if (adjExternal == adj) //outgoing
222 if (adj->twinNode()->degree() == 1)
224 do {
225 adjExternal = adjExternal->faceCycleSucc();
226 } while ( (adjExternal->theNode() == center) ||
227 (adjExternal->twinNode() == center));
228 }//if degree 1
229 else
230 adjExternal = adjExternal->faceCycleSucc()->faceCycleSucc();
232 if (adjExternal == adj->twin()) //incoming
234 if (adj->twinNode()->degree() == 1)
236 do {
237 adjExternal = adjExternal->faceCycleSucc();
238 } while ( (adjExternal->theNode() == center) ||
239 (adjExternal->twinNode() == center));
240 }//if degree 1
241 else
242 adjExternal = adjExternal->faceCyclePred()->faceCyclePred();
244 adjEntry stopper = adj->twin();
245 adjEntry runner = stopper->cyclicSucc();
246 while (runner != stopper)
248 outAdj.pushBack(runner);
249 runner = runner->cyclicSucc();
250 }//while
252 }//foralladj of center
254 //we do not insert a boundary if the subgraph is not
255 //connected to the rest of the graph
256 if (outAdj.empty()) return;
258 //---------------------------------------
259 //now split the edges and save adjEntries
260 //we maintain two lists of adjentries
261 List<adjEntry> targetEntries, sourceEntries;
263 //we need to find out if edge is outgoing
264 bool isOut = false;
265 SListIterator<adjEntry> it = outAdj.begin();
266 while (it.valid())
268 //outgoing edges of clique nodes
269 adjEntry splitAdj = (*it);
271 edge splitEdge = splitAdj->theEdge();
273 isOut = (splitAdj->theNode() == splitEdge->source());
275 //-------------------------------------------------------
276 //check if external face was saved over edges to be split
277 bool splitOuter = false;
278 bool splitInner = false;
279 if (adjExternal == splitAdj)
281 splitOuter = true;
282 //adjExternal = adjExternal->faceCycleSucc();
284 if (adjExternal == splitAdj->twin())
286 splitInner = true;
287 //adjExternal = adjExternal->faceCyclePred();
291 //combinatorial version
292 //edge newEdge = E.split(splitEdge);
293 //simple version
294 edge newEdge = split(splitEdge);
295 setCrossingType(newEdge->source());
297 //store the adjEntries depending on in/out direction
298 if (isOut)
300 //splitresults "upper" edge to old target node is newEdge!
301 sourceEntries.pushBack(newEdge->adjSource());
302 targetEntries.pushBack(splitEdge->adjTarget());
303 if (splitOuter) adjExternal = newEdge->adjSource();
304 if (splitInner) adjExternal = newEdge->adjTarget();
305 }//if outgoing
306 else
308 sourceEntries.pushBack(splitEdge->adjTarget());
309 targetEntries.pushBack(newEdge->adjSource());
310 if (splitOuter) adjExternal = splitEdge->adjTarget();
311 if (splitInner) adjExternal = splitEdge->adjSource();
312 }//else outgoing
314 //go on with next edge
315 it++;
317 }//while outedges
320 //we need pairs of adjEntries
321 OGDF_ASSERT(targetEntries.size() == sourceEntries.size());
322 //now flip first target entry to front
323 //should be nonempty
324 adjEntry flipper = targetEntries.popFrontRet();
325 targetEntries.pushBack(flipper);
327 edge e;
329 //connect the new nodes to form the boundary
330 while (!targetEntries.empty())
332 //combinatorial version
333 //edge e = E.splitFace(sourceEntries.popFrontRet(), targetEntries.popFrontRet());
334 //simple version
335 e = newEdge(sourceEntries.popFrontRet(), targetEntries.popFrontRet());
336 this->typeOf(e) = Graph::association;
337 setCliqueBoundary(e);
340 //keep it simple: just assign the last adjEntry to boundaryAdj
341 //we have to save at the original, the copy may be replaced
342 OGDF_ASSERT(m_boundaryAdj[original(center)] == 0)
343 m_boundaryAdj[original(center)] = e->adjSource();
345 }//insertBoundary
348 //*****************************************************************************
349 //embedding and crossings
351 bool PlanRep::embed()
353 return planarEmbed(*this);
356 void PlanRep::removeUnnecessaryCrossing(
357 adjEntry adjA1,
358 adjEntry adjA2,
359 adjEntry adjB1,
360 adjEntry adjB2)
362 node v = adjA1->theNode();
364 if(adjA1->theEdge()->source() == v)
365 moveSource(adjA1->theEdge(), adjA2->twin(), before);
366 else
367 moveTarget(adjA1->theEdge(), adjA2->twin(), before);
369 if(adjB1->theEdge()->source() == v)
370 moveSource(adjB1->theEdge(), adjB2->twin(), before);
371 else
372 moveTarget(adjB1->theEdge(), adjB2->twin(), before);
374 edge eOrigA = original(adjA1->theEdge());
375 edge eOrigB = original(adjB1->theEdge());
377 if (eOrigA != 0)
378 m_eCopy[eOrigA].del(m_eIterator[adjA2->theEdge()]);
379 if (eOrigB != 0)
380 m_eCopy[eOrigB].del(m_eIterator[adjB2->theEdge()]);
382 delEdge(adjB2->theEdge());
383 delEdge(adjA2->theEdge());
385 delNode(v);
388 void PlanRep::removePseudoCrossings()
390 node v, vSucc;
391 for(v = firstNode(); v != 0; v = vSucc)
393 vSucc = v->succ();
395 if (typeOf(v) != PlanRep::dummy || v->degree() != 4)
396 continue;
398 adjEntry adj1 = v->firstAdj();
399 adjEntry adj2 = adj1->succ();
400 adjEntry adj3 = adj2->succ();
401 adjEntry adj4 = adj3->succ();
403 if(original(adj1->theEdge()) == original(adj2->theEdge()))
404 removeUnnecessaryCrossing(adj1,adj2,adj3,adj4);
405 else if (original(adj2->theEdge()) == original(adj3->theEdge()))
406 removeUnnecessaryCrossing(adj2,adj3,adj4,adj1);
410 void PlanRep::insertEdgePathEmbedded(
411 edge eOrig,
412 CombinatorialEmbedding &E,
413 const SList<adjEntry> &crossedEdges)
415 GraphCopy::insertEdgePathEmbedded(eOrig,E,crossedEdges);
416 Graph::EdgeType edgeType = m_pGraphAttributes ?
417 m_pGraphAttributes->type(eOrig) : Graph::association;
419 long et = m_oriEdgeTypes[eOrig];
421 ListConstIterator<edge> it;
422 for(it = chain(eOrig).begin(); it.valid(); ++it)
424 m_eType[*it] = edgeType;
425 m_edgeTypes[*it] = et;
426 if (!original((*it)->target()))
428 OGDF_ASSERT((*it)->target()->degree() == 4)
429 OGDF_ASSERT(it != chain(eOrig).rbegin())
430 setCrossingType((*it)->target());
435 void PlanRep::insertEdgePath(
436 edge eOrig,
437 const SList<adjEntry> &crossedEdges)
439 GraphCopy::insertEdgePath(eOrig,crossedEdges);
441 //old types
442 Graph::EdgeType edgeType = m_pGraphAttributes ?
443 m_pGraphAttributes->type(eOrig) : Graph::association;
445 //new types
446 long et = m_oriEdgeTypes[eOrig];
448 ListConstIterator<edge> it;
449 for(it = chain(eOrig).begin(); it.valid(); ++it)
451 m_eType[*it] = edgeType;
452 m_edgeTypes[*it] = et;
453 if (!original((*it)->target()))
455 OGDF_ASSERT((*it)->target()->degree() == 4)
456 setCrossingType((*it)->target());
461 edge PlanRep::insertCrossing(
462 edge &crossingEdge,
463 edge crossedEdge,
464 bool topDown)
466 EdgeType eTypi = m_eType[crossingEdge];
467 EdgeType eTypd = m_eType[crossedEdge];
468 edgeType eTypsi = m_edgeTypes[crossingEdge];
469 edgeType eTypsd = m_edgeTypes[crossedEdge];
471 edge newCopy = GraphCopy::insertCrossing(crossingEdge, crossedEdge, topDown);
473 //Do not use original types, they may differ from the copy
474 //type due to conflict resolution in preprocessing (expand crossings)
475 m_eType[crossingEdge] = eTypi;
476 m_eType[newCopy] = eTypd;
477 m_edgeTypes[crossingEdge] = eTypsi;
478 m_edgeTypes[newCopy] = eTypsd;
480 setCrossingType(newCopy->source());
481 OGDF_ASSERT(isCrossingType(newCopy->source()))
483 //TODO: hier sollte man die NodeTypes setzen, d.h. crossing
485 return newCopy;
490 void PlanRep::removeCrossing(node v)
492 OGDF_ASSERT(v->degree() == 4)
493 OGDF_ASSERT(isCrossingType(v))
495 adjEntry a1 = v->firstAdj();
496 adjEntry b1 = a1->cyclicSucc();
497 adjEntry a2 = b1->cyclicSucc();
498 adjEntry b2 = a2->cyclicSucc();
500 removeUnnecessaryCrossing(a1, a2, b1, b2);
503 }//removeCrossing
507 void PlanRep::expand(bool lowDegreeExpand)
509 node v;
510 forall_nodes(v,*this)
513 // Replace vertices with high degree by cages and
514 // replace degree 4 vertices with two generalizations
515 // adjacent in the embedding list by a cage.
516 if ((v->degree() > 4) && (typeOf(v) != Graph::dummy) && !lowDegreeExpand)
518 edge e;
520 //Set the type of the node v. It remains in the graph
521 // as one of the nodes of the expanded face.
522 typeOf(v) = Graph::highDegreeExpander;
524 // Scan the list of edges of v to find the adjacent edges of v
525 // according to the planar embedding. All except one edge
526 // will get a new adjacent node
527 SList<edge> adjEdges;
528 {forall_adj_edges(e,v)
529 adjEdges.pushBack(e);
532 //The first edge remains at v. remove it from the list.
533 e = adjEdges.popFrontRet();
535 // Create the list of high degree expanders
536 // We need degree(v)-1 of them to construct a face.
537 // and set expanded Node to v
538 setExpandedNode(v, v);
539 SListPure<node> expander;
540 for (int i = 0; i < v->degree()-1; i++)
542 node u = newNode();
543 typeOf(u) = Graph::highDegreeExpander;
544 setExpandedNode(u, v);
545 expander.pushBack(u);
548 // We move the target node of each ingoing generalization of v to a new
549 // node stored in expander.
550 // Note that, for each such edge e, the target node of the original
551 // edge is then different from the original of the target node of e
552 // (the latter is 0 because u is a new (dummy) node)
553 SListConstIterator<edge> it;
554 SListConstIterator<node> itn;
556 NodeArray<adjEntry> ar(*this);
558 itn = expander.begin();
560 for (it = adjEdges.begin(); it.valid(); it++)
562 // Did we allocate enough dummy nodes?
563 OGDF_ASSERT(itn.valid());
565 if ((*it)->source() == v)
566 moveSource(*it,*itn);
567 else
568 moveTarget(*it,*itn);
569 ar[*itn] = (*itn)->firstAdj();
570 itn++;
572 ar[v] = v->firstAdj();
574 // Now introduce the circular list of new edges
575 // forming the border of the merge face. Keep the embedding.
576 adjEntry adjPrev = v->firstAdj();
578 // cout <<endl << "INTRODUCING CIRCULAR EDGES" << endl;
579 for (itn = expander.begin(); itn.valid(); itn++)
581 // cout << adjPrev << " " << (*itn)->firstAdj() << endl;
582 e = Graph::newEdge(adjPrev,(*itn)->firstAdj());
583 setExpansionEdge(e, 2);//can be removed if edgetypes work properly
585 setExpansion(e);
586 setAssociation(e);
588 typeOf(e) = association; //???
590 if (!expandAdj(v))
591 expandAdj(v) = e->adjSource();
592 adjPrev = (*itn)->firstAdj();
595 e = newEdge(adjPrev,v->lastAdj());
597 typeOf(e) = association; //???
598 setExpansionEdge(e, 2);//can be removed if edgetypes work properly
599 setAssociation(e);
601 }//highdegree
603 // Replace all vertices with degree > 2 by cages.
604 else if (v->degree() >= 2 && typeOf(v) != Graph::dummy &&
605 lowDegreeExpand)
607 edge e;
609 //Set the type of the node v. It remains in the graph
610 // as one of the nodes of the expanded face.
611 typeOf(v) = Graph::lowDegreeExpander; //high??
613 // Scan the list of edges of v to find the adjacent edges of v
614 // according to the planar embedding. All except one edge
615 // will get a new adjacent node
616 SList<edge> adjEdges;
617 {forall_adj_edges(e,v)
618 adjEdges.pushBack(e);
621 //The first edge remains at v. remove it from the list.
622 // Check if it is a generalization.
623 e = adjEdges.popFrontRet();
625 // Create the list of high degree expanders
626 // We need degree(v)-1 of them to construct a face.
627 // and set expanded Node to v
628 setExpandedNode(v, v);
629 SListPure<node> expander;
630 for (int i = 0; i < v->degree()-1; i++)
632 node u = newNode();
633 typeOf(u) = Graph::highDegreeExpander;
634 setExpandedNode(u, v);
635 expander.pushBack(u);
638 // We move the target node of each ingoing generalization of v to a new
639 // node stored in expander.
640 // Note that, for each such edge e, the target node of the original
641 // edge is then different from the original of the target node of e
642 // (the latter is 0 because u is a new (dummy) node)
643 SListConstIterator<edge> it;
644 SListConstIterator<node> itn;
646 NodeArray<adjEntry> ar(*this);
648 itn = expander.begin();
650 for (it = adjEdges.begin(); it.valid(); it++)
652 // Did we allocate enough dummy nodes?
653 OGDF_ASSERT(itn.valid());
655 if ((*it)->source() == v)
656 moveSource(*it,*itn);
657 else
658 moveTarget(*it,*itn);
659 ar[*itn] = (*itn)->firstAdj();
660 itn++;
662 ar[v] = v->firstAdj();
664 // Now introduce the circular list of new edges
665 // forming the border of the merge face. Keep the embedding.
666 adjEntry adjPrev = v->firstAdj();
668 for (itn = expander.begin(); itn.valid(); itn++)
670 e = newEdge(adjPrev,(*itn)->firstAdj());
671 if (!expandAdj(v)) expandAdj(v) = e->adjSource();
672 typeOf(e) = association; //???
673 setExpansionEdge(e, 2);
675 //new types
676 setAssociation(e); //should be dummy type?
677 setExpansion(e);
679 adjPrev = (*itn)->firstAdj();
681 e = newEdge(adjPrev,v->lastAdj());
682 typeOf(e) = association; //???
683 setExpansionEdge(e, 2);
686 }//forallnodes
688 }//expand
691 void PlanRep::expandLowDegreeVertices(OrthoRep &OR)
693 node v;
694 forall_nodes(v,*this)
696 if (!(isVertex(v)) || expandAdj(v) != 0)
697 continue;
699 SList<edge> adjEdges;
700 SListPure<Tuple2<node,int> > expander;
702 node u = v;
703 bool firstTime = true;
705 setExpandedNode(v, v);
707 adjEntry adj;
708 forall_adj(adj,v) {
709 adjEdges.pushBack(adj->theEdge());
711 if(!firstTime)
712 u = newNode();
714 setExpandedNode(u, v);
715 typeOf(u) = Graph::lowDegreeExpander;
716 expander.pushBack(Tuple2<node,int>(u,OR.angle(adj)));
717 firstTime = false;
720 SListConstIterator<edge> it;
721 SListConstIterator<Tuple2<node,int> > itn;
723 itn = expander.begin().succ();
725 for (it = adjEdges.begin().succ(); it.valid(); ++it)
727 // Did we allocate enough dummy nodes?
728 OGDF_ASSERT(itn.valid());
730 if ((*it)->source() == v)
731 moveSource(*it,(*itn).x1());
732 else
733 moveTarget(*it,(*itn).x1());
734 ++itn;
737 adjEntry adjPrev = v->firstAdj();
738 itn = expander.begin();
739 int nBends = (*itn).x2();
741 edge e;
742 for (++itn; itn.valid(); itn++)
744 e = newEdge(adjPrev,(*itn).x1()->firstAdj());
746 OR.bend(e->adjSource()).set(convexBend,nBends);
747 OR.bend(e->adjTarget()).set(reflexBend,nBends);
748 OR.angle(adjPrev) = 1;
749 OR.angle(e->adjSource()) = 2;
750 OR.angle(e->adjTarget()) = 1;
752 nBends = (*itn).x2();
754 typeOf(e) = association; //???
755 setExpansionEdge(e, 2);
757 adjPrev = (*itn).x1()->firstAdj();
760 e = newEdge(adjPrev,v->lastAdj());
761 typeOf(e) = association; //???
762 setExpansionEdge(e, 2);
764 expandAdj(v) = e->adjSource();
766 OR.bend(e->adjSource()).set(convexBend,nBends);
767 OR.bend(e->adjTarget()).set(reflexBend,nBends);
768 OR.angle(adjPrev) = 1;
769 OR.angle(e->adjSource()) = 2;
770 OR.angle(e->adjTarget()) = 1;
773 }//expandlowdegreevertices
775 void PlanRep::collapseVertices(const OrthoRep &OR, Layout &drawing)
777 node v;
778 forall_nodes(v,*this) {
779 const OrthoRep::VertexInfoUML *vi = OR.cageInfo(v);
781 if(vi == 0 ||
782 (typeOf(v) != Graph::highDegreeExpander &&
783 typeOf(v) != Graph::lowDegreeExpander))
784 continue;
786 node vOrig = original(v);
787 OGDF_ASSERT(vOrig != 0);
789 node vCenter = newNode();
790 m_vOrig[vCenter] = vOrig;
791 m_vCopy[vOrig] = vCenter;
792 m_vOrig[v] = 0;
794 node lowerLeft = vi->m_corner[odNorth]->theNode();
795 node lowerRight = vi->m_corner[odWest ]->theNode();
796 node upperLeft = vi->m_corner[odEast ]->theNode();
797 drawing.x(vCenter) = 0.5*(drawing.x(lowerLeft)+drawing.x(lowerRight));
798 drawing.y(vCenter) = 0.5*(drawing.y(lowerLeft)+drawing.y(upperLeft ));
800 edge eOrig;
801 forall_adj_edges(eOrig,vOrig) {
802 if(eOrig->target() == vOrig) {
803 node connect = m_eCopy[eOrig].back()->target();
804 edge eNew = newEdge(connect,vCenter);
805 m_eOrig[eNew] = eOrig;
806 m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew);
808 } else {
809 node connect = m_eCopy[eOrig].front()->source();
810 edge eNew = newEdge(vCenter,connect);
811 m_eOrig[eNew] = eOrig;
812 m_eIterator[eNew] = m_eCopy[eOrig].pushFront(eNew);
818 //-------------------------
819 //object types
820 //set type of eCopy according to type of eOrig
821 void PlanRep::setCopyType(edge eCopy, edge eOrig)
823 OGDF_ASSERT(original(eCopy) == eOrig)
824 m_eType[eCopy] = m_pGraphAttributes ? m_pGraphAttributes->type(eOrig) : Graph::association;
825 if (eOrig)
827 switch (m_pGraphAttributes ? m_pGraphAttributes->type(eOrig) : Graph::association)
829 case Graph::generalization: setGeneralization(eCopy); break;
830 case Graph::association: setAssociation(eCopy); break;
831 case Graph::dependency: setDependency(eCopy); break;
832 OGDF_NODEFAULT
833 }//switch
834 }//if original
835 }//setCopyType
838 void PlanRep::removeDeg1Nodes(Stack<Deg1RestoreInfo> &S, const NodeArray<bool> &mark)
840 for(node v = firstNode(); v != 0; v = v->succ())
842 if(mark[v] || v->degree() == 0)
843 continue;
845 adjEntry adjRef;
846 for(adjRef = v->firstAdj();
847 adjRef != 0 && mark[adjRef->twinNode()];
848 adjRef = adjRef->succ()) ;
850 if(adjRef == 0) {
851 // only marked nodes adjacent with v (need no reference entry)
852 adjEntry adj;
853 forall_adj(adj,v) {
854 node x = adj->twinNode();
855 S.push(Deg1RestoreInfo(m_eOrig[adj->theEdge()],m_vOrig[x],0));
856 delCopy(x);
859 } else {
860 adjEntry adj, adjNext, adjStart = adjRef;
861 for(adj = adjRef->cyclicSucc(); adj != adjStart; adj = adjNext)
863 adjNext = adj->cyclicSucc();
864 node x = adj->twinNode();
865 if(mark[x]) {
866 S.push(Deg1RestoreInfo(m_eOrig[adj->theEdge()],m_vOrig[x],adjRef));
867 delCopy(x);
868 } else
869 adjRef = adj;
876 void PlanRep::restoreDeg1Nodes(Stack<Deg1RestoreInfo> &S, List<node> &deg1s)
878 while(!S.empty())
880 Deg1RestoreInfo info = S.pop();
881 adjEntry adjRef = info.m_adjRef;
882 node vOrig = info.m_deg1Original;
883 edge eOrig = info.m_eOriginal;
885 node v = newNode(vOrig);
887 if(adjRef) {
888 if(vOrig == eOrig->source())
889 newEdge(eOrig, v, adjRef);
890 else
891 newEdge(eOrig, adjRef, v);
892 } else {
893 if(vOrig == eOrig->source())
894 newEdge(eOrig);
895 else
896 newEdge(eOrig);
898 deg1s.pushBack(v);
903 node PlanRep::newCopy(node v, Graph::NodeType vTyp)
905 OGDF_ASSERT(m_vCopy[v] == 0)
907 node u = newNode();
908 m_vCopy[v] = u;
909 m_vOrig[u] = v;
910 //TODO:Typ?
911 m_vType[u] = vTyp;
913 return u;
916 //inserts copy for original edge eOrig after adAfter
917 edge PlanRep::newCopy(node v, adjEntry adAfter, edge eOrig)
919 OGDF_ASSERT(eOrig->graphOf() == &(original()))
920 OGDF_ASSERT(m_eCopy[eOrig].size() == 0)
921 edge e;
922 if (adAfter != 0)
923 e = Graph::newEdge(v, adAfter);
924 else
926 node w = copy(eOrig->opposite(original(v)));
927 OGDF_ASSERT(w)
928 e = Graph::newEdge(v, w);
929 }//else
930 m_eOrig[e] = eOrig;
931 m_eIterator[e] = m_eCopy[eOrig].pushBack(e);
932 //set type of copy
933 if (m_pGraphAttributes != 0)
934 setCopyType(e, eOrig);
936 return e;
938 //inserts copy for original edge eOrig preserving the embedding
939 edge PlanRep::newCopy(node v, adjEntry adAfter, edge eOrig, CombinatorialEmbedding &E)
941 OGDF_ASSERT(eOrig->graphOf() == &(original()))
942 OGDF_ASSERT(m_eCopy[eOrig].size() == 0)
944 edge e;
945 //GraphCopy checks direction for us
946 e = GraphCopy::newEdge(v, adAfter, eOrig, E);
947 //set type of copy
948 if (m_pGraphAttributes != 0)
949 setCopyType(e, eOrig);
951 return e;
955 edge PlanRep::split(edge e)
957 bool cageBound = (m_expandedNode[e->source()] && m_expandedNode[e->target()])
958 && (m_expandedNode[e->source()] == m_expandedNode[e->target()]);
959 node expNode = (cageBound ? m_expandedNode[e->source()] : 0);
961 edge eNew = GraphCopy::split(e);
962 m_eType[eNew] = m_eType[e];
963 m_edgeTypes[eNew] = m_edgeTypes[e];
964 m_expansionEdge[eNew] = m_expansionEdge[e];
966 m_expandedNode[eNew->source()] = expNode;
968 return eNew;
972 } // end namespace ogdf