library of assembled shared sources

http://lass.cocamware.com

quad_tree.inl

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 
00044 
00045 /** @class lass::spat::QuadTree
00046  *  A spatial container for generic objects.  The object needs a traits class which
00047  *  contains the necessary functions to perform the quad tree management for the
00048  *  particular ObjectType.  The traits class needs as a basis the following interface:
00049  *  <tt>
00050  *      static TAabb aabb(const TSimplePolygon3D& iP);
00051  *      static bool contains( const TSimplePolygon3D& iP, const TPoint& point)
00052  *  </tt>
00053  *  The above functions are only examples.  The dimensionality of the primitives must
00054  *  match but can be of any order.  So the quad tree can be used to classify in
00055  *  2 and 3 dimensions.  In three dimensions the more common name is OctTree.
00056  *
00057  *  Higher level divisions can in theory be supported but the dimensional specific
00058  *  part must be reimplemented.  Altough this is only 2 functions and could be written
00059  *  generally this is not yet available.
00060  *
00061  *  @brief a Quad tree for general objects
00062  *  @author Tom De Muer [TDM]
00063  */
00064 
00065 #ifndef LASS_GUARDIAN_OF_INCLUSION_SPAT_QUAD_TREE_INL
00066 #define LASS_GUARDIAN_OF_INCLUSION_SPAT_QUAD_TREE_INL
00067 
00068 #include "spat_common.h"
00069 #include "quad_tree.h"
00070 
00071 namespace lass
00072 {
00073 namespace spat
00074 {
00075 
00076 // --- public --------------------------------------------------------------------------------------
00077 
00078 template <typename O, typename OT>
00079 QuadTree<O, OT>::QuadTree(size_t maxSize, size_t maxLevel):
00080     root_(0),
00081     maxSize_(maxSize),
00082     maxLevel_(maxLevel)
00083 {
00084 }
00085 
00086 
00087 
00088 template <typename O, typename OT>
00089 QuadTree<O, OT>::~QuadTree()
00090 {
00091     delete root_;
00092 }
00093 
00094 /*
00095 template
00096 <
00097     class ObjectType,
00098     typename ObjectTraits
00099 >
00100 QuadTree<O, OT>::QuadTree(const TPoint& center,const TVector& extents, size_t maxSize, size_t maxLevel):
00101     root_(new QuadNode(center, extents)),
00102     maxSize_(maxSize),
00103     maxLevel_(maxLevel)
00104 {
00105 }
00106 
00107 template
00108 <
00109     class ObjectType,
00110     typename ObjectTraits
00111 >
00112 QuadTree<O, OT>::QuadTree(const TAabb& box, size_t maxSize, size_t maxLevel):
00113     maxSize_(maxSize),
00114     maxLevel_(maxLevel)
00115 {
00116     TVector extents = box.max()-box.min();
00117     extents *= 0.5;
00118     root_ = new QuadNode(box.center(), extents);
00119 }
00120 */
00121 
00122 template <typename O, typename OT>
00123 QuadTree<O, OT>::QuadTree(TObjectIterator first, TObjectIterator last, size_t maxSize, size_t maxLevel):
00124     root_(0),
00125     end_(last),
00126     maxSize_(maxSize),
00127     maxLevel_(maxLevel)
00128 {
00129     aabb_ = TObjectTraits::aabbEmpty();
00130     for (TObjectIterator i = first; i != last; ++i)
00131     {
00132         aabb_ = TObjectTraits::aabbJoin(aabb_, TObjectTraits::objectAabb(i));
00133     }
00134 
00135     const TPoint min = TObjectTraits::aabbMin(aabb_);
00136     const TPoint max = TObjectTraits::aabbMax(aabb_);
00137     TPoint center;
00138     TVector extents;
00139     for (size_t k = 0; k < dimension; ++k)
00140     {
00141         TObjectTraits::coord(center, k, (TObjectTraits::coord(max, k) + TObjectTraits::coord(min, k)) / 2);
00142         TObjectTraits::coord(extents, k, (TObjectTraits::coord(max, k) - TObjectTraits::coord(min, k)) / 2);
00143     }
00144 
00145     root_ = new QuadNode(center, extents);
00146     while (first != last)
00147     {
00148         add(first++);
00149     }
00150 }
00151 
00152 
00153 
00154 template <typename O, typename OT>
00155 void QuadTree<O, OT>::reset()
00156 {
00157     QuadTree temp;
00158     swap(temp);
00159 }
00160 
00161 
00162 
00163 template <typename O, typename OT>
00164 void QuadTree<O, OT>::reset(TObjectIterator first, TObjectIterator last)
00165 {
00166     QuadTree temp(first, last);
00167     swap(temp);
00168 }
00169 
00170 
00171 
00172 template <typename O, typename OT>
00173 void QuadTree<O, OT>::add(TObjectIterator object)
00174 {
00175     if (!TObjectTraits::aabbContains(aabb_, TObjectTraits::objectAabb(object)))
00176     {
00177         LASS_THROW("object not within QuadTree");
00178     }
00179     root_->add(object, maxSize_, maxLevel_);
00180 }
00181 
00182 
00183 
00184 template <typename O, typename OT>
00185 const bool QuadTree<O, OT>::contains(const TPoint& point, const TInfo* info) const
00186 {
00187     if (!root_ || !TObjectTraits::aabbContains(aabb_, point))
00188     {
00189         return false;
00190     }
00191 
00192     LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00193     QuadNode* node = root_;
00194     while (!node->leaf)
00195     {
00196         LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_NODE;
00197         node = node->node[findSubNode(node->center, point)];
00198         LASS_ASSERT(node); // if it's not a leaf, there should be a child node
00199     }
00200 
00201     for (typename TObjectIterators::const_iterator i = node->data.begin(); i != node->data.end(); ++i)
00202     {
00203         LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00204         if (TObjectTraits::objectContains(*i, point, info))
00205         {
00206             return true;
00207         }
00208     }
00209     return false;
00210 }
00211 
00212 
00213 
00214 template <typename O, typename OT>
00215 template <typename OutputIterator>
00216 OutputIterator QuadTree<O, OT>::find(const TPoint& point, OutputIterator result, const TInfo* info) const
00217 {
00218     if (!root_ || !TObjectTraits::aabbContains(aabb_, point))
00219     {
00220         return result;
00221     }
00222 
00223     LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00224     QuadNode* node = root_;
00225     while (!node->leaf)
00226     {
00227         LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_NODE;
00228         node = node->node[findSubNode(node->center, point)];
00229         LASS_ASSERT(node); // if it's not a leaf, there should be a child node
00230     }
00231 
00232     for (typename TObjectIterators::const_iterator i = node->data.begin(); i != node->data.end(); ++i)
00233     {
00234         LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00235         if (TObjectTraits::objectContains(*i, point, info))
00236         {
00237             *result++ = *i;
00238         }
00239     }
00240     return result;
00241 }
00242 
00243 
00244 
00245 template <typename O, typename OT>
00246 const typename QuadTree<O, OT>::TObjectIterator 
00247 QuadTree<O, OT>::intersect(
00248         const TRay& ray, TReference t, TParam tMin, const TInfo* info) const
00249 {
00250     if (!root_)
00251     {
00252         return end_;
00253     }
00254 
00255     const TPoint min = TObjectTraits::aabbMin(aabb_);
00256     const TPoint max = TObjectTraits::aabbMax(aabb_);
00257     const TPoint center = middle(min, max);
00258     TPoint support = TObjectTraits::raySupport(ray);
00259     TVector direction = TObjectTraits::rayDirection(ray);
00260     const size_t flipMask = forcePositiveDirection(center, support, direction);
00261     const TVector reciprocalDirection = TObjectTraits::vectorReciprocal(direction);
00262     TVector tNear;
00263     TVector tFar;
00264     nearAndFar(min, max, support, reciprocalDirection, tNear, tFar);
00265     const TValue tNearMax = maxComponent(tNear);
00266     const TValue tFarMin = minComponent(tFar);
00267     if (tFarMin < tNearMax || tFarMin <= tMin)
00268     {
00269         return end_;
00270     }
00271 
00272     return doIntersect(root_, ray, t, tMin, info, tNear, tFar, flipMask);
00273 }
00274 
00275 
00276 
00277 template <typename O, typename OT>
00278 const bool QuadTree<O, OT>::intersects(
00279         const TRay& ray, TParam tMin, TParam tMax, const TInfo* info) const
00280 {
00281     if (!root_)
00282     {
00283         return false;
00284     }
00285 
00286     const TPoint min = TObjectTraits::aabbMin(aabb_);
00287     const TPoint max = TObjectTraits::aabbMax(aabb_);
00288     const TPoint center = middle(min, max);
00289     //const TVector size = subtract(max, min);
00290     TPoint support = TObjectTraits::raySupport(ray);
00291     TVector direction = TObjectTraits::rayDirection(ray);
00292     const size_t flipMask = forcePositiveDirection(center, support, direction);
00293     const TVector reciprocalDirection = TObjectTraits::vectorReciprocal(direction);
00294     TVector tNear;
00295     TVector tFar;
00296     nearAndFar(min, max, support, reciprocalDirection, tNear, tFar);
00297     const TValue tNearMax = maxComponent(tNear);
00298     const TValue tFarMin = minComponent(tFar);
00299     if (tFarMin < tNearMax || tFarMin <= tMin)
00300     {
00301         return false;
00302     }
00303 
00304     return doIntersects(root_, ray, tMin, tMax, info, tNear, tFar, flipMask);
00305 }
00306 
00307 
00308 
00309 template <typename O, typename OT>
00310 const typename QuadTree<O, OT>::Neighbour
00311 QuadTree<O, OT>::nearestNeighbour(const TPoint& point, const TInfo* info) const
00312 {
00313     Neighbour nearest(end_, std::numeric_limits<TValue>::infinity());
00314     if (root_)
00315     {
00316         doNearestNeighbour(root_, point, info, nearest);
00317     }
00318     return nearest;
00319 }
00320 
00321 
00322 
00323 template <typename O, typename OT>
00324 template <typename RandomAccessIterator>
00325 RandomAccessIterator
00326 QuadTree<O, OT>::rangeSearch(
00327         const TPoint& target, TParam maxRadius, size_t maxCount, RandomAccessIterator first, 
00328         const TInfo* info) const
00329 {
00330     if (!root_ || maxRadius == 0)
00331     {
00332         return first;
00333     }
00334     TValue squaredRadius = maxRadius * maxRadius;
00335     return doRangeSearch(root_, target, squaredRadius, maxCount, first, first, info);
00336 }
00337 
00338 
00339 
00340 template <typename O, typename OT>
00341 size_t QuadTree<O, OT>::objectCount() const
00342 {
00343     return root_ ? root_->objectCount() : 0;
00344 }
00345 
00346 
00347 
00348 template <typename O, typename OT>
00349 const typename QuadTree<O, OT>::TAabb& 
00350 QuadTree<O, OT>::aabb() const
00351 {
00352     return aabb_;
00353 }
00354 
00355 
00356 
00357 template <typename O, typename OT>
00358 const size_t QuadTree<O, OT>::depth() const
00359 {
00360     return root_ ? root_->depth() : 0;
00361 }
00362 
00363 
00364 
00365 
00366 template <typename O, typename OT>
00367 const typename QuadTree<O, OT>::TValue
00368 QuadTree<O, OT>::averageDepth() const
00369 {
00370     return root_ ? root_->averageDepth() : 0;
00371 }
00372 
00373 
00374 
00375 template <typename O, typename OT>
00376 void QuadTree<O, OT>::swap(QuadTree& other)
00377 {
00378     std::swap(aabb_, other.aabb_);
00379     std::swap(root_, other.root_);
00380     std::swap(end_, other.end_);
00381     std::swap(maxSize_, other.maxSize_);
00382     std::swap(maxLevel_, other.maxLevel_);
00383 }
00384 
00385 
00386 
00387 template <typename O, typename OT>
00388 const typename QuadTree<O, OT>::TObjectIterator
00389 QuadTree<O, OT>::end() const
00390 {
00391     return end_;
00392 }
00393 
00394 
00395 
00396 // --- private -------------------------------------------------------------------------------------
00397 
00398 /**
00399  *  Reference: J. Revelles, C. Urena, and M. Lastra. An efficient parametric algorithm for octree 
00400  *  traversal. In Eighth International Conference in Central Europe on Computer Graphics, 
00401  *  Visualization and Interactive Digital Media (WSCG 2000), pages 212–-219, Plzen, Czech Republic, 
00402  *  2000.
00403  */
00404 template <typename O, typename OT>
00405 const typename QuadTree<O, OT>::TObjectIterator 
00406 QuadTree<O, OT>::doIntersect(
00407         const QuadNode* node,
00408         const TRay& ray, TReference t, TParam tMin, const TInfo* info,
00409         const TVector& tNear, const TVector& tFar, size_t flipMask) const
00410 {
00411     LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00412     if (!node || minComponent(tFar) < tMin)
00413     {
00414         return end_;
00415     }
00416 
00417 
00418     if (node->leaf)
00419     {
00420         LASS_ASSERT(std::count(node->node, node->node + subNodeCount, static_cast<QuadNode*>(0)) == subNodeCount);
00421 
00422         const size_t n = node->data.size();
00423         TValue tBest = 0;
00424         TObjectIterator best = end_;
00425         for (size_t i = 0; i < n; ++i)
00426         {
00427             LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00428             TValue tCandidate = 0;
00429             if (TObjectTraits::objectIntersect(node->data[i], ray, tCandidate, tMin, info))
00430             {
00431                 LASS_ASSERT(tCandidate > tMin);
00432                 if (best == end_ || tCandidate < tBest)
00433                 {
00434                     LASS_ASSERT(tCandidate > tMin);
00435                     best = node->data[i];
00436                     tBest = tCandidate;
00437                 }
00438             }
00439         }
00440 
00441         if (best != end_)
00442         {
00443             t = tBest;
00444         }
00445         return best;
00446     }
00447 
00448     const TVector tMiddle = middle(tNear, tFar);
00449     TObjectIterator best = end_;
00450     TValue tBest = 0;
00451     size_t i = entryNode(tNear, tMiddle);
00452     do
00453     {
00454         QuadNode* const child = node->node[i ^ flipMask];
00455         TVector tChildNear = tNear;
00456         TVector tChildFar = tFar;
00457         childNearAndFar(tChildNear, tChildFar, tMiddle, i);
00458         
00459         TValue tCandidate;
00460         TObjectIterator candidate = doIntersect(
00461             child, ray, tCandidate, tMin, info, tChildNear, tChildFar, flipMask);
00462         if (candidate != end_)
00463         {
00464             if (best == end_ || tCandidate < tBest)
00465             {
00466                 best = candidate;
00467                 tBest = tCandidate;
00468             }
00469         }
00470 
00471         if (best != end_ && tBest < minComponent(tChildFar))
00472         {
00473             t = tBest;
00474             return best;
00475         }
00476 
00477         i = nextNode(i, tChildFar);
00478     }
00479     while (i != size_t(-1));
00480 
00481     if (best != end_)
00482     {
00483         t = tBest;
00484     }
00485     return best;
00486 }
00487 
00488 
00489 
00490 template <typename O, typename OT>
00491 const bool QuadTree<O, OT>::doIntersects(
00492         const QuadNode* node,
00493         const TRay& ray, TParam tMin, TParam tMax, const TInfo* info,
00494         const TVector& tNear, const TVector& tFar, size_t flipMask) const
00495 {
00496     LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00497     if (!node || minComponent(tFar) < tMin || maxComponent(tNear) > tMax)
00498     {
00499         return false;
00500     }
00501 
00502     if (node->leaf)
00503     {
00504         LASS_ASSERT(std::count(node->node, node->node + subNodeCount, static_cast<QuadNode*>(0)) == subNodeCount);
00505 
00506         const size_t n = node->data.size();
00507         TValue tBest = 0;
00508         TObjectIterator best = end_;
00509         for (size_t i = 0; i < n; ++i)
00510         {
00511             LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00512             if (TObjectTraits::objectIntersects(node->data[i], ray, tMin, tMax, info))
00513             {
00514                 return true;
00515             }
00516         }
00517 
00518         return false;
00519     }
00520 
00521     const TVector tMiddle = middle(tNear, tFar);
00522     size_t i = entryNode(tNear, tMiddle);
00523     do
00524     {
00525         QuadNode* const child = node->node[i ^ flipMask];
00526         TVector tChildNear = tNear;
00527         TVector tChildFar = tFar;
00528         childNearAndFar(tChildNear, tChildFar, tMiddle, i);
00529         if (doIntersects(child, ray, tMin, tMax, info, tChildNear, tChildFar, flipMask))
00530         {
00531             return true;
00532         }
00533         i = nextNode(i, tChildFar);
00534     }
00535     while (i != size_t(-1));
00536 
00537     return false;
00538 }
00539 
00540 
00541 
00542 template <typename O, typename OT>
00543 void QuadTree<O, OT>::doNearestNeighbour(
00544         const QuadNode* node, const TPoint& point, const TInfo* info, Neighbour& best) const
00545 {
00546     LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00547     if (node->leaf)
00548     {
00549         const size_t n = node->data.size();
00550         for (size_t i = 0; i < n; ++i)
00551         {
00552             LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00553             const TValue squaredDistance = 
00554                 TObjectTraits::objectSquaredDistance(node->data[i], point, info);
00555             if (squaredDistance < best.squaredDistance())
00556             {
00557                 best = Neighbour(node->data[i], squaredDistance);
00558             }
00559         }
00560     }
00561     else
00562     {
00563         // first, determine squared distances to children and find closest one.
00564         TValue sqrNodeDists[subNodeCount];
00565         size_t nearestNode = 0;
00566         for (size_t i = 0; i < subNodeCount; ++i)
00567         {
00568             sqrNodeDists[i] = 0;
00569             const TPoint& center = node->node[i]->center;
00570             const TVector& extents = node->node[i]->extents;
00571             for (size_t k = 0; k < dimension; ++k)
00572             {
00573                 const TValue d = num::abs(TObjectTraits::coord(center, k) - TObjectTraits::coord(point, k)) -
00574                     TObjectTraits::coord(extents, k);
00575                 if (d > 0)
00576                 {
00577                     sqrNodeDists[i] += d * d;
00578                 }
00579             }
00580             if (sqrNodeDists[i] < sqrNodeDists[nearestNode])
00581             {
00582                 nearestNode = i;
00583             }
00584         }
00585 
00586         // visit closest node first, and then the others.
00587         if (sqrNodeDists[nearestNode] < best.squaredDistance())
00588         {
00589             doNearestNeighbour(node->node[nearestNode], point, info, best);
00590         }
00591         for (size_t i = 0; i < subNodeCount; ++i)
00592         {
00593             if (sqrNodeDists[i] < best.squaredDistance() && i != nearestNode)
00594             {
00595                 doNearestNeighbour(node->node[i], point, info, best);
00596             }
00597         }
00598     }
00599 }
00600 
00601 
00602 
00603 template <typename O, typename OT>
00604 template <typename RandomIterator>
00605 RandomIterator QuadTree<O, OT>::doRangeSearch(
00606     const QuadNode* node, const TPoint& target, TReference squaredRadius, size_t maxCount,
00607     RandomIterator first, RandomIterator last, const TInfo* info) const
00608 {
00609     LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00610     LASS_ASSERT(squaredRadius >= 0);
00611 
00612     if (node->leaf)
00613     {
00614         const size_t n = node->data.size();
00615         for (size_t i = 0; i < n; ++i)
00616         {
00617             LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00618             const TValue sqrDist = TObjectTraits::objectSquaredDistance(node->data[i], target, info);
00619             if (sqrDist < squaredRadius)
00620             {
00621                 Neighbour candidate(node->data[i], sqrDist);
00622 #pragma LASS_FIXME("use letterboxing to avoid duplicates instead of naive search [Bramz]")
00623                 if (std::find(first, last, candidate) == last)
00624                 {
00625                     *last++ = candidate;
00626                     std::push_heap(first, last);
00627                     LASS_ASSERT(last >= first);
00628                     if (static_cast<size_t>(last - first) > maxCount)
00629                     {
00630                         std::pop_heap(first, last);
00631                         --last;
00632                         squaredRadius = first->squaredDistance();
00633                     }
00634                 }
00635             }
00636         }
00637         return last;
00638     }
00639 
00640     // first, determine squared distances to children and find closest one.
00641     TValue sqrNodeDists[subNodeCount];
00642     size_t nearestNode = 0;
00643     for (size_t i = 0; i < subNodeCount; ++i)
00644     {
00645         sqrNodeDists[i] = 0;
00646         const TPoint& center = node->node[i]->center;
00647         const TVector& extents = node->node[i]->extents;
00648         for (size_t k = 0; k < dimension; ++k)
00649         {
00650             const TValue d = num::abs(TObjectTraits::coord(center, k) - TObjectTraits::coord(target, k)) -
00651                 TObjectTraits::coord(extents, k);
00652             if (d > 0)
00653             {
00654                 sqrNodeDists[i] += d * d;
00655             }
00656         }
00657         if (sqrNodeDists[i] < sqrNodeDists[nearestNode])
00658         {
00659             nearestNode = i;
00660         }
00661     }
00662 
00663     if (sqrNodeDists[nearestNode] < squaredRadius)
00664     {
00665         last = doRangeSearch(node->node[nearestNode], target, squaredRadius, maxCount, first, last, info);
00666     }
00667     for (size_t i = 0; i < subNodeCount; ++i)
00668     {
00669         if (sqrNodeDists[i] < squaredRadius && i != nearestNode)
00670         {
00671             last = doRangeSearch(node->node[i], target, squaredRadius, maxCount, first, last, info);
00672         }
00673     }
00674     return last;
00675 }
00676 
00677 
00678 
00679 // --- QuadNode ------------------------------------------------------------------------------------
00680 
00681 template <typename O, typename OT>
00682 QuadTree<O, OT>::QuadNode::QuadNode( const TPoint& center, const TVector& extents) :
00683     center(center), extents(extents), leaf(true)
00684 {
00685     std::fill(node, node + subNodeCount, static_cast<QuadNode*>(0));
00686 }
00687 
00688 
00689 
00690 template <typename O, typename OT>
00691 QuadTree<O, OT>::QuadNode::~QuadNode()
00692 {
00693     // destruct in reverse order
00694     size_t i = subNodeCount;
00695     while (i > 0)
00696     {
00697         delete node[--i];
00698     }
00699 }
00700 
00701 
00702 
00703 template <typename O, typename OT>
00704 size_t QuadTree<O, OT>::QuadNode::objectCount() const
00705 {
00706     size_t cumulCount = data.size();
00707     for (size_t i=0;i<subNodeCount;++i)
00708     {
00709         if (node[i])
00710             cumulCount += node[i]->objectCount();
00711     }
00712     return cumulCount;
00713 }
00714 
00715 
00716 
00717 template <typename O, typename OT>
00718 void QuadTree<O, OT>::QuadNode::add(
00719         TObjectIterator object, size_t maxSize, size_t maxLevel, size_t level, bool mayDecompose)
00720 {
00721     if (leaf)
00722     {
00723         data.push_back(object);
00724         if (mayDecompose && data.size() > maxSize && level < maxLevel)
00725         {
00726             decompose(maxSize, maxLevel, level);
00727         }
00728     }
00729     else
00730     {
00731         for (size_t i=0;i<subNodeCount;++i)
00732         {
00733             if (TObjectTraits::objectOverlaps(object, node[i]->aabb()))
00734             {
00735                 node[i]->add(object, maxSize, maxLevel, level + 1);
00736             }
00737         }
00738     }
00739 }
00740 
00741 
00742 
00743 template <typename O, typename OT>
00744 typename QuadTree<O, OT>::TAabb QuadTree<O, OT>::QuadNode::aabb() const
00745 {
00746     /* Reconstruction of the aabb everytime an object gets inserted to the quadnode
00747     *  Altough this is not very efficient, it is only needed during construction.  Better
00748     *  storage via center and dx,dy can give more efficient lookup code which is the main
00749     *  interest.  Storing the aabb would give too much overhead in comparison with the gain
00750     *  in speed.
00751     */
00752     //std::cout << "center:"<<center << std::endl;
00753     //std::cout << "extents:"<<extents << std::endl;
00754     TAabb result(center-extents,center+extents);
00755     //std::cout << "result:"<<result << std::endl;
00756     return result;
00757 }
00758 
00759 
00760 
00761 template <typename O, typename OT>
00762 void QuadTree<O, OT>::QuadNode::decompose(size_t maxSize, size_t maxLevel, size_t level)
00763 {
00764     if (leaf) // only decompose leaf nodes, others are already decomposed
00765     {
00766         buildSubNodes(this);
00767         leaf = false;
00768 
00769         TAabb nodeAabb[subNodeCount];       // cache node aabb
00770         for (size_t i=0;i<subNodeCount;++i)
00771             nodeAabb[i] = node[i]->aabb();
00772 
00773         //const size_t maxCopies = subNodeCount * data.size() * 2 / 3;
00774         size_t copies = 0;
00775         for (typename TObjectIterators::iterator vit = data.begin(); vit != data.end(); ++vit)
00776         {
00777             const TAabb tempAabb = TObjectTraits::objectAabb( *vit );
00778             
00779             /* for each object we test wether it is contained in one of the
00780             *  subnodes of the quadnode.  If it is even partially in one then move
00781             *  the object down the tree, but only one level
00782             */
00783             for (size_t i = 0; i < subNodeCount; ++i)
00784             {
00785                 if (TObjectTraits::objectOverlaps(*vit, nodeAabb[i]))
00786                 {
00787                     node[i]->add(*vit, maxSize, maxLevel, level + 1, false);
00788                     ++copies;
00789                 }
00790             }
00791         }
00792 
00793         data.clear();
00794     }
00795 }
00796 
00797 
00798 
00799 template <typename O, typename OT>
00800 void QuadTree<O, OT>::QuadNode::absorb()
00801 {
00802     if (!leaf)
00803     {
00804         for (size_t i=0;i<subNodeCount;++i)
00805         {
00806             node[i]->absorb();
00807             std::copy(node[i]->data.begin(), node[i]->data.end(), std::back_inserter(data));
00808             delete node[i];
00809         }
00810         std::sort(data.begin(), data.end());
00811         typename TObjectIterators::iterator last = std::unique(data.begin(), data.end());
00812         data.erase(last, data.end());
00813         leaf = true;
00814     }
00815 }
00816 
00817 
00818 
00819 template <typename O, typename OT>
00820 size_t QuadTree<O, OT>::QuadNode::depth() const
00821 {
00822     if (leaf)
00823         return 1;
00824 
00825     size_t depth=node[0]->depth();
00826     for (size_t i=1;i<subNodeCount;++i)
00827         depth = std::max(depth,node[i]->depth());
00828     return depth + 1;
00829 }
00830 
00831 
00832 
00833 template <typename O, typename OT>
00834 const typename QuadTree<O, OT>::TValue 
00835 QuadTree<O, OT>::QuadNode::averageDepth() const
00836 {
00837     if (leaf)
00838         return 1;
00839 
00840     TValue depth = 0;
00841     for (size_t i = 1; i < subNodeCount; ++i)
00842         depth += node[i]->averageDepth();
00843     return depth / subNodeCount + 1;
00844 }
00845 
00846 
00847 
00848 }
00849 }
00850 
00851 #endif
00852 
00853 // EOF

Generated on Mon Nov 10 14:21:07 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo