1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
|
/*
* $Revision: 2564 $
*
* last checkin:
* $Author: gutwenger $
* $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $
***************************************************************/
/** \file
* \brief Declaration of class UMLGraph.
*
* \author Carsten Gutwenger and Sebastian Leipert
*
* \par License:
* This file is part of the Open Graph Drawing Framework (OGDF).
*
* \par
* Copyright (C)<br>
* See README.txt in the root directory of the OGDF installation for details.
*
* \par
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Version 2 or 3 as published by the Free Software Foundation;
* see the file LICENSE.txt included in the packaging of this file
* for details.
*
* \par
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* \par
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* \see http://www.gnu.org/copyleft/gpl.html
***************************************************************/
#ifdef _MSC_VER
#pragma once
#endif
#ifndef OGDF_UML_GRAPH_H
#define OGDF_UML_GRAPH_H
#include <ogdf/basic/GraphAttributes.h>
#include <ogdf/basic/AdjEntryArray.h>
#include <ogdf/basic/SList.h>
namespace ogdf {
class OGDF_EXPORT UMLGraph : public GraphAttributes
{
public:
// construction
// dummy default constructor (place-holder)
UMLGraph() : GraphAttributes(), m_pG(0) { }
// creates UML graph in which each edge is an association
explicit UMLGraph(Graph &G, long initAttributes = 0);
// destruction
virtual ~UMLGraph();
//(re)initialization
virtual void init(Graph &G, long initAttr)
{
m_pG = &G;
GraphAttributes::init(G, initAttr);
m_hierarchyParent.init(constGraph(), 0);
m_upwardEdge.init(constGraph(), false);
}
operator const Graph &() const { return *m_pGraph; }
//----------------------------------------------------------------------------
//structural changes
//merge generalizations at a common superclass
void insertGenMergers();
//insert mergers per node with given edges
node doInsertMergers(node v, SList<edge> &inGens);
void undoGenMergers();
//replace (dense) subgraphs given in list clique by
//inserting a center node connected to each node (=>star)
//and deleting all edges between nodes in clique
//returns center node
void replaceByStar(List< List<node> > &cliques);
//undo clique replacements
void undoStars();
//boolean switches restore of all hidden edges in single clique call
void undoStar(node center, bool restoreAllEdges);
//returns the size of a circular drawing for a clique around center v
DRect cliqueRect(node v)
{
return m_cliqueCircleSize[v];
}
DPoint cliquePos(node v)
{
return m_cliqueCirclePos[v];
}
//compute circle positions for all nodes around center
//using the ordering given in this UMLGraph, calls
//ccP(List...)
//rectMin is a temporary solution until compaction with constraints allows stretching
//of rect to clique size, it gives the min(w,h) of the given fixed size rect around the clique
void computeCliquePosition(node center, double rectMin);//, const adjEntry &startAdj);
//compute positions for the nodes in adjNodes on a circle
//tries to keep the relative placement of the nodes in the clique
//rectangle (left, right,...) to avoid clique crossings of outgoing edges
void computeCliquePosition(List<node> &adjNodes, node center, double rectMin = -1.0);
//allow change, but should not be declared const
Graph& pureGraph() const {return *m_pG;}
//set status value
//void setAlign(edge e, bool b) {m_alignEdge[e] = b;}
//set status of edges to be specially embedded (if alignment)
void setUpwards(adjEntry a, bool b) {m_upwardEdge[a] = b;}
bool upwards(adjEntry a) const {return m_upwardEdge[a];}
// writes attributed graph in GML format to file fileName
void writeGML(const char *fileName);
// writes attributed graph in GML format to output stream os
void writeGML(ostream &os);
//adjust the parent field for all nodes after insertion of
//mergers. If insertion is done per node via doinsert, adjust
//has to be called afterwards. Otherwise, insertgenmergers calls it.
void adjustHierarchyParents();
//use the node position and bend position information to
//derive an ordering of the edges around each node
//this does not need to result in a correct combinatorial embedding
void sortEdgesFromLayout();
//-------------------
//status retrieval
//returns true if edge was inserted during clique replacement
//TODO: check here how to guarantee that value is defined,
//edgearray is only valid if there are cliques replaced
bool isReplacement(edge e)
{
return m_replacementEdge[e];
}
const SListPure<node> ¢erNodes() {return m_centerNodes;}
//default size of inserted clique replacement center nodes
void setDefaultCliqueCenterSize(double i) {m_cliqueCenterSize = max(i, 1.0);}
double getDefaultCliqueCenterSize() {return m_cliqueCenterSize;}
//-------------------------------------------------------------------------
//modelling of association classes
class AssociationClass {
public:
AssociationClass(edge e, double width = 1.0, double height = 1.0,
double x = 0.0, double y = 0.0)
: m_width(width), m_height(height), m_x(x), m_y(y), m_edge(e), m_node(0)
{ }
double m_width;
double m_height;
double m_x;
double m_y;
edge m_edge;
node m_node;
};
const SListPure<AssociationClass*> &assClassList() const {return m_assClassList;}
const AssociationClass* assClass(edge e) const {return m_assClass[e];}
//adds association class to edge e
//void createAssociationClass(edge e, double width = 1.0, double height = 1.0)
node createAssociationClass(edge e, double width = 1.0, double height = 1.0)
{
AssociationClass* ac = new AssociationClass(e, width, height);
m_assClass[e] = ac;
m_assClassList.pushBack(ac);
//we already insert the node here, but not the edge
//when we always insert this node here, we can remove the associationclass
//class and information later on
node v = m_pG->newNode();
m_height[v] = ac->m_height;
m_width[v] = ac->m_width;
m_associationClassModel[ac->m_edge] = v;
ac->m_node = v;
//guarantee correct angle at edge to edge connection
if (m_attributes & GraphAttributes::nodeType)
{
m_vType[v] = Graph::associationClass;
}
return v;
}
//this modelling should only take place in the preprocessing steps
//of the drawing algorithms?
//insert representation for association class in underlying graph
void modelAssociationClasses()
{
SListIterator<UMLGraph::AssociationClass*> it = m_assClassList.begin();
while (it.valid())
{
modelAssociationClass((*it));
it++;
}//while
}
node modelAssociationClass(AssociationClass* ac)
{
node dummy = m_pG->split(ac->m_edge)->source();
m_height[dummy] = 1; //just a dummy size
m_width[dummy] = 1;
OGDF_ASSERT(ac->m_node)
m_pG->newEdge(ac->m_node, dummy);
return dummy;
}
void undoAssociationClasses()
{
SListIterator<UMLGraph::AssociationClass*> it = m_assClassList.begin();
while (it.valid())
{
undoAssociationClass((*it));
it++;
}//while
}
//remove the modeling of the association class without removing the information
void undoAssociationClass(AssociationClass* ac)
{
node v = m_associationClassModel[ac->m_edge];
OGDF_ASSERT(v)
OGDF_ASSERT(v->degree() == 1)
if (v->degree() != 1) throw AlgorithmFailureException(afcLabel);
//save layout information
ac->m_x = x(v);
ac->m_y = y(v);
//remove node and unsplit edge
//run around the dummy node connected to v
adjEntry outAdj = v->firstAdj();
adjEntry dummyAdj = outAdj->twin();
node dummy = dummyAdj->theNode();
OGDF_ASSERT(dummy->degree() == 3)
//we do not delete the node if we already inserted it in create...
//because it is a part of the graph now (in contrast to the split node)
m_pG->delEdge(v->firstAdj()->theEdge());
OGDF_ASSERT(v->degree() == 0)
m_pG->unsplit(dummy);
}//undoAssociationClass
protected:
node replaceByStar(List<node> &clique, NodeArray<int> &cliqueNum);
DRect circularBound(node center);
private:
Graph *m_pG;
//information about edges that are deleted in clique processing
class CliqueInfo {
public:
CliqueInfo(node v, int i) : m_target(v), m_edgeIndex(i) {}
node m_target; //target node of deleted edge
int m_edgeIndex; //index of deleted edge, has to be restored
};
double m_cliqueCenterSize; //default size of inserted clique replacement center nodes
SListPure<edge> m_mergeEdges;
SListPure<node> m_centerNodes; //center nodes introduced at clique replacement
EdgeArray<bool> m_replacementEdge; //used to mark clique replacement edges
//may be we can join this with edge type
NodeArray<DRect> m_cliqueCircleSize; //save the bounding box size of the
//circular drawing of the clique at center
NodeArray<DPoint> m_cliqueCirclePos; //save the position of the node in the
//circular drawing of the clique
//---------------------------------------------------
//structures for association classes
//may be replaced later by generic structures for different types
SListPure<AssociationClass*> m_assClassList; //saves all accociation classes
EdgeArray<AssociationClass*> m_assClass; //association class for list
EdgeArray<node> m_associationClassModel; //modelled classes are stored
//***************************************************
//the following arrays are only set and updated in insertgenmergers
//used to classify edges for embedding with alignment
AdjEntryArray<bool> m_upwardEdge;
//used to derive edge types for alignment in PlanRepUML
//(same hierarchyparent => edge connects (half)brothers
//only set during insertgenmergers to avoid the extra computation
NodeArray<node> m_hierarchyParent;
};
} // end namespace ogdf
#endif
|