File: UMLGraph.h

package info (click to toggle)
tulip 4.6.0dfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 139,284 kB
  • ctags: 35,942
  • sloc: cpp: 289,758; ansic: 27,264; python: 1,256; sh: 923; yacc: 522; xml: 337; makefile: 258; php: 66; lex: 55
file content (320 lines) | stat: -rw-r--r-- 10,205 bytes parent folder | download
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> &centerNodes() {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