Open
Graph Drawing
Framework

 v.2012.05
 

CompactionConstraintGraph.h
Go to the documentation of this file.
00001 /*
00002  * $Revision: 2299 $
00003  * 
00004  * last checkin:
00005  *   $Author: gutwenger $ 
00006  *   $Date: 2012-05-07 15:57:08 +0200 (Mon, 07 May 2012) $ 
00007  ***************************************************************/
00008  
00046 #ifdef _MSC_VER
00047 #pragma once
00048 #endif
00049 
00050 
00051 #ifndef OGDF_COMP_CONSTR_GRAPH_H
00052 #define OGDF_COMP_CONSTR_GRAPH_H
00053 
00054 
00055 #include <ogdf/orthogonal/OrthoRep.h>
00056 #include <ogdf/internal/orthogonal/RoutingChannel.h>
00057 #include <ogdf/orthogonal/MinimumEdgeDistances.h>
00058 
00059 
00060 namespace ogdf {
00061 
00062 
00063     // types of edges in the constraint graph
00064     enum ConstraintEdgeType {
00065         cetBasicArc, 
00066         cetVertexSizeArc, 
00067         cetVisibilityArc,
00068         cetFixToZeroArc, //can be compacted to zero length, can be fixed
00069         cetReducibleArc, //can be compacted to zero length
00070         cetMedianArc //inserted to replace some reducible in fixzerolength
00071     };
00072 
00073 //---------------------------------------------------------
00074 // CompactionConstraintGraph
00075 // base class implementing common behaviour of all parameterized
00076 // CompactionConstraintGraph<ATYPE>
00077 //---------------------------------------------------------
00078 class CompactionConstraintGraphBase : protected Graph
00079 {
00080 public:
00081 
00082     // output for debugging only
00083     void writeGML(const char *fileName) const ;
00084     void writeGML(ostream &os) const;
00085     //output edges on external face
00086     void writeGML(const char *fileName, NodeArray<bool> one) const ;
00087     void writeGML(ostream &os, NodeArray<bool> one) const;
00088 
00089     //return constraint arc representing input edge e in constraint graph
00090     edge basicArc(edge e) const {
00091         return m_edgeToBasicArc[e];
00092     }
00093 
00094     //***************************
00095     //return some edge properties
00096     //***************************
00097     //returns true if e is vertical edge in PlanRepUML hierarchy
00098     bool verticalGen(edge e) const {return m_verticalGen[e];}
00099     //returns true if e is basic arc of vertical edge in PlanRepUML hierarchy
00100     //Precond.: e is arc in the constraint graph
00101     bool verticalArc(edge e) const {return m_verticalArc[e];}
00102     //edge lies on cage border
00103     bool onBorder(edge e) const {return m_border[e]>0;}
00104     //these are subject to length fixation if length < sep
00105     bool fixOnBorder(edge e) const {return (m_border[e] == 2);}
00106 
00107     //trigger alignment (=>some special edge handling to support al.)
00108     void align(bool b) {m_align = b;}
00109 
00110     //return if arc is important for alignment
00111     //these are the arcs representing node to gen. merger edges
00112     bool alignmentArc(edge e) const {return m_alignmentArc[e];}
00113 
00114     const PlanRep& getPlanRep() const {return *m_pPR;}
00115 
00116     edge pathToOriginal(node v) {return m_pathToEdge[v];}
00117 
00118 protected:
00119     // construction
00120     CompactionConstraintGraphBase(const OrthoRep &OR,
00121         const PlanRep &PG,
00122         OrthoDir arcDir,
00123         int costGen = 1,
00124         int costAssoc = 1, bool align = false);
00125 
00126     // computes topological numbering on the segments of the constraint graph.
00127     void computeTopologicalSegmentNum(NodeArray<int> &topNum);
00128 
00129     // remove "arcs" from visibArcs which we already have in the constraint graph
00130     // (as basic arcs)
00131     void removeRedundantVisibArcs(SListPure<Tuple2<node,node> > &visibArcs);
00132 
00133     const OrthoRep *m_pOR;
00134     const PlanRep *m_pPR;
00135     OrthoDir m_arcDir;
00136     OrthoDir m_oppArcDir;
00137 
00138     int m_edgeCost[2];
00139 
00140     NodeArray<SListPure<node> > m_path; // list of nodes contained in a segment
00141     NodeArray<node> m_pathNode;         // segment containing a node in PG
00142     EdgeArray<edge> m_edgeToBasicArc;   // basic arc representing an edge in PG
00143 
00144     EdgeArray<int>    m_cost;    // cost of an edge
00145     EdgeArray<ConstraintEdgeType> m_type;
00146 
00147     //test fuer vorkomp. der Generalisierungen
00148     EdgeArray<bool> m_verticalGen; //generalization that runs vertical relative to hierarchy
00149     EdgeArray<bool> m_verticalArc; //arc corresponding to such an edge
00150     EdgeArray<int> m_border; //only used for cage precompaction in flowcompaction computecoords
00151 
00152     //basic arcs that have to be short for alignment (node to gen expander)
00153     EdgeArray<bool> m_alignmentArc;
00154 
00155     NodeArray<edge> m_pathToEdge; //save the (single!) edge (segment) for a pathNode
00156     NodeArray<edge> m_originalEdge; //save edge for the basic arcs
00157     
00158     // embeds constraint graph such that all sources and sinks lie in a common
00159     // face
00160     void embed();
00161 
00162     virtual void writeLength(ostream &os, edge e) const = 0;
00163 
00164 private:
00165 
00166     //set special costs for node to merger generalizations
00167     bool m_align;
00168 
00169     void insertPathVertices(const PlanRep &PG);
00170     void dfsInsertPathVertex(
00171         node v,
00172         node pathVertex,
00173         NodeArray<bool> &visited,
00174         const NodeArray<node> &genOpposite);
00175 
00176     void insertBasicArcs(const PlanRep &PG);
00177 
00178     node m_superSource;
00179     node m_superSink;
00180     SList<node> m_sources;
00181     SList<node> m_sinks;
00182 
00183 
00184 };
00185 
00186 
00187 //---------------------------------------------------------
00188 // CompactionConstraintGraph
00189 // represents a constraint graph used for compaction
00190 //  vertices: maximally connected horiz. (resp. vert.) paths
00191 //  basic arcs: paths connected by edges of opposite direction
00192 //  vertex size arcs: care for minimum size of cages
00193 //  visibility arcs: paths seeing each other
00194 // Each edge has a (minimum) length and cost.
00195 //---------------------------------------------------------
00196 template<class ATYPE>
00197 class CompactionConstraintGraph : public CompactionConstraintGraphBase
00198 {
00199 public:
00200     // construction
00201     CompactionConstraintGraph(const OrthoRep &OR,
00202         const PlanRep &PG,
00203         OrthoDir arcDir,
00204         ATYPE sep,
00205         int costGen = 1,
00206         int costAssoc = 1,
00207         bool align = false) :
00208             CompactionConstraintGraphBase(OR, PG, arcDir, costGen, costAssoc, align),
00209             m_length((Graph&)*this, sep), m_extraNode((Graph&)*this, false), 
00210             m_extraOfs((Graph&)*this, 0), m_extraRep((Graph&)*this, 0)
00211     {
00212         OGDF_ASSERT(&(const Graph &)PG == &(const Graph &)OR);
00213         m_sep       = sep;
00214         
00215         m_centerPriority = true; //should centering of single edges have prio. to gen. length
00216         m_genToMedian = true;  //should outgoing merger gen. be drawn to merger median
00217         initializeCosts();
00218         
00219     }//constructor
00220 
00221     // output for debugging only
00222     void writeGML(const char *fileName) const ;
00223     void writeGML(ostream &os) const;
00224 
00225 
00226     // returns underlying graph
00227     const Graph &getGraph() const { return (Graph&)*this; }
00228     Graph &getGraph() { return (Graph&)*this; }
00229 
00230     
00231     const OrthoRep &getOrthoRep() const {
00232         return *m_pOR;
00233     }
00234 
00235     
00236     // returns list of nodes contained in segment v
00237     // Precodn.: v is in the constraint graph
00238     const SListPure<node> &nodesIn(node v) const {
00239         return m_path[v];
00240     }
00241 
00242     // returns the segment (path node in constraint graph) containing v
00243     // Precond.: v is a node in the associated planarized representation
00244     node pathNodeOf(node v) const {
00245         return m_pathNode[v];
00246     }
00247 
00248     // returns length of edge e
00249     // Precond.: e is an edge in the constraint graph
00250     ATYPE length(edge e) const {
00251         return m_length[e];
00252     }
00253 
00254     // returns cost of edge e
00255     // Precond.: e is an edge in the constraint graph
00256     int cost(edge e) const {
00257         return m_cost[e];
00258     }
00259 
00260     // returns type of edge e
00261     // Precond.: e is an edge in the constraint graph
00262     ConstraintEdgeType typeOf(edge e) const {
00263         return m_type[e];
00264     }
00265 
00266     //returns node status
00267     bool extraNode(node v) const {
00268         return m_extraNode[v];
00269     }
00270     //returns extraNode position, change to save mem, only need some entries
00271     ATYPE extraOfs(node v) const {
00272         return m_extraOfs[v];
00273     }
00274     //returns extraNode existing anchor representant
00275     node extraRep(node v) const {
00276         return m_extraRep[v];
00277     }
00278 
00279     //get / set centerPriority (center single edges?)
00280     bool centerPriority() {return m_centerPriority;}
00281     void centerPriority(bool b) { m_centerPriority = b;}
00282 
00283     // computes the total costs for coordintes given by pos, i.e.,
00284     // the sum of the weighted lengths of edges in the constraint graph.
00285     ATYPE computeTotalCosts(const NodeArray<ATYPE> &pos) const;
00286 
00287 
00288     // inserts arcs for respecting sizes of vertices and achieving desired
00289     // placement of generalizations if vertices are represented by variable
00290     // cages; also corrects length of arcs belonging to cages which are
00291     // adjacent to a corner; takes routing channels into account.
00292     void insertVertexSizeArcs(const PlanRep &PG,
00293         const NodeArray<ATYPE> &sizeOrig,
00294         const RoutingChannel<ATYPE> &rc);
00295 
00296     // inserts arcs for respecting sizes of vertices and achieving desired
00297     // placement of generalizations if vertices are represented by tight cages;
00298     // also corrects length of arcs belonging to cages which are adjacent to
00299     // a corner; takes special distances between edge segments attached at
00300     // a vertex (delta's and epsilon's) into account.
00301     void insertVertexSizeArcs(
00302         const PlanRep &PG,
00303         const NodeArray<ATYPE> &sizeOrig,
00304         const MinimumEdgeDistances<ATYPE> &minDist);
00305 
00306     // inserts arcs connecting segments which can see each other in a drawing
00307     // of the associated planarized representation PG which is given by
00308     // posDir and posOppDir. 
00309     void insertVisibilityArcs(
00310         const PlanRep &PG,  // associated planarized representation
00311         const NodeArray<ATYPE> &posDir,  // position of segment containing
00312                                          // vertex in PG
00313         const NodeArray<ATYPE> &posOppDir);  // position of orthogonal segment
00314                                              // containing vertex in PG
00315 
00316     void insertVisibilityArcs(
00317         const PlanRep &PG,
00318         const NodeArray<ATYPE> &posDir,
00319         const NodeArray<ATYPE> &posOrthDir,
00320         const MinimumEdgeDistances<ATYPE> &minDist);
00321 
00322 
00323     //set min sep for multi edge original
00324     void setMinimumSeparation(const PlanRep &PG,
00325         const NodeArray<int> coord, 
00326         const MinimumEdgeDistances<ATYPE> &minDist);
00327 
00328 
00329     // embeds constraint graph such that all sources and sinks lie in a common
00330     // face
00331     void embed() {
00332         CompactionConstraintGraphBase::embed();
00333     }
00334 
00335 
00336     // performs feasibility test for position assignment pos, i.e., checks if
00337     // the segment positions given by pos fulfill the constraints in the
00338     // compaction constraint graph
00339     // (for debuging only)
00340     bool isFeasible(const NodeArray<ATYPE> &pos);
00341 
00342     //returns the separation value
00343     ATYPE separation() const {return m_sep;} 
00344 
00345     //return PG result for flowcompaction
00346     bool areMulti(edge e1, edge e2) const;
00347 
00348 
00349 private:
00350     //---------------------------------------------------------
00351     // CompactionConstraintGraph::Interval
00352     // represents an interval on the sweep line
00353     //---------------------------------------------------------
00354     struct Interval
00355     {
00356         Interval(node v, ATYPE low, ATYPE high) {
00357             m_low = low;
00358             m_high = high;
00359             m_pathNode = v;
00360         }
00361 
00362         ATYPE m_low, m_high; // lower and upper bound
00363         node m_pathNode;     // corresponding segment
00364 
00365         // output operator
00366         friend ostream &operator<<(ostream &os,
00367             const Interval &interval)
00368         {
00369             os << "[" << interval.m_low << "," << interval.m_high <<
00370                 ";" << interval.m_pathNode << "]";
00371             return os;
00372         }
00373 
00374     };
00375 
00376     //---------------------------------------------------------
00377     // CompactionConstraintGraph::SegmentComparer
00378     // comparer class used for sorting segments by increasing position
00379     // (given by segPos) such that two overlapping segments come in the
00380     // order imposed by the embedding (given by secSort: segment which
00381     // comes first has secSort = 0, the other has 1)
00382     //---------------------------------------------------------
00383     class SegmentComparer
00384     {
00385     public:
00386         SegmentComparer(const NodeArray<ATYPE> &segPos,
00387             const NodeArray<int> &secSort) {
00388             m_pPos = &segPos;
00389             m_pSec = &secSort;
00390         }
00391 
00392         int compare(const node &x, const node &y) const {
00393             ATYPE d = (*m_pPos)[x] - (*m_pPos)[y];
00394             if (d < 0)
00395                 return -1;
00396             else if (d > 0)
00397                 return 1;
00398             else
00399                 return (*m_pSec)[x] - (*m_pSec)[y];
00400         }
00401 
00402         OGDF_AUGMENT_COMPARER(node)
00403     private:
00404         const NodeArray<ATYPE> *m_pPos;
00405         const NodeArray<int>    *m_pSec;
00406     };
00407 
00408     virtual void writeLength(ostream &os, edge e) const {
00409         os << m_length[e];
00410     }
00411 
00412     void setBasicArcsZeroLength(const PlanRep &PG);
00413     void resetGenMergerLengths(const PlanRep &PG, adjEntry adjFirst);
00414     void setBoundaryCosts(adjEntry cornerDir,adjEntry cornerOppDir);
00415 
00416     bool checkSweepLine(const List<Interval> &sweepLine);
00417 
00418     ATYPE m_sep;
00419 
00420     EdgeArray<ATYPE> m_length;  // length of an edge
00421 
00422     NodeArray<bool> m_extraNode; //node does not represent drawing node
00423     //as we dont have positions, we save a drawing representant and an offset 
00424     NodeArray<ATYPE> m_extraOfs; //offset of extra node to its rep, should change this
00425     NodeArray<node> m_extraRep; //existing representant of extranodes position anchor
00426 
00427     //**********************
00428     //COST SETTINGS SECTION
00429 
00430     // we make vertex size arcs more expensive than basic arcs in order
00431     // to get small cages
00432     // should be replaced by option/value dependent on e.g. degree
00433     int m_vertexArcCost;  //get small cages
00434     int m_bungeeCost;     //middle position distance penalty
00435     int m_MedianArcCost;  //draw merger gen at median of incoming generalizations
00436     int m_doubleBendCost; //try to minimize double bends
00437     bool m_genToMedian;   //draw outgoing generalization from merger above ingoing gen.
00438     //this does not work if generalization costs are set very small by the user
00439     //because there must be a minimum cost for centering
00440     bool m_centerPriority;  //should centering be more expensive than generalizations
00441 
00442     //factor of costs relative to generalization
00443     static const int c_vertexArcFactor;
00444     static const int c_bungeeFactor;
00445     static const int c_doubleBendFactor; // = 20; //double bends cost factor*vertexArcCost
00446     static const int c_MedianFactor;     //median arcs cost  factor*vertexArcCost
00447 
00448 
00449 protected:
00450     //node v has no representation in drawing, only internal representation
00451     void setExtra(node v, node rep, ATYPE ofs) 
00452         {m_extraNode[v] = true; m_extraRep[v] = rep; m_extraOfs[v] = ofs;}
00453 
00454     void initializeCosts() 
00455     {
00456         // we make vertex size arcs more expensive than basic arcs in order
00457         // to get small cages; not necessary if cage size fixed in improvement
00458         // cost should be dependend on degree 
00459         // Z.B. DURCH OPTION ODER WERT; DER VON DER ZAHL ADJAZENTER KANTEN ABHAENGIG IST
00460         // should be derived by number of edges times something  
00461         int costGen = m_edgeCost[Graph::generalization];
00462 
00463         m_vertexArcCost = c_vertexArcFactor*costGen; //spaeter aus Kompaktierungsmodul uebergeben
00464         if (m_centerPriority)
00465             m_bungeeCost = c_bungeeFactor*costGen+1;//-1;//for distance to middle position,
00466         else
00467             m_bungeeCost = c_bungeeFactor*4+1;//-1;//for distance to middle position,
00468                                    //addition value should be < gen cost!!!
00469         m_MedianArcCost = c_MedianFactor*m_vertexArcCost;
00470         m_doubleBendCost = c_doubleBendFactor*m_vertexArcCost;
00471     }//initializeCosts
00472 };
00473 
00474 //********************************
00475 //initialization of static members 
00476 template<class ATYPE>
00477 const int CompactionConstraintGraph<ATYPE>::c_vertexArcFactor = 20;
00478 template<class ATYPE>
00479 const int CompactionConstraintGraph<ATYPE>::c_bungeeFactor = 20;
00480 template<class ATYPE>
00481 const int CompactionConstraintGraph<ATYPE>::c_doubleBendFactor = 20; //double bends cost mxxx*vertexArcCost
00482 //factor *VertexArcCost, costs for pulling generalization to median position at merger
00483 template<class ATYPE>
00484 const int CompactionConstraintGraph<ATYPE>::c_MedianFactor = 10*c_doubleBendFactor; 
00485 
00486 
00487 //************************************
00488 //
00489 // implementation of member functions
00490 //
00491 //************************************
00492 }
00493 
00494 #include <ogdf/planarity/PlanRep.h>
00495 
00496 namespace ogdf {
00497 
00498 
00499 // allow 0-length for sides of generalization merger cages
00500 template<class ATYPE>
00501 void CompactionConstraintGraph<ATYPE>::resetGenMergerLengths(
00502     const PlanRep &PG,
00503     adjEntry adjFirst)
00504 {
00505     adjEntry adj = adjFirst;
00506     int faceSize = 0;
00507 
00508     do {
00509         if ((m_pOR->direction(adj) == m_arcDir ||
00510             m_pOR->direction(adj) == m_oppArcDir) &&
00511             (PG.typeOf(adj->theNode()) == Graph::dummy ||
00512             PG.typeOf(adj->twinNode()) == Graph::dummy))
00513         {
00514             m_length[m_edgeToBasicArc[adj]] = 0;
00515         }
00516 
00517         adj = adj->faceCycleSucc();
00518         faceSize++;
00519     } while(adj != adjFirst);
00520 
00521 //****************************************
00522 //generalization position section
00523 //pull upper generalization to median of merger cage's incoming lower generalizations
00524 
00525     if (m_genToMedian)
00526     {
00527         if ((m_pOR->direction(adjFirst) == m_arcDir) ||
00528             (m_pOR->direction(adjFirst) == m_oppArcDir) )
00529         {
00530             int numIncoming = faceSize - 3;   
00531             int median = (numIncoming / 2) + 1;
00532             
00533             //if (numIncoming == 2) ... just the middle position
00534             node upper = m_pathNode[adjFirst->theNode()];
00535             if (PG.typeOf(adjFirst->theNode()) != Graph::generalizationMerger) 
00536               OGDF_THROW(AlgorithmFailureException);
00537             node vMin;
00538             if (m_pOR->direction(adjFirst) == m_arcDir)
00539               vMin = adjFirst->faceCyclePred()->theNode();
00540             else vMin = adjFirst->faceCycleSucc()->theNode();
00541             adj = adjFirst->faceCycleSucc(); //target right or left boundary, depending on drawing direction
00542             for (int i = 0; i < median; i++) 
00543                 adj = adj->faceCycleSucc();
00544             node lower = m_pathNode[adj->theNode()];
00545             node vCenter = newNode();
00546             setExtra(vCenter, vMin, 0);
00547             //it seems we dont need the helper, as only source-adjEntries lying on
00548             //the outer face are considered later, but keep it in mind
00549             /*
00550             edge helper = newEdge(m_pathNode[vMin], vCenter);
00551             m_length[helper] = 0;
00552             m_cost[helper] = 0;
00553             m_type[helper] = cetReducibleArc;
00554             */
00555  
00556             edge e1 = newEdge(vCenter,upper);
00557             m_length[e1] = 0;
00558             m_cost[e1]   = m_MedianArcCost; 
00559             m_type[e1]   = cetMedianArc;
00560 
00561             edge e2 = newEdge(vCenter,lower);
00562             m_length[e2] = 0;
00563             m_cost[e2]   = m_MedianArcCost;
00564             m_type[e2]   = cetMedianArc;
00565         }//if compaction dir
00566     }//if gentomedian option set
00567 //*******************************************
00568 }
00569 
00570 
00571 // set cost of edges on the cage boundary to 0
00572 template<class ATYPE>
00573 void CompactionConstraintGraph<ATYPE>::setBoundaryCosts(
00574     adjEntry cornerDir,
00575     adjEntry cornerOppDir)
00576 {
00577     /*
00578     adjEntry adj;
00579     for (adj = cornerDir; m_pOR->direction(adj) == m_arcDir; adj = adj->faceCycleSucc())
00580         m_cost[m_edgeToBasicArc[adj]] = 0;
00581     for (adj = cornerOppDir; m_pOR->direction(adj) == m_oppArcDir; adj = adj->faceCycleSucc())
00582         m_cost[m_edgeToBasicArc[adj]] = 0;
00583     */
00584     //test fuer multi separation
00585     adjEntry adj;
00586     for (adj = cornerDir; m_pOR->direction(adj) == m_arcDir; adj = adj->faceCycleSucc())
00587     {
00588         m_cost[m_edgeToBasicArc[adj]] = 0;
00589 
00590         if (m_pathNode[adj->twin()->cyclicSucc()->theNode()] &&
00591             (m_pOR->direction(adj->faceCycleSucc()) == m_arcDir)
00592             )
00593             m_originalEdge[m_pathNode[adj->twin()->cyclicSucc()->theNode()]] = 
00594                 m_pPR->original(adj->twin()->cyclicSucc()->theEdge());
00595 
00596     }
00597     for (adj = cornerOppDir; m_pOR->direction(adj) == m_oppArcDir; adj = adj->faceCycleSucc())
00598     {
00599         m_cost[m_edgeToBasicArc[adj]] = 0;
00600 
00601         if (m_pathNode[adj->twin()->cyclicSucc()->theNode()])
00602             m_originalEdge[m_pathNode[adj->twin()->cyclicSucc()->theNode()]] = 
00603                 m_pPR->original(adj->twin()->cyclicSucc()->theEdge());
00604     }
00605 }
00606 
00607 
00608 //
00609 // insert arcs required for respecting vertex sizes, sizes of routing channels
00610 // and position of attached generalizations
00611 // vertices are represented by variable cages
00612 template<class ATYPE>
00613 void CompactionConstraintGraph<ATYPE>::insertVertexSizeArcs(
00614     const PlanRep &PG,
00615     const NodeArray<ATYPE> &sizeOrig,
00616     const RoutingChannel<ATYPE> &rc)
00617 {
00618  
00619     // segments in constraint graph are sides sMin and sMax; other two side
00620     // are sides in which adjacency entries run in direction m_arcDir and
00621     // m_oppArcDir
00622     OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
00623     OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
00624 
00625     const ATYPE overhang = rc.overhang();
00626 
00627     node v;
00628     forall_nodes(v,PG)
00629     {
00630         if (PG.expandAdj(v) == 0) continue;
00631 
00632         if(PG.typeOf(v) == Graph::generalizationMerger)
00633         {
00634             resetGenMergerLengths(PG,PG.expandAdj(v));
00635 
00636         }
00637         else // high/low-degree expander
00638         {
00639             ATYPE size = sizeOrig[v];
00640 
00641             const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v);
00642 
00643             // determine routing channels rcMin and rcMax
00644             ATYPE rcMin = overhang + rc(v,dirMin);
00645             ATYPE rcMax = overhang + rc(v,dirMax);
00646         
00647             adjEntry cornerDir    = vi.m_corner[m_arcDir];
00648             adjEntry cornerOppDir = vi.m_corner[m_oppArcDir];
00649             adjEntry cornerMin    = vi.m_corner[dirMin];
00650             adjEntry cornerMax    = vi.m_corner[dirMax];
00651 
00652             // set cost of edges on the cage boundary to 0
00653             setBoundaryCosts(cornerDir,cornerOppDir);
00654 
00655             const OrthoRep::SideInfoUML &sDir = vi.m_side[m_arcDir];
00656             const OrthoRep::SideInfoUML &sOppDir = vi.m_side[m_oppArcDir];
00657 
00658             // correct lengths of edges within cage adjacent to corners
00659             if(sDir.totalAttached() > 0) {
00660                 m_length[m_edgeToBasicArc[cornerDir]] = rcMin;
00661                 m_length[m_edgeToBasicArc[cornerMax->faceCyclePred()]] = rcMax;
00662             } else {
00663                 // if no edges are attached at this side we need no constraint
00664                 m_length[m_edgeToBasicArc[cornerDir]] = 0;
00665                 delEdge(m_edgeToBasicArc[cornerDir]);
00666             }
00667 
00668             if(sOppDir.totalAttached() > 0) {
00669                 m_length[m_edgeToBasicArc[cornerOppDir]] = rcMax;
00670                 m_length[m_edgeToBasicArc[cornerMin->faceCyclePred()]] = rcMin;
00671             } else {
00672                 // if no edges are attached at this side we need no constraint
00673                 m_length[m_edgeToBasicArc[cornerOppDir]] = 0;
00674                 delEdge(m_edgeToBasicArc[cornerOppDir]);
00675             }
00676 
00677 
00678             // insert arcs for respecting vertex size / position of generalizations
00679             node vMin = m_pathNode[cornerDir->theNode()];
00680             node vMax = m_pathNode[cornerOppDir->theNode()];
00681 
00682             // any attached generalizations ?
00683             if (sDir.m_adjGen == 0 && sOppDir.m_adjGen == 0)
00684             {
00685                 // no, only one arc for vertex size + routing channels
00686                 edge e = newEdge(vMin,vMax);
00687                 m_length[e] = rcMin + size + rcMax - 2*overhang;
00688                 m_cost  [e] = 2*m_vertexArcCost;
00689                 m_type  [e] = cetVertexSizeArc;
00690 
00691             } else {
00692                 // yes, then two arcs for each side with an attached generalization
00693                 ATYPE minHalf = size/2;
00694                 ATYPE maxHalf = size - minHalf;
00695                 ATYPE lenMin = rcMin + minHalf - overhang;
00696                 ATYPE lenMax = maxHalf + rcMax - overhang;
00697 
00698                 if (sDir.m_adjGen != 0) {
00699                     node vCenter = m_pathNode[sDir.m_adjGen->theNode()];
00700                     edge e1 = newEdge(vMin,vCenter);
00701                     m_length[e1] = lenMin;
00702                     m_cost  [e1] = m_vertexArcCost;
00703                     m_type  [e1] = cetVertexSizeArc;
00704                     edge e2 = newEdge(vCenter,vMax);
00705                     m_length[e2] = lenMax;
00706                     m_cost  [e2] = m_vertexArcCost;
00707                     m_type  [e2] = cetVertexSizeArc;
00708                 }
00709 
00710                 if (sOppDir.m_adjGen != 0) {
00711                     node vCenter = m_pathNode[sOppDir.m_adjGen->theNode()];
00712                     edge e1 = newEdge(vMin,vCenter);
00713                     m_length[e1] = lenMin;
00714                     m_cost  [e1] = m_vertexArcCost;
00715                     m_type  [e1] = cetVertexSizeArc;
00716                     edge e2 = newEdge(vCenter,vMax);
00717                     m_length[e2] = lenMax;
00718                     m_cost  [e2] = m_vertexArcCost;
00719                     m_type  [e2] = cetVertexSizeArc;
00720                 }
00721 
00722             }
00723 
00724         } // high/lowDegreeExpander
00725     }
00726 }
00727 
00728 
00729 template<class ATYPE>
00730 void CompactionConstraintGraph<ATYPE>::setBasicArcsZeroLength(
00731     const PlanRep &PG)
00732 {
00733     edge e;
00734     forall_edges(e,PG)
00735     {
00736         edge arc = m_edgeToBasicArc[e];
00737         if (arc == 0) continue;
00738 
00739         node v = e->source();
00740         node w = e->target();
00741         if ( ((PG.typeOf(v) == Graph::dummy) && (PG.typeOf(w) == Graph::dummy) &&
00742             (v->degree() == 2) && w->degree() == 2) &&
00743             (m_pOR->angle(e->adjSource()) == m_pOR->angle(e->adjTarget()) ) && //no uturns
00744             (PG.typeOf(e) != Graph::generalization)
00745            )
00746         {
00747             m_length[arc] = 0;
00748             m_type[arc] = cetFixToZeroArc;
00749             //we make fixtozero arcs as expensive as possible
00750             m_cost[arc] = m_doubleBendCost;
00751         }
00752     }
00753 }
00754 
00755 
00756 
00757 //
00758 // insert arcs required for respecting vertex sizes
00759 // and position of attached generalizations
00760 // vertices are represented by tight cages
00761 template<class ATYPE>
00762 void CompactionConstraintGraph<ATYPE>::insertVertexSizeArcs(
00763     const PlanRep &PG,
00764     const NodeArray<ATYPE> &sizeOrig,
00765     const MinimumEdgeDistances<ATYPE> &minDist)
00766 {
00767     // set the length of all basic arcs corresponding to inner edge segments
00768     // to 0
00769     setBasicArcsZeroLength(PG);
00770 
00771     // segments in constraint graph are sides sMin and sMax; other two side
00772     // are sides in which adjacency entries run in direction m_arcDir and
00773     // m_oppArcDir
00774     OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
00775     OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
00776 
00777     node v;
00778     forall_nodes(v,PG)
00779     {
00780         if (PG.expandAdj(v) == 0) continue;
00781 
00782         if(PG.typeOf(v) == Graph::generalizationMerger)
00783         {
00784             resetGenMergerLengths(PG,PG.expandAdj(v));
00785 
00786         }
00787         else // high/low-degree expander
00788         {
00789             ATYPE size = sizeOrig[v];
00790             const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v);
00791 
00792             adjEntry cornerDir    = vi.m_corner[m_arcDir];
00793             adjEntry cornerOppDir = vi.m_corner[m_oppArcDir];
00794             adjEntry cornerMin    = vi.m_corner[dirMin];
00795             adjEntry cornerMax    = vi.m_corner[dirMax];
00796 
00797             adjEntry adj = cornerDir, last = cornerMax->faceCyclePred();
00798             if(adj != last) {
00799                 m_length[m_edgeToBasicArc[adj]]  = minDist.epsilon(v,m_arcDir,0);
00800                 m_length[m_edgeToBasicArc[last]] = minDist.epsilon(v,m_arcDir,1);
00801                 int i = 0;
00802                 for(adj = adj->faceCycleSucc(); adj != last; adj = adj->faceCycleSucc()) {
00803                     if (PG.typeOf(adj->cyclicPred()->theEdge()) == Graph::generalization)
00804                         i++;
00805                     m_length[m_edgeToBasicArc[adj]] = minDist.delta(v,m_arcDir,i);
00806                 }
00807             }
00808 
00809             adj = cornerOppDir, last = cornerMin->faceCyclePred();
00810             if(adj != last) {
00811                 m_length[m_edgeToBasicArc[adj]]  = minDist.epsilon(v,m_oppArcDir,0);
00812                 m_length[m_edgeToBasicArc[last]] = minDist.epsilon(v,m_oppArcDir,1);
00813                 int i = 0;
00814                 for(adj = adj->faceCycleSucc(); adj != last; adj = adj->faceCycleSucc()) {
00815                     if (PG.typeOf(adj->cyclicPred()->theEdge()) == Graph::generalization)
00816                         i++;
00817                     m_length[m_edgeToBasicArc[adj]] = minDist.delta(v,m_oppArcDir,i);
00818                 }
00819             }
00820 
00821 
00822             // insert arcs for respecting vertex size / position of generalizations
00823             node vMin = m_pathNode[cornerDir->theNode()];
00824             node vMax = m_pathNode[cornerOppDir->theNode()];
00825 
00826             const OrthoRep::SideInfoUML &sDir = vi.m_side[m_arcDir];
00827             const OrthoRep::SideInfoUML &sOppDir = vi.m_side[m_oppArcDir];
00828 
00829             // any attached generalizations ?
00830             if (sDir.m_adjGen == 0 && sOppDir.m_adjGen == 0)
00831             {
00832                 //check for single edge case => special treatment
00833                 //generic case could handle all numbers
00834                 
00835                 if ((sDir.totalAttached() == 1) || (sOppDir.totalAttached() == 1))
00836                     {
00837                         //first, insert a new center node and connect it
00838                         ATYPE lenMin = size/2;
00839                         ATYPE lenMax = size - lenMin;
00840                         node vCenter = newNode();
00841                         setExtra(vCenter, cornerDir->theNode(), lenMin);
00842  
00843                         edge e1 = newEdge(vMin,vCenter);
00844                         m_length[e1] = lenMin;
00845                         //if (lenMin < minDist.epsilon(v,m_arcDir,0)) exit(1);
00846                         m_cost[e1]   = m_vertexArcCost;
00847                         m_type[e1]   = cetVertexSizeArc;
00848                         edge e2 = newEdge(vCenter,vMax);
00849                         m_length[e2] = lenMax;
00850                         m_cost[e2]   = m_vertexArcCost;
00851                         m_type[e2]   = cetVertexSizeArc;
00852 
00853                         if (sDir.totalAttached() == 1)
00854                             {
00855                      
00856                         //then, insert a moveable node connecting center
00857                         //and outgoing segment
00858                         node vBungee = newNode();
00859                         //+1 should fix the fixzerolength problem
00860                         setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_arcDir,0) );
00861 
00862                         edge eToBungee = newEdge(vMin, vBungee);
00863                         m_type[eToBungee] = cetMedianArc; //cetBasicArc; //is this ok !!!!!!!!!!!!!!
00864                         m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!!
00865                         m_length[eToBungee] = minDist.epsilon(v,m_arcDir,0);
00866 
00867                         edge eBungeeCenter = newEdge(vBungee, vCenter);
00868                         //bungee, center and outgoing segment may build column if in the middle
00869                         m_type[eBungeeCenter] = cetMedianArc; 
00870                         m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
00871                         m_length[eBungeeCenter] = 0;
00872 
00873                             //attention: pathnode construct works only if degree 1
00874                         edge eBungeeOut =  newEdge(vBungee, m_pathNode[cornerDir->twinNode()]);
00875                         if (m_pathNode[cornerDir->twinNode()] == vMin) exit(1);
00876                         //bungee, center and outgoing segment may build column if in the middle
00877                         m_type[eBungeeOut] = cetMedianArc; 
00878                         m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
00879                         m_length[eBungeeOut] = 0;
00880 /*
00881                         //connect outgoing segment and "right" segment, maybe obsolete
00882                         edge eFromOut = newEdge(m_pathNode[cornerDir->twinNode()], vMax);
00883                         m_type[eFromOut] = cetBasicArc; //!!!!!!!!!!!!!!!!!!!!!!!
00884                         m_cost[eFromOut] = 0; //!!!!!!!!!!!!!!!!!!!
00885                         m_length[eFromOut] = minDist.epsilon(v,m_arcDir,1);
00886   */                      
00887                             }//if sDir case
00888                        if ( (sOppDir.totalAttached() == 1) && !(m_pathNode[cornerOppDir->twinNode()] == vMin) )
00889                             {
00890                      
00891                         //then, insert a moveable node connecting center
00892                         //and outgoing segment
00893                         node vBungee = newNode();
00894                         //+1 for not fixzerolength
00895                         setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_oppArcDir,0) );
00896 
00897                         edge eToBungee = newEdge(vMin, vBungee);
00898                         m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!!
00899                         m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!!
00900                         m_length[eToBungee] = minDist.epsilon(v,m_oppArcDir,0);
00901 
00902                         edge eBungeeCenter = newEdge(vBungee, vCenter);
00903                         //bungee, center and outgoing segment may build column if in the middle
00904                         m_type[eBungeeCenter] = cetMedianArc; 
00905                         m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
00906                         m_length[eBungeeCenter] = 0;
00907 
00908                             //attention: pathnode construct works only if degree 1, sometimes not at all
00909                         edge eBungeeOut =  newEdge(vBungee, m_pathNode[cornerOppDir->twinNode()]);
00910                         //bungee, center and outgoing segment may build column if in the middle
00911                         m_type[eBungeeOut] = cetMedianArc; 
00912                         m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
00913                         m_length[eBungeeOut] = 0;
00914 /*
00915                         //connect outgoing segment and "right" segment, maybe obsolete
00916                         edge eFromOut = newEdge(m_pathNode[cornerOppDir->twinNode()], vMax);
00917                         m_type[eFromOut] = cetBasicArc; //!!!!!!!!!!!!!!!!!!!!!!!
00918                         m_cost[eFromOut] = 0; //!!!!!!!!!!!!!!!!!!!
00919                         m_length[eFromOut] = minDist.epsilon(v,m_oppArcDir,0);
00920                         */
00921                             }//if sOppDir case
00922                 }//if special case
00923                 else
00924                     {
00925                       // no, only one arc for vertex size + routing channels
00926                       edge e = newEdge(vMin,vMax);
00927                       m_length[e] = size;
00928                       m_cost[e]   = 2*m_vertexArcCost;
00929                       m_type[e]   = cetVertexSizeArc;
00930                     }//else special case
00931 
00932 
00933             } else {
00934                 // yes, then two arcs for each side with an attached generalization
00935                 ATYPE lenMin = size/2;
00936                 ATYPE lenMax = size - lenMin;
00937 
00938                 //ATYPE len = size/2;
00939 
00940                 if (sDir.m_adjGen != 0) {
00941                     node vCenter = m_pathNode[sDir.m_adjGen->theNode()];
00942                     edge e1 = newEdge(vMin,vCenter);
00943                     m_length[e1] = lenMin;
00944                     m_cost  [e1] = m_vertexArcCost;
00945                     m_type  [e1] = cetVertexSizeArc;
00946                     edge e2 = newEdge(vCenter,vMax);
00947                     m_length[e2] = lenMax;
00948                     m_cost  [e2] = m_vertexArcCost;
00949                     m_type  [e2] = cetVertexSizeArc;
00950                 }
00951                 else 
00952                 {
00953                   if (sDir.totalAttached() == 1)
00954                   {
00955                       node vCenter = newNode();//m_pathNode[sOppDir.m_adjGen->theNode()];  //newNode();
00956                       setExtra(vCenter, cornerDir->theNode(), lenMin);
00957  
00958                       edge e1 = newEdge(vMin,vCenter);
00959                       m_length[e1] = lenMin;
00960                       m_cost[e1]   = m_vertexArcCost;
00961                       m_type[e1]   = cetVertexSizeArc;
00962                       edge e2 = newEdge(vCenter,vMax);
00963                       m_length[e2] = lenMax;
00964                       m_cost[e2]   = m_vertexArcCost;
00965                       m_type[e2]   = cetVertexSizeArc;
00966 
00967                       //then, insert a moveable node connecting center
00968                       //and outgoing segment
00969                       node vBungee = newNode();
00970                       //+1 for not fixzerolength
00971                       setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_arcDir,0) );
00972 
00973                       edge eToBungee = newEdge(vMin, vBungee);
00974                       m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!!
00975                       m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!!
00976                       m_length[eToBungee] = minDist.epsilon(v,m_arcDir,0);
00977 
00978                       edge eBungeeCenter = newEdge(vBungee, vCenter);
00979                       //bungee, center and outgoing segment may build column if in the middle
00980                       m_type[eBungeeCenter] = cetMedianArc; 
00981                       m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
00982                       m_length[eBungeeCenter] = 0;
00983 
00984                       //attention: pathnode construct works only if degree 1
00985                       edge eBungeeOut =  newEdge(vBungee, m_pathNode[cornerDir->twinNode()]);
00986                       //bungee, center and outgoing segment may build column if in the middle
00987                       m_type[eBungeeOut] = cetMedianArc; 
00988                       m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
00989                       m_length[eBungeeOut] = 0;
00990 
00991                             }//if sDir case
00992                 }//else, only oppdir
00993                 if (sOppDir.m_adjGen != 0) {
00994                     node vCenter = m_pathNode[sOppDir.m_adjGen->theNode()];
00995                     edge e1 = newEdge(vMin,vCenter);
00996                     m_length[e1] = lenMin;
00997                     m_cost  [e1] = m_vertexArcCost;
00998                     m_type  [e1] = cetVertexSizeArc;
00999                     edge e2 = newEdge(vCenter,vMax);
01000                     m_length[e2] = lenMax;
01001                     m_cost  [e2] = m_vertexArcCost;
01002                     m_type  [e2] = cetVertexSizeArc;
01003                 }
01004                 else
01005                 {
01006                   //special case single edge to middle position
01007                   if ( (sOppDir.totalAttached() == 1) && !(m_pathNode[cornerOppDir->twinNode()] == vMin) )
01008                   {
01009                         node vCenter = newNode();//m_pathNode[sDir.m_adjGen->theNode()];//newNode();
01010                         setExtra(vCenter, cornerDir->theNode(), lenMin);
01011  
01012                         edge e1 = newEdge(vMin,vCenter);
01013                         m_length[e1] = lenMin;
01014                         m_cost[e1]   = m_vertexArcCost;
01015                         m_type[e1]   = cetVertexSizeArc;
01016                         edge e2 = newEdge(vCenter,vMax);
01017                         m_length[e2] = lenMax;
01018                         m_cost[e2]   = m_vertexArcCost;
01019                         m_type[e2]   = cetVertexSizeArc;
01020                         //then, insert a moveable node connecting center
01021                         //and outgoing segment
01022                         node vBungee = newNode();
01023                         //+1 for not fixzerolength
01024                         setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_oppArcDir,0) );
01025 
01026                         edge eToBungee = newEdge(vMin, vBungee);
01027                         m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!!
01028                         m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!!
01029                         m_length[eToBungee] = minDist.epsilon(v,m_oppArcDir,0);
01030 
01031                         edge eBungeeCenter = newEdge(vBungee, vCenter);
01032                         //bungee, center and outgoing segment may build column if in the middle
01033                         m_type[eBungeeCenter] = cetMedianArc; 
01034                         m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
01035                         m_length[eBungeeCenter] = 0;
01036 
01037                             //attention: pathnode construct works only if degree 1
01038                         edge eBungeeOut =  newEdge(vBungee, m_pathNode[cornerOppDir->twinNode()]);
01039                         //bungee, center and outgoing segment may build column if in the middle
01040                         m_type[eBungeeOut] = cetMedianArc; 
01041                         m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!!
01042                         m_length[eBungeeOut] = 0;
01043 
01044                   }//if sOppDir case
01045                 }//else only dir gen
01046 
01047             }
01048 
01049             // set cost of edges on the cage boundary to 0
01050             setBoundaryCosts(cornerDir,cornerOppDir);
01051 
01052         } // high/lowDegreeExpander
01053     }
01054 //if (m_arcDir == odEast) writeGML("eastvertexsizeinserted.gml");
01055 //else writeGML("northvertexsizeinserted.gml");
01056 
01057 }
01058 
01059 
01060 // computes the total costs for coordintes given by pos, i.e.,
01061 // the sum of the weighted lengths of edges in the constraint graph.
01062 template<class ATYPE>
01063 ATYPE CompactionConstraintGraph<ATYPE>::computeTotalCosts(
01064     const NodeArray<ATYPE> &pos) const
01065 {
01066     ATYPE c = 0;
01067 
01068     edge e;
01069     forall_edges(e,*this) 
01070     { 
01071         c += cost(e) * (pos[e->target()] - pos[e->source()]);
01072     }
01073 
01074     return c;
01075 }
01076 
01077 
01078 //
01079 // insertion of visibility arcs
01080 
01081 // checks if intervals on the sweep line are in correct order
01082 template<class ATYPE>
01083 bool CompactionConstraintGraph<ATYPE>::checkSweepLine(const List<Interval> &sweepLine)
01084 {
01085     if (sweepLine.empty()) 
01086         return true;
01087 
01088     ListConstIterator<Interval> it = sweepLine.begin();
01089 
01090     if((*it).m_high < (*it).m_low)
01091         return false;
01092 
01093     ATYPE x = (*it).m_low;
01094 
01095     for(++it; it.valid(); ++it) {
01096         if((*it).m_high < (*it).m_low)
01097             return false;
01098         if ((*it).m_high > x)
01099             return false;
01100         x = (*it).m_low;
01101     }
01102 
01103     return true;
01104 }
01105 
01106 
01107 template<class ATYPE>
01108 void CompactionConstraintGraph<ATYPE>::insertVisibilityArcs(
01109     const PlanRep &PG,
01110     const NodeArray<ATYPE> &posDir,
01111     const NodeArray<ATYPE> &posOrthDir
01112     )
01113 {
01114     MinimumEdgeDistances<ATYPE> minDist(PG, m_sep);
01115 
01116     node v;
01117     forall_nodes(v,PG)
01118     {
01119         if(PG.expandAdj(v) == 0) continue;
01120 
01121         for(int d = 0; d < 4; ++d) {
01122             minDist.delta(v,OrthoDir(d),0) = m_sep;//currentSeparation;
01123             minDist.delta(v,OrthoDir(d),1) = m_sep;//currentSeparation;
01124         }
01125     }
01126 
01127     insertVisibilityArcs(PG,posDir,posOrthDir,minDist);
01128 }
01129 
01130 
01131 
01132 // inserts arcs connecting segments which can see each other in a drawing
01133 // of the associated planarized representation PG which is given by
01134 // posDir and posOppDir. 
01135 
01136 //ersetze mindist.delta durch min(m_sep, mindist.delta) fuer skalierung 
01137 template<class ATYPE>
01138 void CompactionConstraintGraph<ATYPE>::insertVisibilityArcs(
01139     const PlanRep &PG,
01140     const NodeArray<ATYPE> &posDir,
01141     const NodeArray<ATYPE> &posOrthDir,
01142     const MinimumEdgeDistances<ATYPE> &minDist)
01143 {
01144     OrthoDir segDir    = OrthoRep::prevDir(m_arcDir);
01145     OrthoDir segOppDir = OrthoRep::nextDir(m_arcDir);
01146 
01147     // list of visibility arcs which have to be inserted
01148     SListPure<Tuple2<node,node> > visibArcs;
01149 
01150     // lower and upper bound of segments
01151     NodeArray<ATYPE> low(getGraph()), lowReal(getGraph()), high(getGraph());
01152     NodeArray<ATYPE> segPos(getGraph(), 0); // position of segments
01153     NodeArray<int>   topNum(getGraph()/*,0*/); // secondary sorting criteria for segments
01154 
01155     // compute position and lower/upper bound of segments
01156     // We have to take care that segments cannot be shifted one upon the other,
01157     // e.g., if we have two segments (l1,h1) and (l2,h2) with l2 > h2 and
01158     // the distance l2-h2 is smaller than separation, the segments can see
01159     // each other. We do this by enlarging the lower bound of all segments
01160     // by separation if this lower bound is realized by a bend.
01161     //
01162     // Note: Be careful at segments attached at a vertex which are closer
01163     // than separation to each other. Possible solution: Remove visibility
01164     // arcs of segments which are connected by orthogonal segments to the
01165     // same vertex and bend in opposite directions.
01166     node v;
01167     forall_nodes(v,*this) {
01168 
01169         //special case nodes
01170         if (m_path[v].empty()) continue;
01171 
01172         SListConstIterator<node> it = m_path[v].begin();
01173 
01174         segPos[v] = posDir[*it];
01175         low[v] = high[v] = posOrthDir[*it];
01176         node nodeLow = *it;
01177         for(++it; it.valid(); ++it) {
01178             ATYPE x = posOrthDir[*it];
01179             if (x < low [v]) {
01180                 low [v] = x;
01181                 nodeLow = *it;
01182             }
01183             if (x > high[v]) high[v] = x;
01184         }
01185         lowReal[v] = low[v];
01186         Graph::NodeType typeLow = PG.typeOf(nodeLow);
01187         if(typeLow == Graph::dummy || typeLow == Graph::generalizationExpander) {
01188             /*bool subtractSep = true;
01189             if (nodeLow->degree() == 2) {
01190                 adjEntry adj;
01191                 forall_adj(adj,nodeLow) {
01192                     if(m_pOR->direction(adj) == m_arcDir || m_pOR->direction(adj) == m_oppArcDir)
01193                         break;
01194                 }
01195                 if (adj) {
01196                     for(adjEntry adj2 = adj->faceCycleSucc();
01197                         m_pOR->direction(adj2) == m_pOR->direction(adj);
01198                         adj2 = adj2->twin()->faceCycleSucc()) ;
01199                     if(posDir[adj->theNode()] == posDir[adj2->twinNode()])
01200                     subtractSep = false;
01201                 }
01202             }
01203             //if (subtractSep)*/
01204                 low[v] -= m_sep;
01205         }
01206     }
01207 
01208     // correct "-= m_sep" ...
01209     OrthoDir dirMin = OrthoRep::prevDir(m_arcDir);
01210     OrthoDir dirMax = OrthoRep::nextDir(m_arcDir);
01211     bool isCaseA = (m_arcDir == odEast || m_arcDir == odSouth);
01212     const int angleAtMin = (m_arcDir == odEast || m_arcDir == odSouth) ? 3 : 1;
01213     const int angleAtMax = (m_arcDir == odEast || m_arcDir == odSouth) ? 1 : 3;
01214     forall_nodes(v,PG)
01215     {
01216         if(PG.expandAdj(v) == 0) continue;
01217         const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v);
01218 
01219         int i = 0;
01220         adjEntry adj;
01221     
01222         for (adj = (isCaseA) ? vi.m_corner[dirMin]->faceCycleSucc()->faceCycleSucc() : vi.m_corner[dirMin]->faceCycleSucc();
01223             m_pOR->direction((isCaseA) ? adj : adj->faceCycleSucc()) == dirMin; //m_pOR->direction(adj) == dirMin;
01224             adj = adj->faceCycleSucc()) 
01225         {
01226             adjEntry adjCross = adj->cyclicPred();
01227             adjEntry adjTwin = adjCross->twin();
01228 
01229             adjEntry adjPred = adj->faceCyclePred();
01230             ATYPE delta = (isCaseA) ?
01231                 min(abs(posOrthDir[adjPred->theNode()] - posOrthDir[adjPred->twinNode()]), m_sep) :
01232                 min(abs(posOrthDir[adj->theNode()] - posOrthDir[adj->twinNode()]), m_sep);
01233             ATYPE boundary = (isCaseA) ?
01234                 min(posOrthDir[adjPred->theNode()], posOrthDir[adjPred->twinNode()]) :
01235                 min(posOrthDir[adj->theNode()],     posOrthDir[adj->twinNode()]);
01236 
01237             if (PG.typeOf(adjCross->theEdge()) == Graph::generalization)
01238             {
01239                 if (isCaseA) {
01240                     if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander &&
01241                         m_pOR->angle(adjTwin) == 2)
01242                     {
01243                         node s1 = m_pathNode[adjTwin->theNode()];
01244                         node s2 = m_pathNode[adjTwin->cyclicSucc()->twinNode()];
01245                         low[s1] = lowReal[s1] - delta; // minDist.delta(v,dirMin,i);
01246                         low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMin,i);
01247                     }
01248                     ++i;
01249                 } else {
01250                     ++i;
01251                     if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander &&
01252                         m_pOR->angle(adjTwin->cyclicPred()) == 2)
01253                     {
01254                         node s1 = m_pathNode[adjTwin->theNode()];
01255                         node s2 = m_pathNode[adjTwin->cyclicPred()->twinNode()];
01256                         low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMin,i);
01257                         low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMin,i);
01258                     }
01259                 }
01260                 continue;
01261             }
01262 
01263             //we save the current direction and stop if we run in opposite
01264             OrthoDir runDir = m_pOR->direction(adjCross);
01265             // if -> while
01266             while (PG.typeOf(adjTwin->theNode()) == Graph::dummy &&
01267                 adjTwin->theNode()->degree() == 2 &&
01268                 m_pOR->angle(adjTwin) == angleAtMin)
01269             {
01270                 // We handle the case if an edge segment adjacent to a vertex
01271                 // is separated by less than separation from edge segments above.
01272                 node s = m_edgeToBasicArc[adjCross]->source();
01273                 if(lowReal[s] != low[s])
01274                 {
01275                     if(low[s] >= boundary) // nothing to do?
01276                         break;
01277                     low[s] = boundary;
01278                     //low[s] += m_sep - delta; //minDist.delta(v,dirMin,i);
01279 
01280                     // If the compaction has eliminated bends, we can have the situation
01281                     // that segment s has length 0 and the next segment s' (following the
01282                     // edge) is at the same position (the edge arc has length 0).
01283                     // In this case, the low-value of s' must be lowered (low[s'] := lowReal[s']
01284                     // is approproate). The same situation can appear several times in a
01285                     // row.
01286                     //collect chains of segments compacted to zero length
01287                     for( ; ; ) { //while(true/*lowReal[s] == high[s]*/) {
01288                         do {
01289                             adjCross = adjCross->faceCycleSucc();
01290                         } while(m_pOR->direction(adjCross) == segDir ||
01291                             m_pOR->direction(adjCross) == segOppDir);
01292 
01293                         if(adjCross->theNode()->degree() != 2) // no longer a bend point?
01294                             break;
01295 
01296                         node sNext = m_edgeToBasicArc[adjCross]->opposite(s);
01297 
01298                         if(segPos[sNext] != segPos[s])
01299                             break;
01300 
01301                         low[sNext] = lowReal[sNext];  //?
01302                         s = sNext;
01303                     }//while
01304                 }//if 
01305 
01306                 adjTwin = adjCross->twin(); // update of twin for while
01307                 //check if we have to stop
01308                 if (runDir != m_pOR->direction(adjCross)) break;
01309             }//while dummy bend
01310         }
01311 
01312         i = 0;
01313         for (adj = (isCaseA) ? vi.m_corner[dirMax]->faceCycleSucc() : vi.m_corner[dirMax]->faceCycleSucc()->faceCycleSucc();
01314             m_pOR->direction((isCaseA) ? adj->faceCycleSucc() : adj) == dirMax; // m_pOR->direction(adj) == dirMax;
01315             adj = adj->faceCycleSucc())
01316         {
01317             adjEntry adjCross = adj->cyclicPred();
01318             adjEntry adjTwin = adjCross->twin();
01319 
01320             //ATYPE delta = -posOrthDir[adj->twinNode()] + posOrthDir[adj->theNode()];
01321             adjEntry adjPred = adj->faceCyclePred();
01322             ATYPE delta = (isCaseA) ?
01323                 min(abs(posOrthDir[adj->twinNode()] - posOrthDir[adj->theNode()]), m_sep) :
01324                 min(abs(posOrthDir[adjPred->theNode()] - posOrthDir[adjPred->twinNode()]), m_sep);
01325             ATYPE boundary = (isCaseA) ?
01326                 min(posOrthDir[adj->twinNode()], posOrthDir[adj->theNode()]) :
01327                 min(posOrthDir[adjPred->theNode()],     posOrthDir[adjPred->twinNode()]);
01328 
01329             if (PG.typeOf(adjCross->theEdge()) == Graph::generalization)
01330             {
01331                 if (isCaseA) {
01332                     ++i;
01333                     if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander &&
01334                         m_pOR->angle(adjTwin->cyclicPred()) == 2)
01335                     {
01336                         node s1 = m_pathNode[adjTwin->theNode()];
01337                         node s2 = m_pathNode[adjTwin->cyclicPred()->twinNode()];
01338                         low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMax,i);
01339                         low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMax,i);
01340                     }
01341                 } else {
01342                     if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander &&
01343                         m_pOR->angle(adjTwin) == 2)
01344                     {
01345                         node s1 = m_pathNode[adjTwin->theNode()];
01346                         node s2 = m_pathNode[adjTwin->cyclicSucc()->twinNode()];
01347                         low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMax,i);
01348                         low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMax,i);
01349                     }
01350                     ++i;
01351                 }
01352                 continue;
01353             }
01354 
01355             
01356             //we save the current direction and stop if we run in opposite
01357             OrthoDir runDir = m_pOR->direction(adjCross);
01358             // if -> while
01359             while (PG.typeOf(adjTwin->theNode()) == Graph::dummy &&
01360                 adjTwin->theNode()->degree() == 2 &&
01361                 m_pOR->angle(adjTwin) == angleAtMax)
01362             {
01363                 node s = m_edgeToBasicArc[adjCross]->target();
01364                 if(lowReal[s] != low[s])
01365                 {
01366                     if(low[s] >= boundary) // nothing to do?
01367                         break;
01368                     low[s] = boundary;
01369                     //low[s] += m_sep - delta; //minDist.delta(v,dirMax,i);
01370 
01371                     // If the compaction has eliminated bends, we can have the situation
01372                     // that segment s has length 0 and the next segment s' (following the
01373                     // edge) is at the same position (the edge arc has length 0).
01374                     // In this case, the low-value of s' must be lowered (low[s'] := lowReal[s']
01375                     // is approproate). The same situation can appear several times in a
01376                     // row.
01377                     //collect chains of segments compacted to zero length
01378                     for( ; ; ) /*lowReal[s] == high[s]*/ 
01379                     {
01380                         do 
01381                         {
01382                             adjCross = adjCross->faceCycleSucc();
01383                         } while(m_pOR->direction(adjCross) == segDir ||
01384                                 m_pOR->direction(adjCross) == segOppDir);
01385 
01386                         if(adjCross->theNode()->degree() != 2) // no longer a bend point?
01387                             break;
01388 
01389                         node sNext = m_edgeToBasicArc[adjCross]->opposite(s);
01390 
01391                         if(segPos[sNext] != segPos[s])
01392                             break;
01393 
01394                         low[sNext] = lowReal[sNext];//was: low[s]
01395                         s = sNext;
01396                     }
01397                 }//if lowreal != low
01398 
01399                 adjTwin = adjCross->twin(); // update of twin for while
01400 
01401                 //check if we have to stop
01402                 if (runDir != m_pOR->direction(adjCross)) break;
01403             }//while dummy 
01404         }
01405     }
01406 
01407     // compute topological numbering of segments as second sorting criteria
01408     // in order to process overlapping segments in the order imposed by the
01409     // embedding
01410     computeTopologicalSegmentNum(topNum);
01411 
01412 
01413     // sort segments
01414     SegmentComparer cmpBySegPos(segPos,topNum);
01415     List<node> sortedPathNodes;
01416     allNodes(sortedPathNodes);
01417     sortedPathNodes.quicksort(cmpBySegPos);
01418 
01419     // add segments in the order given by sortedPathNodes to sweep line
01420     List<Interval> sweepLine;
01421 
01422     ListIterator<node> itV;
01423     for(itV = sortedPathNodes.begin(); itV.valid(); ++itV)
01424     {
01425      //special case nodes
01426         if (m_path[*itV].empty()) continue;
01427         OGDF_ASSERT_IF(dlExtendedChecking,checkSweepLine(sweepLine));
01428 
01429         node v = *itV;
01430         ListIterator<Interval> it;
01431         for(it = sweepLine.begin(); it.valid(); ++it) {
01432             if ((*it).m_low < high[v])
01433                 break;
01434         }
01435 
01436         if (!it.valid()) {
01437             sweepLine.pushBack(Interval(v,low[v],high[v]));
01438             continue;
01439         }
01440 
01441         if((*it).m_high <= low[v]) {
01442             sweepLine.insertBefore(Interval(v,low[v],high[v]),it);
01443             continue;
01444         }
01445 
01446         ListIterator<Interval> itUp = it, itSucc;
01447         // we store if itUp will be deleted in order not to 
01448         // access the deleted iterator later
01449         bool isItUpDel = ( ((*itUp).m_low >= low[v]) && ((*itUp).m_high <= high[v]) ); 
01450 
01451         for(; it.valid() && (*it).m_low >= low[v]; it = itSucc) {
01452             itSucc = it.succ();
01453             if ((*it).m_high <= high[v]) {
01454                 visibArcs.pushBack(Tuple2<node,node>((*it).m_pathNode,v));
01455                 sweepLine.del(it);
01456             }
01457         }
01458 
01459         if (it == itUp && (*it).m_high > high[v]) {
01460             node w = (*it).m_pathNode;
01461             sweepLine.insertAfter(Interval(w,(*it).m_low,low[v]),it);
01462             (*it).m_low = high[v];
01463             sweepLine.insertAfter(Interval(v,low[v],high[v]),it);
01464             visibArcs.pushBack(Tuple2<node,node>(w,v));
01465 
01466         } else {
01467             if ( (!isItUpDel) && itUp != it && (*itUp).m_low < high[v]) {
01468                 (*itUp).m_low = high[v];
01469                 visibArcs.pushBack(Tuple2<node,node>((*itUp).m_pathNode,v));
01470             }
01471             if (it.valid()) {
01472                 if ((*it).m_high > low[v]) {
01473                     (*it).m_high = low[v];
01474                     visibArcs.pushBack(Tuple2<node,node>((*it).m_pathNode,v));
01475                 }
01476                 sweepLine.insertBefore(Interval(v,low[v],high[v]),it);
01477 
01478             } else {
01479                 sweepLine.pushBack(Interval(v,low[v],high[v]));
01480             }
01481         }
01482 
01483     }
01484 
01485     // remove all arcs from visibArcs that are already in the constraint graph
01486     removeRedundantVisibArcs(visibArcs);
01487 
01488     // compute original adjacency entry corresponding to a segment
01489     // We use this in order to omit visibility arcs between segments which
01490     // belong to the same edge if they can see each other from the same side
01491     // of the edge; if they see each other from different sides the arc is
01492     // essential!
01493     NodeArray<adjEntry> correspEdge(getGraph(),0);
01494     forall_nodes(v,PG) {
01495         node seg = m_pathNode[v];
01496         adjEntry adj;
01497         forall_adj(adj,v) {
01498             if(m_pOR->direction(adj) != segDir) continue;
01499             edge eAdj = adj->theEdge();
01500             edge eOrig = PG.original(eAdj);
01501             if (eOrig == 0) continue;
01502             if (adj == eAdj->adjSource())
01503                 correspEdge[seg] = eOrig->adjSource();
01504             else
01505                 correspEdge[seg] = eOrig->adjTarget();
01506         }
01507     }
01508 
01509     // remove visibility arcs between ...
01510     SListIterator<Tuple2<node,node> > itT, itTSucc, itTPred;
01511     for(itT = visibArcs.begin(); itT.valid(); itT = itTSucc) {
01512         itTSucc = itT.succ();
01513         node v = (*itT).x1(), w = (*itT).x2();
01514 
01515         // remove arcs which connect segments belonging to the same edge
01516         if (correspEdge[v] && (correspEdge[v] == correspEdge[w]))
01517         {
01518             if (itTPred.valid())
01519                 visibArcs.delSucc(itTPred);
01520             else
01521                 visibArcs.popFront();
01522         }
01523 
01524         else
01525             itTPred = itT;
01526     }
01527 
01528 
01529 
01530     for(itT = visibArcs.begin(); itT.valid(); ++itT) {
01531         //***********************************CHECK if
01532         node v = (*itT).x1(), w = (*itT).x2();
01533         if (!(m_extraNode[v] || m_extraNode[w]))
01534             {
01535             //******************************CHECK if
01536       node boundRepresentant1 = m_path[v].front();
01537       node boundRepresentant2 = m_path[w].front();
01538       node en1 = m_pPR->expandedNode(boundRepresentant1);
01539       node en2 = m_pPR->expandedNode(boundRepresentant2);
01540       //do not insert visibility in cages
01541       if (!( ( en1 && en2 ) && ( en1 == en2) ))
01542           {
01543             edge e = newEdge(v,w);
01544 
01545             //hier vielleicht multiedges abfangen: length auf max(min(sep, dists), minDist.sep)
01546 
01547             m_length[e] = max(m_sep, minDist.separation()); //m_sep;
01548             m_cost  [e] = 0;
01549             m_type  [e] = cetVisibilityArc;
01550         
01551             //writeGML("visibilityinserted.gml");
01552           }//special if 2
01553             }//special if 1
01554     }
01555 
01556     OGDF_ASSERT_IF(dlExtendedChecking,checkSweepLine(sweepLine));
01557 
01558 }//insertvisibilityarcs
01559 
01560 
01561 
01562 // performs feasibility test for position assignment pos, i.e., checks if
01563 // the segment positions given by pos fulfill the constraints in the
01564 // compaction constraint graph
01565 template<class ATYPE>
01566 bool CompactionConstraintGraph<ATYPE>::isFeasible(
01567     const NodeArray<ATYPE> &pos)
01568 {
01569     edge e;
01570     forall_edges(e, getGraph()) {
01571         node v = m_path[e->source()].front();
01572         node w = m_path[e->target()].front();;
01573         if (pos[w] - pos[v] < length(e)) {
01574             cout << "feasibility check failed for edge " << e << endl;
01575             cout << "  representatives: " << v << ", " << w << endl;
01576             cout << "  length: " << length(e) << endl;
01577             cout << "  actual distance: " << pos[w] - pos[v] << endl;
01578             cout << "  type of " << e << ": ";
01579             switch(m_type[e]) {
01580             case cetBasicArc: cout << "basic arc" << endl;
01581                 break;
01582             case cetVertexSizeArc: cout << "vertex-size arc" << endl;
01583                 break;
01584             case cetVisibilityArc: cout << "visibility arc" << endl;
01585                 break;
01586             case cetMedianArc: cout << "median arc" << endl;
01587                 break;
01588             case cetReducibleArc: cout << "reducible arc" <<endl;
01589                 break;
01590             case cetFixToZeroArc: cout << "fixtozero arc" <<endl;
01591 
01592             }
01593             return false;
01594         }
01595     }
01596 
01597     return true;
01598 }
01599 
01600 //colouring for extranode
01601 template<class ATYPE>
01602 void CompactionConstraintGraph<ATYPE>::writeGML(const char *filename) const
01603 {
01604     ofstream os(filename);
01605     writeGML(os);
01606 }
01607 
01608 template<class ATYPE>
01609 void CompactionConstraintGraph<ATYPE>::writeGML(ostream &os) const
01610 {
01611     const Graph &G = *this;
01612 
01613     NodeArray<int> id(getGraph());
01614     int nextId = 0;
01615 
01616     os.setf(ios::showpoint);
01617     os.precision(10);
01618 
01619     os << "Creator \"ogdf::CompactionConstraintGraphBase::writeGML\"\n";
01620     os << "directed 1\n";
01621 
01622     os << "graph [\n";
01623 
01624     node v;
01625     forall_nodes(v,G) {
01626         os << "node [\n";
01627 
01628         os << "id " << (id[v] = nextId++) << "\n";
01629 
01630         if (m_extraNode[v])
01631             {
01632                 os << "label \"" << "0" << "\"\n";
01633             }
01634         else 
01635             {   
01636                 os << "label \"" << m_pPR->expandedNode(m_path[v].front()) << "\"\n";
01637             }
01638 
01639         os << "graphics [\n";
01640         os << "x 0.0\n";
01641         os << "y 0.0\n";
01642         os << "w 30.0\n";
01643         os << "h 30.0\n";
01644         if (m_extraNode[v])
01645                 os << "fill \"#00FFFF\"\n";
01646         else 
01647                 os << "fill \"#FFFF00\"\n";
01648         os << "]\n"; // graphics
01649 
01650         os << "]\n"; // node
01651     }
01652 
01653 
01654     edge e;
01655     forall_edges(e,G) {
01656         os << "edge [\n";
01657 
01658         os << "source " << id[e->source()] << "\n";
01659         os << "target " << id[e->target()] << "\n";
01660 
01661         // nice idea to use the edge length as edge labels, but Graphwin-
01662         // garbage is not able to show the graph (thinks it has to set
01663         // the y-coordinates of all nodes to NAN)
01664         /*os << "label \"";
01665         writeLength(os,e);
01666         os << "\"\n";*/
01667 
01668         os << "graphics [\n";
01669 
01670         os << "type \"line\"\n";
01671         os << "arrow \"last\"\n";
01672         switch(m_type[e])
01673         {
01674         case cetBasicArc: // red
01675             os << "fill \"#FF0000\"\n";
01676             break;
01677         case cetVertexSizeArc: // blue
01678             os << "fill \"#0000FF\"\n";
01679             break;
01680         case cetVisibilityArc: // green
01681             os << "fill \"#00FF00\"\n";
01682             break;
01683         case cetReducibleArc: // red
01684             os << "fill \"#FF0000\"\n";
01685             break;
01686         case cetFixToZeroArc: // violett
01687             os << "fill \"#AF00FF\"\n";
01688             break;
01689         case cetMedianArc: // rose
01690             os << "fill \"#FF00FF\"\n";
01691             break;
01692         }
01693 
01694         os << "]\n"; // graphics
01695 
01696         /*os << "LabelGraphics [\n";
01697         os << "type \"text\"\n";
01698         os << "fill \"#000000\"\n";
01699         os << "anchor \"w\"\n";
01700         os << "]\n";*/
01701 
01702         os << "]\n"; // edge
01703     }
01704 
01705     os << "]\n"; // graph
01706 }
01707 
01708 
01709 } // end namespace ogdf
01710 
01711 
01712 #endif