Open
Graph Drawing
Framework

 v.2012.05
 

OrthoRep.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  
00043 #ifdef _MSC_VER
00044 #pragma once
00045 #endif
00046 
00047 
00048 #ifndef OGDF_ORTHO_REP_H
00049 #define OGDF_ORTHO_REP_H
00050 
00051 
00052 #include <ogdf/basic/GraphCopy.h>
00053 #include <ogdf/basic/FaceArray.h>
00054 #include <ogdf/basic/tuples.h>
00055 #include <ogdf/basic/Stack.h>
00056 
00057 
00058 namespace ogdf {
00059 
00060     class OGDF_EXPORT PlanRep;
00061     class OGDF_EXPORT PlanRepUML;
00062 
00063 
00064 // type for bends (convex or reflex)
00065 enum BendType { convexBend = '0', reflexBend = '1' };
00066 
00067 // type of (orthogonal) directions
00068 // horizontal: odEast or odWest
00069 // vertical:   odNorth or odSouth
00070 enum OrthoDir {
00071     odNorth     = 0,
00072     odEast      = 1,
00073     odSouth     = 2,
00074     odWest      = 3,
00075     odUndefined = 4
00076 };
00077 
00078 
00079 //---------------------------------------------------------
00080 // BendString
00081 // represents the bends on an edge e consisting of vertical
00082 // and horizontal segments
00083 //---------------------------------------------------------
00084 class OGDF_EXPORT BendString
00085 {
00086 public:
00087     // constructs empty bend string
00088     BendString() {
00089         m_pBend = 0;
00090         m_len = 0;
00091     }
00092 
00093     // constructs bend string as given by str
00094     // Precond.: str is a 0 terminated C++ string consisting of '0's and '1's
00095     BendString(const char *str) {
00096         init(str);
00097     }
00098 
00099     // constructs bend string consisting of n c's
00100     // Precond.: c is '0' or '1'
00101     BendString(char c, size_t n) {
00102         init(c,n);
00103     }
00104 
00105     // copy constructor
00106     BendString(const BendString &bs) {
00107         init(bs);
00108     }
00109 
00110 
00111     // destructor
00112     ~BendString() {
00113         delete [] m_pBend;
00114     }
00115 
00116 
00117     // returns i'th character in bend string
00118     char operator[](size_t i) const {
00119         // range check
00120         OGDF_ASSERT(i < m_len);
00121         return m_pBend[i];
00122     }
00123 
00124     char &operator[](size_t i) {
00125         // range check
00126         OGDF_ASSERT(i < m_len);
00127         return m_pBend[i];
00128     }
00129 
00130     // returns number of characters in bend string
00131     size_t size() const {
00132         return m_len;
00133     }
00134 
00135     // returns a pointer to the 0 terminated string
00136     // or a 0-pointer if empty
00137     const char *toString() const {
00138         return m_pBend;
00139     }
00140 
00141     // sets bend string to the string given by str
00142     // Precond.: str is a 0 terminated C++ string consisting of '0's and '1's
00143     void set(const char *str) {
00144         delete [] m_pBend;
00145         init(str);
00146     }
00147 
00148     // sets bend string to the string consisting of n c's
00149     // Precond.: c is '0' or '1'
00150     void set(char c, size_t n) {
00151         delete [] m_pBend;
00152         init(c,n);
00153     }
00154 
00155 
00156     // sets bend string to the empty bend string
00157     void set() {
00158         delete [] m_pBend;
00159         m_pBend = 0;
00160         m_len = 0;
00161     }
00162 
00163 
00164     // assignment operator
00165     BendString &operator=(const BendString &bs) {
00166         delete [] m_pBend;
00167         init(bs);
00168         return *this;
00169     }
00170 
00171     BendString &operator+=(const BendString &bs) {
00172         char* temp = new char[m_len+bs.m_len+1];
00173 
00174         m_len = m_len + bs.m_len;
00175         
00176         if (m_len == 0) 
00177         {
00178           *temp = 0;//temp = 0;
00179         } 
00180         else 
00181         {
00182           char *p = temp;
00183           if (m_pBend != 0)
00184           {
00185             const char *str = m_pBend;
00186             while ((*p++ = *str++) != 0) ;
00187           }
00188           else {*p = '0'; p++;}
00189           if (bs.m_len > 0)
00190           {
00191             p--;
00192             const char *str1 = bs.m_pBend;
00193             while ((*p++ = *str1++) != 0) ;
00194           }
00195         }
00196 
00197         delete[] m_pBend;
00198         m_pBend = temp;
00199 
00200         return *this;
00201     }
00202 
00203     // output operator
00204     // example output: "001101001" or ""
00205     friend ostream &operator<<(ostream &os, const BendString &bs) {
00206         if (bs.size() == 0)
00207             os << "\"\"";
00208         else
00209             os << "\"" << bs.m_pBend << "\"";
00210         return os;
00211     }
00212 
00213 private:
00214     void init(const char *str);
00215     void init(char c, size_t n);
00216     void init(const BendString &bs);
00217 
00218 
00219     // poiner to 0 terminated character string
00220     char *m_pBend;
00221     // length of string (number of characters without ending 0)
00222     size_t m_len;
00223 };
00224 
00225 
00226 
00227 //---------------------------------------------------------
00228 // OrthoRep
00229 // orthogonal representation of an embedded graph
00230 //---------------------------------------------------------
00231 class OGDF_EXPORT OrthoRep
00232 {
00233 public:
00234 
00235     //---------------------------------------------------------
00236     // information about a side of a vertex in UML diagrams
00237     //---------------------------------------------------------
00238     struct SideInfoUML {
00239         // adjacency entry of generalization attached at the side
00240         // (or 0 if none)
00241         adjEntry m_adjGen;
00242         // number of attached edges which have corresponding edges in the
00243         // original graph to the left (index 0) or right of the
00244         // attached generalization. If no generalization is attached,
00245         // m_nAttached[0] is the total number of attached edges.
00246         int m_nAttached[2];
00247 
00248         // constructor
00249         SideInfoUML() {
00250             m_adjGen = 0;
00251             m_nAttached[0] = m_nAttached[1] = 0;
00252         }
00253 
00254         // returns the total number of edges attached at this side
00255         int totalAttached() const {
00256             int nGen = (m_adjGen == 0) ? 0 : 1;
00257             return nGen + m_nAttached[0] + m_nAttached[1];
00258         }
00259 
00260         
00261         // output operator for debugging
00262         friend ostream &operator<<(ostream &os, const SideInfoUML &si)
00263         {
00264             os << "{ " << si.m_nAttached[0] <<
00265                 ", " << si.m_adjGen <<
00266                 ", " << si.m_nAttached[1] << " }";
00267             return os;
00268         }
00269     };
00270 
00271     //only for debugging purposes
00272     adjEntry externalAdjEntry() const {return m_adjExternal;}
00273     adjEntry alignAdjEntry() const {return m_adjAlign;}
00274 
00275 
00276     //---------------------------------------------------------
00277     // further information about the cages of vertices in UML diagrams
00278     //---------------------------------------------------------
00279     struct VertexInfoUML {
00280         // side information (odNorth, odEast, odSouth, odWest corresponds to
00281         // left, top, right, bottom)
00282         SideInfoUML m_side[4];
00283         // m_corner[dir] is adjacency entry in direction dir starting at
00284         // a corner
00285         adjEntry m_corner[4];
00286 
00287         // constructor
00288         VertexInfoUML() {
00289 #ifdef OGDF_DEBUG
00290             m_corner[0] = m_corner[1] = m_corner[2] = m_corner[3] = 0;
00291 #endif
00292         }
00293         OGDF_NEW_DELETE
00294     };
00295 
00296 
00297     // construction
00298 
00299     // dummy
00300     OrthoRep() { m_pE = 0; }
00301     // associates orthogonal representation with embedding E
00302     OrthoRep(CombinatorialEmbedding &E);
00303 
00304     // destruction
00305     ~OrthoRep() {
00306         freeCageInfoUML();
00307     }
00308 
00309     // reinitialization: associates orthogonal representation with embedding E
00310     void init(CombinatorialEmbedding &E);
00311 
00312 
00313     //
00314     // access functions
00315     //
00316 
00317     // returns associated embedding
00318     operator const CombinatorialEmbedding &() const {
00319         return *m_pE;
00320     }
00321 
00322     // returns associated graph
00323     operator const Graph &() const {
00324         return *m_pE;
00325     }
00326 
00327     // returns angle between adj and its successor
00328     // (return value is angle divided by 90 degree)
00329     int angle(adjEntry adj) const {
00330         return m_angle[adj];
00331     }
00332 
00333     int &angle(adjEntry adj) {
00334         return m_angle[adj];
00335     }
00336 
00337 
00338     // returns bend string of adjacency entry adj
00339     const BendString &bend(adjEntry adj) const {
00340         return m_bends[adj];
00341     }
00342 
00343     BendString &bend(adjEntry adj) {
00344         return m_bends[adj];
00345     }
00346 
00347     // returns direction of adjacency entry
00348     OrthoDir direction(adjEntry adj) const {
00349         return m_dir[adj];
00350     }
00351 
00352 
00353     // returns cage info
00354     const VertexInfoUML *cageInfo(node v) const {
00355         return m_umlCageInfo[v];
00356     }
00357 
00358     // returns cage info
00359     VertexInfoUML *cageInfo(node v) {
00360         return m_umlCageInfo[v];
00361     }
00362 
00363 
00364 
00365     //
00366     // update functions
00367     //
00368 
00369     // normalizes the orthogonal representation, i.e., sets an artficial
00370     // vertex on each bend
00371     void normalize();
00372 
00373     // checks if the orth. repr. is normalized, i.e., each bend string is empty
00374     bool isNormalized() const;
00375 
00376     // removes rectangular ears (pattern "100") by splitting edges and faces.
00377     // Afterwards, each internal face is a rectangle and the external face
00378     // contains no rectangular ear (but is not necessarily the complement of
00379     // a rectangle).
00380     // Precond.: The orth. repr. is normalized and contains no 0-degree angles
00381     void dissect();
00382     // same as dissect, attempting to save artificial nodes and allow preprocessing
00383     void dissect2(PlanRepUML* PG = 0);
00384     // undoes a previous dissect() by removing dissection edges and unsplitting
00385     // vertices
00386     void undissect(bool align = false);
00387 
00388 
00389     // assigns consistent directions to adjacency entries
00390     void orientate();
00391 
00392     // assigns consistent directions to adj. entries such that most
00393     // generalizations are directed in preferedDir
00394     void orientate(const PlanRep &PG, OrthoDir preferedDir);
00395 
00396     // assigns consistent directions to adjacency entries,
00397     // assigning dir to adj (fixing all others)
00398     void orientate(adjEntry adj, OrthoDir dir);
00399 
00400     // returns true iff orientate() has been called before.
00401     // If not, direction() may not be called since adj. entry array is not
00402     // initialized!
00403     bool isOrientated() const {
00404         return m_dir.valid();
00405     }
00406 
00407 
00408     // rotates all directions of adjacency entries by r
00409     void rotate(int r);
00410 
00411 
00412     // computes further information about cages
00413     void computeCageInfoUML(const PlanRep &PG/*, double sep*/);
00414 
00415 
00416     // checks if the orth. repr. is a legal shape description, i.e., if there
00417     // is an orthogonal embedding realizing this shape (if 0-degree angles are
00418     // present, the condition is necessary but not sufficient).
00419     // If false is returned, error contains a description of the reason.
00420     bool check(String &error);
00421 
00422 
00423     //
00424     // static members
00425     //
00426 
00427     // exchanges '1'->'0' and vice versa
00428     static char flip(char c) {
00429         return (c == '0') ? '1' : '0';
00430     }
00431 
00432     static OrthoDir oppDir(OrthoDir d) {
00433         return OrthoDir((d + 2) & 3);
00434     }
00435 
00436     static OrthoDir nextDir(OrthoDir d) {
00437         return OrthoDir((d + 1) & 3);
00438     }
00439 
00440     static OrthoDir prevDir(OrthoDir d) {
00441         return OrthoDir((d + 3) & 3);
00442     }
00443 
00444     friend ostream &operator<<(ostream &os, const OrthoRep &op) {
00445         edge e;
00446         const Graph& E = op;
00447         forall_edges(e, E)
00448         {
00449           os << e <<": src angle "<<op.angle(e->adjSource())<<" bend "<<op.bend(e->adjSource())
00450               <<"\n"<<" tgt angle "<<op.angle(e->adjTarget())<<" bend "<<op.bend(e->adjTarget())
00451               
00452               <<"\n";
00453         }
00454         return os;
00455     }
00456 
00457 
00458 
00459 private:
00460     void orientateFace(adjEntry adj, OrthoDir dir);
00461     void freeCageInfoUML();
00462 
00463     // associated combinatorial embedding
00464     CombinatorialEmbedding *m_pE;
00465 
00466     // * 90 deg = angle between e and its successor
00467     AdjEntryArray<int> m_angle;
00468     // bends on edge e
00469     AdjEntryArray<BendString> m_bends;
00470     // direction of adjacency entries
00471     AdjEntryArray<OrthoDir> m_dir;
00472 
00473     // information about cages of original vertices; used for orthogonal
00474     // representations of PlanRep's
00475     NodeArray<VertexInfoUML *> m_umlCageInfo;
00476 
00477     // The following members are used for undoing dissection
00478     EdgeArray<bool> m_dissectionEdge; // = true iff dissection edge
00479     //check if special gener. sons alignment edge
00480     EdgeArray<bool> m_alignmentEdge; // = true iff alignment edge
00481     // contains all nodes created by splitting non-dissection edges while
00482     // dissect()
00483     StackPure<node> m_splitNodes;
00484     // stores adjacency entry on external face for restoring in undissect()
00485     adjEntry m_adjExternal;
00486     // stores adjacency entry on preliminary external face in alignment case
00487     adjEntry m_adjAlign;
00488     //starts dissection phase for special pattern 1 replacement before standard dissection
00489     bool m_preprocess;
00490     //special pattern after pattern 1
00491     bool m_pattern2;
00492 };
00493 
00494 
00495 } // end namespace ogdf
00496 
00497 
00498 #endif