Add tests for UpdateCrypto
[TortoiseGit.git] / ext / OGDF / ogdf / orthogonal / CompactionConstraintGraph.h
blobab8e802c83c98ad2ce72955c2ea72b3a4a5e0e98
1 /*
2 * $Revision: 2566 $
4 * last checkin:
5 * $Author: gutwenger $
6 * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $
7 ***************************************************************/
9 /** \file
10 * \brief Declares CompactionConstraintGraph.
12 * I.e. a representation of constraint graphs (dependency graphs)
13 * used in compaction algorithms.
15 * \author Carsten Gutwenger
17 * \par License:
18 * This file is part of the Open Graph Drawing Framework (OGDF).
20 * \par
21 * Copyright (C)<br>
22 * See README.txt in the root directory of the OGDF installation for details.
24 * \par
25 * This program is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU General Public License
27 * Version 2 or 3 as published by the Free Software Foundation;
28 * see the file LICENSE.txt included in the packaging of this file
29 * for details.
31 * \par
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
37 * \par
38 * You should have received a copy of the GNU General Public
39 * License along with this program; if not, write to the Free
40 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
41 * Boston, MA 02110-1301, USA.
43 * \see http://www.gnu.org/copyleft/gpl.html
44 ***************************************************************/
47 #ifdef _MSC_VER
48 #pragma once
49 #endif
52 #ifndef OGDF_COMP_CONSTR_GRAPH_H
53 #define OGDF_COMP_CONSTR_GRAPH_H
56 #include <ogdf/orthogonal/OrthoRep.h>
57 #include <ogdf/internal/orthogonal/RoutingChannel.h>
58 #include <ogdf/orthogonal/MinimumEdgeDistances.h>
61 namespace ogdf {
64 // types of edges in the constraint graph
65 enum ConstraintEdgeType {
66 cetBasicArc,
67 cetVertexSizeArc,
68 cetVisibilityArc,
69 cetFixToZeroArc, //can be compacted to zero length, can be fixed
70 cetReducibleArc, //can be compacted to zero length
71 cetMedianArc //inserted to replace some reducible in fixzerolength
74 //---------------------------------------------------------
75 // CompactionConstraintGraph
76 // base class implementing common behaviour of all parameterized
77 // CompactionConstraintGraph<ATYPE>
78 //---------------------------------------------------------
79 class CompactionConstraintGraphBase : protected Graph
81 public:
83 // output for debugging only
84 void writeGML(const char *fileName) const ;
85 void writeGML(ostream &os) const;
86 //output edges on external face
87 void writeGML(const char *fileName, NodeArray<bool> one) const ;
88 void writeGML(ostream &os, NodeArray<bool> one) const;
90 //return constraint arc representing input edge e in constraint graph
91 edge basicArc(edge e) const {
92 return m_edgeToBasicArc[e];
95 //***************************
96 //return some edge properties
97 //***************************
98 //returns true if e is vertical edge in PlanRepUML hierarchy
99 bool verticalGen(edge e) const {return m_verticalGen[e];}
100 //returns true if e is basic arc of vertical edge in PlanRepUML hierarchy
101 //Precond.: e is arc in the constraint graph
102 bool verticalArc(edge e) const {return m_verticalArc[e];}
103 //edge lies on cage border
104 bool onBorder(edge e) const {return m_border[e]>0;}
105 //these are subject to length fixation if length < sep
106 bool fixOnBorder(edge e) const {return (m_border[e] == 2);}
108 //trigger alignment (=>some special edge handling to support al.)
109 void align(bool b) {m_align = b;}
111 //return if arc is important for alignment
112 //these are the arcs representing node to gen. merger edges
113 bool alignmentArc(edge e) const {return m_alignmentArc[e];}
115 const PlanRep& getPlanRep() const {return *m_pPR;}
117 edge pathToOriginal(node v) {return m_pathToEdge[v];}
119 protected:
120 // construction
121 CompactionConstraintGraphBase(const OrthoRep &OR,
122 const PlanRep &PG,
123 OrthoDir arcDir,
124 int costGen = 1,
125 int costAssoc = 1, bool align = false);
127 // computes topological numbering on the segments of the constraint graph.
128 void computeTopologicalSegmentNum(NodeArray<int> &topNum);
130 // remove "arcs" from visibArcs which we already have in the constraint graph
131 // (as basic arcs)
132 void removeRedundantVisibArcs(SListPure<Tuple2<node,node> > &visibArcs);
134 const OrthoRep *m_pOR;
135 const PlanRep *m_pPR;
136 OrthoDir m_arcDir;
137 OrthoDir m_oppArcDir;
139 int m_edgeCost[2];
141 NodeArray<SListPure<node> > m_path; // list of nodes contained in a segment
142 NodeArray<node> m_pathNode; // segment containing a node in PG
143 EdgeArray<edge> m_edgeToBasicArc; // basic arc representing an edge in PG
145 EdgeArray<int> m_cost; // cost of an edge
146 EdgeArray<ConstraintEdgeType> m_type;
148 //test fuer vorkomp. der Generalisierungen
149 EdgeArray<bool> m_verticalGen; //generalization that runs vertical relative to hierarchy
150 EdgeArray<bool> m_verticalArc; //arc corresponding to such an edge
151 EdgeArray<int> m_border; //only used for cage precompaction in flowcompaction computecoords
153 //basic arcs that have to be short for alignment (node to gen expander)
154 EdgeArray<bool> m_alignmentArc;
156 NodeArray<edge> m_pathToEdge; //save the (single!) edge (segment) for a pathNode
157 NodeArray<edge> m_originalEdge; //save edge for the basic arcs
159 // embeds constraint graph such that all sources and sinks lie in a common
160 // face
161 void embed();
163 virtual void writeLength(ostream &os, edge e) const = 0;
165 private:
167 //set special costs for node to merger generalizations
168 bool m_align;
170 void insertPathVertices(const PlanRep &PG);
171 void dfsInsertPathVertex(
172 node v,
173 node pathVertex,
174 NodeArray<bool> &visited,
175 const NodeArray<node> &genOpposite);
177 void insertBasicArcs(const PlanRep &PG);
179 node m_superSource;
180 node m_superSink;
181 SList<node> m_sources;
182 SList<node> m_sinks;
188 //---------------------------------------------------------
189 // CompactionConstraintGraph
190 // represents a constraint graph used for compaction
191 // vertices: maximally connected horiz. (resp. vert.) paths
192 // basic arcs: paths connected by edges of opposite direction
193 // vertex size arcs: care for minimum size of cages
194 // visibility arcs: paths seeing each other
195 // Each edge has a (minimum) length and cost.
196 //---------------------------------------------------------
197 template<class ATYPE>
198 class CompactionConstraintGraph : public CompactionConstraintGraphBase
200 public:
201 // construction
202 CompactionConstraintGraph(const OrthoRep &OR,
203 const PlanRep &PG,
204 OrthoDir arcDir,
205 ATYPE sep,
206 int costGen = 1,
207 int costAssoc = 1,
208 bool align = false) :
209 CompactionConstraintGraphBase(OR, PG, arcDir, costGen, costAssoc, align)
211 OGDF_ASSERT(&(const Graph &)PG == &(const Graph &)OR);
213 m_length .init((Graph&)*this, sep);
214 m_extraNode.init((Graph&)*this, false);
215 m_extraOfs .init((Graph&)*this, 0);
216 m_extraRep .init((Graph&)*this, 0);
218 m_sep = sep;
220 m_centerPriority = true; //should centering of single edges have prio. to gen. length
221 m_genToMedian = true; //should outgoing merger gen. be drawn to merger median
222 initializeCosts();
224 }//constructor
226 // output for debugging only
227 void writeGML(const char *fileName) const ;
228 void writeGML(ostream &os) const;
231 // returns underlying graph
232 const Graph &getGraph() const { return (Graph&)*this; }
233 Graph &getGraph() { return (Graph&)*this; }
236 const OrthoRep &getOrthoRep() const {
237 return *m_pOR;
241 // returns list of nodes contained in segment v
242 // Precodn.: v is in the constraint graph
243 const SListPure<node> &nodesIn(node v) const {
244 return m_path[v];
247 // returns the segment (path node in constraint graph) containing v
248 // Precond.: v is a node in the associated planarized representation
249 node pathNodeOf(node v) const {
250 return m_pathNode[v];
253 // returns length of edge e
254 // Precond.: e is an edge in the constraint graph
255 ATYPE length(edge e) const {
256 return m_length[e];
259 // returns cost of edge e
260 // Precond.: e is an edge in the constraint graph
261 int cost(edge e) const {
262 return m_cost[e];
265 // returns type of edge e
266 // Precond.: e is an edge in the constraint graph
267 ConstraintEdgeType typeOf(edge e) const {
268 return m_type[e];
271 //returns node status
272 bool extraNode(node v) const {
273 return m_extraNode[v];
276 //returns extraNode position, change to save mem, only need some entries
277 ATYPE extraOfs(node v) const {
278 return m_extraOfs[v];
281 //returns extraNode existing anchor representant
282 node extraRep(node v) const {
283 return m_extraRep[v];
286 //get / set centerPriority (center single edges?)
287 bool centerPriority() {return m_centerPriority;}
288 void centerPriority(bool b) { m_centerPriority = b;}
290 // computes the total costs for coordintes given by pos, i.e.,
291 // the sum of the weighted lengths of edges in the constraint graph.
292 ATYPE computeTotalCosts(const NodeArray<ATYPE> &pos) const;
295 // inserts arcs for respecting sizes of vertices and achieving desired
296 // placement of generalizations if vertices are represented by variable
297 // cages; also corrects length of arcs belonging to cages which are
298 // adjacent to a corner; takes routing channels into account.
299 void insertVertexSizeArcs(
300 const PlanRep &PG,
301 const NodeArray<ATYPE> &sizeOrig,
302 const RoutingChannel<ATYPE> &rc);
304 // inserts arcs for respecting sizes of vertices and achieving desired
305 // placement of generalizations if vertices are represented by tight cages;
306 // also corrects length of arcs belonging to cages which are adjacent to
307 // a corner; takes special distances between edge segments attached at
308 // a vertex (delta's and epsilon's) into account.
309 void insertVertexSizeArcs(
310 const PlanRep &PG,
311 const NodeArray<ATYPE> &sizeOrig,
312 const MinimumEdgeDistances<ATYPE> &minDist);
314 // inserts arcs connecting segments which can see each other in a drawing
315 // of the associated planarized representation PG which is given by
316 // posDir and posOppDir.
317 void insertVisibilityArcs(
318 const PlanRep &PG, // associated planarized representation
319 const NodeArray<ATYPE> &posDir, // position of segment containing
320 // vertex in PG
321 const NodeArray<ATYPE> &posOppDir); // position of orthogonal segment
322 // containing vertex in PG
324 void insertVisibilityArcs(
325 const PlanRep &PG,
326 const NodeArray<ATYPE> &posDir,
327 const NodeArray<ATYPE> &posOrthDir,
328 const MinimumEdgeDistances<ATYPE> &minDist);
331 //set min sep for multi edge original
332 void setMinimumSeparation(const PlanRep &PG,
333 const NodeArray<int> coord,
334 const MinimumEdgeDistances<ATYPE> &minDist);
337 // embeds constraint graph such that all sources and sinks lie in a common
338 // face
339 void embed() {
340 CompactionConstraintGraphBase::embed();
344 // performs feasibility test for position assignment pos, i.e., checks if
345 // the segment positions given by pos fulfill the constraints in the
346 // compaction constraint graph
347 // (for debuging only)
348 bool isFeasible(const NodeArray<ATYPE> &pos);
350 //returns the separation value
351 ATYPE separation() const {return m_sep;}
353 //return PG result for flowcompaction
354 bool areMulti(edge e1, edge e2) const;
357 private:
358 //---------------------------------------------------------
359 // CompactionConstraintGraph::Interval
360 // represents an interval on the sweep line
361 //---------------------------------------------------------
362 struct Interval
364 Interval(node v, ATYPE low, ATYPE high) {
365 m_low = low;
366 m_high = high;
367 m_pathNode = v;
370 ATYPE m_low, m_high; // lower and upper bound
371 node m_pathNode; // corresponding segment
373 // output operator
374 friend ostream &operator<<(ostream &os,
375 const Interval &interval)
377 os << "[" << interval.m_low << "," << interval.m_high <<
378 ";" << interval.m_pathNode << "]";
379 return os;
384 //---------------------------------------------------------
385 // CompactionConstraintGraph::SegmentComparer
386 // comparer class used for sorting segments by increasing position
387 // (given by segPos) such that two overlapping segments come in the
388 // order imposed by the embedding (given by secSort: segment which
389 // comes first has secSort = 0, the other has 1)
390 //---------------------------------------------------------
391 class SegmentComparer
393 public:
394 SegmentComparer(const NodeArray<ATYPE> &segPos,
395 const NodeArray<int> &secSort) {
396 m_pPos = &segPos;
397 m_pSec = &secSort;
400 int compare(const node &x, const node &y) const {
401 ATYPE d = (*m_pPos)[x] - (*m_pPos)[y];
402 if (d < 0)
403 return -1;
404 else if (d > 0)
405 return 1;
406 else
407 return (*m_pSec)[x] - (*m_pSec)[y];
410 OGDF_AUGMENT_COMPARER(node)
411 private:
412 const NodeArray<ATYPE> *m_pPos;
413 const NodeArray<int> *m_pSec;
416 virtual void writeLength(ostream &os, edge e) const {
417 os << m_length[e];
420 void setBasicArcsZeroLength(const PlanRep &PG);
421 void resetGenMergerLengths(const PlanRep &PG, adjEntry adjFirst);
422 void setBoundaryCosts(adjEntry cornerDir,adjEntry cornerOppDir);
424 bool checkSweepLine(const List<Interval> &sweepLine);
426 ATYPE m_sep;
428 EdgeArray<ATYPE> m_length; // length of an edge
430 NodeArray<bool> m_extraNode; //node does not represent drawing node
431 //as we dont have positions, we save a drawing representant and an offset
432 NodeArray<ATYPE> m_extraOfs; //offset of extra node to its rep, should change this
433 NodeArray<node> m_extraRep; //existing representant of extranodes position anchor
435 //**********************
436 //COST SETTINGS SECTION
438 // we make vertex size arcs more expensive than basic arcs in order
439 // to get small cages
440 // should be replaced by option/value dependent on e.g. degree
441 int m_vertexArcCost; //get small cages
442 int m_bungeeCost; //middle position distance penalty
443 int m_MedianArcCost; //draw merger gen at median of incoming generalizations
444 int m_doubleBendCost; //try to minimize double bends
445 bool m_genToMedian; //draw outgoing generalization from merger above ingoing gen.
446 //this does not work if generalization costs are set very small by the user
447 //because there must be a minimum cost for centering
448 bool m_centerPriority; //should centering be more expensive than generalizations
450 //factor of costs relative to generalization
451 static const int c_vertexArcFactor;
452 static const int c_bungeeFactor;
453 static const int c_doubleBendFactor; // = 20; //double bends cost factor*vertexArcCost
454 static const int c_MedianFactor; //median arcs cost factor*vertexArcCost
457 protected:
458 //node v has no representation in drawing, only internal representation
459 void setExtra(node v, node rep, ATYPE ofs) {
460 m_extraNode[v] = true;
461 m_extraRep[v] = rep;
462 m_extraOfs[v] = ofs;
465 void initializeCosts()
467 // we make vertex size arcs more expensive than basic arcs in order
468 // to get small cages; not necessary if cage size fixed in improvement
469 // cost should be dependend on degree
470 // Z.B. DURCH OPTION ODER WERT; DER VON DER ZAHL ADJAZENTER KANTEN ABHAENGIG IST
471 // should be derived by number of edges times something
472 int costGen = m_edgeCost[Graph::generalization];
474 m_vertexArcCost = c_vertexArcFactor*costGen; //spaeter aus Kompaktierungsmodul uebergeben
475 if (m_centerPriority)
476 m_bungeeCost = c_bungeeFactor*costGen+1;//-1;//for distance to middle position,
477 else
478 m_bungeeCost = c_bungeeFactor*4+1;//-1;//for distance to middle position,
479 //addition value should be < gen cost!!!
480 m_MedianArcCost = c_MedianFactor*m_vertexArcCost;
481 m_doubleBendCost = c_doubleBendFactor*m_vertexArcCost;
482 }//initializeCosts
485 //********************************
486 //initialization of static members
487 template<class ATYPE>
488 const int CompactionConstraintGraph<ATYPE>::c_vertexArcFactor = 20;
489 template<class ATYPE>
490 const int CompactionConstraintGraph<ATYPE>::c_bungeeFactor = 20;
491 template<class ATYPE>
492 const int CompactionConstraintGraph<ATYPE>::c_doubleBendFactor = 20; //double bends cost mxxx*vertexArcCost
493 //factor *VertexArcCost, costs for pulling generalization to median position at merger
494 template<class ATYPE>
495 const int CompactionConstraintGraph<ATYPE>::c_MedianFactor = 10*c_doubleBendFactor;
498 //************************************
500 // implementation of member functions
502 //************************************
505 #include <ogdf/planarity/PlanRep.h>
507 namespace ogdf {
510 // allow 0-length for sides of generalization merger cages
511 template<class ATYPE>
512 void CompactionConstraintGraph<ATYPE>::resetGenMergerLengths(
513 const PlanRep &PG,
514 adjEntry adjFirst)
516 adjEntry adj = adjFirst;
517 int faceSize = 0;
519 do {
520 if ((m_pOR->direction(adj) == m_arcDir ||
521 m_pOR->direction(adj) == m_oppArcDir) &&
522 (PG.typeOf(adj->theNode()) == Graph::dummy ||
523 PG.typeOf(adj->twinNode()) == Graph::dummy))
525 m_length[m_edgeToBasicArc[adj]] = 0;
528 adj = adj->faceCycleSucc();
529 faceSize++;
530 } while(adj != adjFirst);
532 //****************************************
533 //generalization position section
534 //pull upper generalization to median of merger cage's incoming lower generalizations
536 if (m_genToMedian)
538 if ((m_pOR->direction(adjFirst) == m_arcDir) ||
539 (m_pOR->direction(adjFirst) == m_oppArcDir) )
541 int numIncoming = faceSize - 3;
542 int median = (numIncoming / 2) + 1;
544 //if (numIncoming == 2) ... just the middle position
545 node upper = m_pathNode[adjFirst->theNode()];
546 if (PG.typeOf(adjFirst->theNode()) != Graph::generalizationMerger)
547 OGDF_THROW(AlgorithmFailureException);
548 node vMin;
549 if (m_pOR->direction(adjFirst) == m_arcDir)
550 vMin = adjFirst->faceCyclePred()->theNode();
551 else vMin = adjFirst->faceCycleSucc()->theNode();
552 adj = adjFirst->faceCycleSucc(); //target right or left boundary, depending on drawing direction
553 for (int i = 0; i < median; i++)
554 adj = adj->faceCycleSucc();
555 node lower = m_pathNode[adj->theNode()];
556 node vCenter = newNode();
557 setExtra(vCenter, vMin, 0);
558 //it seems we dont need the helper, as only source-adjEntries lying on
559 //the outer face are considered later, but keep it in mind
561 edge helper = newEdge(m_pathNode[vMin], vCenter);
562 m_length[helper] = 0;
563 m_cost[helper] = 0;
564 m_type[helper] = cetReducibleArc;
567 edge e1 = newEdge(vCenter,upper);
568 m_length[e1] = 0;
569 m_cost[e1] = m_MedianArcCost;
570 m_type[e1] = cetMedianArc;
572 edge e2 = newEdge(vCenter,lower);
573 m_length[e2] = 0;
574 m_cost[e2] = m_MedianArcCost;
575 m_type[e2] = cetMedianArc;
576 }//if compaction dir
577 }//if gentomedian option set
578 //*******************************************
582 // set cost of edges on the cage boundary to 0
583 template<class ATYPE>
584 void CompactionConstraintGraph<ATYPE>::setBoundaryCosts(
585 adjEntry cornerDir,
586 adjEntry cornerOppDir)
589 adjEntry adj;
590 for (adj = cornerDir; m_pOR->direction(adj) == m_arcDir; adj = adj->faceCycleSucc())
591 m_cost[m_edgeToBasicArc[adj]] = 0;
592 for (adj = cornerOppDir; m_pOR->direction(adj) == m_oppArcDir; adj = adj->faceCycleSucc())
593 m_cost[m_edgeToBasicArc[adj]] = 0;
595 //test fuer multi separation
596 adjEntry adj;
597 for (adj = cornerDir; m_pOR->direction(adj) == m_arcDir; adj = adj->faceCycleSucc())
599 m_cost[m_edgeToBasicArc[adj]] = 0;
601 if (m_pathNode[adj->twin()->cyclicSucc()->theNode()] &&
602 (m_pOR->direction(adj->faceCycleSucc()) == m_arcDir)
604 m_originalEdge[m_pathNode[adj->twin()->cyclicSucc()->theNode()]] =
605 m_pPR->original(adj->twin()->cyclicSucc()->theEdge());
608 for (adj = cornerOppDir; m_pOR->direction(adj) == m_oppArcDir; adj = adj->faceCycleSucc())
610 m_cost[m_edgeToBasicArc[adj]] = 0;
612 if (m_pathNode[adj->twin()->cyclicSucc()->theNode()])
613 m_originalEdge[m_pathNode[adj->twin()->cyclicSucc()->theNode()]] =
614 m_pPR->original(adj->twin()->cyclicSucc()->theEdge());
620 // insert arcs required for respecting vertex sizes, sizes of routing channels
621 // and position of attached generalizations
622 // vertices are represented by variable cages
623 template<class ATYPE>
624 void CompactionConstraintGraph<ATYPE>::insertVertexSizeArcs(
625 const PlanRep &PG,
626 const NodeArray<ATYPE> &sizeOrig,
627 const RoutingChannel<ATYPE> &rc)
630 // segments in constraint graph are sides sMin and sMax; other two side
631 // are sides in which adjacency entries run in direction m_arcDir and
632 // m_oppArcDir
633 OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
634 OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
636 const ATYPE overhang = rc.overhang();
638 node v;
639 forall_nodes(v,PG)
641 if (PG.expandAdj(v) == 0) continue;
643 if(PG.typeOf(v) == Graph::generalizationMerger)
645 resetGenMergerLengths(PG,PG.expandAdj(v));
648 else // high/low-degree expander
650 ATYPE size = sizeOrig[v];
652 const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v);
654 // determine routing channels rcMin and rcMax
655 ATYPE rcMin = overhang + rc(v,dirMin);
656 ATYPE rcMax = overhang + rc(v,dirMax);
658 adjEntry cornerDir = vi.m_corner[m_arcDir];
659 adjEntry cornerOppDir = vi.m_corner[m_oppArcDir];
660 adjEntry cornerMin = vi.m_corner[dirMin];
661 adjEntry cornerMax = vi.m_corner[dirMax];
663 // set cost of edges on the cage boundary to 0
664 setBoundaryCosts(cornerDir,cornerOppDir);
666 const OrthoRep::SideInfoUML &sDir = vi.m_side[m_arcDir];
667 const OrthoRep::SideInfoUML &sOppDir = vi.m_side[m_oppArcDir];
669 // correct lengths of edges within cage adjacent to corners
670 if(sDir.totalAttached() > 0) {
671 m_length[m_edgeToBasicArc[cornerDir]] = rcMin;
672 m_length[m_edgeToBasicArc[cornerMax->faceCyclePred()]] = rcMax;
673 } else {
674 // if no edges are attached at this side we need no constraint
675 m_length[m_edgeToBasicArc[cornerDir]] = 0;
676 delEdge(m_edgeToBasicArc[cornerDir]);
679 if(sOppDir.totalAttached() > 0) {
680 m_length[m_edgeToBasicArc[cornerOppDir]] = rcMax;
681 m_length[m_edgeToBasicArc[cornerMin->faceCyclePred()]] = rcMin;
682 } else {
683 // if no edges are attached at this side we need no constraint
684 m_length[m_edgeToBasicArc[cornerOppDir]] = 0;
685 delEdge(m_edgeToBasicArc[cornerOppDir]);
689 // insert arcs for respecting vertex size / position of generalizations
690 node vMin = m_pathNode[cornerDir->theNode()];
691 node vMax = m_pathNode[cornerOppDir->theNode()];
693 // any attached generalizations ?
694 if (sDir.m_adjGen == 0 && sOppDir.m_adjGen == 0)
696 // no, only one arc for vertex size + routing channels
697 edge e = newEdge(vMin,vMax);
698 m_length[e] = rcMin + size + rcMax - 2*overhang;
699 m_cost [e] = 2*m_vertexArcCost;
700 m_type [e] = cetVertexSizeArc;
702 } else {
703 // yes, then two arcs for each side with an attached generalization
704 ATYPE minHalf = size/2;
705 ATYPE maxHalf = size - minHalf;
706 ATYPE lenMin = rcMin + minHalf - overhang;
707 ATYPE lenMax = maxHalf + rcMax - overhang;
709 if (sDir.m_adjGen != 0) {
710 node vCenter = m_pathNode[sDir.m_adjGen->theNode()];
711 edge e1 = newEdge(vMin,vCenter);
712 m_length[e1] = lenMin;
713 m_cost [e1] = m_vertexArcCost;
714 m_type [e1] = cetVertexSizeArc;
715 edge e2 = newEdge(vCenter,vMax);
716 m_length[e2] = lenMax;
717 m_cost [e2] = m_vertexArcCost;
718 m_type [e2] = cetVertexSizeArc;
721 if (sOppDir.m_adjGen != 0) {
722 node vCenter = m_pathNode[sOppDir.m_adjGen->theNode()];
723 edge e1 = newEdge(vMin,vCenter);
724 m_length[e1] = lenMin;
725 m_cost [e1] = m_vertexArcCost;
726 m_type [e1] = cetVertexSizeArc;
727 edge e2 = newEdge(vCenter,vMax);
728 m_length[e2] = lenMax;
729 m_cost [e2] = m_vertexArcCost;
730 m_type [e2] = cetVertexSizeArc;
735 } // high/lowDegreeExpander
740 template<class ATYPE>
741 void CompactionConstraintGraph<ATYPE>::setBasicArcsZeroLength(
742 const PlanRep &PG)
744 edge e;
745 forall_edges(e,PG)
747 edge arc = m_edgeToBasicArc[e];
748 if (arc == 0) continue;
750 node v = e->source();
751 node w = e->target();
752 if ( ((PG.typeOf(v) == Graph::dummy) && (PG.typeOf(w) == Graph::dummy) &&
753 (v->degree() == 2) && w->degree() == 2) &&
754 (m_pOR->angle(e->adjSource()) == m_pOR->angle(e->adjTarget()) ) && //no uturns
755 (PG.typeOf(e) != Graph::generalization)
758 m_length[arc] = 0;
759 m_type[arc] = cetFixToZeroArc;
760 //we make fixtozero arcs as expensive as possible
761 m_cost[arc] = m_doubleBendCost;
769 // insert arcs required for respecting vertex sizes
770 // and position of attached generalizations
771 // vertices are represented by tight cages
772 template<class ATYPE>
773 void CompactionConstraintGraph<ATYPE>::insertVertexSizeArcs(
774 const PlanRep &PG,
775 const NodeArray<ATYPE> &sizeOrig,
776 const MinimumEdgeDistances<ATYPE> &minDist)
778 // set the length of all basic arcs corresponding to inner edge segments
779 // to 0
780 setBasicArcsZeroLength(PG);
782 // segments in constraint graph are sides sMin and sMax; other two side
783 // are sides in which adjacency entries run in direction m_arcDir and
784 // m_oppArcDir
785 OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
786 OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
788 node v;
789 forall_nodes(v,PG)
791 if (PG.expandAdj(v) == 0) continue;
793 if(PG.typeOf(v) == Graph::generalizationMerger)
795 resetGenMergerLengths(PG,PG.expandAdj(v));
798 else // high/low-degree expander
800 ATYPE size = sizeOrig[v];
801 const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v);
803 adjEntry cornerDir = vi.m_corner[m_arcDir];
804 adjEntry cornerOppDir = vi.m_corner[m_oppArcDir];
805 adjEntry cornerMin = vi.m_corner[dirMin];
806 adjEntry cornerMax = vi.m_corner[dirMax];
808 adjEntry adj = cornerDir, last = cornerMax->faceCyclePred();
809 if(adj != last) {
810 m_length[m_edgeToBasicArc[adj]] = minDist.epsilon(v,m_arcDir,0);
811 m_length[m_edgeToBasicArc[last]] = minDist.epsilon(v,m_arcDir,1);
812 int i = 0;
813 for(adj = adj->faceCycleSucc(); adj != last; adj = adj->faceCycleSucc()) {
814 if (PG.typeOf(adj->cyclicPred()->theEdge()) == Graph::generalization)
815 i++;
816 m_length[m_edgeToBasicArc[adj]] = minDist.delta(v,m_arcDir,i);
820 adj = cornerOppDir, last = cornerMin->faceCyclePred();
821 if(adj != last) {
822 m_length[m_edgeToBasicArc[adj]] = minDist.epsilon(v,m_oppArcDir,0);
823 m_length[m_edgeToBasicArc[last]] = minDist.epsilon(v,m_oppArcDir,1);
824 int i = 0;
825 for(adj = adj->faceCycleSucc(); adj != last; adj = adj->faceCycleSucc()) {
826 if (PG.typeOf(adj->cyclicPred()->theEdge()) == Graph::generalization)
827 i++;
828 m_length[m_edgeToBasicArc[adj]] = minDist.delta(v,m_oppArcDir,i);
833 // insert arcs for respecting vertex size / position of generalizations
834 node vMin = m_pathNode[cornerDir->theNode()];
835 node vMax = m_pathNode[cornerOppDir->theNode()];
837 const OrthoRep::SideInfoUML &sDir = vi.m_side[m_arcDir];
838 const OrthoRep::SideInfoUML &sOppDir = vi.m_side[m_oppArcDir];
840 // any attached generalizations ?
841 if (sDir.m_adjGen == 0 && sOppDir.m_adjGen == 0)
843 //check for single edge case => special treatment
844 //generic case could handle all numbers
846 if ((sDir.totalAttached() == 1) || (sOppDir.totalAttached() == 1))
848 //first, insert a new center node and connect it
849 ATYPE lenMin = size/2;
850 ATYPE lenMax = size - lenMin;
851 node vCenter = newNode();
852 setExtra(vCenter, cornerDir->theNode(), lenMin);
854 edge e1 = newEdge(vMin,vCenter);
855 m_length[e1] = lenMin;
856 //if (lenMin < minDist.epsilon(v,m_arcDir,0)) exit(1);
857 m_cost[e1] = m_vertexArcCost;
858 m_type[e1] = cetVertexSizeArc;
859 edge e2 = newEdge(vCenter,vMax);
860 m_length[e2] = lenMax;
861 m_cost[e2] = m_vertexArcCost;
862 m_type[e2] = cetVertexSizeArc;
864 if (sDir.totalAttached() == 1)
867 //then, insert a moveable node connecting center
868 //and outgoing segment
869 node vBungee = newNode();
870 //+1 should fix the fixzerolength problem
871 setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_arcDir,0) );
873 edge eToBungee = newEdge(vMin, vBungee);
874 m_type[eToBungee] = cetMedianArc; //cetBasicArc; //is this ok !!!!!!!!!!!!!!
875 m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!!
876 m_length[eToBungee] = minDist.epsilon(v,m_arcDir,0);
878 edge eBungeeCenter = newEdge(vBungee, vCenter);
879 //bungee, center and outgoing segment may build column if in the middle
880 m_type[eBungeeCenter] = cetMedianArc;
881 m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
882 m_length[eBungeeCenter] = 0;
884 //attention: pathnode construct works only if degree 1
885 edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerDir->twinNode()]);
886 if (m_pathNode[cornerDir->twinNode()] == vMin) exit(1);
887 //bungee, center and outgoing segment may build column if in the middle
888 m_type[eBungeeOut] = cetMedianArc;
889 m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
890 m_length[eBungeeOut] = 0;
892 //connect outgoing segment and "right" segment, maybe obsolete
893 edge eFromOut = newEdge(m_pathNode[cornerDir->twinNode()], vMax);
894 m_type[eFromOut] = cetBasicArc; //!!!!!!!!!!!!!!!!!!!!!!!
895 m_cost[eFromOut] = 0; //!!!!!!!!!!!!!!!!!!!
896 m_length[eFromOut] = minDist.epsilon(v,m_arcDir,1);
898 }//if sDir case
899 if ( (sOppDir.totalAttached() == 1) && !(m_pathNode[cornerOppDir->twinNode()] == vMin) )
902 //then, insert a moveable node connecting center
903 //and outgoing segment
904 node vBungee = newNode();
905 //+1 for not fixzerolength
906 setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_oppArcDir,0) );
908 edge eToBungee = newEdge(vMin, vBungee);
909 m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!!
910 m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!!
911 m_length[eToBungee] = minDist.epsilon(v,m_oppArcDir,0);
913 edge eBungeeCenter = newEdge(vBungee, vCenter);
914 //bungee, center and outgoing segment may build column if in the middle
915 m_type[eBungeeCenter] = cetMedianArc;
916 m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
917 m_length[eBungeeCenter] = 0;
919 //attention: pathnode construct works only if degree 1, sometimes not at all
920 edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerOppDir->twinNode()]);
921 //bungee, center and outgoing segment may build column if in the middle
922 m_type[eBungeeOut] = cetMedianArc;
923 m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
924 m_length[eBungeeOut] = 0;
926 //connect outgoing segment and "right" segment, maybe obsolete
927 edge eFromOut = newEdge(m_pathNode[cornerOppDir->twinNode()], vMax);
928 m_type[eFromOut] = cetBasicArc; //!!!!!!!!!!!!!!!!!!!!!!!
929 m_cost[eFromOut] = 0; //!!!!!!!!!!!!!!!!!!!
930 m_length[eFromOut] = minDist.epsilon(v,m_oppArcDir,0);
932 }//if sOppDir case
933 }//if special case
934 else
936 // no, only one arc for vertex size + routing channels
937 edge e = newEdge(vMin,vMax);
938 m_length[e] = size;
939 m_cost[e] = 2*m_vertexArcCost;
940 m_type[e] = cetVertexSizeArc;
941 }//else special case
944 } else {
945 // yes, then two arcs for each side with an attached generalization
946 ATYPE lenMin = size/2;
947 ATYPE lenMax = size - lenMin;
949 //ATYPE len = size/2;
951 if (sDir.m_adjGen != 0) {
952 node vCenter = m_pathNode[sDir.m_adjGen->theNode()];
953 edge e1 = newEdge(vMin,vCenter);
954 m_length[e1] = lenMin;
955 m_cost [e1] = m_vertexArcCost;
956 m_type [e1] = cetVertexSizeArc;
957 edge e2 = newEdge(vCenter,vMax);
958 m_length[e2] = lenMax;
959 m_cost [e2] = m_vertexArcCost;
960 m_type [e2] = cetVertexSizeArc;
962 else
964 if (sDir.totalAttached() == 1)
966 node vCenter = newNode();//m_pathNode[sOppDir.m_adjGen->theNode()]; //newNode();
967 setExtra(vCenter, cornerDir->theNode(), lenMin);
969 edge e1 = newEdge(vMin,vCenter);
970 m_length[e1] = lenMin;
971 m_cost[e1] = m_vertexArcCost;
972 m_type[e1] = cetVertexSizeArc;
973 edge e2 = newEdge(vCenter,vMax);
974 m_length[e2] = lenMax;
975 m_cost[e2] = m_vertexArcCost;
976 m_type[e2] = cetVertexSizeArc;
978 //then, insert a moveable node connecting center
979 //and outgoing segment
980 node vBungee = newNode();
981 //+1 for not fixzerolength
982 setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_arcDir,0) );
984 edge eToBungee = newEdge(vMin, vBungee);
985 m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!!
986 m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!!
987 m_length[eToBungee] = minDist.epsilon(v,m_arcDir,0);
989 edge eBungeeCenter = newEdge(vBungee, vCenter);
990 //bungee, center and outgoing segment may build column if in the middle
991 m_type[eBungeeCenter] = cetMedianArc;
992 m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
993 m_length[eBungeeCenter] = 0;
995 //attention: pathnode construct works only if degree 1
996 edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerDir->twinNode()]);
997 //bungee, center and outgoing segment may build column if in the middle
998 m_type[eBungeeOut] = cetMedianArc;
999 m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
1000 m_length[eBungeeOut] = 0;
1002 }//if sDir case
1003 }//else, only oppdir
1004 if (sOppDir.m_adjGen != 0) {
1005 node vCenter = m_pathNode[sOppDir.m_adjGen->theNode()];
1006 edge e1 = newEdge(vMin,vCenter);
1007 m_length[e1] = lenMin;
1008 m_cost [e1] = m_vertexArcCost;
1009 m_type [e1] = cetVertexSizeArc;
1010 edge e2 = newEdge(vCenter,vMax);
1011 m_length[e2] = lenMax;
1012 m_cost [e2] = m_vertexArcCost;
1013 m_type [e2] = cetVertexSizeArc;
1015 else
1017 //special case single edge to middle position
1018 if ( (sOppDir.totalAttached() == 1) && !(m_pathNode[cornerOppDir->twinNode()] == vMin) )
1020 node vCenter = newNode();//m_pathNode[sDir.m_adjGen->theNode()];//newNode();
1021 setExtra(vCenter, cornerDir->theNode(), lenMin);
1023 edge e1 = newEdge(vMin,vCenter);
1024 m_length[e1] = lenMin;
1025 m_cost[e1] = m_vertexArcCost;
1026 m_type[e1] = cetVertexSizeArc;
1027 edge e2 = newEdge(vCenter,vMax);
1028 m_length[e2] = lenMax;
1029 m_cost[e2] = m_vertexArcCost;
1030 m_type[e2] = cetVertexSizeArc;
1031 //then, insert a moveable node connecting center
1032 //and outgoing segment
1033 node vBungee = newNode();
1034 //+1 for not fixzerolength
1035 setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_oppArcDir,0) );
1037 edge eToBungee = newEdge(vMin, vBungee);
1038 m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!!
1039 m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!!
1040 m_length[eToBungee] = minDist.epsilon(v,m_oppArcDir,0);
1042 edge eBungeeCenter = newEdge(vBungee, vCenter);
1043 //bungee, center and outgoing segment may build column if in the middle
1044 m_type[eBungeeCenter] = cetMedianArc;
1045 m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
1046 m_length[eBungeeCenter] = 0;
1048 //attention: pathnode construct works only if degree 1
1049 edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerOppDir->twinNode()]);
1050 //bungee, center and outgoing segment may build column if in the middle
1051 m_type[eBungeeOut] = cetMedianArc;
1052 m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
1053 m_length[eBungeeOut] = 0;
1055 }//if sOppDir case
1056 }//else only dir gen
1060 // set cost of edges on the cage boundary to 0
1061 setBoundaryCosts(cornerDir,cornerOppDir);
1063 } // high/lowDegreeExpander
1065 //if (m_arcDir == odEast) writeGML("eastvertexsizeinserted.gml");
1066 //else writeGML("northvertexsizeinserted.gml");
1070 // computes the total costs for coordintes given by pos, i.e.,
1071 // the sum of the weighted lengths of edges in the constraint graph.
1072 template<class ATYPE>
1073 ATYPE CompactionConstraintGraph<ATYPE>::computeTotalCosts(
1074 const NodeArray<ATYPE> &pos) const
1076 ATYPE c = 0;
1078 edge e;
1079 forall_edges(e,*this)
1081 c += cost(e) * (pos[e->target()] - pos[e->source()]);
1084 return c;
1089 // insertion of visibility arcs
1091 // checks if intervals on the sweep line are in correct order
1092 template<class ATYPE>
1093 bool CompactionConstraintGraph<ATYPE>::checkSweepLine(const List<Interval> &sweepLine)
1095 if (sweepLine.empty())
1096 return true;
1098 ListConstIterator<Interval> it = sweepLine.begin();
1100 if((*it).m_high < (*it).m_low)
1101 return false;
1103 ATYPE x = (*it).m_low;
1105 for(++it; it.valid(); ++it) {
1106 if((*it).m_high < (*it).m_low)
1107 return false;
1108 if ((*it).m_high > x)
1109 return false;
1110 x = (*it).m_low;
1113 return true;
1117 template<class ATYPE>
1118 void CompactionConstraintGraph<ATYPE>::insertVisibilityArcs(
1119 const PlanRep &PG,
1120 const NodeArray<ATYPE> &posDir,
1121 const NodeArray<ATYPE> &posOrthDir
1124 MinimumEdgeDistances<ATYPE> minDist(PG, m_sep);
1126 node v;
1127 forall_nodes(v,PG)
1129 if(PG.expandAdj(v) == 0) continue;
1131 for(int d = 0; d < 4; ++d) {
1132 minDist.delta(v,OrthoDir(d),0) = m_sep;//currentSeparation;
1133 minDist.delta(v,OrthoDir(d),1) = m_sep;//currentSeparation;
1137 insertVisibilityArcs(PG,posDir,posOrthDir,minDist);
1142 // inserts arcs connecting segments which can see each other in a drawing
1143 // of the associated planarized representation PG which is given by
1144 // posDir and posOppDir.
1146 //ersetze mindist.delta durch min(m_sep, mindist.delta) fuer skalierung
1147 template<class ATYPE>
1148 void CompactionConstraintGraph<ATYPE>::insertVisibilityArcs(
1149 const PlanRep &PG,
1150 const NodeArray<ATYPE> &posDir,
1151 const NodeArray<ATYPE> &posOrthDir,
1152 const MinimumEdgeDistances<ATYPE> &minDist)
1154 OrthoDir segDir = OrthoRep::prevDir(m_arcDir);
1155 OrthoDir segOppDir = OrthoRep::nextDir(m_arcDir);
1157 // list of visibility arcs which have to be inserted
1158 SListPure<Tuple2<node,node> > visibArcs;
1160 // lower and upper bound of segments
1161 NodeArray<ATYPE> low(getGraph()), lowReal(getGraph()), high(getGraph());
1162 NodeArray<ATYPE> segPos(getGraph(), 0); // position of segments
1163 NodeArray<int> topNum(getGraph()/*,0*/); // secondary sorting criteria for segments
1165 // compute position and lower/upper bound of segments
1166 // We have to take care that segments cannot be shifted one upon the other,
1167 // e.g., if we have two segments (l1,h1) and (l2,h2) with l2 > h2 and
1168 // the distance l2-h2 is smaller than separation, the segments can see
1169 // each other. We do this by enlarging the lower bound of all segments
1170 // by separation if this lower bound is realized by a bend.
1172 // Note: Be careful at segments attached at a vertex which are closer
1173 // than separation to each other. Possible solution: Remove visibility
1174 // arcs of segments which are connected by orthogonal segments to the
1175 // same vertex and bend in opposite directions.
1176 node v;
1177 forall_nodes(v,*this) {
1179 //special case nodes
1180 if (m_path[v].empty()) continue;
1182 SListConstIterator<node> it = m_path[v].begin();
1184 segPos[v] = posDir[*it];
1185 low[v] = high[v] = posOrthDir[*it];
1186 node nodeLow = *it;
1187 for(++it; it.valid(); ++it) {
1188 ATYPE x = posOrthDir[*it];
1189 if (x < low [v]) {
1190 low [v] = x;
1191 nodeLow = *it;
1193 if (x > high[v]) high[v] = x;
1195 lowReal[v] = low[v];
1196 Graph::NodeType typeLow = PG.typeOf(nodeLow);
1197 if(typeLow == Graph::dummy || typeLow == Graph::generalizationExpander) {
1198 /*bool subtractSep = true;
1199 if (nodeLow->degree() == 2) {
1200 adjEntry adj;
1201 forall_adj(adj,nodeLow) {
1202 if(m_pOR->direction(adj) == m_arcDir || m_pOR->direction(adj) == m_oppArcDir)
1203 break;
1205 if (adj) {
1206 for(adjEntry adj2 = adj->faceCycleSucc();
1207 m_pOR->direction(adj2) == m_pOR->direction(adj);
1208 adj2 = adj2->twin()->faceCycleSucc()) ;
1209 if(posDir[adj->theNode()] == posDir[adj2->twinNode()])
1210 subtractSep = false;
1213 //if (subtractSep)*/
1214 low[v] -= m_sep;
1218 // correct "-= m_sep" ...
1219 OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
1220 OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
1221 bool isCaseA = (m_arcDir == odEast || m_arcDir == odSouth);
1222 const int angleAtMin = (m_arcDir == odEast || m_arcDir == odSouth) ? 3 : 1;
1223 const int angleAtMax = (m_arcDir == odEast || m_arcDir == odSouth) ? 1 : 3;
1224 forall_nodes(v,PG)
1226 if(PG.expandAdj(v) == 0) continue;
1227 const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v);
1229 int i = 0;
1230 adjEntry adj;
1232 for (adj = (isCaseA) ? vi.m_corner[dirMin]->faceCycleSucc()->faceCycleSucc() : vi.m_corner[dirMin]->faceCycleSucc();
1233 m_pOR->direction((isCaseA) ? adj : adj->faceCycleSucc()) == dirMin; //m_pOR->direction(adj) == dirMin;
1234 adj = adj->faceCycleSucc())
1236 adjEntry adjCross = adj->cyclicPred();
1237 adjEntry adjTwin = adjCross->twin();
1239 adjEntry adjPred = adj->faceCyclePred();
1240 ATYPE delta = (isCaseA) ?
1241 min(abs(posOrthDir[adjPred->theNode()] - posOrthDir[adjPred->twinNode()]), m_sep) :
1242 min(abs(posOrthDir[adj->theNode()] - posOrthDir[adj->twinNode()]), m_sep);
1243 ATYPE boundary = (isCaseA) ?
1244 min(posOrthDir[adjPred->theNode()], posOrthDir[adjPred->twinNode()]) :
1245 min(posOrthDir[adj->theNode()], posOrthDir[adj->twinNode()]);
1247 if (PG.typeOf(adjCross->theEdge()) == Graph::generalization)
1249 if (isCaseA) {
1250 if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander &&
1251 m_pOR->angle(adjTwin) == 2)
1253 node s1 = m_pathNode[adjTwin->theNode()];
1254 node s2 = m_pathNode[adjTwin->cyclicSucc()->twinNode()];
1255 low[s1] = lowReal[s1] - delta; // minDist.delta(v,dirMin,i);
1256 low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMin,i);
1258 ++i;
1259 } else {
1260 ++i;
1261 if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander &&
1262 m_pOR->angle(adjTwin->cyclicPred()) == 2)
1264 node s1 = m_pathNode[adjTwin->theNode()];
1265 node s2 = m_pathNode[adjTwin->cyclicPred()->twinNode()];
1266 low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMin,i);
1267 low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMin,i);
1270 continue;
1273 //we save the current direction and stop if we run in opposite
1274 OrthoDir runDir = m_pOR->direction(adjCross);
1275 // if -> while
1276 while (PG.typeOf(adjTwin->theNode()) == Graph::dummy &&
1277 adjTwin->theNode()->degree() == 2 &&
1278 m_pOR->angle(adjTwin) == angleAtMin)
1280 // We handle the case if an edge segment adjacent to a vertex
1281 // is separated by less than separation from edge segments above.
1282 node s = m_edgeToBasicArc[adjCross]->source();
1283 if(lowReal[s] != low[s])
1285 if(low[s] >= boundary) // nothing to do?
1286 break;
1287 low[s] = boundary;
1288 //low[s] += m_sep - delta; //minDist.delta(v,dirMin,i);
1290 // If the compaction has eliminated bends, we can have the situation
1291 // that segment s has length 0 and the next segment s' (following the
1292 // edge) is at the same position (the edge arc has length 0).
1293 // In this case, the low-value of s' must be lowered (low[s'] := lowReal[s']
1294 // is approproate). The same situation can appear several times in a
1295 // row.
1296 //collect chains of segments compacted to zero length
1297 for( ; ; ) { //while(true/*lowReal[s] == high[s]*/) {
1298 do {
1299 adjCross = adjCross->faceCycleSucc();
1300 } while(m_pOR->direction(adjCross) == segDir ||
1301 m_pOR->direction(adjCross) == segOppDir);
1303 if(adjCross->theNode()->degree() != 2) // no longer a bend point?
1304 break;
1306 node sNext = m_edgeToBasicArc[adjCross]->opposite(s);
1308 if(segPos[sNext] != segPos[s])
1309 break;
1311 low[sNext] = lowReal[sNext]; //?
1312 s = sNext;
1313 }//while
1314 }//if
1316 adjTwin = adjCross->twin(); // update of twin for while
1317 //check if we have to stop
1318 if (runDir != m_pOR->direction(adjCross)) break;
1319 }//while dummy bend
1322 i = 0;
1323 for (adj = (isCaseA) ? vi.m_corner[dirMax]->faceCycleSucc() : vi.m_corner[dirMax]->faceCycleSucc()->faceCycleSucc();
1324 m_pOR->direction((isCaseA) ? adj->faceCycleSucc() : adj) == dirMax; // m_pOR->direction(adj) == dirMax;
1325 adj = adj->faceCycleSucc())
1327 adjEntry adjCross = adj->cyclicPred();
1328 adjEntry adjTwin = adjCross->twin();
1330 //ATYPE delta = -posOrthDir[adj->twinNode()] + posOrthDir[adj->theNode()];
1331 adjEntry adjPred = adj->faceCyclePred();
1332 ATYPE delta = (isCaseA) ?
1333 min(abs(posOrthDir[adj->twinNode()] - posOrthDir[adj->theNode()]), m_sep) :
1334 min(abs(posOrthDir[adjPred->theNode()] - posOrthDir[adjPred->twinNode()]), m_sep);
1335 ATYPE boundary = (isCaseA) ?
1336 min(posOrthDir[adj->twinNode()], posOrthDir[adj->theNode()]) :
1337 min(posOrthDir[adjPred->theNode()], posOrthDir[adjPred->twinNode()]);
1339 if (PG.typeOf(adjCross->theEdge()) == Graph::generalization)
1341 if (isCaseA) {
1342 ++i;
1343 if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander &&
1344 m_pOR->angle(adjTwin->cyclicPred()) == 2)
1346 node s1 = m_pathNode[adjTwin->theNode()];
1347 node s2 = m_pathNode[adjTwin->cyclicPred()->twinNode()];
1348 low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMax,i);
1349 low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMax,i);
1351 } else {
1352 if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander &&
1353 m_pOR->angle(adjTwin) == 2)
1355 node s1 = m_pathNode[adjTwin->theNode()];
1356 node s2 = m_pathNode[adjTwin->cyclicSucc()->twinNode()];
1357 low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMax,i);
1358 low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMax,i);
1360 ++i;
1362 continue;
1366 //we save the current direction and stop if we run in opposite
1367 OrthoDir runDir = m_pOR->direction(adjCross);
1368 // if -> while
1369 while (PG.typeOf(adjTwin->theNode()) == Graph::dummy &&
1370 adjTwin->theNode()->degree() == 2 &&
1371 m_pOR->angle(adjTwin) == angleAtMax)
1373 node s = m_edgeToBasicArc[adjCross]->target();
1374 if(lowReal[s] != low[s])
1376 if(low[s] >= boundary) // nothing to do?
1377 break;
1378 low[s] = boundary;
1379 //low[s] += m_sep - delta; //minDist.delta(v,dirMax,i);
1381 // If the compaction has eliminated bends, we can have the situation
1382 // that segment s has length 0 and the next segment s' (following the
1383 // edge) is at the same position (the edge arc has length 0).
1384 // In this case, the low-value of s' must be lowered (low[s'] := lowReal[s']
1385 // is approproate). The same situation can appear several times in a
1386 // row.
1387 //collect chains of segments compacted to zero length
1388 for( ; ; ) /*lowReal[s] == high[s]*/
1392 adjCross = adjCross->faceCycleSucc();
1393 } while(m_pOR->direction(adjCross) == segDir ||
1394 m_pOR->direction(adjCross) == segOppDir);
1396 if(adjCross->theNode()->degree() != 2) // no longer a bend point?
1397 break;
1399 node sNext = m_edgeToBasicArc[adjCross]->opposite(s);
1401 if(segPos[sNext] != segPos[s])
1402 break;
1404 low[sNext] = lowReal[sNext];//was: low[s]
1405 s = sNext;
1407 }//if lowreal != low
1409 adjTwin = adjCross->twin(); // update of twin for while
1411 //check if we have to stop
1412 if (runDir != m_pOR->direction(adjCross)) break;
1413 }//while dummy
1417 // compute topological numbering of segments as second sorting criteria
1418 // in order to process overlapping segments in the order imposed by the
1419 // embedding
1420 computeTopologicalSegmentNum(topNum);
1423 // sort segments
1424 SegmentComparer cmpBySegPos(segPos,topNum);
1425 List<node> sortedPathNodes;
1426 allNodes(sortedPathNodes);
1427 sortedPathNodes.quicksort(cmpBySegPos);
1429 // add segments in the order given by sortedPathNodes to sweep line
1430 List<Interval> sweepLine;
1432 ListIterator<node> itV;
1433 for(itV = sortedPathNodes.begin(); itV.valid(); ++itV)
1435 //special case nodes
1436 if (m_path[*itV].empty()) continue;
1437 OGDF_ASSERT_IF(dlExtendedChecking,checkSweepLine(sweepLine));
1439 node v = *itV;
1440 ListIterator<Interval> it;
1441 for(it = sweepLine.begin(); it.valid(); ++it) {
1442 if ((*it).m_low < high[v])
1443 break;
1446 if (!it.valid()) {
1447 sweepLine.pushBack(Interval(v,low[v],high[v]));
1448 continue;
1451 if((*it).m_high <= low[v]) {
1452 sweepLine.insertBefore(Interval(v,low[v],high[v]),it);
1453 continue;
1456 ListIterator<Interval> itUp = it, itSucc;
1457 // we store if itUp will be deleted in order not to
1458 // access the deleted iterator later
1459 bool isItUpDel = ( ((*itUp).m_low >= low[v]) && ((*itUp).m_high <= high[v]) );
1461 for(; it.valid() && (*it).m_low >= low[v]; it = itSucc) {
1462 itSucc = it.succ();
1463 if ((*it).m_high <= high[v]) {
1464 visibArcs.pushBack(Tuple2<node,node>((*it).m_pathNode,v));
1465 sweepLine.del(it);
1469 if (it == itUp && (*it).m_high > high[v]) {
1470 node w = (*it).m_pathNode;
1471 sweepLine.insertAfter(Interval(w,(*it).m_low,low[v]),it);
1472 (*it).m_low = high[v];
1473 sweepLine.insertAfter(Interval(v,low[v],high[v]),it);
1474 visibArcs.pushBack(Tuple2<node,node>(w,v));
1476 } else {
1477 if ( (!isItUpDel) && itUp != it && (*itUp).m_low < high[v]) {
1478 (*itUp).m_low = high[v];
1479 visibArcs.pushBack(Tuple2<node,node>((*itUp).m_pathNode,v));
1481 if (it.valid()) {
1482 if ((*it).m_high > low[v]) {
1483 (*it).m_high = low[v];
1484 visibArcs.pushBack(Tuple2<node,node>((*it).m_pathNode,v));
1486 sweepLine.insertBefore(Interval(v,low[v],high[v]),it);
1488 } else {
1489 sweepLine.pushBack(Interval(v,low[v],high[v]));
1495 // remove all arcs from visibArcs that are already in the constraint graph
1496 removeRedundantVisibArcs(visibArcs);
1498 // compute original adjacency entry corresponding to a segment
1499 // We use this in order to omit visibility arcs between segments which
1500 // belong to the same edge if they can see each other from the same side
1501 // of the edge; if they see each other from different sides the arc is
1502 // essential!
1503 NodeArray<adjEntry> correspEdge(getGraph(),0);
1504 forall_nodes(v,PG) {
1505 node seg = m_pathNode[v];
1506 adjEntry adj;
1507 forall_adj(adj,v) {
1508 if(m_pOR->direction(adj) != segDir) continue;
1509 edge eAdj = adj->theEdge();
1510 edge eOrig = PG.original(eAdj);
1511 if (eOrig == 0) continue;
1512 if (adj == eAdj->adjSource())
1513 correspEdge[seg] = eOrig->adjSource();
1514 else
1515 correspEdge[seg] = eOrig->adjTarget();
1519 // remove visibility arcs between ...
1520 SListIterator<Tuple2<node,node> > itT, itTSucc, itTPred;
1521 for(itT = visibArcs.begin(); itT.valid(); itT = itTSucc) {
1522 itTSucc = itT.succ();
1523 node v = (*itT).x1(), w = (*itT).x2();
1525 // remove arcs which connect segments belonging to the same edge
1526 if (correspEdge[v] && (correspEdge[v] == correspEdge[w]))
1528 if (itTPred.valid())
1529 visibArcs.delSucc(itTPred);
1530 else
1531 visibArcs.popFront();
1534 else
1535 itTPred = itT;
1540 for(itT = visibArcs.begin(); itT.valid(); ++itT) {
1541 //***********************************CHECK if
1542 node v = (*itT).x1(), w = (*itT).x2();
1543 if (!(m_extraNode[v] || m_extraNode[w]))
1545 //******************************CHECK if
1546 node boundRepresentant1 = m_path[v].front();
1547 node boundRepresentant2 = m_path[w].front();
1548 node en1 = m_pPR->expandedNode(boundRepresentant1);
1549 node en2 = m_pPR->expandedNode(boundRepresentant2);
1550 //do not insert visibility in cages
1551 if (!( ( en1 && en2 ) && ( en1 == en2) ))
1553 edge e = newEdge(v,w);
1555 //hier vielleicht multiedges abfangen: length auf max(min(sep, dists), minDist.sep)
1557 m_length[e] = max(m_sep, minDist.separation()); //m_sep;
1558 m_cost [e] = 0;
1559 m_type [e] = cetVisibilityArc;
1561 //writeGML("visibilityinserted.gml");
1562 }//special if 2
1563 }//special if 1
1566 OGDF_ASSERT_IF(dlExtendedChecking,checkSweepLine(sweepLine));
1568 }//insertvisibilityarcs
1572 // performs feasibility test for position assignment pos, i.e., checks if
1573 // the segment positions given by pos fulfill the constraints in the
1574 // compaction constraint graph
1575 template<class ATYPE>
1576 bool CompactionConstraintGraph<ATYPE>::isFeasible(
1577 const NodeArray<ATYPE> &pos)
1579 edge e;
1580 forall_edges(e, getGraph()) {
1581 node v = m_path[e->source()].front();
1582 node w = m_path[e->target()].front();;
1583 if (pos[w] - pos[v] < length(e)) {
1584 cout << "feasibility check failed for edge " << e << endl;
1585 cout << " representatives: " << v << ", " << w << endl;
1586 cout << " length: " << length(e) << endl;
1587 cout << " actual distance: " << pos[w] - pos[v] << endl;
1588 cout << " type of " << e << ": ";
1589 switch(m_type[e]) {
1590 case cetBasicArc: cout << "basic arc" << endl;
1591 break;
1592 case cetVertexSizeArc: cout << "vertex-size arc" << endl;
1593 break;
1594 case cetVisibilityArc: cout << "visibility arc" << endl;
1595 break;
1596 case cetMedianArc: cout << "median arc" << endl;
1597 break;
1598 case cetReducibleArc: cout << "reducible arc" <<endl;
1599 break;
1600 case cetFixToZeroArc: cout << "fixtozero arc" <<endl;
1603 return false;
1607 return true;
1610 //colouring for extranode
1611 template<class ATYPE>
1612 void CompactionConstraintGraph<ATYPE>::writeGML(const char *filename) const
1614 ofstream os(filename);
1615 writeGML(os);
1618 template<class ATYPE>
1619 void CompactionConstraintGraph<ATYPE>::writeGML(ostream &os) const
1621 const Graph &G = *this;
1623 NodeArray<int> id(getGraph());
1624 int nextId = 0;
1626 os.setf(ios::showpoint);
1627 os.precision(10);
1629 os << "Creator \"ogdf::CompactionConstraintGraphBase::writeGML\"\n";
1630 os << "graph [\n";
1631 os << " directed 1\n";
1633 node v;
1634 forall_nodes(v,G) {
1635 os << " node [\n";
1636 os << " id " << (id[v] = nextId++) << "\n";
1638 if (m_extraNode[v]) {
1639 os << " label \"" << "0" << "\"\n";
1640 } else {
1641 os << " label \"" << m_pPR->expandedNode(m_path[v].front()) << "\"\n";
1644 os << " graphics [\n";
1645 os << " x 0.0\n";
1646 os << " y 0.0\n";
1647 os << " w 30.0\n";
1648 os << " h 30.0\n";
1649 if (m_extraNode[v])
1650 os << " fill \"#00FFFF\"\n";
1651 else
1652 os << " fill \"#FFFF00\"\n";
1653 os << " ]\n"; // graphics
1655 os << " ]\n"; // node
1658 edge e;
1659 forall_edges(e,G) {
1660 os << " edge [\n";
1661 os << " source " << id[e->source()] << "\n";
1662 os << " target " << id[e->target()] << "\n";
1664 // nice idea to use the edge length as edge labels, but Graphwin-
1665 // garbage is not able to show the graph (thinks it has to set
1666 // the y-coordinates of all nodes to NAN)
1667 #if 0
1668 os << " label \"";
1669 writeLength(os, e);
1670 os << "\"\n";
1671 #endif
1673 os << " graphics [\n";
1675 os << " type \"line\"\n";
1676 os << " arrow \"last\"\n";
1677 switch(m_type[e])
1679 case cetBasicArc: // red
1680 os << " fill \"#FF0000\"\n";
1681 break;
1682 case cetVertexSizeArc: // blue
1683 os << " fill \"#0000FF\"\n";
1684 break;
1685 case cetVisibilityArc: // green
1686 os << " fill \"#00FF00\"\n";
1687 break;
1688 case cetReducibleArc: // red
1689 os << " fill \"#FF0000\"\n";
1690 break;
1691 case cetFixToZeroArc: // violett
1692 os << " fill \"#AF00FF\"\n";
1693 break;
1694 case cetMedianArc: // rose
1695 os << " fill \"#FF00FF\"\n";
1696 break;
1699 os << " ]\n"; // graphics
1701 #if 0
1702 os << " LabelGraphics [\n";
1703 os << " type \"text\"\n";
1704 os << " fill \"#000000\"\n";
1705 os << " anchor \"w\"\n";
1706 os << " ]\n";
1707 #endif
1709 os << " ]\n"; // edge
1712 os << "]\n"; // graph
1716 } // end namespace ogdf
1719 #endif