Library of Assembled Shared Sources
quad_tree_helper.h
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43
44
45/** @class lass::spat::QuadTree
46 * A spatial container for generic objects. The object needs a traits class which
47 * contains the necessary functions to perform the quad tree management for the
48 * particular ObjectType. The traits class needs as a basis the following interface:
49 * <tt>
50 * static TAabb aabb(const TSimplePolygon3D& iP);
51 * static bool contains( const TSimplePolygon3D& iP, const TPoint& point)
52 * </tt>
53 * The above functions are only examples. The dimensionality of the primitives must
54 * match but can be of any order. So the quad tree can be used to classify in
55 * 2 and 3 dimensions. In three dimensions the more common name is OctTree.
56 *
57 * Higher level divisions can in theory be supported but the dimensional specific
58 * part must be reimplemented. Altough this is only 2 functions and could be written
59 * generally this is not yet available.
60 *
61 * @brief a Quad tree for general objects
62 * @author Tom De Muer [TDM]
63 */
64
65#ifndef LASS_GUARDIAN_OF_INCLUSION_SPAT_IMPL_QUAD_TREE_HELPER_H
66#define LASS_GUARDIAN_OF_INCLUSION_SPAT_IMPL_QUAD_TREE_HELPER_H
67
68#include "../spat_common.h"
69#include "../../prim/point_2d.h"
70#include "../../prim/point_3d.h"
71
72namespace lass
73{
74namespace spat
75{
76namespace impl
77{
78
79template <typename ObjectTraits, typename PointType>
80class QuadTreeHelper
81{
82 enum { dimension = ObjectTraits::dimension };
83protected:
84 typedef ObjectTraits TObjectTraits;
85 typedef typename ObjectTraits::TPoint TPoint;
86 typedef typename ObjectTraits::TVector TVector;
87 typedef typename ObjectTraits::TValue TValue;
88
89 static TValue minComponent(const TVector& v)
90 {
91 TValue best = TObjectTraits::coord(v, 0);
92 for (size_t k = 1; k < dimension; ++k)
93 {
94 best = std::min(best, TObjectTraits::coord(v, k));
95 }
96 return best;
97 }
98
99 static TValue maxComponent(const TVector& v)
100 {
101 TValue best = TObjectTraits::coord(v, 0);
102 for (size_t k = 1; k < dimension; ++k)
103 {
104 best = std::max(best, TObjectTraits::coord(v, k));
105 }
106 return best;
107 }
108
109 template <typename V>
110 static const V middle(const V& a, const V& b)
111 {
112 V result;
113 for (size_t k = 0; k < dimension; ++k)
114 {
115 TObjectTraits::coord(result, k, (TObjectTraits::coord(a, k) + TObjectTraits::coord(b, k)) / 2);
116 }
117 return result;
118 }
119
120 static const TValue squaredDistance(const TPoint& a, const TPoint& b)
121 {
122 TValue d = 0;
123 for (size_t k = 0; k < dimension; ++k)
124 {
125 d += num::sqr(TObjectTraits::coord(a, k) - TObjectTraits::coord(b, k));
126 }
127 return d;
128 }
129
130 static size_t entryNode(const TVector& tNear, const TVector& tMiddle)
131 {
132 const TValue tEntry = maxComponent(tNear);
133 size_t iEntry = 0;
134 for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
135 {
136 iEntry |= (TObjectTraits::coord(tMiddle, k) < tEntry) ? mask : 0;
137 }
138 return iEntry;
139 }
140
141 static size_t nextNode(size_t i, const TVector& tFar)
142 {
143 size_t nextMask = 1;
144 TValue min = TObjectTraits::coord(tFar, 0);
145 for (size_t k = 1, mask = 2; k < dimension; ++k, mask *= 2)
146 {
147 const TValue x = TObjectTraits::coord(tFar, k);
148 if (x < min)
149 {
150 min = x;
151 nextMask = mask;
152 }
153 }
154 if (i & nextMask)
155 {
156 return size_t(-1);
157 }
158 return i | nextMask;
159 }
160
161 static size_t findSubNode(const TPoint& center, const TPoint& point)
162 {
163 size_t i = 0;
164 for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
165 {
166 i |= TObjectTraits::coord(point, k) >= TObjectTraits::coord(center, k) ? mask : 0;
167 }
168 return i;
169 }
170
171 static size_t forcePositiveDirection(const TPoint& center, TPoint& support, TVector& direction)
172 {
173 size_t flipMask = 0;
174 for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
175 {
176 const TValue d = TObjectTraits::coord(direction, k);
177 if (d < 0)
178 {
179 TObjectTraits::coord(support, k,
180 2 * TObjectTraits::coord(center, k) - TObjectTraits::coord(support, k));
181 TObjectTraits::coord(direction, k, -d);
182 flipMask |= mask;
183 }
184 }
185 return flipMask;
186 }
187
188 static void nearAndFar(const TPoint& min, const TPoint& max, const TPoint& support,
189 const TVector& reciprocalDirection, TVector& tNear, TVector& tFar)
190 {
191 for (size_t k = 0; k < dimension; ++k)
192 {
193 TObjectTraits::coord(tNear, k, TObjectTraits::coord(reciprocalDirection, k) *
194 (TObjectTraits::coord(min, k) - TObjectTraits::coord(support, k)));
195 TObjectTraits::coord(tFar, k, TObjectTraits::coord(reciprocalDirection, k) *
196 (TObjectTraits::coord(max, k) - TObjectTraits::coord(support, k)));
197 }
198 }
199
200 static void childNearAndFar(TVector& tNear, TVector& tFar, const TVector& tMiddle, size_t iChild)
201 {
202 for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
203 {
204 if (iChild & mask)
205 {
206 TObjectTraits::coord(tNear, k, TObjectTraits::coord(tMiddle, k));
207 }
208 else
209 {
210 TObjectTraits::coord(tFar, k, TObjectTraits::coord(tMiddle, k));
211 }
212 }
213 }
214};
215
216
217//*
218template <typename ObjectTraits, typename T>
219class QuadTreeHelper<ObjectTraits, prim::Point2D<T> >
220{
221protected:
222 typedef ObjectTraits TObjectTraits;
223 typedef typename ObjectTraits::TPoint TPoint;
224 typedef typename ObjectTraits::TVector TVector;
225 typedef typename ObjectTraits::TValue TValue;
226 enum { dimension = 2 };
227
228 static TValue minComponent(const TVector& v)
229 {
230 return std::min(v.x, v.y);
231 }
232
233 static TValue maxComponent(const TVector& v)
234 {
235 return std::max(v.x, v.y);
236 }
237
238 template <typename V>
239 static const V middle(const V& a, const V& b)
240 {
241 return V((a.x + b.x) / 2, (a.y + b.y) / 2);
242 }
243
244 static const TValue squaredDistance(const TPoint& a, const TPoint& b)
245 {
246 return prim::squaredDistance(a, b);
247 }
248
249 static size_t entryNode(const TVector& tNear, const TVector& tMiddle)
250 {
251 const TValue tEntry = maxComponent(tNear);
252 return (tMiddle.x < tEntry ? 0x1 : 0) | (tMiddle.y < tEntry ? 0x2 : 0);
253 }
254
255 static size_t nextNode(size_t i, const TVector& tFar)
256 {
257 if (tFar.x < tFar.y)
258 {
259 return i & 0x1 ? size_t(-1) : i | 0x1;
260 }
261 else
262 {
263 return i & 0x2 ? size_t(-1) : i | 0x2;
264 }
265 }
266
267 static size_t findSubNode(const TPoint& center, const TPoint& point)
268 {
269 return (point.x >= center.x ? 0x1 : 0x0) | (point.y >= center.y ? 0x2 : 0x0);
270 }
271
272 static size_t forcePositiveDirection(const TPoint& center, TPoint& support, TVector& direction)
273 {
274 size_t flipMask = 0;
275 if (direction.x < 0)
276 {
277 support.x = 2 * center.x - support.x;
278 direction.x = -direction.x;
279 flipMask |= 0x1;
280 }
281 if (direction.y < 0)
282 {
283 support.y = 2 * center.y - support.y;
284 direction.y = -direction.y;
285 flipMask |= 0x2;
286 }
287 return flipMask;
288 }
289
290 /* Swap components so that near[k] <= far[k], and return according flipMask.
291 *
292 * When traversing the nodes, we always assume that near[k] <= far[k] so that
293 * we go from "left" to "right" in the tree. If this is not the case, we
294 * virtually flip the whole tree left to right, and use the flipMask to select
295 * the correct child nodes.
296 */
297 static size_t forceMinToMax(TVector& near, TVector& far)
298 {
299 size_t flipMask = 0;
300 if (near.x > far.x)
301 {
302 std::swap(near.x, far.x);
303 flipMask |= 0x1;
304 }
305 if (near.y > far.y)
306 {
307 std::swap(near.y, far.y);
308 flipMask |= 0x2;
309 }
310 return flipMask;
311 }
312
313 static void nearAndFar(const TPoint& min, const TPoint& max, const TPoint& support,
314 const TVector& reciprocalDirection, TVector& tNear, TVector& tFar)
315 {
316 tNear = reciprocalDirection * (min - support);
317 tFar = reciprocalDirection * (max - support);
318 }
319
320 static void childNearAndFar(TVector& tNear, TVector& tFar, const TVector& tMiddle, size_t iChild)
321 {
322 (iChild & 0x1 ? tNear : tFar).x = tMiddle.x;
323 (iChild & 0x2 ? tNear : tFar).y = tMiddle.y;
324 }
325};
326
327
328
329template <typename ObjectTraits, typename T>
330class QuadTreeHelper<ObjectTraits, prim::Point3D<T> >
331{
332 enum { dimension = 3 };
333protected:
334 typedef ObjectTraits TObjectTraits;
335 typedef typename ObjectTraits::TPoint TPoint;
336 typedef typename ObjectTraits::TVector TVector;
337 typedef typename ObjectTraits::TValue TValue;
338
339 static TValue minComponent(const TVector& v)
340 {
341 return std::min(std::min(v.x, v.y), v.z);
342 }
343
344 static TValue maxComponent(const TVector& v)
345 {
346 return std::max(std::max(v.x, v.y), v.z);
347 }
348
349 template <typename V>
350 static const V middle(const V& a, const V& b)
351 {
352 return V(
353 (a.x + b.x) / 2,
354 (a.y + b.y) / 2,
355 (a.z + b.z) / 2);
356 }
357
358 static const TValue squaredDistance(const TPoint& a, const TPoint& b)
359 {
360 return prim::squaredDistance(a, b);
361 }
362
363 static size_t entryNode(const TVector& tNear, const TVector& tMiddle)
364 {
365 const TValue tEntry = maxComponent(tNear);
366 return (tMiddle.x < tEntry ? 0x1 : 0)
367 | (tMiddle.y < tEntry ? 0x2 : 0)
368 | (tMiddle.z < tEntry ? 0x4 : 0);
369 }
370
371 static size_t nextNode(size_t i, const TVector& tFar)
372 {
373 if (tFar.x < tFar.y && tFar.x < tFar.z)
374 {
375 return i & 0x1 ? size_t(-1) : i | 0x1;
376 }
377 else if (tFar.y < tFar.z)
378 {
379 return i & 0x2 ? size_t(-1) : i | 0x2;
380 }
381 else
382 {
383 return i & 0x4 ? size_t(-1) : i | 0x4;
384 }
385 }
386
387 static size_t findSubNode(const TPoint& center, const TPoint& point)
388 {
389 return (point.x >= center.x ? 0x1 : 0x0)
390 | (point.y >= center.y ? 0x2 : 0x0)
391 | (point.z >= center.z ? 0x4 : 0x0);
392 }
393
394 static size_t forcePositiveDirection(const TPoint& center, TPoint& support, TVector& direction)
395 {
396 size_t flipMask = 0;
397 for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
398 {
399 if (direction[k] < 0)
400 {
401 support[k] = 2 * center[k] - support[k];
402 direction[k] = -direction[k];
403 flipMask |= mask;
404 }
405 }
406 return flipMask;
407 }
408
409 /* Swap components so that near[k] <= far[k], and return according flipMask.
410 *
411 * When traversing the nodes, we always assume that near[k] <= far[k] so that
412 * we go from "left" to "right" in the tree. If this is not the case, we
413 * virtually flip the whole tree left to right, and use the flipMask to select
414 * the correct child nodes.
415 */
416 static size_t forceMinToMax(TVector& near, TVector& far)
417 {
418 size_t flipMask = 0;
419 if (near.x > far.x)
420 {
421 std::swap(near.x, far.x);
422 flipMask |= 0x1;
423 }
424 if (near.y > far.y)
425 {
426 std::swap(near.y, far.y);
427 flipMask |= 0x2;
428 }
429 if (near.z > far.z)
430 {
431 std::swap(near.z, far.z);
432 flipMask |= 0x4;
433 }
434 return flipMask;
435 }
436
437 static void nearAndFar(const TPoint& min, const TPoint& max, const TPoint& support,
438 const TVector& reciprocalDirection, TVector& tNear, TVector& tFar)
439 {
440 tNear = reciprocalDirection * (min - support);
441 tFar = reciprocalDirection * (max - support);
442 }
443
444 static void childNearAndFar(TVector& tNear, TVector& tFar, const TVector& tMiddle, size_t iChild)
445 {
446 (iChild & 0x1 ? tNear : tFar).x = tMiddle.x;
447 (iChild & 0x2 ? tNear : tFar).y = tMiddle.y;
448 (iChild & 0x4 ? tNear : tFar).z = tMiddle.z;
449 }
450};
451/**/
452}
453}
454}
455
456#endif
457
458// EOF
T sqr(const T &x)
return x * x
Definition basic_ops.h:162
spatial subdivisions, quadtrees, octrees, meshes in 2D and 3D, triangulators, ...
Definition aabb8_tree.h:80
Library for Assembled Shared Sources.
Definition config.h:53