6 * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $
7 ***************************************************************/
10 * \brief Implements class NearestRectangleFinder
12 * \author Carsten Gutwenger
15 * This file is part of the Open Graph Drawing Framework (OGDF).
19 * See README.txt in the root directory of the OGDF installation for details.
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
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.
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>
47 #include <ogdf/basic/List.h>
48 #include <ogdf/basic/BoundedStack.h>
54 //---------------------------------------------------------
56 // represents a pair of a coordinate (x or y) and the index
58 //---------------------------------------------------------
59 struct OGDF_EXPORT
NearestRectangleFinder::PairCoordId
61 PairCoordId(double coord
, int index
) {
68 friend ostream
&operator<<(ostream
&os
, const PairCoordId
&p
) {
69 os
<< "(" << p
.m_coord
<< "," << p
.m_index
<< ")";
78 //---------------------------------------------------------
80 // comparer class for sorting PairCoordId according to
81 // decreasing coordinate
82 //---------------------------------------------------------
83 class NearestRectangleFinder::CoordComparer
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 //---------------------------------------------------------
100 // comparer class for sorting points (given by index) by
101 // decreasing y-coordinate
102 //---------------------------------------------------------
103 class NearestRectangleFinder::YCoordComparer
106 YCoordComparer(const Array
<DPoint
> &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
;
121 const Array
<DPoint
> *m_point
;
126 //---------------------------------------------------------
127 // NearestRectangleFinder
128 //---------------------------------------------------------
130 void NearestRectangleFinder::find(
131 const Array
<RectRegion
> ®ion
,
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 ...
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
)
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
);
200 while(nextBottom
.valid() && (*nextBottom
).m_coord
> p
.m_y
) {
201 active
.del(posInActive
[(*nextBottom
).m_index
]);
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;
219 xDist
= left
- p
.m_x
;
220 else if (right
< p
.m_x
)
221 xDist
= p
.m_x
- right
;
223 if(xDist
< minDist
) {
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())
243 if((*itTop
).m_coord
< p
.m_y
- minDist
)
244 itTop
= ListIterator
<PairCoordId
>();
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;
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);
264 // update visited rectangles
265 visitedRectangles
.push((*itTop
).m_index
);
266 distance
[(*itTop
).m_index
] = dist
;
274 if((*itBottom
).m_coord
> p
.m_y
+ minDist
)
275 itBottom
= ListIterator
<PairCoordId
>();
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;
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);
295 // update visited rectangles
296 visitedRectangles
.push((*itBottom
).m_index
);
297 distance
[(*itBottom
).m_index
] = dist
;
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();
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
> ®ion
,
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;
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;
360 yDist
= bottom
- p
.m_y
;
361 else if (top
< p
.m_y
)
363 OGDF_ASSERT(yDist
>= 0);
365 double dist
= xDist
+ yDist
;
373 //const RectRegion &rect = region[minDistIndex];
374 if(minDist
<= m_maxAllowedDistance
)
375 nearest
[i
].pushBack(PairRectDist(minDistIndex
,minDist
));
382 } // end namespace ogdf