6 * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $
7 ***************************************************************/
10 * \brief Declares CompactionConstraintGraph.
12 * I.e. a representation of constraint graphs (dependency graphs)
13 * used in compaction algorithms.
15 * \author Carsten Gutwenger
18 * This file is part of the Open Graph Drawing Framework (OGDF).
22 * See README.txt in the root directory of the OGDF installation for details.
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
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.
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 ***************************************************************/
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>
64 // types of edges in the constraint graph
65 enum ConstraintEdgeType
{
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
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
];}
121 CompactionConstraintGraphBase(const OrthoRep
&OR
,
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
132 void removeRedundantVisibArcs(SListPure
<Tuple2
<node
,node
> > &visibArcs
);
134 const OrthoRep
*m_pOR
;
135 const PlanRep
*m_pPR
;
137 OrthoDir m_oppArcDir
;
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
163 virtual void writeLength(ostream
&os
, edge e
) const = 0;
167 //set special costs for node to merger generalizations
170 void insertPathVertices(const PlanRep
&PG
);
171 void dfsInsertPathVertex(
174 NodeArray
<bool> &visited
,
175 const NodeArray
<node
> &genOpposite
);
177 void insertBasicArcs(const PlanRep
&PG
);
181 SList
<node
> m_sources
;
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
202 CompactionConstraintGraph(const OrthoRep
&OR
,
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);
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
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 {
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 {
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 {
259 // returns cost of edge e
260 // Precond.: e is an edge in the constraint graph
261 int cost(edge e
) const {
265 // returns type of edge e
266 // Precond.: e is an edge in the constraint graph
267 ConstraintEdgeType
typeOf(edge e
) const {
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(
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(
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
321 const NodeArray
<ATYPE
> &posOppDir
); // position of orthogonal segment
322 // containing vertex in PG
324 void insertVisibilityArcs(
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
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;
358 //---------------------------------------------------------
359 // CompactionConstraintGraph::Interval
360 // represents an interval on the sweep line
361 //---------------------------------------------------------
364 Interval(node v
, ATYPE low
, ATYPE high
) {
370 ATYPE m_low
, m_high
; // lower and upper bound
371 node m_pathNode
; // corresponding segment
374 friend ostream
&operator<<(ostream
&os
,
375 const Interval
&interval
)
377 os
<< "[" << interval
.m_low
<< "," << interval
.m_high
<<
378 ";" << interval
.m_pathNode
<< "]";
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
394 SegmentComparer(const NodeArray
<ATYPE
> &segPos
,
395 const NodeArray
<int> &secSort
) {
400 int compare(const node
&x
, const node
&y
) const {
401 ATYPE d
= (*m_pPos
)[x
] - (*m_pPos
)[y
];
407 return (*m_pSec
)[x
] - (*m_pSec
)[y
];
410 OGDF_AUGMENT_COMPARER(node
)
412 const NodeArray
<ATYPE
> *m_pPos
;
413 const NodeArray
<int> *m_pSec
;
416 virtual void writeLength(ostream
&os
, edge e
) const {
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
);
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
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;
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,
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
;
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>
510 // allow 0-length for sides of generalization merger cages
511 template<class ATYPE
>
512 void CompactionConstraintGraph
<ATYPE
>::resetGenMergerLengths(
516 adjEntry adj
= adjFirst
;
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();
530 } while(adj
!= adjFirst
);
532 //****************************************
533 //generalization position section
534 //pull upper generalization to median of merger cage's incoming lower generalizations
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
);
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;
564 m_type[helper] = cetReducibleArc;
567 edge e1
= newEdge(vCenter
,upper
);
569 m_cost
[e1
] = m_MedianArcCost
;
570 m_type
[e1
] = cetMedianArc
;
572 edge e2
= newEdge(vCenter
,lower
);
574 m_cost
[e2
] = m_MedianArcCost
;
575 m_type
[e2
] = cetMedianArc
;
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(
586 adjEntry cornerOppDir
)
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
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(
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
633 OrthoDir dirMin
= OrthoRep::prevDir(m_arcDir
);
634 OrthoDir dirMax
= OrthoRep::nextDir(m_arcDir
);
636 const ATYPE overhang
= rc
.overhang();
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
;
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
;
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
;
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(
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
)
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(
775 const NodeArray
<ATYPE
> &sizeOrig
,
776 const MinimumEdgeDistances
<ATYPE
> &minDist
)
778 // set the length of all basic arcs corresponding to inner edge segments
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
785 OrthoDir dirMin
= OrthoRep::prevDir(m_arcDir
);
786 OrthoDir dirMax
= OrthoRep::nextDir(m_arcDir
);
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();
810 m_length
[m_edgeToBasicArc
[adj
]] = minDist
.epsilon(v
,m_arcDir
,0);
811 m_length
[m_edgeToBasicArc
[last
]] = minDist
.epsilon(v
,m_arcDir
,1);
813 for(adj
= adj
->faceCycleSucc(); adj
!= last
; adj
= adj
->faceCycleSucc()) {
814 if (PG
.typeOf(adj
->cyclicPred()->theEdge()) == Graph::generalization
)
816 m_length
[m_edgeToBasicArc
[adj
]] = minDist
.delta(v
,m_arcDir
,i
);
820 adj
= cornerOppDir
, last
= cornerMin
->faceCyclePred();
822 m_length
[m_edgeToBasicArc
[adj
]] = minDist
.epsilon(v
,m_oppArcDir
,0);
823 m_length
[m_edgeToBasicArc
[last
]] = minDist
.epsilon(v
,m_oppArcDir
,1);
825 for(adj
= adj
->faceCycleSucc(); adj
!= last
; adj
= adj
->faceCycleSucc()) {
826 if (PG
.typeOf(adj
->cyclicPred()->theEdge()) == Graph::generalization
)
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);
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);
936 // no, only one arc for vertex size + routing channels
937 edge e
= newEdge(vMin
,vMax
);
939 m_cost
[e
] = 2*m_vertexArcCost
;
940 m_type
[e
] = cetVertexSizeArc
;
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
;
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;
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
;
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;
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
1079 forall_edges(e
,*this)
1081 c
+= cost(e
) * (pos
[e
->target()] - pos
[e
->source()]);
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())
1098 ListConstIterator
<Interval
> it
= sweepLine
.begin();
1100 if((*it
).m_high
< (*it
).m_low
)
1103 ATYPE x
= (*it
).m_low
;
1105 for(++it
; it
.valid(); ++it
) {
1106 if((*it
).m_high
< (*it
).m_low
)
1108 if ((*it
).m_high
> x
)
1117 template<class ATYPE
>
1118 void CompactionConstraintGraph
<ATYPE
>::insertVisibilityArcs(
1120 const NodeArray
<ATYPE
> &posDir
,
1121 const NodeArray
<ATYPE
> &posOrthDir
1124 MinimumEdgeDistances
<ATYPE
> minDist(PG
, m_sep
);
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(
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.
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
];
1187 for(++it
; it
.valid(); ++it
) {
1188 ATYPE x
= posOrthDir
[*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) {
1201 forall_adj(adj,nodeLow) {
1202 if(m_pOR->direction(adj) == m_arcDir || m_pOR->direction(adj) == m_oppArcDir)
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)*/
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;
1226 if(PG
.expandAdj(v
) == 0) continue;
1227 const OrthoRep::VertexInfoUML
&vi
= *m_pOR
->cageInfo(v
);
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
)
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);
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);
1273 //we save the current direction and stop if we run in opposite
1274 OrthoDir runDir
= m_pOR
->direction(adjCross
);
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?
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
1296 //collect chains of segments compacted to zero length
1297 for( ; ; ) { //while(true/*lowReal[s] == high[s]*/) {
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?
1306 node sNext
= m_edgeToBasicArc
[adjCross
]->opposite(s
);
1308 if(segPos
[sNext
] != segPos
[s
])
1311 low
[sNext
] = lowReal
[sNext
]; //?
1316 adjTwin
= adjCross
->twin(); // update of twin for while
1317 //check if we have to stop
1318 if (runDir
!= m_pOR
->direction(adjCross
)) break;
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
)
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);
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);
1366 //we save the current direction and stop if we run in opposite
1367 OrthoDir runDir
= m_pOR
->direction(adjCross
);
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?
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
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?
1399 node sNext
= m_edgeToBasicArc
[adjCross
]->opposite(s
);
1401 if(segPos
[sNext
] != segPos
[s
])
1404 low
[sNext
] = lowReal
[sNext
];//was: low[s]
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;
1417 // compute topological numbering of segments as second sorting criteria
1418 // in order to process overlapping segments in the order imposed by the
1420 computeTopologicalSegmentNum(topNum
);
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
));
1440 ListIterator
<Interval
> it
;
1441 for(it
= sweepLine
.begin(); it
.valid(); ++it
) {
1442 if ((*it
).m_low
< high
[v
])
1447 sweepLine
.pushBack(Interval(v
,low
[v
],high
[v
]));
1451 if((*it
).m_high
<= low
[v
]) {
1452 sweepLine
.insertBefore(Interval(v
,low
[v
],high
[v
]),it
);
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
) {
1463 if ((*it
).m_high
<= high
[v
]) {
1464 visibArcs
.pushBack(Tuple2
<node
,node
>((*it
).m_pathNode
,v
));
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
));
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
));
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
);
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
1503 NodeArray
<adjEntry
> correspEdge(getGraph(),0);
1504 forall_nodes(v
,PG
) {
1505 node seg
= m_pathNode
[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();
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
);
1531 visibArcs
.popFront();
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;
1559 m_type
[e
] = cetVisibilityArc
;
1561 //writeGML("visibilityinserted.gml");
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
)
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
<< ": ";
1590 case cetBasicArc
: cout
<< "basic arc" << endl
;
1592 case cetVertexSizeArc
: cout
<< "vertex-size arc" << endl
;
1594 case cetVisibilityArc
: cout
<< "visibility arc" << endl
;
1596 case cetMedianArc
: cout
<< "median arc" << endl
;
1598 case cetReducibleArc
: cout
<< "reducible arc" <<endl
;
1600 case cetFixToZeroArc
: cout
<< "fixtozero arc" <<endl
;
1610 //colouring for extranode
1611 template<class ATYPE
>
1612 void CompactionConstraintGraph
<ATYPE
>::writeGML(const char *filename
) const
1614 ofstream
os(filename
);
1618 template<class ATYPE
>
1619 void CompactionConstraintGraph
<ATYPE
>::writeGML(ostream
&os
) const
1621 const Graph
&G
= *this;
1623 NodeArray
<int> id(getGraph());
1626 os
.setf(ios::showpoint
);
1629 os
<< "Creator \"ogdf::CompactionConstraintGraphBase::writeGML\"\n";
1631 os
<< " directed 1\n";
1636 os
<< " id " << (id
[v
] = nextId
++) << "\n";
1638 if (m_extraNode
[v
]) {
1639 os
<< " label \"" << "0" << "\"\n";
1641 os
<< " label \"" << m_pPR
->expandedNode(m_path
[v
].front()) << "\"\n";
1644 os
<< " graphics [\n";
1650 os
<< " fill \"#00FFFF\"\n";
1652 os
<< " fill \"#FFFF00\"\n";
1653 os
<< " ]\n"; // graphics
1655 os
<< " ]\n"; // node
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)
1673 os
<< " graphics [\n";
1675 os
<< " type \"line\"\n";
1676 os
<< " arrow \"last\"\n";
1679 case cetBasicArc
: // red
1680 os
<< " fill \"#FF0000\"\n";
1682 case cetVertexSizeArc
: // blue
1683 os
<< " fill \"#0000FF\"\n";
1685 case cetVisibilityArc
: // green
1686 os
<< " fill \"#00FF00\"\n";
1688 case cetReducibleArc
: // red
1689 os
<< " fill \"#FF0000\"\n";
1691 case cetFixToZeroArc
: // violett
1692 os
<< " fill \"#AF00FF\"\n";
1694 case cetMedianArc
: // rose
1695 os
<< " fill \"#FF00FF\"\n";
1699 os
<< " ]\n"; // graphics
1702 os
<< " LabelGraphics [\n";
1703 os
<< " type \"text\"\n";
1704 os
<< " fill \"#000000\"\n";
1705 os
<< " anchor \"w\"\n";
1709 os
<< " ]\n"; // edge
1712 os
<< "]\n"; // graph
1716 } // end namespace ogdf