Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
CompactionConstraintGraph.h
Go to the documentation of this file.
1
35#pragma once
36
37
38#include <ogdf/basic/Graph.h>
40#include <ogdf/basic/List.h>
41#include <ogdf/basic/SList.h>
42#include <ogdf/basic/basic.h>
43#include <ogdf/basic/comparer.h>
45#include <ogdf/basic/tuples.h>
51
52#include <algorithm>
53#include <iostream>
54#include <string>
55
56namespace ogdf {
57
60public:
63
65 bool verticalGen(edge e) const { return m_verticalGen[e]; }
66
69 bool verticalArc(edge e) const { return m_verticalArc[e]; }
70
72
74 void align(bool b) { m_align = b; }
75
78 bool alignmentArc(edge e) const { return m_alignmentArc[e]; }
79
81
82protected:
85 int costGen = 1, int costAssoc = 1, bool align = false);
86
87 int m_edgeCost[2];
88
89 //test fuer vorkomp. der Generalisierungen
92
95
97
98private:
99 //set special costs for node to merger generalizations
101
103 void dfsInsertPathVertex(node v, node pathVertex, NodeArray<bool>& visited,
104 const NodeArray<node>& genOpposite);
105
106 void insertBasicArcs(const PlanRep& PG);
107};
108
119template<class ATYPE>
121public:
123 CompactionConstraintGraph(const OrthoRep& OR, const PlanRep& PG, OrthoDir arcDir, ATYPE sep,
124 int costGen = 1, int costAssoc = 1, bool align = false)
125 : CompactionConstraintGraphBase(OR, PG, arcDir, costGen, costAssoc, align) {
126 OGDF_ASSERT(&(const Graph&)PG == &(const Graph&)OR);
127
128 m_length.init((Graph&)*this, sep);
129 m_extraOfs.init((Graph&)*this, 0);
130 m_extraRep.init((Graph&)*this, nullptr);
131
132 m_sep = sep;
133
134 m_centerPriority = true; //should centering of single edges have prio. to gen. length
135 m_genToMedian = true; //should outgoing merger gen. be drawn to merger median
136
138 }
139
142 ATYPE length(edge e) const { return m_length[e]; }
143
145 ATYPE extraOfs(node v) const { return m_extraOfs[v]; }
146
149
151 void centerPriority(bool b) { m_centerPriority = b; }
152
155 ATYPE computeTotalCosts(const NodeArray<ATYPE>& pos) const;
156
161 void insertVertexSizeArcs(const PlanRep& PG, const NodeArray<ATYPE>& sizeOrig,
162 const RoutingChannel<ATYPE>& rc);
163
169 void insertVertexSizeArcs(const PlanRep& PG, const NodeArray<ATYPE>& sizeOrig,
170 const MinimumEdgeDistances<ATYPE>& minDist);
171
175 void insertVisibilityArcs(const PlanRep& PG,
176 const NodeArray<ATYPE>& posDir,
177 const NodeArray<ATYPE>& posOppDir
178 );
179
180 void insertVisibilityArcs(const PlanRep& PG, const NodeArray<ATYPE>& posDir,
181 const NodeArray<ATYPE>& posOrthDir, const MinimumEdgeDistances<ATYPE>& minDist);
182
184 void setMinimumSeparation(const PlanRep& PG, const NodeArray<int>& coord,
185 const MinimumEdgeDistances<ATYPE>& minDist);
186
191 bool isFeasible(const NodeArray<ATYPE>& pos);
192
194 ATYPE separation() const { return m_sep; }
195
197 bool areMulti(edge e1, edge e2) const;
198
199private:
201 struct Interval {
202 Interval(node v, ATYPE low, ATYPE high) {
203 m_low = low;
204 m_high = high;
205 m_pathNode = v;
206 }
207
208 ATYPE m_low, m_high;
210
212 friend std::ostream& operator<<(std::ostream& os, const Interval& interval) {
213 os << "[" << interval.m_low << "," << interval.m_high << ";" << interval.m_pathNode
214 << "]";
215 return os;
216 }
217 };
218
224 public:
225 SegmentComparer(const NodeArray<ATYPE>& segPos, const NodeArray<int>& secSort) {
226 m_pPos = &segPos;
227 m_pSec = &secSort;
228 }
229
230 int compare(const node& x, const node& y) const {
231 ATYPE d = (*m_pPos)[x] - (*m_pPos)[y];
232 if (d < 0) {
233 return -1;
234 } else if (d > 0) {
235 return 1;
236 } else {
237 return (*m_pSec)[x] - (*m_pSec)[y];
238 }
239 }
240
242 private:
245 };
246
247 virtual string getLengthString(edge e) const override { return to_string(m_length[e]); }
248
249 void setBasicArcsZeroLength(const PlanRep& PG);
250 void resetGenMergerLengths(const PlanRep& PG, adjEntry adjFirst);
251 void setBoundaryCosts(adjEntry cornerDir, adjEntry cornerOppDir);
252
253 bool checkSweepLine(const List<Interval>& sweepLine) const;
254
255 ATYPE m_sep;
256
258
260
263
264 // we make vertex size arcs more expensive than basic arcs in order
265 // to get small cages
266 // should be replaced by option/value dependent on e.g. degree
272 //this does not work if generalization costs are set very small by the user
273 //because there must be a minimum cost for centering
275
276 //factor of costs relative to generalization
277 static const int c_vertexArcFactor;
278 static const int c_bungeeFactor;
279 static const int c_doubleBendFactor;
280 static const int c_MedianFactor;
281
283
284protected:
286 void setExtra(node v, node rep, ATYPE ofs) {
287 m_extraNode[v] = true;
288 m_extraRep[v] = rep;
289 m_extraOfs[v] = ofs;
290 }
291
293 // we make vertex size arcs more expensive than basic arcs in order
294 // to get small cages; not necessary if cage size fixed in improvement
295 // cost should be dependend on degree
296 // Z.B. DURCH OPTION ODER WERT; DER VON DER ZAHL ADJAZENTER KANTEN ABHAENGIG IST
297 // should be derived by number of edges times something
298 int costGen = m_edgeCost[static_cast<int>(Graph::EdgeType::generalization)];
299
300 m_vertexArcCost = c_vertexArcFactor * costGen; //spaeter aus Kompaktierungsmodul uebergeben
301 if (m_centerPriority) {
302 m_bungeeCost = c_bungeeFactor * costGen + 1; //-1;//for distance to middle position,
303 } else {
304 m_bungeeCost = c_bungeeFactor * 4 + 1; //-1;//for distance to middle position,
305 }
306 //addition value should be < gen cost!!!
309 }
310};
311
312//initialization of static members
313template<class ATYPE>
315template<class ATYPE>
317template<class ATYPE>
319 20; //double bends cost mxxx*vertexArcCost
320//factor *VertexArcCost, costs for pulling generalization to median position at merger
321template<class ATYPE>
322const int CompactionConstraintGraph<ATYPE>::c_MedianFactor = 10 * c_doubleBendFactor;
323
324// allow 0-length for sides of generalization merger cages
325template<class ATYPE>
327 adjEntry adj = adjFirst;
328 int faceSize = 0;
329
330 do {
331 if ((m_pOR->direction(adj) == m_arcDir || m_pOR->direction(adj) == m_oppArcDir)
332 && (PG.typeOf(adj->theNode()) == Graph::NodeType::dummy
333 || PG.typeOf(adj->twinNode()) == Graph::NodeType::dummy)) {
334 m_length[m_edgeToBasicArc[adj]] = 0;
335 }
336
337 adj = adj->faceCycleSucc();
338 faceSize++;
339 } while (adj != adjFirst);
340
341 //generalization position section
342 //pull upper generalization to median of merger cage's incoming lower generalizations
343
344 if (m_genToMedian
345 && (m_pOR->direction(adjFirst) == m_arcDir || m_pOR->direction(adjFirst) == m_oppArcDir)) {
346 int numIncoming = faceSize - 3;
347 int median = (numIncoming / 2) + 1;
348
349 // if (numIncoming == 2) ... just the middle position
350 node upper = m_pathNode[adjFirst->theNode()];
353 }
354
355 node vMin;
356 if (m_pOR->direction(adjFirst) == m_arcDir) {
357 vMin = adjFirst->faceCyclePred()->theNode();
358 } else {
359 vMin = adjFirst->faceCycleSucc()->theNode();
360 }
361
362 adj = adjFirst->faceCycleSucc(); // target right or left boundary, depending on drawing direction
363 for (int i = 0; i < median; i++) {
364 adj = adj->faceCycleSucc();
365 }
366
367 node lower = m_pathNode[adj->theNode()];
368 node vCenter = newNode();
369 setExtra(vCenter, vMin, 0);
370
371 // it seems we dont need the helper, as only source-adjEntries lying on
372 // the outer face are considered later, but keep it in mind
373#if 0
374 edge helper = newEdge(m_pathNode[vMin], vCenter);
375 m_length[helper] = 0;
376 m_cost[helper] = 0;
377 m_type[helper] = ConstraintEdgeType::ReducibleArc;
378#endif
379
380 edge e1 = newEdge(vCenter, upper);
381 m_length[e1] = 0;
382 m_cost[e1] = m_MedianArcCost;
384
385 edge e2 = newEdge(vCenter, lower);
386 m_length[e2] = 0;
387 m_cost[e2] = m_MedianArcCost;
389 }
390}
391
392// set cost of edges on the cage boundary to 0
393template<class ATYPE>
395#if 0
396 adjEntry adj;
397 for (adj = cornerDir; m_pOR->direction(adj) == m_arcDir; adj = adj->faceCycleSucc())
398 m_cost[m_edgeToBasicArc[adj]] = 0;
399 for (adj = cornerOppDir; m_pOR->direction(adj) == m_oppArcDir; adj = adj->faceCycleSucc())
400 m_cost[m_edgeToBasicArc[adj]] = 0;
401#endif
402 //test for multi separation
403 adjEntry adj;
404 for (adj = cornerDir; m_pOR->direction(adj) == m_arcDir; adj = adj->faceCycleSucc()) {
405 m_cost[m_edgeToBasicArc[adj]] = 0;
406
407 if (m_pathNode[adj->twin()->cyclicSucc()->theNode()]
408 && (m_pOR->direction(adj->faceCycleSucc()) == m_arcDir)) {
409 m_originalEdge[m_pathNode[adj->twin()->cyclicSucc()->theNode()]] =
410 m_pPR->original(adj->twin()->cyclicSucc()->theEdge());
411 }
412 }
413 for (adj = cornerOppDir; m_pOR->direction(adj) == m_oppArcDir; adj = adj->faceCycleSucc()) {
414 m_cost[m_edgeToBasicArc[adj]] = 0;
415
416 if (m_pathNode[adj->twin()->cyclicSucc()->theNode()]) {
417 m_originalEdge[m_pathNode[adj->twin()->cyclicSucc()->theNode()]] =
418 m_pPR->original(adj->twin()->cyclicSucc()->theEdge());
419 }
420 }
421}
422
423//
424// insert arcs required for respecting vertex sizes, sizes of routing channels
425// and position of attached generalizations
426// vertices are represented by variable cages
427template<class ATYPE>
429 const NodeArray<ATYPE>& sizeOrig, const RoutingChannel<ATYPE>& rc) {
430 // segments in constraint graph are sides sMin and sMax; other two side
431 // are sides in which adjacency entries run in direction m_arcDir and
432 // m_oppArcDir
433 OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
434 OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
435
436 const ATYPE overhang = rc.overhang();
437
438 for (node v : PG.nodes) {
439 if (PG.expandAdj(v) == nullptr) {
440 continue;
441 }
442
444 resetGenMergerLengths(PG, PG.expandAdj(v));
445
446 } else // high/low-degree expander
447 {
448 ATYPE size = sizeOrig[v];
449
450 const OrthoRep::VertexInfoUML& vi = *m_pOR->cageInfo(v);
451
452 // determine routing channels rcMin and rcMax
453 ATYPE rcMin = overhang + rc(v, dirMin);
454 ATYPE rcMax = overhang + rc(v, dirMax);
455
456 adjEntry cornerDir = vi.m_corner[static_cast<int>(m_arcDir)];
457 adjEntry cornerOppDir = vi.m_corner[static_cast<int>(m_oppArcDir)];
458 adjEntry cornerMin = vi.m_corner[static_cast<int>(dirMin)];
459 adjEntry cornerMax = vi.m_corner[static_cast<int>(dirMax)];
460
461 // set cost of edges on the cage boundary to 0
462 setBoundaryCosts(cornerDir, cornerOppDir);
463
464 const OrthoRep::SideInfoUML& sDir = vi.m_side[static_cast<int>(m_arcDir)];
465 const OrthoRep::SideInfoUML& sOppDir = vi.m_side[static_cast<int>(m_oppArcDir)];
466
467 // correct lengths of edges within cage adjacent to corners
468 if (sDir.totalAttached() > 0) {
469 m_length[m_edgeToBasicArc[cornerDir]] = rcMin;
470 m_length[m_edgeToBasicArc[cornerMax->faceCyclePred()]] = rcMax;
471 } else {
472 // if no edges are attached at this side we need no constraint
473 m_length[m_edgeToBasicArc[cornerDir]] = 0;
474 delEdge(m_edgeToBasicArc[cornerDir]);
475 }
476
477 if (sOppDir.totalAttached() > 0) {
478 m_length[m_edgeToBasicArc[cornerOppDir]] = rcMax;
479 m_length[m_edgeToBasicArc[cornerMin->faceCyclePred()]] = rcMin;
480 } else {
481 // if no edges are attached at this side we need no constraint
482 m_length[m_edgeToBasicArc[cornerOppDir]] = 0;
483 delEdge(m_edgeToBasicArc[cornerOppDir]);
484 }
485
486
487 // insert arcs for respecting vertex size / position of generalizations
488 node vMin = m_pathNode[cornerDir->theNode()];
489 node vMax = m_pathNode[cornerOppDir->theNode()];
490
491 // any attached generalizations ?
492 if (sDir.m_adjGen == nullptr && sOppDir.m_adjGen == nullptr) {
493 // no, only one arc for vertex size + routing channels
494 edge e = newEdge(vMin, vMax);
495 m_length[e] = rcMin + size + rcMax - 2 * overhang;
496 m_cost[e] = 2 * m_vertexArcCost;
498
499 } else {
500 // yes, then two arcs for each side with an attached generalization
501 ATYPE minHalf = size / 2;
502 ATYPE maxHalf = size - minHalf;
503 ATYPE lenMin = rcMin + minHalf - overhang;
504 ATYPE lenMax = maxHalf + rcMax - overhang;
505
506 if (sDir.m_adjGen != nullptr) {
507 node vCenter = m_pathNode[sDir.m_adjGen->theNode()];
508 edge e1 = newEdge(vMin, vCenter);
509 m_length[e1] = lenMin;
510 m_cost[e1] = m_vertexArcCost;
512 edge e2 = newEdge(vCenter, vMax);
513 m_length[e2] = lenMax;
514 m_cost[e2] = m_vertexArcCost;
516 }
517
518 if (sOppDir.m_adjGen != nullptr) {
519 node vCenter = m_pathNode[sOppDir.m_adjGen->theNode()];
520 edge e1 = newEdge(vMin, vCenter);
521 m_length[e1] = lenMin;
522 m_cost[e1] = m_vertexArcCost;
524 edge e2 = newEdge(vCenter, vMax);
525 m_length[e2] = lenMax;
526 m_cost[e2] = m_vertexArcCost;
528 }
529 }
530 }
531 }
532}
533
534template<class ATYPE>
536 for (edge e : PG.edges) {
537 edge arc = m_edgeToBasicArc[e];
538 if (arc == nullptr) {
539 continue;
540 }
541
542 node v = e->source();
543 node w = e->target();
544 if (((PG.typeOf(v) == Graph::NodeType::dummy) && (PG.typeOf(w) == Graph::NodeType::dummy)
545 && (v->degree() == 2) && w->degree() == 2)
546 && (m_pOR->angle(e->adjSource()) == m_pOR->angle(e->adjTarget())) && //no uturns
548 m_length[arc] = 0;
550 //we make fixtozero arcs as expensive as possible
551 m_cost[arc] = m_doubleBendCost;
552 }
553 }
554}
555
556//
557// insert arcs required for respecting vertex sizes
558// and position of attached generalizations
559// vertices are represented by tight cages
560template<class ATYPE>
562 const NodeArray<ATYPE>& sizeOrig, const MinimumEdgeDistances<ATYPE>& minDist) {
563 // set the length of all basic arcs corresponding to inner edge segments
564 // to 0
565 setBasicArcsZeroLength(PG);
566
567 // segments in constraint graph are sides sMin and sMax; other two side
568 // are sides in which adjacency entries run in direction m_arcDir and
569 // m_oppArcDir
570 OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
571 OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
572
573 for (node v : PG.nodes) {
574 if (PG.expandAdj(v) == nullptr) {
575 continue;
576 }
577
579 resetGenMergerLengths(PG, PG.expandAdj(v));
580
581 } else // high/low-degree expander
582 {
583 ATYPE size = sizeOrig[v];
584 const OrthoRep::VertexInfoUML& vi = *m_pOR->cageInfo(v);
585
586 adjEntry cornerDir = vi.m_corner[static_cast<int>(m_arcDir)];
587 adjEntry cornerOppDir = vi.m_corner[static_cast<int>(m_oppArcDir)];
588 adjEntry cornerMin = vi.m_corner[static_cast<int>(dirMin)];
589 adjEntry cornerMax = vi.m_corner[static_cast<int>(dirMax)];
590
591 adjEntry adj = cornerDir, last = cornerMax->faceCyclePred();
592 if (adj != last) {
593 m_length[m_edgeToBasicArc[adj]] = minDist.epsilon(v, m_arcDir, 0);
594 m_length[m_edgeToBasicArc[last]] = minDist.epsilon(v, m_arcDir, 1);
595 int i = 0;
596 for (adj = adj->faceCycleSucc(); adj != last; adj = adj->faceCycleSucc()) {
598 i++;
599 }
600 m_length[m_edgeToBasicArc[adj]] = minDist.delta(v, m_arcDir, i);
601 }
602 }
603
604 adj = cornerOppDir, last = cornerMin->faceCyclePred();
605 if (adj != last) {
606 m_length[m_edgeToBasicArc[adj]] = minDist.epsilon(v, m_oppArcDir, 0);
607 m_length[m_edgeToBasicArc[last]] = minDist.epsilon(v, m_oppArcDir, 1);
608 int i = 0;
609 for (adj = adj->faceCycleSucc(); adj != last; adj = adj->faceCycleSucc()) {
611 i++;
612 }
613 m_length[m_edgeToBasicArc[adj]] = minDist.delta(v, m_oppArcDir, i);
614 }
615 }
616
617
618 // insert arcs for respecting vertex size / position of generalizations
619 node vMin = m_pathNode[cornerDir->theNode()];
620 node vMax = m_pathNode[cornerOppDir->theNode()];
621
622 const OrthoRep::SideInfoUML& sDir = vi.m_side[static_cast<int>(m_arcDir)];
623 const OrthoRep::SideInfoUML& sOppDir = vi.m_side[static_cast<int>(m_oppArcDir)];
624
625 // any attached generalizations ?
626 if (sDir.m_adjGen == nullptr && sOppDir.m_adjGen == nullptr) {
627 //check for single edge case => special treatment
628 //generic case could handle all numbers
629
630 if (sDir.totalAttached() == 1 || sOppDir.totalAttached() == 1) {
631 //first, insert a new center node and connect it
632 ATYPE lenMin = size / 2;
633 ATYPE lenMax = size - lenMin;
634 node vCenter = newNode();
635 setExtra(vCenter, cornerDir->theNode(), lenMin);
636
637 edge e1 = newEdge(vMin, vCenter);
638 m_length[e1] = lenMin;
639 m_cost[e1] = m_vertexArcCost;
641 edge e2 = newEdge(vCenter, vMax);
642 m_length[e2] = lenMax;
643 m_cost[e2] = m_vertexArcCost;
645
646 if (sDir.totalAttached() == 1) {
647 //then, insert a moveable node connecting center
648 //and outgoing segment
649 node vBungee = newNode();
650 //+1 should fix the fixzerolength problem
651 setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v, m_arcDir, 0));
652
653 edge eToBungee = newEdge(vMin, vBungee);
654 m_type[eToBungee] = ConstraintEdgeType::MedianArc;
655 //BasicArc; // XXX: is this ok?
656 m_cost[eToBungee] = 0; // XXX: what about this?
657 m_length[eToBungee] = minDist.epsilon(v, m_arcDir, 0);
658
659 edge eBungeeCenter = newEdge(vBungee, vCenter);
660 //bungee, center and outgoing segment may build column if in the middle
661 m_type[eBungeeCenter] = ConstraintEdgeType::MedianArc;
662 m_cost[eBungeeCenter] = m_bungeeCost; // XXX: what about this?
663 m_length[eBungeeCenter] = 0;
664
665 //attention: pathnode construct works only if degree 1
666 edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerDir->twinNode()]);
667 //bungee, center and outgoing segment may build column if in the middle
668 m_type[eBungeeOut] = ConstraintEdgeType::MedianArc;
669 m_cost[eBungeeOut] = m_bungeeCost; // XXX: what about this?
670 m_length[eBungeeOut] = 0;
671#if 0
672 //connect outgoing segment and "right" segment, maybe obsolete
673 edge eFromOut = newEdge(m_pathNode[cornerDir->twinNode()], vMax);
674 m_type[eFromOut] = ConstraintEdgeType::BasicArc; // XXX
675 m_cost[eFromOut] = 0; // XXX
676 m_length[eFromOut] = minDist.epsilon(v,m_arcDir,1);
677#endif
678 }
679 if (sOppDir.totalAttached() == 1 && m_pathNode[cornerOppDir->twinNode()] != vMin) {
680 //then, insert a moveable node connecting center
681 //and outgoing segment
682 node vBungee = newNode();
683 //+1 for not fixzerolength
684 setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v, m_oppArcDir, 0));
685
686 edge eToBungee = newEdge(vMin, vBungee);
687 m_type[eToBungee] = ConstraintEdgeType::MedianArc;
688 //BasicArc; // XXX: is this ok?
689 m_cost[eToBungee] = 0; // XXX: what about this?
690 m_length[eToBungee] = minDist.epsilon(v, m_oppArcDir, 0);
691
692 edge eBungeeCenter = newEdge(vBungee, vCenter);
693 //bungee, center and outgoing segment may build column if in the middle
694 m_type[eBungeeCenter] = ConstraintEdgeType::MedianArc;
695 m_cost[eBungeeCenter] = m_bungeeCost; // XXX: what about this?
696 m_length[eBungeeCenter] = 0;
697
698 //attention: pathnode construct works only if degree 1, sometimes not at all
699 edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerOppDir->twinNode()]);
700 //bungee, center and outgoing segment may build column if in the middle
701 m_type[eBungeeOut] = ConstraintEdgeType::MedianArc;
702 m_cost[eBungeeOut] = m_bungeeCost; // XXX: what about this?
703 m_length[eBungeeOut] = 0;
704#if 0
705 //connect outgoing segment and "right" segment, maybe obsolete
706 edge eFromOut = newEdge(m_pathNode[cornerOppDir->twinNode()], vMax);
707 m_type[eFromOut] = ConstraintEdgeType::BasicArc; // XXX
708 m_cost[eFromOut] = 0; // XXX
709 m_length[eFromOut] = minDist.epsilon(v,m_oppArcDir,0);
710#endif
711 }
712 } else {
713 // no, only one arc for vertex size + routing channels
714 edge e = newEdge(vMin, vMax);
715 m_length[e] = size;
716 m_cost[e] = 2 * m_vertexArcCost;
718 }
719 } else {
720 // yes, then two arcs for each side with an attached generalization
721 ATYPE lenMin = size / 2;
722 ATYPE lenMax = size - lenMin;
723
724#if 0
725 ATYPE len = size/2;
726#endif
727
728 if (sDir.m_adjGen != nullptr) {
729 node vCenter = m_pathNode[sDir.m_adjGen->theNode()];
730 edge e1 = newEdge(vMin, vCenter);
731 m_length[e1] = lenMin;
732 m_cost[e1] = m_vertexArcCost;
734 edge e2 = newEdge(vCenter, vMax);
735 m_length[e2] = lenMax;
736 m_cost[e2] = m_vertexArcCost;
738 } else {
739 if (sDir.totalAttached() == 1) {
740 node vCenter = newNode();
741 //m_pathNode[sOppDir.m_adjGen->theNode()]; //newNode();
742 setExtra(vCenter, cornerDir->theNode(), lenMin);
743
744 edge e1 = newEdge(vMin, vCenter);
745 m_length[e1] = lenMin;
746 m_cost[e1] = m_vertexArcCost;
748 edge e2 = newEdge(vCenter, vMax);
749 m_length[e2] = lenMax;
750 m_cost[e2] = m_vertexArcCost;
752
753 //then, insert a moveable node connecting center
754 //and outgoing segment
755 node vBungee = newNode();
756 //+1 for not fixzerolength
757 setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v, m_arcDir, 0));
758
759 edge eToBungee = newEdge(vMin, vBungee);
760 m_type[eToBungee] = ConstraintEdgeType::MedianArc;
761 //BasicArc; // XXX: is this ok?
762 m_cost[eToBungee] = 0; // XXX: what about this?
763 m_length[eToBungee] = minDist.epsilon(v, m_arcDir, 0);
764
765 edge eBungeeCenter = newEdge(vBungee, vCenter);
766 //bungee, center and outgoing segment may build column if in the middle
767 m_type[eBungeeCenter] = ConstraintEdgeType::MedianArc;
768 m_cost[eBungeeCenter] = m_bungeeCost; // XXX: what about this?
769 m_length[eBungeeCenter] = 0;
770
771 //attention: pathnode construct works only if degree 1
772 edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerDir->twinNode()]);
773 //bungee, center and outgoing segment may build column if in the middle
774 m_type[eBungeeOut] = ConstraintEdgeType::MedianArc;
775 m_cost[eBungeeOut] = m_bungeeCost; // XXX: what about this?
776 m_length[eBungeeOut] = 0;
777 }
778 }
779 if (sOppDir.m_adjGen != nullptr) {
780 node vCenter = m_pathNode[sOppDir.m_adjGen->theNode()];
781 edge e1 = newEdge(vMin, vCenter);
782 m_length[e1] = lenMin;
783 m_cost[e1] = m_vertexArcCost;
785 edge e2 = newEdge(vCenter, vMax);
786 m_length[e2] = lenMax;
787 m_cost[e2] = m_vertexArcCost;
789 } else {
790 //special case single edge to middle position
791 if (sOppDir.totalAttached() == 1 && m_pathNode[cornerOppDir->twinNode()] != vMin) {
792 node vCenter = newNode();
793 //m_pathNode[sDir.m_adjGen->theNode()];//newNode();
794 setExtra(vCenter, cornerDir->theNode(), lenMin);
795
796 edge e1 = newEdge(vMin, vCenter);
797 m_length[e1] = lenMin;
798 m_cost[e1] = m_vertexArcCost;
800 edge e2 = newEdge(vCenter, vMax);
801 m_length[e2] = lenMax;
802 m_cost[e2] = m_vertexArcCost;
804 //then, insert a moveable node connecting center
805 //and outgoing segment
806 node vBungee = newNode();
807 //+1 for not fixzerolength
808 setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v, m_oppArcDir, 0));
809
810 edge eToBungee = newEdge(vMin, vBungee);
811 m_type[eToBungee] = ConstraintEdgeType::MedianArc;
812 //BasicArc; // XXX: is this ok?
813 m_cost[eToBungee] = 0; // XXX: what about this?
814 m_length[eToBungee] = minDist.epsilon(v, m_oppArcDir, 0);
815
816 edge eBungeeCenter = newEdge(vBungee, vCenter);
817 //bungee, center and outgoing segment may build column if in the middle
818 m_type[eBungeeCenter] = ConstraintEdgeType::MedianArc;
819 m_cost[eBungeeCenter] = m_bungeeCost; // XXX: what about this?
820 m_length[eBungeeCenter] = 0;
821
822 //attention: pathnode construct works only if degree 1
823 edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerOppDir->twinNode()]);
824 //bungee, center and outgoing segment may build column if in the middle
825 m_type[eBungeeOut] = ConstraintEdgeType::MedianArc;
826 m_cost[eBungeeOut] = m_bungeeCost; // XXX: what about this?
827 m_length[eBungeeOut] = 0;
828 }
829 }
830 }
831
832 // set cost of edges on the cage boundary to 0
833 setBoundaryCosts(cornerDir, cornerOppDir);
834 }
835 }
836#if 0
837 if (m_arcDir == OrthoDir::East) {
838 writeGML("eastvertexsizeinserted.gml");
839 } else {
840 writeGML("northvertexsizeinserted.gml");
841 }
842#endif
843}
844
845// computes the total costs for coordintes given by pos, i.e.,
846// the sum of the weighted lengths of edges in the constraint graph.
847template<class ATYPE>
849 ATYPE c = 0;
850 for (edge e : edges) {
851 c += cost(e) * (pos[e->target()] - pos[e->source()]);
852 }
853
854 return c;
855}
856
857//
858// insertion of visibility arcs
859
860// checks if intervals on the sweep line are in correct order
861template<class ATYPE>
863 if (sweepLine.empty()) {
864 return true;
865 }
866
867 ListConstIterator<Interval> it = sweepLine.begin();
868
869 if ((*it).m_high < (*it).m_low) {
870 return false;
871 }
872
873 ATYPE x = (*it).m_low;
874
875 for (++it; it.valid(); ++it) {
876 if ((*it).m_high < (*it).m_low) {
877 return false;
878 }
879 if ((*it).m_high > x) {
880 return false;
881 }
882 x = (*it).m_low;
883 }
884
885 return true;
886}
887
888template<class ATYPE>
890 const NodeArray<ATYPE>& posDir, const NodeArray<ATYPE>& posOrthDir) {
891 MinimumEdgeDistances<ATYPE> minDist(PG, m_sep);
892
893 for (node v : PG.nodes) {
894 if (PG.expandAdj(v) == nullptr) {
895 continue;
896 }
897
898 for (int d = 0; d < 4; ++d) {
899 minDist.delta(v, OrthoDir(d), 0) = m_sep; //currentSeparation;
900 minDist.delta(v, OrthoDir(d), 1) = m_sep; //currentSeparation;
901 }
902 }
903
904 insertVisibilityArcs(PG, posDir, posOrthDir, minDist);
905}
906
907// inserts arcs connecting segments which can see each other in a drawing
908// of the associated planarized representation PG which is given by
909// posDir and posOppDir.
910
911//ersetze mindist.delta durch min(m_sep, mindist.delta) fuer skalierung
912template<class ATYPE>
914 const NodeArray<ATYPE>& posDir, const NodeArray<ATYPE>& posOrthDir,
915 const MinimumEdgeDistances<ATYPE>& minDist) {
916 OrthoDir segDir = OrthoRep::prevDir(m_arcDir);
917 OrthoDir segOppDir = OrthoRep::nextDir(m_arcDir);
918
919 // list of visibility arcs which have to be inserted
921
922 // lower and upper bound of segments
923 NodeArray<ATYPE> low(getGraph()), lowReal(getGraph()), high(getGraph());
924 NodeArray<ATYPE> segPos(getGraph(), 0); // position of segments
925 NodeArray<int> topNum(getGraph() /*,0*/); // secondary sorting criteria for segments
926
927 // compute position and lower/upper bound of segments
928 // We have to take care that segments cannot be shifted one upon the other,
929 // e.g., if we have two segments (l1,h1) and (l2,h2) with l2 > h2 and
930 // the distance l2-h2 is smaller than separation, the segments can see
931 // each other. We do this by enlarging the lower bound of all segments
932 // by separation if this lower bound is realized by a bend.
933 //
934 // Note: Be careful at segments attached at a vertex which are closer
935 // than separation to each other. Possible solution: Remove visibility
936 // arcs of segments which are connected by orthogonal segments to the
937 // same vertex and bend in opposite directions.
938 for (node v : nodes) {
939 //special case nodes
940 if (m_path[v].empty()) {
941 continue;
942 }
943
944 SListConstIterator<node> it = m_path[v].begin();
945
946 segPos[v] = posDir[*it];
947 low[v] = high[v] = posOrthDir[*it];
948 node nodeLow = *it;
949 for (++it; it.valid(); ++it) {
950 ATYPE x = posOrthDir[*it];
951 if (x < low[v]) {
952 low[v] = x;
953 nodeLow = *it;
954 }
955 if (x > high[v]) {
956 high[v] = x;
957 }
958 }
959 lowReal[v] = low[v];
960 Graph::NodeType typeLow = PG.typeOf(nodeLow);
962#if 0
963 bool subtractSep = true;
964 if (nodeLow->degree() == 2) {
965 adjEntry adjFound = nullptr;
966 for(adjEntry adj : nodeLow->adjEntries) {
967 if(m_pOR->direction(adj) == m_arcDir || m_pOR->direction(adj) == m_oppArcDir) {
968 adjFound = adj;
969 break;
970 }
971 }
972 if (adjFound) {
973 for(adjEntry adj2 = adjFound->faceCycleSucc();
974 m_pOR->direction(adj2) == m_pOR->direction(adjFound);
975 adj2 = adj2->twin()->faceCycleSucc()) ;
976 if(posDir[adjFound->theNode()] == posDir[adj2->twinNode()])
977 subtractSep = false;
978 }
979 }
980 if (subtractSep)
981 low[v] -= m_sep;
982#else
983 low[v] -= m_sep;
984#endif
985 }
986 }
987
988 // correct "-= m_sep" ...
989 OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
990 OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
991 bool isCaseA = (m_arcDir == OrthoDir::East || m_arcDir == OrthoDir::South);
992 const int angleAtMin = (m_arcDir == OrthoDir::East || m_arcDir == OrthoDir::South) ? 3 : 1;
993 const int angleAtMax = (m_arcDir == OrthoDir::East || m_arcDir == OrthoDir::South) ? 1 : 3;
994
995 for (node v : PG.nodes) {
996 if (PG.expandAdj(v) == nullptr) {
997 continue;
998 }
999 const OrthoRep::VertexInfoUML& vi = *m_pOR->cageInfo(v);
1000
1001 // int i = 0;
1002 adjEntry adj;
1003
1004 for (adj = isCaseA ? vi.m_corner[static_cast<int>(dirMin)]->faceCycleSucc()->faceCycleSucc()
1005 : vi.m_corner[static_cast<int>(dirMin)]->faceCycleSucc();
1006 m_pOR->direction((isCaseA) ? adj : adj->faceCycleSucc())
1007 == dirMin; //m_pOR->direction(adj) == dirMin;
1008 adj = adj->faceCycleSucc()) {
1009 adjEntry adjCross = adj->cyclicPred();
1010 adjEntry adjTwin = adjCross->twin();
1011
1012 adjEntry adjPred = adj->faceCyclePred();
1013 ATYPE delta = (isCaseA)
1014 ? min(abs(posOrthDir[adjPred->theNode()] - posOrthDir[adjPred->twinNode()]), m_sep)
1015 : min(abs(posOrthDir[adj->theNode()] - posOrthDir[adj->twinNode()]), m_sep);
1016 ATYPE boundary = (isCaseA)
1017 ? min(posOrthDir[adjPred->theNode()], posOrthDir[adjPred->twinNode()])
1018 : min(posOrthDir[adj->theNode()], posOrthDir[adj->twinNode()]);
1019
1020 if (PG.typeOf(adjCross->theEdge()) == Graph::EdgeType::generalization) {
1021 if (isCaseA) {
1023 && m_pOR->angle(adjTwin) == 2) {
1024 node s1 = m_pathNode[adjTwin->theNode()];
1025 node s2 = m_pathNode[adjTwin->cyclicSucc()->twinNode()];
1026 low[s1] = lowReal[s1] - delta; // minDist.delta(v,dirMin,i);
1027 low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMin,i);
1028 }
1029 // ++i;
1030 } else {
1031 // ++i;
1033 && m_pOR->angle(adjTwin->cyclicPred()) == 2) {
1034 node s1 = m_pathNode[adjTwin->theNode()];
1035 node s2 = m_pathNode[adjTwin->cyclicPred()->twinNode()];
1036 low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMin,i);
1037 low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMin,i);
1038 }
1039 }
1040 continue;
1041 }
1042
1043 //we save the current direction and stop if we run in opposite
1044 OrthoDir runDir = m_pOR->direction(adjCross);
1045 // if -> while
1046 while (PG.typeOf(adjTwin->theNode()) == Graph::NodeType::dummy
1047 && adjTwin->theNode()->degree() == 2 && m_pOR->angle(adjTwin) == angleAtMin) {
1048 // We handle the case if an edge segment adjacent to a vertex
1049 // is separated by less than separation from edge segments above.
1050 node s = m_edgeToBasicArc[adjCross]->source();
1051 if (lowReal[s] != low[s]) {
1052 if (low[s] >= boundary) { // nothing to do?
1053 break;
1054 }
1055 low[s] = boundary;
1056#if 0
1057 low[s] += m_sep - delta; //minDist.delta(v,dirMin,i);
1058#endif
1059
1060 // If the compaction has eliminated bends, we can have the situation
1061 // that segment s has length 0 and the next segment s' (following the
1062 // edge) is at the same position (the edge arc has length 0).
1063 // In this case, the low-value of s' must be lowered (low[s'] := lowReal[s']
1064 // is approproate). The same situation can appear several times in a
1065 // row.
1066 //collect chains of segments compacted to zero length
1067 for (;;) { //while(true/*lowReal[s] == high[s]*/) {
1068 do {
1069 adjCross = adjCross->faceCycleSucc();
1070 } while (m_pOR->direction(adjCross) == segDir
1071 || m_pOR->direction(adjCross) == segOppDir);
1072
1073 if (adjCross->theNode()->degree() != 2) { // no longer a bend point?
1074 break;
1075 }
1076
1077 node sNext = m_edgeToBasicArc[adjCross]->opposite(s);
1078
1079 if (segPos[sNext] != segPos[s]) {
1080 break;
1081 }
1082
1083 low[sNext] = lowReal[sNext]; //?
1084 s = sNext;
1085 }
1086 }
1087
1088 adjTwin = adjCross->twin(); // update of twin for while
1089 //check if we have to stop
1090 if (runDir != m_pOR->direction(adjCross)) {
1091 break;
1092 }
1093 }
1094 }
1095
1096 // i = 0;
1097 for (adj = isCaseA ? vi.m_corner[static_cast<int>(dirMax)]->faceCycleSucc()
1098 : vi.m_corner[static_cast<int>(dirMax)]->faceCycleSucc()->faceCycleSucc();
1099 m_pOR->direction((isCaseA) ? adj->faceCycleSucc() : adj)
1100 == dirMax; // m_pOR->direction(adj) == dirMax;
1101 adj = adj->faceCycleSucc()) {
1102 adjEntry adjCross = adj->cyclicPred();
1103 adjEntry adjTwin = adjCross->twin();
1104
1105#if 0
1106 ATYPE delta = -posOrthDir[adj->twinNode()] + posOrthDir[adj->theNode()];
1107#endif
1108 adjEntry adjPred = adj->faceCyclePred();
1109 ATYPE delta = (isCaseA)
1110 ? min(abs(posOrthDir[adj->twinNode()] - posOrthDir[adj->theNode()]), m_sep)
1111 : min(abs(posOrthDir[adjPred->theNode()] - posOrthDir[adjPred->twinNode()]),
1112 m_sep);
1113 ATYPE boundary = (isCaseA)
1114 ? min(posOrthDir[adj->twinNode()], posOrthDir[adj->theNode()])
1115 : min(posOrthDir[adjPred->theNode()], posOrthDir[adjPred->twinNode()]);
1116
1117 if (PG.typeOf(adjCross->theEdge()) == Graph::EdgeType::generalization) {
1118 if (isCaseA) {
1119 // ++i;
1121 && m_pOR->angle(adjTwin->cyclicPred()) == 2) {
1122 node s1 = m_pathNode[adjTwin->theNode()];
1123 node s2 = m_pathNode[adjTwin->cyclicPred()->twinNode()];
1124 low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMax,i);
1125 low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMax,i);
1126 }
1127 } else {
1129 && m_pOR->angle(adjTwin) == 2) {
1130 node s1 = m_pathNode[adjTwin->theNode()];
1131 node s2 = m_pathNode[adjTwin->cyclicSucc()->twinNode()];
1132 low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMax,i);
1133 low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMax,i);
1134 }
1135 // ++i;
1136 }
1137 continue;
1138 }
1139
1140
1141 //we save the current direction and stop if we run in opposite
1142 OrthoDir runDir = m_pOR->direction(adjCross);
1143 // if -> while
1144 while (PG.typeOf(adjTwin->theNode()) == Graph::NodeType::dummy
1145 && adjTwin->theNode()->degree() == 2 && m_pOR->angle(adjTwin) == angleAtMax) {
1146 node s = m_edgeToBasicArc[adjCross]->target();
1147 if (lowReal[s] != low[s]) {
1148 if (low[s] >= boundary) { // nothing to do?
1149 break;
1150 }
1151 low[s] = boundary;
1152#if 0
1153 low[s] += m_sep - delta; //minDist.delta(v,dirMax,i);
1154#endif
1155
1156 // If the compaction has eliminated bends, we can have the situation
1157 // that segment s has length 0 and the next segment s' (following the
1158 // edge) is at the same position (the edge arc has length 0).
1159 // In this case, the low-value of s' must be lowered (low[s'] := lowReal[s']
1160 // is approproate). The same situation can appear several times in a
1161 // row.
1162 //collect chains of segments compacted to zero length
1163 for (;;) /*lowReal[s] == high[s]*/
1164 {
1165 do {
1166 adjCross = adjCross->faceCycleSucc();
1167 } while (m_pOR->direction(adjCross) == segDir
1168 || m_pOR->direction(adjCross) == segOppDir);
1169
1170 if (adjCross->theNode()->degree() != 2) { // no longer a bend point?
1171 break;
1172 }
1173
1174 node sNext = m_edgeToBasicArc[adjCross]->opposite(s);
1175
1176 if (segPos[sNext] != segPos[s]) {
1177 break;
1178 }
1179
1180 low[sNext] = lowReal[sNext]; //was: low[s]
1181 s = sNext;
1182 }
1183 }
1184
1185 adjTwin = adjCross->twin(); // update of twin for while
1186
1187 //check if we have to stop
1188 if (runDir != m_pOR->direction(adjCross)) {
1189 break;
1190 }
1191 }
1192 }
1193 }
1194
1195 // compute topological numbering of segments as second sorting criteria
1196 // in order to process overlapping segments in the order imposed by the
1197 // embedding
1198 computeTopologicalSegmentNum(topNum);
1199
1200
1201 // sort segments
1202 SegmentComparer cmpBySegPos(segPos, topNum);
1203 List<node> sortedPathNodes;
1204 allNodes(sortedPathNodes);
1205 sortedPathNodes.quicksort(cmpBySegPos);
1206
1207 // add segments in the order given by sortedPathNodes to sweep line
1208 List<Interval> sweepLine;
1209
1211 for (itV = sortedPathNodes.begin(); itV.valid(); ++itV) {
1212 //special case nodes
1213 if (m_path[*itV].empty()) {
1214 continue;
1215 }
1216 OGDF_HEAVY_ASSERT(checkSweepLine(sweepLine));
1217
1218 node v = *itV;
1220 for (it = sweepLine.begin(); it.valid(); ++it) {
1221 if ((*it).m_low < high[v]) {
1222 break;
1223 }
1224 }
1225
1226 if (!it.valid()) {
1227 sweepLine.pushBack(Interval(v, low[v], high[v]));
1228 continue;
1229 }
1230
1231 if ((*it).m_high <= low[v]) {
1232 sweepLine.insertBefore(Interval(v, low[v], high[v]), it);
1233 continue;
1234 }
1235
1236 ListIterator<Interval> itUp = it, itSucc;
1237 // we store if itUp will be deleted in order not to
1238 // access the deleted iterator later
1239 bool isItUpDel = (((*itUp).m_low >= low[v]) && ((*itUp).m_high <= high[v]));
1240
1241 for (; it.valid() && (*it).m_low >= low[v]; it = itSucc) {
1242 itSucc = it.succ();
1243 if ((*it).m_high <= high[v]) {
1244 visibArcs.pushBack(Tuple2<node, node>((*it).m_pathNode, v));
1245 sweepLine.del(it);
1246 }
1247 }
1248
1249 if (it == itUp && (*it).m_high > high[v]) {
1250 node w = (*it).m_pathNode;
1251 sweepLine.insertAfter(Interval(w, (*it).m_low, low[v]), it);
1252 (*it).m_low = high[v];
1253 sweepLine.insertAfter(Interval(v, low[v], high[v]), it);
1254 visibArcs.pushBack(Tuple2<node, node>(w, v));
1255
1256 } else {
1257 if ((!isItUpDel) && itUp != it && (*itUp).m_low < high[v]) {
1258 (*itUp).m_low = high[v];
1259 visibArcs.pushBack(Tuple2<node, node>((*itUp).m_pathNode, v));
1260 }
1261 if (it.valid()) {
1262 if ((*it).m_high > low[v]) {
1263 (*it).m_high = low[v];
1264 visibArcs.pushBack(Tuple2<node, node>((*it).m_pathNode, v));
1265 }
1266 sweepLine.insertBefore(Interval(v, low[v], high[v]), it);
1267
1268 } else {
1269 sweepLine.pushBack(Interval(v, low[v], high[v]));
1270 }
1271 }
1272 }
1273
1274 // remove all arcs from visibArcs that are already in the constraint graph
1275 removeRedundantVisibArcs(visibArcs);
1276
1277 // compute original adjacency entry corresponding to a segment
1278 // We use this in order to omit visibility arcs between segments which
1279 // belong to the same edge if they can see each other from the same side
1280 // of the edge; if they see each other from different sides the arc is
1281 // essential!
1282 NodeArray<adjEntry> correspEdge(getGraph(), nullptr);
1283
1284 for (node v : PG.nodes) {
1285 node seg = m_pathNode[v];
1286 for (adjEntry adj : v->adjEntries) {
1287 if (m_pOR->direction(adj) != segDir) {
1288 continue;
1289 }
1290 edge eAdj = adj->theEdge();
1291 edge eOrig = PG.original(eAdj);
1292 if (eOrig == nullptr) {
1293 continue;
1294 }
1295 if (adj == eAdj->adjSource()) {
1296 correspEdge[seg] = eOrig->adjSource();
1297 } else {
1298 correspEdge[seg] = eOrig->adjTarget();
1299 }
1300 }
1301 }
1302
1303 // remove visibility arcs between ...
1304 SListIterator<Tuple2<node, node>> itT, itTSucc, itTPred;
1305 for (itT = visibArcs.begin(); itT.valid(); itT = itTSucc) {
1306 itTSucc = itT.succ();
1307 node v = (*itT).x1(), w = (*itT).x2();
1308
1309 // remove arcs which connect segments belonging to the same edge
1310 if (correspEdge[v] && (correspEdge[v] == correspEdge[w])) {
1311 if (itTPred.valid()) {
1312 visibArcs.delSucc(itTPred);
1313 } else {
1314 visibArcs.popFront();
1315 }
1316 }
1317
1318 else {
1319 itTPred = itT;
1320 }
1321 }
1322
1323
1324 for (itT = visibArcs.begin(); itT.valid(); ++itT) {
1325 //CHECK if
1326 node v = (*itT).x1(), w = (*itT).x2();
1327 if (!(m_extraNode[v] || m_extraNode[w])) {
1328 //CHECK if
1329 node boundRepresentant1 = m_path[v].front();
1330 node boundRepresentant2 = m_path[w].front();
1331 node en1 = m_pPR->expandedNode(boundRepresentant1);
1332 node en2 = m_pPR->expandedNode(boundRepresentant2);
1333 //do not insert visibility in cages
1334 if (!((en1 && en2) && (en1 == en2))) {
1335 edge e = newEdge(v, w);
1336
1337 //hier vielleicht multiedges abfangen: length auf max(min(sep, dists), minDist.sep)
1338
1339 m_length[e] = max(m_sep, minDist.separation()); //m_sep;
1340 m_cost[e] = 0;
1342#if 0
1343 writeGML("visibilityinserted.gml");
1344#endif
1345 }
1346 }
1347 }
1348
1349 OGDF_HEAVY_ASSERT(checkSweepLine(sweepLine));
1350}
1351
1352// performs feasibility test for position assignment pos, i.e., checks if
1353// the segment positions given by pos fulfill the constraints in the
1354// compaction constraint graph
1355template<class ATYPE>
1357 for (edge e : getGraph().edges) {
1358 node v = m_path[e->source()].front();
1359 node w = m_path[e->target()].front();
1360 if (pos[w] - pos[v] < length(e)) {
1361 std::cout << "feasibility check failed for edge " << e << std::endl;
1362 std::cout << " representatives: " << v << ", " << w << std::endl;
1363 std::cout << " length: " << length(e) << std::endl;
1364 std::cout << " actual distance: " << pos[w] - pos[v] << std::endl;
1365 std::cout << " type of " << e << ": ";
1366 switch (m_type[e]) {
1368 std::cout << "basic arc" << std::endl;
1369 break;
1371 std::cout << "vertex-size arc" << std::endl;
1372 break;
1374 std::cout << "visibility arc" << std::endl;
1375 break;
1377 std::cout << "median arc" << std::endl;
1378 break;
1380 std::cout << "reducible arc" << std::endl;
1381 break;
1383 std::cout << "fixtozero arc" << std::endl;
1384 }
1385 return false;
1386 }
1387 }
1388
1389 return true;
1390}
1391
1392}
Declares ogdf::CommonCompactionConstraintGraphBase.
Includes declaration of graph class.
Decralation of GraphElement and GraphList classes.
Declaration of doubly linked lists and iterators.
Declaration of class MinimumEdgeDistances which maintains minimum distances between attached edges at...
Declaration of orthogonal representation of planar graphs.
Declaration of a base class for planar representations of graphs and cluster graphs.
Declaration of class RoutingChannel which maintains required size of routing channels and separation,...
Declaration of singly linked lists and iterators.
Basic declarations, included by all source files.
Class for adjacency list elements.
Definition Graph_d.h:143
adjEntry faceCyclePred() const
Returns the cyclic predecessor in face.
Definition Graph_d.h:216
adjEntry twin() const
Returns the corresponding adjacency element associated with the same edge.
Definition Graph_d.h:173
adjEntry cyclicSucc() const
Returns the cyclic successor in the adjacency list.
Definition Graph_d.h:355
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition Graph_d.h:161
adjEntry cyclicPred() const
Returns the cyclic predecessor in the adjacency list.
Definition Graph_d.h:359
node twinNode() const
Returns the associated node of the corresponding adjacency entry (shorthand for twin()->theNode()).
Definition Graph_d.h:176
node theNode() const
Returns the node whose adjacency list contains this element.
Definition Graph_d.h:167
adjEntry faceCycleSucc() const
Returns the cyclic successor in face.
Definition Graph_d.h:213
Exception thrown when an algorithm realizes an internal bug that prevents it from continuing.
Definition exceptions.h:247
Base class for ogdf::CompactionConstraintGraphBase.
NodeArray< bool > m_extraNode
Node does not represent drawing node as we dont have positions we save a drawing representant and an ...
NodeArray< node > m_extraRep
existing representant of extranodes position anchor
Comparer class used for sorting segments by increasing position (given by segPos) such that two overl...
SegmentComparer(const NodeArray< ATYPE > &segPos, const NodeArray< int > &secSort)
Class implementing template-parameter-independent behaviour of ogdf::CompactionConstraintGraph.
void align(bool b)
Triggers alignment (=>some special edge handling to support al.)
bool verticalArc(edge e) const
Returns true if e is basic arc of vertical edge in PlanRepUML hierarchy.
EdgeArray< bool > m_alignmentArc
Basic arcs that have to be short for alignment (node to gen expander)
void dfsInsertPathVertex(node v, node pathVertex, NodeArray< bool > &visited, const NodeArray< node > &genOpposite)
bool verticalGen(edge e) const
Returns true if e is vertical edge in PlanRepUML hierarchy.
EdgeArray< bool > m_verticalGen
generalization that runs vertical relative to hierarchy
bool alignmentArc(edge e) const
Returns if arc is important for alignment. These are the arcs representing node to gen....
void insertPathVertices(const PlanRep &PG)
CompactionConstraintGraphBase(const OrthoRep &OR, const PlanRep &PG, OrthoDir arcDir, int costGen=1, int costAssoc=1, bool align=false)
Construction.
void insertBasicArcs(const PlanRep &PG)
EdgeArray< bool > m_verticalArc
arc corresponding to such an edge
NodeArray< edge > m_pathToEdge
save the (single!) edge (segment) for a pathNode
Represents a constraint graph used for compaction.
ATYPE separation() const
Returns the separation value.
NodeArray< ATYPE > m_extraOfs
offset of extra node to its rep, should change this
bool m_genToMedian
draw outgoing generalization from merger above ingoing gen.
ATYPE extraOfs(node v) const
Returns extraNode position, change to save mem, only need some entries.
EdgeArray< ATYPE > m_length
length of an edge
void insertVertexSizeArcs(const PlanRep &PG, const NodeArray< ATYPE > &sizeOrig, const RoutingChannel< ATYPE > &rc)
Inserts arcs for respecting sizes of vertices and achieving desired placement of generalizations if v...
CompactionConstraintGraph(const OrthoRep &OR, const PlanRep &PG, OrthoDir arcDir, ATYPE sep, int costGen=1, int costAssoc=1, bool align=false)
Construction.
void setMinimumSeparation(const PlanRep &PG, const NodeArray< int > &coord, const MinimumEdgeDistances< ATYPE > &minDist)
Sets min separation for multi edge original.
void resetGenMergerLengths(const PlanRep &PG, adjEntry adjFirst)
void insertVisibilityArcs(const PlanRep &PG, const NodeArray< ATYPE > &posDir, const NodeArray< ATYPE > &posOppDir)
Inserts arcs connecting segments which can see each other in a drawing of the associated planarized r...
int m_doubleBendCost
try to minimize double bends
int m_bungeeCost
middle position distance penalty
bool centerPriority()
Gets centerPriority (center single edges?)
static const int c_MedianFactor
median arcs cost factor*vertexArcCost
bool isFeasible(const NodeArray< ATYPE > &pos)
Performs feasibility test for position assignment pos, i.e., checks if the segment positions given by...
virtual string getLengthString(edge e) const override
int m_MedianArcCost
draw merger gen at median of incoming generalizations
bool m_centerPriority
should centering be more expensive than generalizations
bool checkSweepLine(const List< Interval > &sweepLine) const
static const int c_doubleBendFactor
double bends cost factor*vertexArcCost
ATYPE length(edge e) const
Returns length of edge e.
void setBoundaryCosts(adjEntry cornerDir, adjEntry cornerOppDir)
void setExtra(node v, node rep, ATYPE ofs)
Node v has no representation in drawing, only internal representation.
void centerPriority(bool b)
Sets centerPriority (center single edges?)
bool areMulti(edge e1, edge e2) const
Return PG result for flowcompaction.
ATYPE computeTotalCosts(const NodeArray< ATYPE > &pos) const
Computes the total costs for coordintes given by pos, i.e., the sum of the weighted lengths of edges ...
Class for the representation of edges.
Definition Graph_d.h:364
adjEntry adjSource() const
Returns the corresponding adjacancy entry at source node.
Definition Graph_d.h:408
adjEntry adjTarget() const
Returns the corresponding adjacancy entry at target node.
Definition Graph_d.h:411
const Graph & original() const
Returns a reference to the original graph.
Definition GraphCopy.h:104
Data type for general directed graphs (adjacency list representation).
Definition Graph_d.h:866
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition Graph_d.h:929
NodeType
The type of nodes.
Definition Graph_d.h:909
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition Graph_d.h:932
Doubly linked lists (maintaining the length of the list).
Definition List.h:1451
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition List.h:1547
void del(iterator it)
Removes it from the list.
Definition List.h:1611
iterator insertBefore(const E &x, iterator it)
Inserts element x before it.
Definition List.h:1566
iterator insertAfter(const E &x, iterator it)
Inserts element x after it.
Definition List.h:1572
Encapsulates a pointer to a list element.
Definition List.h:113
bool valid() const
Returns true iff the iterator points to an element.
Definition List.h:153
ListIteratorBase< E, isConst, isReverse > succ() const
Returns successor iterator.
Definition List.h:174
iterator begin()
Returns an iterator to the first element of the list.
Definition List.h:391
bool empty() const
Returns true iff the list is empty.
Definition List.h:286
void quicksort()
Sorts the list using Quicksort.
Definition List.h:1331
Maintains input sizes for improvement compaction (deltas and epsilons)
const ATYPE & epsilon(node v, OrthoDir s, int i) const
const ATYPE & delta(node v, OrthoDir s, int i) const
Class for the representation of nodes.
Definition Graph_d.h:241
int degree() const
Returns the degree of the node (indegree + outdegree).
Definition Graph_d.h:284
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition Graph_d.h:272
Orthogonal representation of an embedded graph.
Definition OrthoRep.h:225
static OrthoDir prevDir(OrthoDir d)
Returns the previous OrthoDir (in a clockwise manner)
Definition OrthoRep.h:400
static OrthoDir nextDir(OrthoDir d)
Returns the next OrthoDir (in a clockwise manner)
Definition OrthoRep.h:395
Planarized representations (of a connected component) of a graph.
Definition PlanRep.h:68
Graph::NodeType typeOf(node v) const
Returns the type of node v.
Definition PlanRep.h:199
adjEntry expandAdj(node v) const
Returns the adjacency entry of a node of an expanded face.
Definition PlanRep.h:160
Maintains input sizes for constructive compaction (size of routing channels, separation,...
ATYPE overhang() const
Encapsulates a pointer to an ogdf::SList element.
Definition SList.h:104
bool valid() const
Returns true iff the iterator points to an element.
Definition SList.h:134
SListIteratorBase< E, isConst > succ() const
Returns successor iterator.
Definition SList.h:152
Singly linked lists.
Definition SList.h:191
iterator begin()
Returns an iterator to the first element of the list.
Definition SList.h:344
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition SList.h:481
void delSucc(iterator itBefore)
Removes the succesor of itBefore.
Definition SList.h:554
void popFront()
Removes the first element from the list.
Definition SList.h:531
Tuples of two elements (2-tuples).
Definition tuples.h:49
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition Graph_d.h:717
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition Graph_d.h:659
Declarations for Comparer objects.
Definition of exception classes.
#define OGDF_AUGMENT_COMPARER(type)
Add this macro to your class to turn it into a full comparer.
Definition comparer.h:183
#define OGDF_THROW(CLASS)
Replacement for throw.
Definition exceptions.h:67
#define OGDF_HEAVY_ASSERT(expr)
Assert condition expr when using heavy debugging. See OGDF_ASSERT.
Definition basic.h:55
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
The namespace for all OGDF objects.
@ ReducibleArc
can be compacted to zero length
@ FixToZeroArc
can be compacted to zero length, can be fixed
@ MedianArc
inserted to replace some reducible in fixzerolength
OrthoDir
Definition OrthoRep.h:56
Represents an interval on the sweep line.
friend std::ostream & operator<<(std::ostream &os, const Interval &interval)
output operator
Information about a side of a vertex in UML diagrams.
Definition OrthoRep.h:228
Further information about the cages of vertices in UML diagrams.
Definition OrthoRep.h:264
Declaration and implementation of class Tuple2, Tuple3 and Tuple4.