Library of Assembled Shared Sources
 
Loading...
Searching...
No Matches
quad_tree.inl
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-2026 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_QUAD_TREE_INL
66#define LASS_GUARDIAN_OF_INCLUSION_SPAT_QUAD_TREE_INL
67
68#include "spat_common.h"
69#include "quad_tree.h"
70
71namespace lass
72{
73namespace spat
74{
75
76// --- public --------------------------------------------------------------------------------------
77
78template <typename O, typename OT, typename SH>
79QuadTree<O, OT, SH>::QuadTree(const TSplitHeuristics& heuristics):
80 SH(heuristics),
81 aabb_(),
82 root_(0),
83 end_(),
84 nodesAllocator_(new TNodesAllocator(sizeof(QuadNode) * numChildren)),
85 numObjects_(0)
86{
87}
88
89
90
91 /** empty quadtree with fixed bounding box
92 */
93template <typename O, typename OT, typename SH>
94QuadTree<O, OT, SH>::QuadTree(const TAabb& aabb, const TSplitHeuristics& heuristics):
95 SH(heuristics),
96 aabb_(aabb),
97 root_(0),
98 end_(),
99 nodesAllocator_(new TNodesAllocator(sizeof(QuadNode) * numChildren)),
100 numObjects_(0)
101{
102 root_ = new QuadNode(aabb, *nodesAllocator_);
103}
104
105
106
107/** empty quadtree with fixed bounding box and end iterator.
108 */
109template <typename O, typename OT, typename SH>
110QuadTree<O, OT, SH>::QuadTree(const TAabb& aabb, const TObjectIterator end, const TSplitHeuristics& heuristics):
111 SH(heuristics),
112 aabb_(aabb),
113 root_(0),
114 end_(end),
115 nodesAllocator_(new TNodesAllocator(sizeof(QuadNode) * numChildren)),
116 numObjects_(0)
117{
118 root_ = new QuadNode(aabb, *nodesAllocator_);
119}
120
121
122
123/** quadtree from objects, with computed bounding box
124 */
125template <typename O, typename OT, typename SH>
126QuadTree<O, OT, SH>::QuadTree(TObjectIterator first, TObjectIterator last, const TSplitHeuristics& heuristics):
127 SH(heuristics),
128 root_(0),
129 end_(last),
130 nodesAllocator_(new TNodesAllocator(sizeof(QuadNode) * numChildren)),
131 numObjects_(0)
133 aabb_ = TObjectTraits::aabbEmpty();
134 for (TObjectIterator i = first; i != last; ++i)
136 aabb_ = TObjectTraits::aabbJoin(aabb_, TObjectTraits::objectAabb(i));
137 }
138
139 // growth hack! Slightly grow the box with a fraction of the diagonal, so that we don't have any sides of zero length.
140 //*
141 TPoint min = TObjectTraits::aabbMin(aabb_);
142 TPoint max = TObjectTraits::aabbMax(aabb_);
143 const TValue growth = num::sqrt(squaredDistance(min, max)) / 1000;
144 for (size_t k = 0; k < dimension; ++k)
146 TObjectTraits::coord(min, k, TObjectTraits::coord(min, k) - growth);
147 TObjectTraits::coord(max, k, TObjectTraits::coord(max, k) + growth);
148 }
149 aabb_ = TObjectTraits::aabbMake(min, max);
150 /**/
151
152 root_ = new QuadNode(aabb_, *nodesAllocator_);
153 while (first != last)
154 {
155 add(first++);
157}
158
160/** move constructor
161 */
162template <typename O, typename OT, typename SH>
163QuadTree<O, OT, SH>::QuadTree(TSelf&& other) noexcept:
164 SH(std::forward<SH>(other)),
165 aabb_(other.aabb_),
166 root_(other.root_),
167 end_(other.end_),
168 nodesAllocator_(std::move(other.nodesAllocator_)),
169 numObjects_(other.numObjects_)
170{
171 other.root_ = nullptr;
172}
173
174
175template <typename O, typename OT, typename SH>
176QuadTree<O, OT, SH>::~QuadTree()
177{
178 delete root_;
179}
180
181
182/** move constructor
183 */
184template <typename O, typename OT, typename SH>
185QuadTree<O, OT, SH>& QuadTree<O, OT, SH>::operator=(TSelf&& other) noexcept
186{
187 TSelf temp(std::move(other));
188 swap(temp);
189 return *this;
190}
191
192
193
194template <typename O, typename OT, typename SH>
195void QuadTree<O, OT, SH>::reset()
196{
197 QuadTree temp(aabb_, end_, static_cast<const SH&>(*this));
198 swap(temp);
199}
200
201
202
203template <typename O, typename OT, typename SH>
204void QuadTree<O, OT, SH>::reset(TObjectIterator first, TObjectIterator last)
205{
206 QuadTree temp(first, last, static_cast<const SH&>(*this));
207 swap(temp);
208}
209
210
211
212template <typename O, typename OT, typename SH>
213void QuadTree<O, OT, SH>::add(TObjectIterator object)
214{
215 LASS_ASSERT(root_);
216 if (!TObjectTraits::aabbContains(aabb_, TObjectTraits::objectAabb(object)))
217 {
218 LASS_THROW("object not within bounding box of tree");
219 }
220 root_->add(object, *this);
221 ++numObjects_;
222}
223
224
225
226template <typename O, typename OT, typename SH>
227void QuadTree<O, OT, SH>::remove(TObjectIterator object)
228{
229 LASS_ASSERT(root_);
230 if (root_->remove(object))
231 {
232 --numObjects_;
233 }
234}
235
236
237
238template <typename O, typename OT, typename SH>
239bool QuadTree<O, OT, SH>::contains(const TPoint& point, const TInfo* info) const
240{
241 LASS_ASSERT(root_);
242
243 if (!TObjectTraits::aabbContains(aabb_, point))
244 {
245 return false;
246 }
247
248 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
249 QuadNode* node = root_;
250 while (!node->isLeaf())
251 {
252 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_NODE;
253 node = &node->children[this->findSubNode(node->center(), point)];
254 LASS_ASSERT(node); // if it's not a leaf, there should be a child node
255 }
256
257 for (typename TObjectIterators::const_iterator i = node->data.begin(); i != node->data.end(); ++i)
258 {
259 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
260 if (TObjectTraits::objectContains(*i, point, info))
261 {
262 return true;
263 }
264 }
265 return false;
266}
267
268
269
270template <typename O, typename OT, typename SH>
271template <typename OutputIterator>
272OutputIterator QuadTree<O, OT, SH>::find(const TPoint& point, OutputIterator result, const TInfo* info) const
273{
274 LASS_ASSERT(root_);
275
276 if (!TObjectTraits::aabbContains(aabb_, point))
277 {
278 return result;
279 }
280
281 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
282 QuadNode* node = root_;
283 while (!node->isLeaf())
284 {
285 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_NODE;
286 node = &node->children[this->findSubNode(node->center(), point)];
287 LASS_ASSERT(node); // if it's not a leaf, there should be a child node
288 }
289
290 for (typename TObjectIterators::const_iterator i = node->data.begin(); i != node->data.end(); ++i)
291 {
292 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
293 if (TObjectTraits::objectContains(*i, point, info))
294 {
295 *result++ = *i;
296 }
297 }
298 return result;
299}
300
301
302
303/** @warning As this algorithm visits multiple leaf nodes, it may find duplicate objects.
304 * This algorithm doesn't care. But if you do, you can use insert_iterators to a set.
305 */
306template <typename O, typename OT, typename SH>
307template <typename OutputIterator>
308OutputIterator QuadTree<O, OT, SH>::find(const TAabb& box, OutputIterator result, const TInfo* info) const
309{
310 LASS_ASSERT(root_);
311 if (!TObjectTraits::aabbIntersects(aabb_, box))
312 {
313 return result;
314 }
315 return doFind(*root_, box, result, info);
316}
317
318
319
320/** @warning As this algorithm visits multiple leaf nodes, it may find duplicate objects.
321 * This algorithm doesn't care. But if you do, you can use insert_iterators to a set.
322 */
323template <typename O, typename OT, typename SH>
324template <typename OutputIterator>
325OutputIterator QuadTree<O, OT, SH>::find(const TRay& ray, TParam tMin, TParam tMax, OutputIterator result, const TInfo* info) const
326{
327 LASS_ASSERT(root_);
328
329 const TPoint min = TObjectTraits::aabbMin(aabb_);
330 const TPoint max = TObjectTraits::aabbMax(aabb_);
331 const TPoint support = TObjectTraits::raySupport(ray);
332 const TVector direction = TObjectTraits::rayDirection(ray);
333 const TVector invDirection = TObjectTraits::vectorReciprocal(direction);
334
335 TVector tNear = invDirection * (min - support);
336 TVector tFar = invDirection * (max - support);
337 const size_t flipMask = this->forceMinToMax(tNear, tFar);
338
339 return doFind(*root_, ray, tMin, tMax, result, info, tNear, tFar, support, invDirection, flipMask);
340}
341
342
343template <typename O, typename OT, typename SH>
344const typename QuadTree<O, OT, SH>::TObjectIterator
345QuadTree<O, OT, SH>::intersect(
346 const TRay& ray, TReference t, TParam tMin, const TInfo* info) const
347{
348 LASS_ASSERT(root_);
349
350 const TPoint min = TObjectTraits::aabbMin(aabb_);
351 const TPoint max = TObjectTraits::aabbMax(aabb_);
352 const TPoint support = TObjectTraits::raySupport(ray);
353 const TVector direction = TObjectTraits::rayDirection(ray);
354 const TVector invDirection = TObjectTraits::vectorReciprocal(direction);
355
356 TVector tNear = invDirection * (min - support);
357 TVector tFar = invDirection * (max - support);
358 const size_t flipMask = this->forceMinToMax(tNear, tFar);
359
360 return doIntersect(*root_, ray, t, tMin, info, tNear, tFar, support, invDirection, flipMask);
361}
362
363
364
365template <typename O, typename OT, typename SH>
366bool QuadTree<O, OT, SH>::intersects(
367 const TRay& ray, TParam tMin, TParam tMax, const TInfo* info) const
368{
369 LASS_ASSERT(root_);
370
371 const TPoint min = TObjectTraits::aabbMin(aabb_);
372 const TPoint max = TObjectTraits::aabbMax(aabb_);
373 const TPoint support = TObjectTraits::raySupport(ray);
374 const TVector direction = TObjectTraits::rayDirection(ray);
375 const TVector invDirection = TObjectTraits::vectorReciprocal(direction);
376
377 TVector tNear = invDirection * (min - support);
378 TVector tFar = invDirection * (max - support);
379 const size_t flipMask = this->forceMinToMax(tNear, tFar);
380
381 return doIntersects(*root_, ray, tMin, tMax, info, tNear, tFar, support, invDirection, flipMask);
382}
383
384
385
386template <typename O, typename OT, typename SH>
387const typename QuadTree<O, OT, SH>::Neighbour
388QuadTree<O, OT, SH>::nearestNeighbour(const TPoint& point, const TInfo* info) const
389{
390 LASS_ASSERT(root_);
391 Neighbour nearest(end_, std::numeric_limits<TValue>::infinity());
392 doNearestNeighbour(*root_, point, info, nearest);
393 return nearest;
394}
395
396
397
398template <typename O, typename OT, typename SH>
399template <typename RandomAccessIterator>
400RandomAccessIterator
401QuadTree<O, OT, SH>::rangeSearch(
402 const TPoint& target, TParam maxRadius, size_t maxCount, RandomAccessIterator first,
403 const TInfo* info) const
404{
405 LASS_ASSERT(root_);
406 if (maxRadius == 0)
407 {
408 return first;
409 }
410 TValue squaredRadius = maxRadius * maxRadius;
411 return doRangeSearch(*root_, target, squaredRadius, maxCount, first, first, info);
412}
413
414
415
416template <typename O, typename OT, typename SH>
417size_t QuadTree<O, OT, SH>::objectCount() const
418{
419 LASS_ASSERT(root_);
420 return root_->objectCount();
421}
422
423
424
425template <typename O, typename OT, typename SH>
426const typename QuadTree<O, OT, SH>::TAabb&
427QuadTree<O, OT, SH>::aabb() const
428{
429 return aabb_;
430}
431
432
433
434template <typename O, typename OT, typename SH>
436{
437 LASS_ASSERT(root_);
438 return root_->depth();
439}
440
441
442
443
444template <typename O, typename OT, typename SH>
445const typename QuadTree<O, OT, SH>::TValue
446QuadTree<O, OT, SH>::averageDepth() const
447{
448 LASS_ASSERT(root_);
449 return root_->averageDepth();
450}
451
452
453
454template <typename O, typename OT, typename SH>
455bool QuadTree<O, OT, SH>::isEmpty() const
456{
457 return numObjects_ == 0;
458}
459
460
461
462template <typename O, typename OT, typename SH>
463void QuadTree<O, OT, SH>::swap(QuadTree& other)
464{
465 SH::swap(other);
466 nodesAllocator_.swap(other.nodesAllocator_);
467 std::swap(aabb_, other.aabb_);
468 std::swap(root_, other.root_);
469 std::swap(end_, other.end_);
470 std::swap(numObjects_, other.numObjects_);
471}
472
473
474
475template <typename O, typename OT, typename SH>
476const typename QuadTree<O, OT, SH>::TObjectIterator
477QuadTree<O, OT, SH>::end() const
478{
479 return end_;
480}
481
482
483
484// --- private -------------------------------------------------------------------------------------
485
486
487template <typename O, typename OT, typename SH>
488template <typename OutputIterator>
489OutputIterator QuadTree<O, OT, SH>::doFind(
490 const QuadNode& node, const TAabb& box, OutputIterator output,
491 const TInfo* info) const
492{
493 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
494
495 if (node.isLeaf())
496 {
497 const typename TObjectIterators::const_iterator end = node.data.end();
498 for (typename TObjectIterators::const_iterator i = node.data.begin(); i != end; ++i)
499 {
500 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
501 if (TObjectTraits::objectIntersects(*i, box, info))
502 {
503 *output++ = *i;
504 }
505 }
506 return output;
507 }
508 for (size_t i = 0; i < numChildren; ++i)
509 {
510 if (node.children[i].bounds.intersects(box))
511 {
512 output = doFind(node.children[i], box, output, info);
513 }
514 }
515 return output;
516}
517
518
519
520template <typename O, typename OT, typename SH>
521template <typename OutputIterator>
522OutputIterator QuadTree<O, OT, SH>::doFind(
523 const QuadNode& node,
524 const TRay& ray, TParam tMin, TParam tMax, OutputIterator output, const TInfo* info,
525 const TVector& tNear, const TVector& tFar, const TPoint& support, const TVector& invDir, size_t flipMask) const
526{
527 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
528
529 const TValue tNearMax = this->maxComponent(tNear);
530 const TValue tFarMin = this->minComponent(tFar);
531 if (tNearMax > tFarMin * (1 + num::sign(tFarMin) * 1e-3f))
532 {
533 return output;
534 }
535
536 if (node.isLeaf())
537 {
538 const typename TObjectIterators::const_iterator end = node.data.end();
539 for (typename TObjectIterators::const_iterator i = node.data.begin(); i != end; ++i)
540 {
541 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
542 if (TObjectTraits::objectIntersects(*i, ray, tMin, tMax, info))
543 {
544 *output++ = *i;
545 }
546 }
547 return output;
548 }
549
550 const TVector tMiddle = invDir * (node.center() - support);
551#if !defined(NDEBUG)
552 for (size_t k = 0; k < dimension; ++k)
553 {
554 LASS_ASSERT((tNear[k] < tMiddle[k] && tMiddle[k] < tFar[k]) || (num::isInf(tNear[k]) && num::isInf(tMiddle[k]) && num::isInf(tFar[k])));
555 }
556#endif
557
558 size_t i = this->entryNode(tNear, tMiddle);
559 do
560 {
561 const QuadNode& child = node.children[i ^ flipMask];
562 TVector tChildNear = tNear;
563 TVector tChildFar = tFar;
564 this->childNearAndFar(tChildNear, tChildFar, tMiddle, i);
565 output = doFind(child, ray, tMin, tMax, output, info, tChildNear, tChildFar, support, invDir, flipMask);
566 i = this->nextNode(i, tChildFar);
567 }
568 while (i != size_t(-1));
569
570 return output;
571}
572
573
574
575/**
576 * Reference: J. Revelles, C. Urena, and M. Lastra. An efficient parametric algorithm for octree
577 * traversal. In Eighth International Conference in Central Europe on Computer Graphics,
578 * Visualization and Interactive Digital Media (WSCG 2000), pages 212--219, Plzen, Czech Republic,
579 * 2000.
580 */
581template <typename O, typename OT, typename SH>
582const typename QuadTree<O, OT, SH>::TObjectIterator
583QuadTree<O, OT, SH>::doIntersect(
584 const QuadNode& node,
585 const TRay& ray, TReference t, TParam tMin, const TInfo* info,
586 const TVector& tNear, const TVector& tFar, const TPoint& support, const TVector& invDir, size_t flipMask) const
587{
588 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
589
590 const TValue tNearMax = std::max(this->maxComponent(tNear), tMin);
591 const TValue tFarMin = this->minComponent(tFar);
592 if (tNearMax > tFarMin * (1 + num::sign(tFarMin) * 1e-3f))
593 {
594 return end_;
595 }
596
597 if (node.isLeaf())
598 {
599 const size_t n = node.data.size();
600 TValue tBest = 0;
601 TObjectIterator best = end_;
602 for (size_t i = 0; i < n; ++i)
603 {
604 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
605 TValue tCandidate = 0;
606 if (TObjectTraits::objectIntersect(node.data[i], ray, tCandidate, tMin, info))
607 {
608 LASS_ASSERT(tCandidate > tMin);
609 if (best == end_ || tCandidate < tBest)
610 {
611 LASS_ASSERT(tCandidate > tMin);
612 best = node.data[i];
613 tBest = tCandidate;
614 }
615 }
616 }
617
618 if (best != end_)
619 {
620 t = tBest;
621 }
622 return best;
623 }
624
625 const TVector tMiddle = invDir * (node.center() - support);
626#if !defined(NDEBUG)
627 for (size_t k = 0; k < dimension; ++k)
628 {
629 LASS_ASSERT((tNear[k] < tMiddle[k] && tMiddle[k] < tFar[k]) || (num::isInf(tNear[k]) && num::isInf(tMiddle[k]) && num::isInf(tFar[k])));
630 }
631#endif
632
633 TObjectIterator best = end_;
634 TValue tBest = 0;
635 size_t i = this->entryNode(tNear, tMiddle);
636 do
637 {
638 const QuadNode& child = node.children[i ^ flipMask];
639 TVector tChildNear = tNear;
640 TVector tChildFar = tFar;
641 this->childNearAndFar(tChildNear, tChildFar, tMiddle, i);
642
643 TValue tCandidate;
644 TObjectIterator candidate = doIntersect(
645 child, ray, tCandidate, tMin, info, tChildNear, tChildFar, support, invDir, flipMask);
646 if (candidate != end_)
647 {
648 if (best == end_ || tCandidate < tBest)
649 {
650 best = candidate;
651 tBest = tCandidate;
652 }
653 }
654
655 const TValue tChildFarMin = this->minComponent(tChildFar);
656 if (best != end_ && tBest < tChildFarMin * (1 - num::sign(tFarMin) * 1e-3f))
657 {
658 t = tBest;
659 return best;
660 }
661
662 i = this->nextNode(i, tChildFar);
663 }
664 while (i != size_t(-1));
665
666 if (best != end_)
667 {
668 t = tBest;
669 }
670 return best;
671}
672
673
674
675template <typename O, typename OT, typename SH>
676bool QuadTree<O, OT, SH>::doIntersects(
677 const QuadNode& node,
678 const TRay& ray, TParam tMin, TParam tMax, const TInfo* info,
679 const TVector& tNear, const TVector& tFar, const TPoint& support, const TVector& invDir, size_t flipMask) const
680{
681 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
682
683 const TValue tNearMax = std::max(this->maxComponent(tNear), tMin);
684 const TValue tFarMin = std::min(this->minComponent(tFar), tMax);
685 if (tNearMax > tFarMin * (1 + num::sign(tFarMin) * 1e-3f))
686 {
687 return false;
688 }
689
690 if (node.isLeaf())
691 {
692 const size_t n = node.data.size();
693 for (size_t i = 0; i < n; ++i)
694 {
695 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
696 if (TObjectTraits::objectIntersects(node.data[i], ray, tMin, tMax, info))
697 {
698 return true;
699 }
700 }
701
702 return false;
703 }
704
705 const TVector tMiddle = invDir * (node.center() - support);
706#if !defined(NDEBUG)
707 for (size_t k = 0; k < dimension; ++k)
708 {
709 LASS_ASSERT((tNear[k] < tMiddle[k] && tMiddle[k] < tFar[k]) || (num::isInf(tNear[k]) && num::isInf(tMiddle[k]) && num::isInf(tFar[k])));
710 }
711#endif
712
713 size_t i = this->entryNode(tNear, tMiddle);
714 do
715 {
716 const QuadNode& child = node.children[i ^ flipMask];
717 TVector tChildNear = tNear;
718 TVector tChildFar = tFar;
719 this->childNearAndFar(tChildNear, tChildFar, tMiddle, i);
720 if (doIntersects(child, ray, tMin, tMax, info, tChildNear, tChildFar, support, invDir, flipMask))
721 {
722 return true;
723 }
724 i = this->nextNode(i, tChildFar);
725 }
726 while (i != size_t(-1));
727
728 return false;
729}
730
731
732
733template <typename O, typename OT, typename SH>
734void QuadTree<O, OT, SH>::doNearestNeighbour(
735 const QuadNode& node, const TPoint& point, const TInfo* info, Neighbour& best) const
736{
737 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
738 if (node.isLeaf())
739 {
740 const size_t n = node.data.size();
741 for (size_t i = 0; i < n; ++i)
742 {
743 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
744 const TValue squaredDistance =
745 TObjectTraits::objectSquaredDistance(node.data[i], point, info);
746 if (squaredDistance < best.squaredDistance())
747 {
748 best = Neighbour(node.data[i], squaredDistance);
749 }
750 }
751 }
752 else
753 {
754 // first, determine squared distances to children and find closest one.
755 TValue sqrNodeDists[numChildren];
756 size_t nearestNode = 0;
757 for (size_t i = 0; i < numChildren; ++i)
758 {
759 sqrNodeDists[i] = node.children[i].sqrDistance(point);
760 if (sqrNodeDists[i] < sqrNodeDists[nearestNode])
761 {
762 nearestNode = i;
763 }
764 }
765
766 // visit closest node first, and then the others.
767 if (sqrNodeDists[nearestNode] < best.squaredDistance())
768 {
769 doNearestNeighbour(node.children[nearestNode], point, info, best);
770 }
771 for (size_t i = 0; i < numChildren; ++i)
772 {
773 if (sqrNodeDists[i] < best.squaredDistance() && i != nearestNode)
774 {
775 doNearestNeighbour(node.children[i], point, info, best);
776 }
777 }
778 }
779}
780
781
782
783template <typename O, typename OT, typename SH>
784template <typename RandomIterator>
785RandomIterator QuadTree<O, OT, SH>::doRangeSearch(
786 const QuadNode& node, const TPoint& target, TReference squaredRadius, size_t maxCount,
787 RandomIterator first, RandomIterator last, const TInfo* info) const
788{
789 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
790 LASS_ASSERT(squaredRadius >= 0);
791
792 if (node.isLeaf())
793 {
794 const size_t n = node.data.size();
795 for (size_t i = 0; i < n; ++i)
796 {
797 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
798 const TValue sqrDist = TObjectTraits::objectSquaredDistance(node.data[i], target, info);
799 if (sqrDist < squaredRadius)
800 {
801 Neighbour candidate(node.data[i], sqrDist);
802// TODO: use a push_heap_unique to avoid duplicates instead of naive search [Bramz]
803// https://sourceforge.net/tracker2/?func=detail&aid=2517748&group_id=118315&atid=680768
804 if (std::find(first, last, candidate) == last)
805 {
806 *last++ = candidate;
807 std::push_heap(first, last);
808 LASS_ASSERT(last >= first);
809 if (static_cast<size_t>(last - first) > maxCount)
810 {
811 std::pop_heap(first, last);
812 --last;
813 squaredRadius = first->squaredDistance();
814 }
815 }
816 }
817 }
818 return last;
819 }
820
821 // first, determine squared distances to children and find closest one.
822 TValue sqrNodeDists[numChildren];
823 size_t nearestNode = 0;
824 for (size_t i = 0; i < numChildren; ++i)
825 {
826 sqrNodeDists[i] = node.children[i].sqrDistance(target);
827 if (sqrNodeDists[i] < sqrNodeDists[nearestNode])
828 {
829 nearestNode = i;
830 }
831 }
832
833 if (sqrNodeDists[nearestNode] < squaredRadius)
834 {
835 last = doRangeSearch(node.children[nearestNode], target, squaredRadius, maxCount, first, last, info);
836 }
837 for (size_t i = 0; i < numChildren; ++i)
838 {
839 if (sqrNodeDists[i] < squaredRadius && i != nearestNode)
840 {
841 last = doRangeSearch(node.children[i], target, squaredRadius, maxCount, first, last, info);
842 }
843 }
844 return last;
845}
846
847
848
849// --- QuadNode ------------------------------------------------------------------------------------
850
851template <typename O, typename OT, typename SH>
852QuadTree<O, OT, SH>::QuadNode::QuadNode(const TAabb& bounds, TNodesAllocator& allocator):
853 bounds(bounds),
854 children(0),
855 allocator_(allocator)
856{
857}
858
859
860
861template <typename O, typename OT, typename SH>
862QuadTree<O, OT, SH>::QuadNode::~QuadNode()
863{
864 deleteChildren(numChildren);
865}
866
867
868
869template <typename O, typename OT, typename SH>
870const typename QuadTree<O, OT, SH>::TPoint
871QuadTree<O, OT, SH>::QuadNode::center() const
872{
873 return QuadTree::middle(TObjectTraits::aabbMin(bounds), TObjectTraits::aabbMax(bounds));
874}
875
876
877
878template <typename O, typename OT, typename SH>
879const typename QuadTree<O, OT, SH>::TValue
880QuadTree<O, OT, SH>::QuadNode::sqrDistance(const TPoint& point) const
881{
882 TValue sqrDist = 0;
883 const TPoint& min = TObjectTraits::aabbMin(bounds);
884 const TPoint& max = TObjectTraits::aabbMax(bounds);
885 for (size_t k = 0; k < dimension; ++k)
886 {
887 const TValue x = TObjectTraits::coord(point, k);
888 const TValue d = std::max(x - TObjectTraits::coord(max, k), TObjectTraits::coord(min, k) - x);
889 if (d > 0)
890 {
891 sqrDist += d * d;
892 }
893 }
894 return sqrDist;
895}
896
897
898
899template <typename O, typename OT, typename SH>
900size_t QuadTree<O, OT, SH>::QuadNode::objectCount() const
901{
902 size_t cumulCount = data.size();
903 if (!isLeaf())
904 {
905 for (size_t i=0;i<numChildren;++i)
906 {
907 cumulCount += children[i].objectCount();
908 }
909 }
910 return cumulCount;
911}
912
913
914
915template <typename O, typename OT, typename SH>
916void QuadTree<O, OT, SH>::QuadNode::add(
917 TObjectIterator object, const TSplitHeuristics& heuristics, size_t level, bool mayDecompose)
918{
919 if (isLeaf())
920 {
921 data.push_back(object);
922 if (mayDecompose && data.size() > heuristics.maxObjectsPerLeaf() && level < heuristics.maxDepth())
923 {
924 decompose(heuristics, level);
925 }
926 }
927 else
928 {
929 bool isAdded = false;
930 for (size_t i=0;i<numChildren;++i)
931 {
932 if (TObjectTraits::objectIntersects(object, children[i].bounds, 0))
933 {
934 children[i].add(object, heuristics, level + 1);
935 isAdded = true;
936 }
937 }
938 LASS_ENFORCE(isAdded)("didn't overlap with any of the child nodes");
939 }
940}
941
942
943
944/** @return true if object was indeed removed, false if it was never found i guess.
945 */
946template <typename O, typename OT, typename SH>
947bool QuadTree<O, OT, SH>::QuadNode::remove(
948 TObjectIterator object)
949{
950 bool isRemoved = false;
951 if (isLeaf())
952 {
953 typename TObjectIterators::iterator last = std::remove(data.begin(), data.end(), object);
954 isRemoved = last != data.end();
955 data.erase(last, data.end());
956 }
957 else
958 {
959 for (size_t i=0;i<numChildren;++i)
960 {
961 if (TObjectTraits::objectIntersects(object, children[i].bounds, 0))
962 {
963 isRemoved |= children[i].remove(object);
964 }
965 }
966 }
967 return isRemoved;
968}
969
970
971
972template <typename O, typename OT, typename SH>
973void QuadTree<O, OT, SH>::QuadNode::decompose(const TSplitHeuristics& heuristics, size_t level)
974{
975 if (!isLeaf())
976 {
977 return;
978 }
979
980 makeChildren();
981
982 //const size_t maxCopies = numChildren * data.size() * 2 / 3;
983 for (typename TObjectIterators::iterator vit = data.begin(); vit != data.end(); ++vit)
984 {
985 /* for each object we test wether it is contained in one of the
986 * subnodes of the quadnode. If it is even partially in one then move
987 * the object down the tree, but only one level
988 */
989 bool isAdded = false;
990 for (size_t i = 0; i < numChildren; ++i)
991 {
992 if (TObjectTraits::objectIntersects(*vit, children[i].bounds, 0))
993 {
994 children[i].add(*vit, heuristics, level + 1, false);
995 isAdded = true;
996 }
997 }
998 LASS_ENFORCE(isAdded)("object is not added to any of the sub nodes");
999 }
1000
1001 data.clear();
1002}
1003
1004
1005
1006template <typename O, typename OT, typename SH>
1007void QuadTree<O, OT, SH>::QuadNode::absorb()
1008{
1009 if (isLeaf())
1010 {
1011 return;
1012 }
1013
1014 for (size_t i=0;i<numChildren;++i)
1015 {
1016 children[i].absorb();
1017 std::copy(children[i].data.begin(), children[i].data.end(), std::back_inserter(data));
1018 }
1019 deleteChildren(numChildren);
1020
1021 std::sort(data.begin(), data.end());
1022 typename TObjectIterators::iterator last = std::unique(data.begin(), data.end());
1023 data.erase(last, data.end());
1024}
1025
1026
1027
1028template <typename O, typename OT, typename SH>
1029size_t QuadTree<O, OT, SH>::QuadNode::depth() const
1030{
1031 if (isLeaf())
1032 return 1;
1033
1034 size_t depth=children[0].depth();
1035 for (size_t i=1;i<numChildren;++i)
1036 depth = std::max(depth,children[i].depth());
1037 return depth + 1;
1038}
1039
1040
1041
1042template <typename O, typename OT, typename SH>
1043const typename QuadTree<O, OT, SH>::TValue
1044QuadTree<O, OT, SH>::QuadNode::averageDepth() const
1045{
1046 if (isLeaf())
1047 return 1;
1048
1049 TValue depth = 0;
1050 for (size_t i = 1; i < numChildren; ++i)
1051 depth += children[i].averageDepth();
1052 return depth / numChildren + 1;
1053}
1054
1055
1056
1057template <typename O, typename OT, typename SH>
1058void QuadTree<O, OT, SH>::QuadNode::makeChildren()
1059{
1060 if (children)
1061 {
1062 return;
1063 }
1064
1065 const TPoint center = this->center();
1066 children = static_cast<QuadNode*>(allocator_.allocate());
1067 size_t i = 0;
1068 try
1069 {
1070 for (i = 0; i < numChildren; ++i)
1071 {
1072 TPoint min = TObjectTraits::aabbMin(bounds);
1073 TPoint max = TObjectTraits::aabbMax(bounds);
1074 for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
1075 {
1076 TObjectTraits::coord(i & mask ? min : max, k, TObjectTraits::coord(center, k));
1077
1078 // // slightly grow the box ...
1079 // //*
1080 // const TValue dx = (TObjectTraits::coord(max, k) - TObjectTraits::coord(min, k)) / 1000;
1081 // TObjectTraits::coord(min, k, TObjectTraits::coord(min, k) - dx);
1082 // TObjectTraits::coord(max, k, TObjectTraits::coord(max, k) + dx);
1083 // /**/
1084 }
1085 new (&children[i]) QuadNode(TObjectTraits::aabbMake(min, max), allocator_);
1086 }
1087 }
1088 catch (...)
1089 {
1090 deleteChildren(i);
1091 throw;
1092 }
1093}
1094
1095
1096
1097template <typename O, typename OT, typename SH>
1098void QuadTree<O, OT, SH>::QuadNode::deleteChildren(size_t count)
1099{
1100 if (!children)
1101 {
1102 return;
1103 }
1104 while (count)
1105 {
1106 children[--count].~QuadNode();
1107 }
1108 allocator_.deallocate(children);
1109 children = 0;
1110}
1111
1112
1113}
1114}
1115
1116#endif
1117
1118// EOF
A spatial container for generic objects.
Definition quad_tree.h:87
OutputIterator find(const TPoint &p, OutputIterator result, const TInfo *info=0) const
find objects containing point and write them to the output iterator.
size_t depth() const
depth.
TSelf & operator=(TSelf &&other) noexcept
move constructor
bool contains(const TPoint &p, const TInfo *info=0) const
return true if any of the objects contains point.
T sign(const T &x)
if x < 0 return -1, else if x > 0 return 1, else return 0.
Definition basic_ops.h:153
bool isInf(const C &iV)
return true if iV equals minus or plus Infinity
Definition num_traits.h:132
spatial subdivisions, quadtrees, octrees, meshes in 2D and 3D, triangulators, ...
Definition aabb8_tree.h:80
Library for Assembled Shared Sources.
Definition config.h:53