Don't import ogdf namespace
[TortoiseGit.git] / ext / OGDF / src / basic / NearestRectangleFinder.cpp
blob9d2da2685da7a50edffd9a33a6494519242d840c
1 /*
2 * $Revision: 2565 $
4 * last checkin:
5 * $Author: gutwenger $
6 * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $
7 ***************************************************************/
9 /** \file
10 * \brief Implements class NearestRectangleFinder
12 * \author Carsten Gutwenger
14 * \par License:
15 * This file is part of the Open Graph Drawing Framework (OGDF).
17 * \par
18 * Copyright (C)<br>
19 * See README.txt in the root directory of the OGDF installation for details.
21 * \par
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * Version 2 or 3 as published by the Free Software Foundation;
25 * see the file LICENSE.txt included in the packaging of this file
26 * for details.
28 * \par
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
34 * \par
35 * You should have received a copy of the GNU General Public
36 * License along with this program; if not, write to the Free
37 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
38 * Boston, MA 02110-1301, USA.
40 * \see http://www.gnu.org/copyleft/gpl.html
41 ***************************************************************/
45 #include <ogdf/basic/NearestRectangleFinder.h>
46 #include <float.h>
47 #include <ogdf/basic/List.h>
48 #include <ogdf/basic/BoundedStack.h>
51 namespace ogdf {
54 //---------------------------------------------------------
55 // PairCoordId
56 // represents a pair of a coordinate (x or y) and the index
57 // of a rectangle
58 //---------------------------------------------------------
59 struct OGDF_EXPORT NearestRectangleFinder::PairCoordId
61 PairCoordId(double coord, int index) {
62 m_coord = coord;
63 m_index = index;
66 PairCoordId() { }
68 friend ostream &operator<<(ostream &os, const PairCoordId &p) {
69 os << "(" << p.m_coord << "," << p.m_index << ")";
70 return os;
73 double m_coord;
74 int m_index;
78 //---------------------------------------------------------
79 // CoordComparer
80 // comparer class for sorting PairCoordId according to
81 // decreasing coordinate
82 //---------------------------------------------------------
83 class NearestRectangleFinder::CoordComparer
85 public:
86 bool less (const PairCoordId &x, const PairCoordId &y) const {
87 return x.m_coord > y.m_coord;
89 bool leq (const PairCoordId &x, const PairCoordId &y) const {
90 return x.m_coord >= y.m_coord;
92 bool equal(const PairCoordId &x, const PairCoordId &y) const {
93 return x.m_coord == y.m_coord;
98 //---------------------------------------------------------
99 // YCoordComparer
100 // comparer class for sorting points (given by index) by
101 // decreasing y-coordinate
102 //---------------------------------------------------------
103 class NearestRectangleFinder::YCoordComparer
105 public:
106 YCoordComparer(const Array<DPoint> &point) {
107 m_point = &point;
110 bool less (int x, int y) const {
111 return (*m_point)[x].m_y > (*m_point)[y].m_y;
113 bool leq (int x, int y) const {
114 return (*m_point)[x].m_y >= (*m_point)[y].m_y;
116 bool equal(int x, int y) const {
117 return (*m_point)[x].m_y == (*m_point)[y].m_y;
120 private:
121 const Array<DPoint> *m_point;
126 //---------------------------------------------------------
127 // NearestRectangleFinder
128 //---------------------------------------------------------
130 void NearestRectangleFinder::find(
131 const Array<RectRegion> &region,
132 const Array<DPoint> &point,
133 Array<List<PairRectDist> > &nearest)
135 const int n = region.size(); // number of rectangles
136 const int m = point.size(); // number of points
138 List<PairCoordId> listTop; // list of max. y-coord. of rectangles
139 List<PairCoordId> listBottom; // list of min. y-coord. of rectangles
141 // build lists listTop and listBottom ...
142 int i;
143 for(i = 0; i < n; ++i) {
144 const RectRegion &rect = region[i];
145 listTop .pushBack(PairCoordId(rect.m_y + rect.m_height/2.0, i));
146 listBottom.pushBack(PairCoordId(rect.m_y - rect.m_height/2.0, i));
149 // ... and sort them by decreasing coordinates
150 CoordComparer comparer;
151 listTop .quicksort(comparer);
152 listBottom.quicksort(comparer);
154 // build array of point indices ...
155 Array<int> sortedPoints(m);
156 for(i = 0; i < m; ++i)
157 sortedPoints[i] = i;
159 // ... and sort them by decreasing y-coordinate
160 YCoordComparer yCoordComparer(point);
161 sortedPoints.quicksort(yCoordComparer);
164 ListPure<int> active; // list of rectangles such that y-coord. of current
165 // point is contained y-projection of rectangle
167 // We traverse the lists listTop and listBottom from start to end such that
168 // the coord. of the current entry in listTop is the first entry below p.y
169 // and the coord. of the current entry in listBottom is the first entry
170 // equal or below p.y
171 ListIterator<PairCoordId> nextTop = listTop .begin();
172 ListIterator<PairCoordId> nextBottom = listBottom.begin();
175 // position of a rectangle in active
176 Array<ListIterator<int> > posInActive(n);
177 // list of rectangles visited for current point
178 BoundedStack<int> visitedRectangles(n);
179 // distance of rectangle to current point (if contained in visitedRectangles)
180 Array<double> distance(n);
182 // the maximal distance we have to explore
183 // (if a rectangle lies at distance m_maxAllowedDistance, it can get
184 // ambigous if there are rectangles with distance <= maxDistanceVisit)
185 double maxDistanceVisit = m_maxAllowedDistance + m_toleranceDistance;
187 // we iterate over all points by decreasing y-coordinate
188 for(i = 0; i < m; ++i)
190 const int nextPoint = sortedPoints[i];
191 const DPoint &p = point[nextPoint];
193 // update active list
194 while(nextTop.valid() && (*nextTop).m_coord >= p.m_y) {
195 int index = (*nextTop).m_index;
196 posInActive[index] = active.pushBack(index);
197 ++nextTop;
200 while(nextBottom.valid() && (*nextBottom).m_coord > p.m_y) {
201 active.del(posInActive[(*nextBottom).m_index]);
202 ++nextBottom;
205 // the largest minDist value we have to consider
206 double minDist = maxDistanceVisit;
208 // look for rectangles with minimal distance in active rectangles
209 // here the distance ist the distance in x-direction
210 ListIterator<int> itActive;
211 for(itActive = active.begin(); itActive.valid(); ++itActive)
213 const RectRegion &rect = region[*itActive];
214 double left = rect.m_x - rect.m_width/2.0;
215 double right = rect.m_x + rect.m_width/2.0;
217 double xDist = 0.0;
218 if(p.m_x < left)
219 xDist = left - p.m_x;
220 else if (right < p.m_x)
221 xDist = p.m_x - right;
223 if(xDist < minDist) {
224 minDist = xDist;
227 visitedRectangles.push(*itActive);
228 distance[*itActive] = xDist;
231 // starting at p.y, we iterate simultaniously upward and downward.
232 // We go upward in listBottom since these rectangles lie completely
233 // above p, and downward in listTop since these rectangles lie
234 // completely below p
235 ListIterator<PairCoordId> itTop = nextTop;
236 ListIterator<PairCoordId> itBottom =
237 (nextBottom.valid()) ? nextBottom.pred() : listBottom.rbegin();
239 while(itTop.valid() || itBottom.valid())
241 if(itTop.valid())
243 if((*itTop).m_coord < p.m_y - minDist)
244 itTop = ListIterator<PairCoordId>();
245 else {
246 // determine distance between *itTop and p
247 const RectRegion &rect = region[(*itTop).m_index];
248 double left = rect.m_x - rect.m_width/2.0;
249 double right = rect.m_x + rect.m_width/2.0;
251 double xDist = 0.0;
252 if(p.m_x < left)
253 xDist = left - p.m_x;
254 else if (right < p.m_x)
255 xDist = p.m_x - right;
257 double dist = xDist + (p.m_y - (*itTop).m_coord);
258 OGDF_ASSERT(dist > 0);
260 if(dist < minDist) {
261 minDist = dist;
264 // update visited rectangles
265 visitedRectangles.push((*itTop).m_index);
266 distance[(*itTop).m_index] = dist;
268 ++itTop;
272 if(itBottom.valid())
274 if((*itBottom).m_coord > p.m_y + minDist)
275 itBottom = ListIterator<PairCoordId>();
276 else {
277 // determine distance between *itBottom and p
278 const RectRegion &rect = region[(*itBottom).m_index];
279 double left = rect.m_x - rect.m_width/2.0;
280 double right = rect.m_x + rect.m_width/2.0;
282 double xDist = 0.0;
283 if(p.m_x < left)
284 xDist = left - p.m_x;
285 else if (right < p.m_x)
286 xDist = p.m_x - right;
288 double dist = xDist + ((*itBottom).m_coord - p.m_y);
289 OGDF_ASSERT(dist > 0);
291 if(dist < minDist) {
292 minDist = dist;
295 // update visited rectangles
296 visitedRectangles.push((*itBottom).m_index);
297 distance[(*itBottom).m_index] = dist;
299 --itBottom;
304 // if the minimum found distance is outside the allowed distance
305 // we return an empty list for p
306 if(minDist > m_maxAllowedDistance) {
307 visitedRectangles.clear();
309 } else {
310 // otherwise we return all rectangles which are at most minimal
311 // distance plus tolerance away
312 double max = minDist + m_toleranceDistance;
313 while(!visitedRectangles.empty())
315 int index = visitedRectangles.pop();
316 if(distance[index] <= max)
317 nearest[nextPoint].pushBack(PairRectDist(index,distance[index]));
324 // simple version of find() which is used for correction checking
325 // this version only computes the nearest rectangle without considering
326 // maxAllowedDistance and toleranceDistance.
327 void NearestRectangleFinder::findSimple(
328 const Array<RectRegion> &region,
329 const Array<DPoint> &point,
330 Array<List<PairRectDist> > &nearest)
332 const int n = region.size();
333 const int m = point.size();
335 for(int i = 0; i < m; ++i)
337 const DPoint &p = point[i];
338 double minDist = DBL_MAX;
339 int minDistIndex = -1;
341 for(int j = 0; j < n; ++j)
343 const RectRegion &rect = region[j];
345 double left = rect.m_x - rect.m_width/2.0;
346 double right = rect.m_x + rect.m_width/2.0;
348 double xDist = 0.0;
349 if(p.m_x < left)
350 xDist = left - p.m_x;
351 else if (right < p.m_x)
352 xDist = p.m_x - right;
353 OGDF_ASSERT(xDist >= 0);
355 double bottom = rect.m_y - rect.m_height/2.0;
356 double top = rect.m_y + rect.m_height/2.0;
358 double yDist = 0.0;
359 if(p.m_y < bottom)
360 yDist = bottom - p.m_y;
361 else if (top < p.m_y)
362 yDist = p.m_y - top;
363 OGDF_ASSERT(yDist >= 0);
365 double dist = xDist + yDist;
367 if(dist < minDist) {
368 minDist = dist;
369 minDistIndex = j;
373 //const RectRegion &rect = region[minDistIndex];
374 if(minDist <= m_maxAllowedDistance)
375 nearest[i].pushBack(PairRectDist(minDistIndex,minDist));
382 } // end namespace ogdf