1 /** \file
2  * \brief Implementation of class UniformGrid
3  *
4  * \author Rene Weiskircher
5  *
6  * \par License:
7  * This file is part of the Open Graph Drawing Framework (OGDF).
8  *
9  * \par
10  * Copyright (C)<br>
11  * See README.md in the OGDF root directory for details.
12  *
13  * \par
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * Version 2 or 3 as published by the Free Software Foundation;
17  * see the file LICENSE.txt included in the packaging of this file
18  * for details.
19  *
20  * \par
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * \par
27  * You should have received a copy of the GNU General Public
28  * License along with this program; if not, see
29  * http://www.gnu.org/copyleft/gpl.html
30  */
31 
32 #include <ogdf/energybased/davidson_harel/UniformGrid.h>
33 
34 namespace ogdf {
35 namespace davidson_harel {
36 
37 const double UniformGrid::m_epsilon = 0.000001;
38 const double UniformGrid::m_edgeMultiplier = 1.0;
39 
40 #if 0
41 int UniformGrid::constructorcounter = 0;
42 #endif
43 
ModifiedBresenham(const IPoint & p1,const IPoint & p2,SList<IPoint> & crossedCells) const44 void UniformGrid::ModifiedBresenham(
45 	const IPoint &p1,
46 	const IPoint &p2,
47 	SList<IPoint> &crossedCells) const
48 {
49 	crossedCells.clear();
50 
51 	int Ax = p1.m_x;
52 	int Ay = p1.m_y;
53 	int Bx = p2.m_x;
54 	int By = p2.m_y;
55 	// INITIALIZE THE COMPONENTS OF THE ALGORITHM THAT ARE NOT AFFECTED BY THE
56 	// SLOPE OR DIRECTION OF THE LINE
57 	int dX = abs(Bx-Ax);	// store the change in X and Y of the line endpoints
58 	int dY = abs(By-Ay);
59 
60 	// DETERMINE "DIRECTIONS" TO INCREMENT X AND Y (REGARDLESS OF DECISION)
61 	int Xincr, Yincr,Xoffset,Yoffset;
62 	if (Ax > Bx) { Xincr=-1; Xoffset = -1;} else { Xincr=1; Xoffset = 0;}	// which direction in X?
63 	if (Ay > By) { Yincr=-1; Yoffset = -1;} else { Yincr=1; Yoffset = 0;}	// which direction in Y?
64 	// the offsets are necessary because we always want the cell left and below
65 	// the point were bresenham wants to draw it
66 
67 	// DETERMINE INDEPENDENT VARIABLE (ONE THAT ALWAYS INCREMENTS BY 1 (OR -1) )
68 	// AND INITIATE APPROPRIATE LINE DRAWING ROUTINE (BASED ON FIRST OCTANT
69 	// ALWAYS). THE X AND Y'S MAY BE FLIPPED IF Y IS THE INDEPENDENT VARIABLE.
70 	if (dX >= dY)	// if X is the independent variable
71 	{
72 		int dPr 	= dY<<1;  // amount to increment decision if right is chosen (always)
73 		int dPru 	= dPr - (dX<<1);   // amount to increment decision if up is chosen
74 		int P 		= dPr - dX;  // decision variable start value
75 		int secondY = Ay+Yincr; //Y-coordinate of secondary point
76 		int testval = P; //if P is equal to testval, the the next point is drawn exactly on the segment. If P is smaller than testval, it is below the segment
77 
78 		for (; dX>=0; dX--)  // process each point in the line one at a time (just use dX)
79 		{
80 			crossedCells.pushBack(IPoint(Ax+Xoffset,Ay+Yoffset));//add the primary cell
81 			crossedCells.pushBack(IPoint(Ax+Xoffset,secondY+Yoffset));//add the secondary cell
82 			if (P > 0)          // is the pixel going right AND up?
83 			{
84 				Ax+=Xincr;	       // increment independent variable
85 				Ay+=Yincr;         // increment dependent variable
86 				P+=dPru;           // increment decision (for up)
87 			}
88 			else                     // is the pixel just going right?
89 			{
90 				Ax+=Xincr;         // increment independent variable
91 				P+=dPr;            // increment decision (for right)
92 			}
93 			if(P - testval < 0) //primary cell above the line
94 				secondY = Ay-Yincr;
95 			else secondY = Ay+Yincr;//primary cell below the line
96 		}
97 	}
98 	else              // if Y is the independent variable
99 	{
100 		int dPr 	= dX<<1;    // amount to increment decision if right is chosen (always)
101 		int dPru 	= dPr - (dY<<1);   // amount to increment decision if up is chosen
102 		int P 		= dPr - dY;  // decision variable start value
103 		int testval = P; // substracting this from P tells us if the cell is drawn left or
104 						// right from the actual segment
105 		int secondX = Ax+Xincr; //X-Coordinate of secondary cell
106 
107 		for (; dY>=0; dY--)            // process each point in the line one at a time (just use dY)
108 		{
109 			crossedCells.pushBack(IPoint(Ax+Xoffset,Ay+Yoffset));// add the primary cell
110 			crossedCells.pushBack(IPoint(secondX+Xoffset,Ay+Yoffset));// add the secondary cell
111 			if (P > 0)               // is the pixel going up AND right?
112 			{
113 				Ax+=Xincr;         // increment dependent variable
114 				Ay+=Yincr;         // increment independent variable
115 				P+=dPru;           // increment decision (for up)
116 			}
117 			else                     // is the pixel just going up?
118 			{
119 				Ay+=Yincr;         // increment independent variable
120 				P+=dPr;            // increment decision (for right)
121 			}
122 			if(P - testval < 0) //primary cell left of the line
123 				secondX = Ax-Xincr;
124 			else secondX = Ax+Xincr;//primary cell right of the line
125 		}
126 	}
127 }
128 
DoubleModifiedBresenham(const DPoint & p1,const DPoint & p2,SList<IPoint> & crossedCells) const129 void UniformGrid::DoubleModifiedBresenham(
130 	const DPoint &p1,
131 	const DPoint &p2,
132 	SList<IPoint> &crossedCells) const
133 {
134 	crossedCells.clear();
135 	// INITIALIZE THE COMPONENTS OF THE ALGORITHM THAT ARE NOT AFFECTED BY THE
136 	// SLOPE OR DIRECTION OF THE LINE
137 	double dX = fabs(p2.m_x-p1.m_x);	// store the change in X and Y of the line endpoints
138 	double dY = fabs(p1.m_y-p2.m_y);
139 
140 
141 	// DETERMINE INDEPENDENT VARIABLE (ONE THAT ALWAYS INCREMENTS BY 1 (OR -1) )
142 	// AND INITIATE APPROPRIATE LINE DRAWING ROUTINE (BASED ON FIRST OCTANT
143 	// ALWAYS). THE X AND Y'S MAY BE FLIPPED IF Y IS THE INDEPENDENT VARIABLE.
144 	if (dX >= dY)	// if X is the independent variable
145 	{
146 		DPoint left,right;
147 		if(p1.m_x > p2.m_x) {
148 			left = p2;
149 			right = p1;
150 		}
151 		else {
152 			left = p1;
153 			right= p2;
154 		}
155 		//Now we determine the coordinates of the start cell
156 		//and the end cell
157 		IPoint start(computeGridPoint(left));
158 		if(p1 == p2) {
159 			crossedCells.pushBack(start);
160 			return;
161 		}
162 		IPoint end(computeGridPoint(right));
163 		//Since computeGridPoint rounds down, this gives us the point p1 and
164 		//below each of the points. This is the address of the cell that contains
165 		//the point
166 #if 0
167 		int Yincr = 1;
168 		if(left.m_y > right.m_y) Yincr = -1;
169 #endif
170 		double slope = (right.m_y-left.m_y)/(right.m_x-left.m_x);
171 		double c = left.m_y-slope*left.m_x;
172 		OGDF_ASSERT(fabs(slope*right.m_x+c - right.m_y) < m_epsilon);
173 		int endX = end.m_x+1;
174 		double dYincr = slope * m_CellSize;
175 		double OldYPos = slope*start.m_x*m_CellSize+c;
176 		int oldY = (int)floor(OldYPos/m_CellSize);
177 		for(int i = start.m_x; i <= endX; i++) {
178 			crossedCells.pushBack(IPoint(i,oldY));
179 			double newY = OldYPos + dYincr;
180 			OGDF_ASSERT(newY - ((i+1)*m_CellSize*slope+c) < m_epsilon);
181 			int newCellY = (int)floor(newY/m_CellSize);
182 			if(newCellY != oldY) {
183 				oldY = newCellY;
184 				crossedCells.pushBack(IPoint(i,oldY));
185 			}
186 			OldYPos = newY;
187 		}
188 	}
189 	else              // if Y is the independent variable
190 	{
191 		DPoint bottom,top;
192 		if(p1.m_y > p2.m_y) {
193 			bottom = p2;
194 			top = p1;
195 		}
196 		else {
197 			bottom = p1;
198 			top = p2;
199 		}
200 		IPoint start(computeGridPoint(bottom));
201 		IPoint end(computeGridPoint(top));
202 #if 0
203 		int Xincr = 1;
204 		if(bottom.m_x > top.m_x) Xincr = -1;
205 #endif
206 		double slope = (top.m_x-bottom.m_x)/(top.m_y-bottom.m_y);
207 		double c = bottom.m_x-slope*bottom.m_y;
208 		OGDF_ASSERT(fabs(slope*top.m_y+c - top.m_x) < m_epsilon);
209 		int endY = end.m_y+1;
210 		double dXincr = slope * m_CellSize;
211 		double OldXPos = slope*start.m_y*m_CellSize+c;
212 		int oldX = (int)floor(OldXPos/m_CellSize);
213 		for(int i = start.m_y; i <= endY; i++) {
214 			crossedCells.pushBack(IPoint(oldX,i));
215 			double newX = OldXPos + dXincr;
216 			OGDF_ASSERT(newX - ((i+1)*m_CellSize*slope+c) < m_epsilon);
217 			int newCellX = (int)floor(newX/m_CellSize);
218 			if(newCellX != oldX) {
219 				oldX = newCellX;
220 				crossedCells.pushBack(IPoint(oldX,i));
221 			}
222 			OldXPos = newX;
223 		}
224 	}
225 }
226 
227 //constructor for computing the grid and the crossings from scratch for the
228 //layout given by AG
UniformGrid(const GraphAttributes & AG)229 UniformGrid::UniformGrid(const GraphAttributes &AG) :
230 	m_layout(AG),
231 	m_graph(AG.constGraph()),
232 	m_crossings(m_graph),
233 	m_cells(m_graph),
234 	m_CellSize(0.0),
235 	m_crossNum(0)
236 {
237 #if 0
238 	std::cout<<"New grid \n";
239 #endif
240 	node v = m_graph.firstNode();
241 	DPoint pos(m_layout.x(v),m_layout.y(v));
242 #ifdef OGDF_DEBUG
243 	m_crossingTests = 0;
244 	m_maxEdgesPerCell = 0;
245 	usedTime(m_time);
246 #endif
247 	DIntersectableRect ir;
248 	computeGridGeometry(v,pos,ir);
249 	double maxLength = max(ir.height(),ir.width());
250 	m_CellSize = maxLength/(m_edgeMultiplier*(m_graph).numberOfEdges());
251 	List<edge> list;
252 	m_graph.allEdges(list);
253 	computeCrossings(list, v, pos);
254 #ifdef OGDF_DEBUG
255 	m_time = usedTime(m_time);
256 #endif
257 }
258 
259 //constructor for computing the grid and the crossings from scratch for
260 //the given layout where node v is moved to newPos
UniformGrid(const GraphAttributes & AG,const node v,const DPoint & newPos)261 UniformGrid::UniformGrid(
262 	const GraphAttributes &AG,
263 	const node v,
264 	const DPoint& newPos)
265 :
266 	m_layout(AG),
267 	m_graph(AG.constGraph()),
268 	m_crossings(m_graph),
269 	m_cells(m_graph),
270 	m_CellSize(0.0),
271 	m_crossNum(0)
272 {
273 #ifdef OGDF_DEBUG
274 	m_crossingTests = 0;
275 	m_maxEdgesPerCell = 0;
276 	usedTime(m_time);
277 #endif
278 	DIntersectableRect ir;
279 	computeGridGeometry(v,newPos,ir);
280 	double maxLength = max(ir.height(),ir.width());
281 	m_CellSize = maxLength/(m_edgeMultiplier*(m_graph).numberOfEdges());
282 	List<edge> list;
283 	m_graph.allEdges(list);
284 	computeCrossings(list, v, newPos);
285 #ifdef OGDF_DEBUG
286 	m_time = usedTime(m_time);
287 #endif
288 }
289 
290 //constructor for computing an updated grid for a given grid where one
291 //vertex is moved to a new position
UniformGrid(const UniformGrid & ug,const node v,const DPoint & newPos)292 UniformGrid::UniformGrid(
293 	const UniformGrid &ug,
294 	const node v,
295 	const DPoint& newPos) :
296 	m_layout(ug.m_layout),
297 	m_graph(ug.m_graph),
298 	m_grid(ug.m_grid),
299 	m_crossings(ug.m_crossings),
300 	m_cells(ug.m_cells),
301 	m_CellSize(ug.m_CellSize),
302 	m_crossNum(ug.m_crossNum)
303 {
304 	//constructorcounter++;
305 #ifdef OGDF_DEBUG
306 	m_crossingTests = 0;
307 	m_maxEdgesPerCell = 0;
308 	usedTime(m_time);
309 	DIntersectableRect ir;
310 	computeGridGeometry(v,newPos,ir);
311 	double size = max(ir.width(),ir.height());
312 	size /= m_graph.numberOfEdges() * m_edgeMultiplier;
313 	OGDF_ASSERT(size > 0.5*m_CellSize);
314 	OGDF_ASSERT(size < 2.0*m_CellSize);
315 #endif
316 	//compute the list of edge incident to v
317 	List<edge> incident;
318 	v->adjEdges(incident);
319 	//set the crossings of all these edges to zero, update the global crossing
320 	//number, remove them from their cells. Note that we cannot insert the edge
321 	//with its new position into the grid in the same loop because we may get
322 	//crossings with other edges incident to v
323 	for(edge e : incident) {
324 		//we clear the list of crossings of e and delete e from the
325 		//crossings lists of all the edges it crosses
326 		List<edge>& c = m_crossings[e];
327 		while(!c.empty()) {
328 			edge crossed = c.popFrontRet();
329 			List<edge>& cl = m_crossings[crossed];
330 			ListIterator<edge> it2 = cl.begin();
331 			while(*it2 != e) ++it2;
332 			cl.del(it2);
333 			m_crossNum--;
334 		}
335 		List<IPoint>& cells = m_cells[e];
336 		//delete e from all its cells
337 		while(!cells.empty()) {
338 			IPoint p = cells.popFrontRet();
339 			List<edge>& eList = m_grid(p.m_x,p.m_y);
340 			ListIterator<edge> it2 = eList.begin();
341 			while(*it2 != e) ++it2;
342 			eList.del(it2);
343 		}
344 	}
345 	// at this point, all the data structures look as if the edges in the
346 	//list incident where not present. Now we reinsert the edges into the
347 	//grid with their new positions and update the crossings
348 	computeCrossings(incident,v,newPos);
349 #ifdef OGDF_DEBUG
350 	m_time = usedTime(m_time);
351 #endif
352 }
353 
354 
computeGridGeometry(const node moved,const DPoint & newPos,DIntersectableRect & ir) const355 void UniformGrid::computeGridGeometry(
356 	const node moved,
357 	const DPoint& newPos,
358 	DIntersectableRect& ir) const
359 {
360 	//first we compute the resolution and size of the grid
361 	double
362 		minX = std::numeric_limits<double>::max(),
363 		minY = std::numeric_limits<double>::max(),
364 		maxX = std::numeric_limits<double>::lowest(),
365 		maxY = std::numeric_limits<double>::lowest();
366 
367 	//find lower left and upper right vertex
368 	for(node v : m_graph.nodes) {
369 		double x, y;
370 		if(v != moved) {// v is the node that was moved
371 			x = m_layout.x(v);
372 			y = m_layout.y(v);
373 		}
374 		else {// v is not the moved node
375 			x = newPos.m_x;
376 			y = newPos.m_y;
377 		}
378 		if(x < minX) minX = x;
379 		if(x > maxX) maxX = x;
380 		if(y < minY) minY = y;
381 		if(y > maxY) maxY = y;
382 	}
383 	ir = DIntersectableRect(minX,minY,maxX,maxY);
384 }
385 
386 
computeCrossings(const List<edge> & toInsert,const node moved,const DPoint & newPos)387 void UniformGrid::computeCrossings(
388 	const List<edge>& toInsert,
389 	const node moved,
390 	const DPoint& newPos)
391 {
392 	//now we compute all the remaining data of the class in one loop
393 	//going through all edges and storing them in the grid.
394 	for (edge e : toInsert)
395 	{
396 		SList<IPoint> crossedCells;
397 		DPoint sPos, tPos;
398 		const node& s = e->source();
399 		if (s != moved) sPos = m_layout.point(s);
400 		else sPos = newPos;
401 		const node& t = e->target();
402 		if (t != moved) tPos = m_layout.point(t);
403 		else tPos = newPos;
404 		DoubleModifiedBresenham(sPos, tPos, crossedCells);
405 		for (const IPoint &p : crossedCells) {
406 			m_cells[e].pushBack(p);
407 			List<edge>& edgeList = m_grid(p.m_x, p.m_y);
408 			if (!edgeList.empty()) { //there are already edges in that list
409 				OGDF_ASSERT(!edgeList.empty());
410 				for (edge e2 : edgeList) {
411 					if (crossingTest(e, e2, moved, newPos, p)) { //two edges cross in p
412 						++m_crossNum;
413 						m_crossings[e].pushBack(e2);
414 						m_crossings[e2].pushBack(e);
415 					}
416 				}
417 			}
418 			//now we insert the new edge into the list and store the position
419 			//returned by pushBack in the corresponding list of m_storedIn
420 			edgeList.pushBack(e);
421 #ifdef OGDF_DEBUG
422 			if (m_maxEdgesPerCell < edgeList.size())
423 				m_maxEdgesPerCell = edgeList.size();
424 #endif
425 		}
426 	}
427 #ifdef OGDF_DEBUG
428 	int sumCros = 0;
429 	for (edge e : m_graph.edges)
430 		sumCros += m_crossings[e].size();
431 	OGDF_ASSERT((sumCros >> 1) == m_crossNum);
432 #endif
433 }
434 
435 
436 //returns true if both edges are not adjacent and cross inside the given cell
crossingTest(const edge e1,const edge e2,const node moved,const DPoint & newPos,const IPoint & cell)437 bool UniformGrid::crossingTest(
438 	const edge e1,
439 	const edge e2,
440 	const node moved,
441 	const DPoint& newPos,
442 	const IPoint& cell)
443 {
444 	bool crosses = false;
445 	node s1 = e1->source(), t1 = e1->target();
446 	node s2 = e2->source(), t2 = e2->target();
447 	if(s1 != s2 && s1 != t2 && t1 != s2 && t1 != t2) {//not adjacent
448 		double xLeft = cell.m_x*m_CellSize;
449 		double xRight = (cell.m_x+1)*m_CellSize;
450 		double xBottom = cell.m_y*m_CellSize;
451 		double xTop = (cell.m_y+1)*m_CellSize;
452 		DPoint ps1,pt1,ps2,pt2;
453 		if(s1 != moved) ps1 = m_layout.point(s1);
454 		else ps1 = newPos;
455 		if(t1 != moved) pt1 = m_layout.point(t1);
456 		else pt1 = newPos;
457 		if(s2 != moved) ps2 = m_layout.point(s2);
458 		else ps2 = newPos;
459 		if(t2 != moved) pt2 = m_layout.point(t2);
460 		else pt2 = newPos;
461 		DSegment l1(ps1,pt1),l2(ps2,pt2);
462 		DPoint crossPoint;
463 #ifdef OGDF_DEBUG
464 		m_crossingTests++;
465 #endif
466 		// TODO: What to do when IntersectionType::Overlapping is returned?
467 		if (l1.intersection(l2,crossPoint) == IntersectionType::SinglePoint
468 		 && crossPoint.m_x >= xLeft
469 		 && crossPoint.m_x < xRight
470 		 && crossPoint.m_y >= xBottom
471 		 && crossPoint.m_y < xTop) {
472 			crosses = true;
473 		}
474 	}
475 	return crosses;
476 }
477 
478 #ifdef OGDF_DEBUG
479 
markCells(SList<IPoint> & result,Array2D<bool> & cells) const480 void UniformGrid::markCells(SList<IPoint> &result, Array2D<bool> &cells) const {
481 	while (!result.empty()) {
482 		IPoint p = result.popFrontRet();
483 		if (cells.low1() <= p.m_x && cells.high1() >= p.m_x
484 		 && cells.low2() <= p.m_y && cells.high2() >= p.m_y)
485 			cells(p.m_x,p.m_y) = true;
486 	}
487 }
488 
489 
checkBresenham(DPoint p1,DPoint p2) const490 void UniformGrid::checkBresenham(DPoint p1, DPoint p2) const
491 {
492 	int crossed = 0;
493 	DPoint bottomleft(min(p1.m_x,p2.m_x),min(p1.m_y,p2.m_y));
494 	DPoint topright(max(max(p1.m_x,p2.m_x),bottomleft.m_x+1.0),
495 		max(max(p1.m_y,p2.m_y),bottomleft.m_y+1.0));
496 	IPoint ibl(computeGridPoint(bottomleft));
497 	IPoint itr(computeGridPoint(topright));
498 	Array2D<bool> cells(ibl.m_x,itr.m_x+1,ibl.m_y,itr.m_y+1,false);
499 	SList<IPoint> result;
500 	DoubleModifiedBresenham(p1,p2,result);
501 	std::cout << "\nList computed by Bresenham:\n";
502 
503 	for(const IPoint &p : result) {
504 		std::cout << computeRealPoint(p) << " ";
505 	}
506 
507 	markCells(result,cells);
508 	std::cout << "\nCrossed cells:\n";
509 	if(p1.m_x == p2.m_x) { //vertical segment
510 		int cellXcoord = (int)floor(p1.m_x/m_CellSize);
511 		double b = floor(min(p1.m_y,p2.m_y)/m_CellSize);
512 		double t = ceil(max(p1.m_y,p2.m_y)/m_CellSize);
513 		OGDF_ASSERT(isInt(b));
514 		OGDF_ASSERT(isInt(t));
515 		int intT = (int)t;
516 		for(int i = int(b); i < intT; i++) {
517 			crossed++;
518 			IPoint p(cellXcoord,i);
519 			std::cout << computeRealPoint(p) << " ";
520 			if(!cells(p.m_x,p.m_y)) {
521 				std::cout << "\nCell " << computeRealPoint(p) << " is not marked!";
522 				OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::Unknown);
523 			}
524 		}
525 	}
526 	else {
527 		if(p1.m_y == p2.m_y) { //horizontal segment
528 			double tmp = floor(p1.m_y/m_CellSize);
529 			OGDF_ASSERT(isInt(tmp));
530 			int cellYcoord = (int)tmp;
531 			double left = floor(min(p1.m_x,p2.m_x)/m_CellSize);
532 			double right = ceil(max(p1.m_x,p2.m_x)/m_CellSize);
533 			OGDF_ASSERT(isInt(left));
534 			OGDF_ASSERT(isInt(right));
535 			int intR = int(right);
536 			for(int i = int(left); i < intR; i++) {
537 				crossed++;
538 				IPoint p(i,cellYcoord);
539 				std::cout << computeRealPoint(p) << " ";
540 				if(!cells(p.m_x,p.m_y)) {
541 					std::cout << "\nCell " << computeRealPoint(p) << " is not marked!";
542 					OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::Unknown);
543 				}
544 			}
545 		}
546 		else {
547 			for(int i = cells.low1(); i <= cells.high1(); i++) {
548 				for(int j = cells.low2(); j <= cells.high2(); j++) {
549 					IPoint p(i,j);
550 					if(crossesCell(p1,p2,p)) {
551 						crossed++;
552 						std::cout << computeRealPoint(p) << " ";
553 						if(!cells(p.m_x,p.m_y)) {
554 							std::cout << "\n Cell " << computeRealPoint(p) << " is not marked!";
555 							OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::Unknown);
556 						}
557 					}
558 				}
559 			}
560 
561 		}
562 	}
563 	if(crossed < max(fabs(p1.m_x-p2.m_x)/m_CellSize,fabs(p1.m_y-p2.m_y)/m_CellSize)) {
564 		std::cout << "\nNot enough crossed cells for " << p1 << " " << p2 << "\n";
565 		OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::Unknown);
566 	}
567 	std::cout << "\n";
568 
569 }
570 
571 
checkBresenham(IPoint p1,IPoint p2) const572 void UniformGrid::checkBresenham(IPoint p1, IPoint p2) const
573 {
574 	int crossed = 0;
575 	int left = min(p1.m_x,p2.m_x)-1;
576 	int right = max(max(p1.m_x,p2.m_x),left+1);
577 	int bottom = min(p1.m_y,p2.m_y)-1;
578 	int top = max(max(p1.m_y,p2.m_y),bottom+1);
579 	Array2D<bool> cells(left,right,bottom,top,false);
580 	SList<IPoint> result;
581 	ModifiedBresenham(p1,p2,result);
582 	std::cout << "\nList computed by Bresenham:\n" << result;
583 	markCells(result,cells);
584 	std::cout << "\nCrossed cells:\n";
585 	if(p1.m_x == p2.m_x) { //vertical segment
586 		for(int i = min(p1.m_y,p2.m_y); i < max(p1.m_y,p2.m_y); i++) {
587 			crossed++;
588 			IPoint p(p1.m_x,i);
589 			std::cout << p << " ";
590 			if(!cells(p.m_x,p.m_y)) {
591 				std::cout << "\nCell " << p << " is not marked!";
592 				OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::Unknown);
593 			}
594 		}
595 	}
596 	else {
597 		if(p1.m_y == p2.m_y) { //horizontal segment
598 			for(int i = min(p1.m_x,p2.m_x); i < max(p1.m_x,p2.m_x); i++) {
599 				crossed++;
600 				IPoint p(i,p1.m_y);
601 				std::cout << p << " ";
602 				if(!cells(i,p1.m_y)) {
603 					std::cout << "\nCell " << p <<" is not marked!";
604 					OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::Unknown);
605 				}
606 			}
607 		}
608 		else {
609 			for(int i = cells.low1(); i <= cells.high1(); i++) {
610 				for(int j = cells.low2(); j <= cells.high2(); j++) {
611 					IPoint p(i,j);
612 					if(crossesCell(p1,p2,p)) {
613 						crossed++;
614 						std::cout << p << " ";
615 						if(!cells(p.m_x,p.m_y)) {
616 							std::cout << "\n Cell " << p << " is not marked!";
617 							OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::Unknown);
618 						}
619 					}
620 				}
621 			}
622 
623 		}
624 	}
625 	if(crossed < max(abs(p1.m_x-p2.m_x),abs(p1.m_y-p2.m_y))) {
626 		std::cout << "\nNot enough crossed cells for " << p1 << " " << p2 << "\n";
627 		OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::Unknown);
628 	}
629 	std::cout << "\n";
630 
631 }
632 
633 
634 //the upper and left boundary does not belong to a cell
crossesCell(IPoint A,IPoint B,const IPoint & CellAdr) const635 bool UniformGrid::crossesCell(
636 	IPoint A,
637 	IPoint B,
638 	const IPoint &CellAdr) const
639 {
640 	return crossesCell(A, B,
641 	                   CellAdr.m_x, CellAdr.m_x + 1,
642 	                   CellAdr.m_y, CellAdr.m_y + 1,
643 	                   CellAdr);
644 }
645 
646 //the upper and left boundary does not belong to a cell
crossesCell(DPoint A,DPoint B,const IPoint & CellAdr) const647 bool UniformGrid::crossesCell(
648 	DPoint A,
649 	DPoint B,
650 	const IPoint &CellAdr) const
651 {
652 	double xLowCell = CellAdr.m_x * m_CellSize;
653 	double yLowCell = CellAdr.m_y * m_CellSize;
654 	return crossesCell(A, B,
655 	                   xLowCell, xLowCell + m_CellSize,
656 	                   yLowCell, yLowCell + m_CellSize,
657 	                   CellAdr);
658 }
659 
660 
intervalIntersect(double a1,double a2,double cell1,double cell2) const661 bool UniformGrid::intervalIntersect(
662 	double a1,
663 	double a2,
664 	double cell1,
665 	double cell2) const
666 {
667 	double epsilon = 0.000001;
668 	bool intersect = true;
669 	if(min(a1,a2)+epsilon >= max(cell1,cell2) || min(cell1,cell2)+epsilon >= max(a1,a2)) intersect = false;
670 	return intersect;
671 }
672 
673 
operator <<(std::ostream & out,const UniformGrid & ug)674 std::ostream &operator<<(std::ostream &out, const UniformGrid &ug)
675 {
676 	out << "\nGrid Size: " << ug.m_CellSize;
677 	out << "\nEpsilon: " << ug.m_epsilon;
678 	out << "\nEdge Multiplier: " << ug.m_edgeMultiplier;
679 	out << "\nCrossing number: " << ug.m_crossNum;
680 #ifdef OGDF_DEBUG
681 	out << "\nCrossing tests: " << ug.m_crossingTests;
682 	out << "\nMax edges per cell: " << ug.m_maxEdgesPerCell;
683 	out << "\nConstruction time: " << ug.m_time;
684 	DIntersectableRect ir;
685 	node v = ug.m_graph.firstNode();
686 	ug.computeGridGeometry(v,ug.m_layout.point(v),ir);
687 	double size = max(ir.width(),ir.height());
688 	std::cout << "\nPreferred Cell Size: " << size / (ug.m_graph.numberOfEdges()*ug.m_edgeMultiplier);
689 #endif
690 	return out;
691 }
692 #endif
693 
694 }}
695