6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of PlanRep base class for planar rep.
12 * \author Karsten Klein
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/basic/simple_graph_alg.h>
46 #include <ogdf/basic/extended_graph_alg.h>
48 #include <ogdf/planarity/PlanRep.h>
53 PlanRep::PlanRep(const Graph
& AG
) :
55 m_pGraphAttributes(NULL
),
56 m_boundaryAdj(AG
, 0),//*this, 0),
57 m_oriEdgeTypes(AG
, 0),
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
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
);
83 m_nodesInCC
[component
[v
]].pushBack(v
);
85 m_currentCC
= -1; // not yet initialized
89 PlanRep::PlanRep(const GraphAttributes
& AG
) :
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
);
119 m_nodesInCC
[component
[v
]].pushBack(v
);
121 m_currentCC
= -1; // not yet initialized
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
) {
141 if ((adj
->index() & 1) == 0) continue;
142 edge eG
= adj
->theEdge();
150 GraphCopy::initByNodes(m_nodesInCC
[i
], m_eAuxCopy
);
152 // set type of edges (gen. or assoc.) in the current CC
154 forall_edges(e
,*this)
155 setCopyType(e
, original(e
));
157 if(m_pGraphAttributes
== 0)
160 // The following part is only relevant with given graph attributes!
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();
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)
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
195 node center
= copy(centerOrig
);
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
206 SList
<adjEntry
> outAdj
;
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
220 if (adjExternal
== adj
) //outgoing
222 if (adj
->twinNode()->degree() == 1)
225 adjExternal
= adjExternal
->faceCycleSucc();
226 } while ( (adjExternal
->theNode() == center
) ||
227 (adjExternal
->twinNode() == center
));
230 adjExternal
= adjExternal
->faceCycleSucc()->faceCycleSucc();
232 if (adjExternal
== adj
->twin()) //incoming
234 if (adj
->twinNode()->degree() == 1)
237 adjExternal
= adjExternal
->faceCycleSucc();
238 } while ( (adjExternal
->theNode() == center
) ||
239 (adjExternal
->twinNode() == center
));
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();
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
265 SListIterator
<adjEntry
> it
= outAdj
.begin();
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
)
282 //adjExternal = adjExternal->faceCycleSucc();
284 if (adjExternal
== splitAdj
->twin())
287 //adjExternal = adjExternal->faceCyclePred();
291 //combinatorial version
292 //edge newEdge = E.split(splitEdge);
294 edge newEdge
= split(splitEdge
);
295 setCrossingType(newEdge
->source());
297 //store the adjEntries depending on in/out direction
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();
308 sourceEntries
.pushBack(splitEdge
->adjTarget());
309 targetEntries
.pushBack(newEdge
->adjSource());
310 if (splitOuter
) adjExternal
= splitEdge
->adjTarget();
311 if (splitInner
) adjExternal
= splitEdge
->adjSource();
314 //go on with next edge
320 //we need pairs of adjEntries
321 OGDF_ASSERT(targetEntries
.size() == sourceEntries
.size());
322 //now flip first target entry to front
324 adjEntry flipper
= targetEntries
.popFrontRet();
325 targetEntries
.pushBack(flipper
);
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());
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();
348 //*****************************************************************************
349 //embedding and crossings
351 bool PlanRep::embed()
353 return planarEmbed(*this);
356 void PlanRep::removeUnnecessaryCrossing(
362 node v
= adjA1
->theNode();
364 if(adjA1
->theEdge()->source() == v
)
365 moveSource(adjA1
->theEdge(), adjA2
->twin(), before
);
367 moveTarget(adjA1
->theEdge(), adjA2
->twin(), before
);
369 if(adjB1
->theEdge()->source() == v
)
370 moveSource(adjB1
->theEdge(), adjB2
->twin(), before
);
372 moveTarget(adjB1
->theEdge(), adjB2
->twin(), before
);
374 edge eOrigA
= original(adjA1
->theEdge());
375 edge eOrigB
= original(adjB1
->theEdge());
378 m_eCopy
[eOrigA
].del(m_eIterator
[adjA2
->theEdge()]);
380 m_eCopy
[eOrigB
].del(m_eIterator
[adjB2
->theEdge()]);
382 delEdge(adjB2
->theEdge());
383 delEdge(adjA2
->theEdge());
388 void PlanRep::removePseudoCrossings()
391 for(v
= firstNode(); v
!= 0; v
= vSucc
)
395 if (typeOf(v
) != PlanRep::dummy
|| v
->degree() != 4)
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(
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(
437 const SList
<adjEntry
> &crossedEdges
)
439 GraphCopy::insertEdgePath(eOrig
,crossedEdges
);
442 Graph::EdgeType edgeType
= m_pGraphAttributes
?
443 m_pGraphAttributes
->type(eOrig
) : Graph::association
;
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(
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
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
);
507 void PlanRep::expand(bool lowDegreeExpand
)
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
)
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
++)
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
);
568 moveTarget(*it
,*itn
);
569 ar
[*itn
] = (*itn
)->firstAdj();
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
588 typeOf(e
) = association
; //???
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
603 // Replace all vertices with degree > 2 by cages.
604 else if (v
->degree() >= 2 && typeOf(v
) != Graph::dummy
&&
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
++)
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
);
658 moveTarget(*it
,*itn
);
659 ar
[*itn
] = (*itn
)->firstAdj();
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);
676 setAssociation(e
); //should be dummy type?
679 adjPrev
= (*itn
)->firstAdj();
681 e
= newEdge(adjPrev
,v
->lastAdj());
682 typeOf(e
) = association
; //???
683 setExpansionEdge(e
, 2);
691 void PlanRep::expandLowDegreeVertices(OrthoRep
&OR
)
694 forall_nodes(v
,*this)
696 if (!(isVertex(v
)) || expandAdj(v
) != 0)
699 SList
<edge
> adjEdges
;
700 SListPure
<Tuple2
<node
,int> > expander
;
703 bool firstTime
= true;
705 setExpandedNode(v
, v
);
709 adjEdges
.pushBack(adj
->theEdge());
714 setExpandedNode(u
, v
);
715 typeOf(u
) = Graph::lowDegreeExpander
;
716 expander
.pushBack(Tuple2
<node
,int>(u
,OR
.angle(adj
)));
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());
733 moveTarget(*it
,(*itn
).x1());
737 adjEntry adjPrev
= v
->firstAdj();
738 itn
= expander
.begin();
739 int nBends
= (*itn
).x2();
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
)
778 forall_nodes(v
,*this) {
779 const OrthoRep::VertexInfoUML
*vi
= OR
.cageInfo(v
);
782 (typeOf(v
) != Graph::highDegreeExpander
&&
783 typeOf(v
) != Graph::lowDegreeExpander
))
786 node vOrig
= original(v
);
787 OGDF_ASSERT(vOrig
!= 0);
789 node vCenter
= newNode();
790 m_vOrig
[vCenter
] = vOrig
;
791 m_vCopy
[vOrig
] = vCenter
;
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
));
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
);
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 //-------------------------
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
;
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;
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)
846 for(adjRef
= v
->firstAdj();
847 adjRef
!= 0 && mark
[adjRef
->twinNode()];
848 adjRef
= adjRef
->succ()) ;
851 // only marked nodes adjacent with v (need no reference entry)
854 node x
= adj
->twinNode();
855 S
.push(Deg1RestoreInfo(m_eOrig
[adj
->theEdge()],m_vOrig
[x
],0));
860 adjEntry adj
, adjNext
, adjStart
= adjRef
;
861 for(adj
= adjRef
->cyclicSucc(); adj
!= adjStart
; adj
= adjNext
)
863 adjNext
= adj
->cyclicSucc();
864 node x
= adj
->twinNode();
866 S
.push(Deg1RestoreInfo(m_eOrig
[adj
->theEdge()],m_vOrig
[x
],adjRef
));
876 void PlanRep::restoreDeg1Nodes(Stack
<Deg1RestoreInfo
> &S
, List
<node
> °1s
)
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
);
888 if(vOrig
== eOrig
->source())
889 newEdge(eOrig
, v
, adjRef
);
891 newEdge(eOrig
, adjRef
, v
);
893 if(vOrig
== eOrig
->source())
903 node
PlanRep::newCopy(node v
, Graph::NodeType vTyp
)
905 OGDF_ASSERT(m_vCopy
[v
] == 0)
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)
923 e
= Graph::newEdge(v
, adAfter
);
926 node w
= copy(eOrig
->opposite(original(v
)));
928 e
= Graph::newEdge(v
, w
);
931 m_eIterator
[e
] = m_eCopy
[eOrig
].pushBack(e
);
933 if (m_pGraphAttributes
!= 0)
934 setCopyType(e
, eOrig
);
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)
945 //GraphCopy checks direction for us
946 e
= GraphCopy::newEdge(v
, adAfter
, eOrig
, E
);
948 if (m_pGraphAttributes
!= 0)
949 setCopyType(e
, eOrig
);
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
;
972 } // end namespace ogdf