library of assembled shared sources

http://lass.cocamware.com

quad_tree_helper.h

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_IMPL_QUAD_TREE_HELPER_H
00066 #define LASS_GUARDIAN_OF_INCLUSION_SPAT_IMPL_QUAD_TREE_HELPER_H
00067 
00068 #include "../spat_common.h"
00069 
00070 namespace lass
00071 {
00072 namespace spat
00073 {
00074 namespace impl
00075 {
00076         
00077 template <typename ObjectTraits, size_t dimension>
00078 class QuadTreeHelper
00079 {
00080 protected:
00081     typedef ObjectTraits TObjectTraits;
00082     typedef typename ObjectTraits::TPoint TPoint;
00083     typedef typename ObjectTraits::TVector TVector;
00084     typedef typename ObjectTraits::TValue TValue;
00085 
00086     const TValue minComponent(const TVector& v) const
00087     {
00088         TValue best = TObjectTraits::coord(v, 0);
00089         for (size_t k = 1; k < dimension; ++k)
00090         {
00091             best = std::min(best, TObjectTraits::coord(v, k));
00092         }
00093         return best;
00094     }
00095 
00096     const TValue maxComponent(const TVector& v) const
00097     {
00098         TValue best = TObjectTraits::coord(v, 0);
00099         for (size_t k = 1; k < dimension; ++k)
00100         {
00101             best = std::max(best, TObjectTraits::coord(v, k));
00102         }
00103         return best;
00104     }
00105 
00106     template <typename V>
00107     const V middle(const V& a, const V& b) const
00108     {
00109         V result;
00110         for (size_t k = 0; k < dimension; ++k)
00111         {
00112             TObjectTraits::coord(result, k, (TObjectTraits::coord(a, k) + TObjectTraits::coord(b, k)) / 2);
00113         }
00114         return result;
00115     }
00116 
00117     const TVector subtract(const TPoint& a, const TPoint& b) const
00118     {
00119         TVector result;
00120         for (size_t k = 0; k < dimension; ++k)
00121         {
00122             TObjectTraits::coord(result, k, TObjectTraits::coord(a, k) - TObjectTraits::coord(b, k));
00123         }
00124         return result;
00125     }
00126 
00127     const size_t entryNode(const TVector& tNear, const TVector& tMiddle) const
00128     {
00129         const TValue tEntry = maxComponent(tNear);
00130         size_t iEntry = 0;
00131         for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
00132         {
00133             iEntry |= (TObjectTraits::coord(tMiddle, k) < tEntry) ? mask : 0;
00134         }
00135         return iEntry;
00136     }
00137 
00138     const size_t nextNode(size_t i, const TVector& tFar) const
00139     {
00140         size_t nextMask = 1;
00141         TValue min = TObjectTraits::coord(tFar, 0);
00142         for (size_t k = 1, mask = 2; k < dimension; ++k, mask *= 2)
00143         {
00144             const TValue x = TObjectTraits::coord(tFar, k);
00145             if (x < min)
00146             {
00147                 min = x;
00148                 nextMask = mask;
00149             }
00150         }
00151         if (i & nextMask)
00152         {
00153             return size_t(-1);
00154         }
00155         return i | nextMask;
00156     }
00157 
00158     const size_t findSubNode(const TPoint& center, const TPoint& point) const
00159     {
00160         size_t i = 0;
00161         for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
00162         {
00163             i |= TObjectTraits::coord(point, k) >= TObjectTraits::coord(center, k) ? mask : 0;
00164         }
00165         return i;
00166     }
00167 
00168     const size_t forcePositiveDirection(const TPoint& center, TPoint& support, TVector& direction) const
00169     {
00170         size_t flipMask = 0;
00171         for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
00172         {
00173             const TValue d = TObjectTraits::coord(direction, k);
00174             if (d < 0)
00175             {
00176                 TObjectTraits::coord(support, k, 
00177                     2 * TObjectTraits::coord(center, k) - TObjectTraits::coord(support, k));
00178                 TObjectTraits::coord(direction, k, -d);
00179                 flipMask |= mask;
00180             }
00181         }
00182         return flipMask;
00183     }
00184 
00185     void nearAndFar(const TPoint& min, const TPoint& max, const TPoint& support, 
00186         const TVector& reciprocalDirection, TVector& tNear, TVector& tFar) const
00187     {
00188         for (size_t k = 0; k < dimension; ++k)
00189         {
00190             TObjectTraits::coord(tNear, k, TObjectTraits::coord(reciprocalDirection, k) *
00191                 (TObjectTraits::coord(min, k) - TObjectTraits::coord(support, k)));
00192             TObjectTraits::coord(tFar, k, TObjectTraits::coord(reciprocalDirection, k) *
00193                 (TObjectTraits::coord(max, k) - TObjectTraits::coord(support, k)));
00194         }
00195     }
00196 
00197     void childNearAndFar(TVector& tNear, TVector& tFar, const TVector& tMiddle, size_t iChild) const
00198     {
00199         for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
00200         {
00201             if (iChild & mask)
00202             {
00203                 TObjectTraits::coord(tNear, k, TObjectTraits::coord(tMiddle, k));
00204             }
00205             else
00206             {
00207                 TObjectTraits::coord(tFar, k, TObjectTraits::coord(tMiddle, k));
00208             }
00209         }
00210     }
00211 
00212     template <typename QuadNodeType> 
00213     static void buildSubNodes(QuadNodeType* parentNode)
00214     {
00215         TVector newExtents(parentNode->extents);
00216         for (size_t k = 0; k < dimension; ++k)
00217         {
00218             TObjectTraits::coord(newExtents, k, TObjectTraits::coord(newExtents, k) / 2);
00219         }
00220 
00221         const size_t nodeCount = 1 << dimension;
00222         for (size_t i = 0; i < nodeCount; ++i)
00223         {
00224             TPoint newCenter = parentNode->center;
00225             for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
00226             {
00227                 TObjectTraits::coord(newCenter, k, 
00228                     TObjectTraits::coord(newCenter, k) + (i & mask ? 1 : -1) * TObjectTraits::coord(newExtents, k));
00229             }
00230             parentNode->node[i] = new QuadNodeType(newCenter, newExtents);
00231         }
00232     }
00233 };
00234 
00235 
00236 
00237 template <typename ObjectTraits>
00238 class QuadTreeHelper<ObjectTraits, 2>
00239 {
00240 protected:
00241     typedef ObjectTraits TObjectTraits;
00242     typedef typename ObjectTraits::TPoint TPoint;
00243     typedef typename ObjectTraits::TVector TVector;
00244     typedef typename ObjectTraits::TValue TValue;
00245     enum { dimension = 2 };
00246 
00247     const TValue minComponent(const TVector& v) const
00248     {
00249         return std::min(TObjectTraits::coord(v, 0), TObjectTraits::coord(v, 1));
00250     }
00251 
00252     const TValue maxComponent(const TVector& v) const
00253     {
00254         return std::max(TObjectTraits::coord(v, 0), TObjectTraits::coord(v, 1));
00255     }
00256 
00257     template <typename V>
00258     const V middle(const V& a, const V& b) const
00259     {
00260         return V(
00261             (TObjectTraits::coord(a, 0) + TObjectTraits::coord(b, 0)) / 2,
00262             (TObjectTraits::coord(a, 1) + TObjectTraits::coord(b, 1)) / 2);
00263     }
00264 
00265     const TVector subtract(const TPoint& a, const TPoint& b) const
00266     {
00267         return TVector(
00268             TObjectTraits::coord(a, 0) - TObjectTraits::coord(b, 0),
00269             TObjectTraits::coord(a, 1) - TObjectTraits::coord(b, 1));
00270     }
00271 
00272     const size_t entryNode(const TVector& tNear, const TVector& tMiddle) const
00273     {
00274         if (TObjectTraits::coord(tNear, 0) > TObjectTraits::coord(tNear, 1))
00275         {
00276             if (TObjectTraits::coord(tMiddle, 1) < TObjectTraits::coord(tNear, 0))
00277             {
00278                 return 0x2;
00279             }
00280         }
00281         else
00282         {
00283             if (TObjectTraits::coord(tMiddle, 0) < TObjectTraits::coord(tNear, 1))
00284             {
00285                 return 0x1;
00286             }
00287         }
00288         return 0x0;
00289     }
00290 
00291     const size_t nextNode(size_t i, const TVector& tFar) const
00292     {
00293         if (TObjectTraits::coord(tFar, 0) <  TObjectTraits::coord(tFar, 1))
00294         {
00295             return i & 0x1 ? size_t(-1) : i | 0x1;
00296         }
00297         else
00298         {
00299             return i & 0x2 ? size_t(-1) : i | 0x2;
00300         }
00301     }
00302 
00303     const size_t findSubNode(const TPoint& center, const TPoint& point) const
00304     {
00305         return (TObjectTraits::coord(point, 0) >= TObjectTraits::coord(center, 0) ? 0x1 : 0x0) 
00306             | (TObjectTraits::coord(point, 1) >= TObjectTraits::coord(center, 1) ? 0x2 : 0x0);
00307     }
00308 
00309     const size_t forcePositiveDirection(const TPoint& center, TPoint& support, TVector& direction) const
00310     {
00311         size_t flipMask = 0;
00312         const TValue dx = TObjectTraits::coord(direction, 0);
00313         if (dx < 0)
00314         {
00315             TObjectTraits::coord(support, 0, 2 * TObjectTraits::coord(center, 0) - TObjectTraits::coord(support, 0));
00316             TObjectTraits::coord(direction, 0, -dx);
00317             flipMask |= 0x1;
00318         }
00319         const TValue dy = TObjectTraits::coord(direction, 1);
00320         if (dy < 0)
00321         {
00322             TObjectTraits::coord(support, 1, 2 * TObjectTraits::coord(center, 1) - TObjectTraits::coord(support, 1));
00323             TObjectTraits::coord(direction, 1, -dy);
00324             flipMask |= 0x2;
00325         }
00326         return flipMask;
00327     }
00328 
00329     void nearAndFar(const TPoint& min, const TPoint& max, const TPoint& support, 
00330         const TVector& reciprocalDirection, TVector& tNear, TVector& tFar) const
00331     {
00332         TObjectTraits::coord(tNear, 0, TObjectTraits::coord(reciprocalDirection, 0) * (TObjectTraits::coord(min, 0) - TObjectTraits::coord(support, 0)));
00333         TObjectTraits::coord(tNear, 1, TObjectTraits::coord(reciprocalDirection, 1) * (TObjectTraits::coord(min, 1) - TObjectTraits::coord(support, 1)));
00334         TObjectTraits::coord(tFar, 0, TObjectTraits::coord(reciprocalDirection, 0) * (TObjectTraits::coord(max, 0) - TObjectTraits::coord(support, 0)));
00335         TObjectTraits::coord(tFar, 1, TObjectTraits::coord(reciprocalDirection, 1) * (TObjectTraits::coord(max, 1) - TObjectTraits::coord(support, 1)));
00336     }
00337 
00338     void childNearAndFar(TVector& tNear, TVector& tFar, const TVector& tMiddle, size_t iChild) const
00339     {
00340         TObjectTraits::coord(iChild & 0x1 ? tNear : tFar, 0, TObjectTraits::coord(tMiddle, 0));
00341         TObjectTraits::coord(iChild & 0x2 ? tNear : tFar, 1, TObjectTraits::coord(tMiddle, 1));
00342     }
00343 
00344     template <typename QuadNodeType> 
00345     static void buildSubNodes(QuadNodeType* parentNode)
00346     {
00347         TVector newExtents(parentNode->extents);
00348         TObjectTraits::coord(newExtents, 0, TObjectTraits::coord(newExtents, 0) / 2);
00349         TObjectTraits::coord(newExtents, 1, TObjectTraits::coord(newExtents, 1) / 2);
00350         
00351         for (size_t i = 0; i < 4; ++i)
00352         {
00353             TPoint newCenter = parentNode->center;
00354             TObjectTraits::coord(newCenter, 0, 
00355                 TObjectTraits::coord(newCenter, 0) + (i & 0x1 ? 1 : -1) * TObjectTraits::coord(newExtents, 0));
00356             TObjectTraits::coord(newCenter, 1, 
00357                 TObjectTraits::coord(newCenter, 1) + (i & 0x2 ? 1 : -1) * TObjectTraits::coord(newExtents, 1));
00358             parentNode->node[i] = new QuadNodeType(newCenter, newExtents);
00359         }
00360     }
00361 };
00362 
00363 
00364 
00365 template <typename ObjectTraits>
00366 class QuadTreeHelper<ObjectTraits, 3>
00367 {
00368     enum { dimension = 3 };
00369 protected:
00370     typedef ObjectTraits TObjectTraits;
00371     typedef typename ObjectTraits::TPoint TPoint;
00372     typedef typename ObjectTraits::TVector TVector;
00373     typedef typename ObjectTraits::TValue TValue;
00374 
00375     const TValue minComponent(const TVector& v) const
00376     {
00377         return std::min(std::min(TObjectTraits::coord(v, 0), TObjectTraits::coord(v, 1)), TObjectTraits::coord(v, 2));
00378     }
00379 
00380     const TValue maxComponent(const TVector& v) const
00381     {
00382         return std::max(std::max(TObjectTraits::coord(v, 0), TObjectTraits::coord(v, 1)), TObjectTraits::coord(v, 2));
00383     }
00384 
00385     template <typename V>
00386     const V middle(const V& a, const V& b) const
00387     {
00388         return V(
00389             (TObjectTraits::coord(a, 0) + TObjectTraits::coord(b, 0)) / 2,
00390             (TObjectTraits::coord(a, 1) + TObjectTraits::coord(b, 1)) / 2,
00391             (TObjectTraits::coord(a, 2) + TObjectTraits::coord(b, 2)) / 2);
00392     }
00393 
00394     const TVector subtract(const TPoint& a, const TPoint& b) const
00395     {
00396         return TVector(
00397             TObjectTraits::coord(a, 0) - TObjectTraits::coord(b, 0),
00398             TObjectTraits::coord(a, 1) - TObjectTraits::coord(b, 1),
00399             TObjectTraits::coord(a, 2) - TObjectTraits::coord(b, 2));
00400     }
00401 
00402     const size_t entryNode(const TVector& tNear, const TVector& tMiddle) const
00403     {
00404         const TValue tEntry = maxComponent(tNear);
00405         size_t iEntry = 0;
00406         for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
00407         {
00408             iEntry |= (TObjectTraits::coord(tMiddle, k) < tEntry) ? mask : 0;
00409         }
00410         return iEntry;
00411     }
00412 
00413     const size_t nextNode(size_t i, const TVector& tFar) const
00414     {
00415         const TValue x = TObjectTraits::coord(tFar, 0);
00416         const TValue y = TObjectTraits::coord(tFar, 1);
00417         const TValue z = TObjectTraits::coord(tFar, 2);
00418         if (x < y && x < z)
00419         {
00420             return i & 0x1 ? size_t(-1) : i | 0x1;
00421         }
00422         else if (y < z)
00423         {
00424             return i & 0x2 ? size_t(-1) : i | 0x2;
00425         }
00426         else
00427         {
00428             return i & 0x4 ? size_t(-1) : i | 0x4;
00429         }
00430     }
00431 
00432     const size_t findSubNode(const TPoint& center, const TPoint& point) const
00433     {
00434         return (TObjectTraits::coord(point, 0) >= TObjectTraits::coord(center, 0) ? 0x1 : 0x0) 
00435             | (TObjectTraits::coord(point, 1) >= TObjectTraits::coord(center, 1) ? 0x2 : 0x0)
00436             | (TObjectTraits::coord(point, 2) >= TObjectTraits::coord(center, 2) ? 0x4 : 0x0);
00437     }
00438 
00439     const size_t forcePositiveDirection(const TPoint& center, TPoint& support, TVector& direction) const
00440     {
00441         size_t flipMask = 0;
00442         for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
00443         {
00444             const TValue d = TObjectTraits::coord(direction, k);
00445             if (d < 0)
00446             {
00447                 TObjectTraits::coord(support, k, 
00448                     2 * TObjectTraits::coord(center, k) - TObjectTraits::coord(support, k));
00449                 TObjectTraits::coord(direction, k, -d);
00450                 flipMask |= mask;
00451             }
00452         }
00453         return flipMask;
00454     }
00455 
00456     void nearAndFar(const TPoint& min, const TPoint& max, const TPoint& support, 
00457         const TVector& reciprocalDirection, TVector& tNear, TVector& tFar) const
00458     {
00459         for (size_t k = 0; k < dimension; ++k)
00460         {
00461             TObjectTraits::coord(tNear, k, TObjectTraits::coord(reciprocalDirection, k) *
00462                 (TObjectTraits::coord(min, k) - TObjectTraits::coord(support, k)));
00463             TObjectTraits::coord(tFar, k, TObjectTraits::coord(reciprocalDirection, k) *
00464                 (TObjectTraits::coord(max, k) - TObjectTraits::coord(support, k)));
00465         }
00466     }
00467 
00468     void childNearAndFar(TVector& tNear, TVector& tFar, const TVector& tMiddle, size_t iChild) const
00469     {
00470         for (size_t k = 0, mask = 1; k < dimension; ++k, mask *= 2)
00471         {
00472             if (iChild & mask)
00473             {
00474                 TObjectTraits::coord(tNear, k, TObjectTraits::coord(tMiddle, k));
00475             }
00476             else
00477             {
00478                 TObjectTraits::coord(tFar, k, TObjectTraits::coord(tMiddle, k));
00479             }
00480         }
00481     }
00482 
00483     template <typename QuadNodeType> 
00484     static void buildSubNodes(QuadNodeType* parentNode)
00485     {
00486         TVector newExtents(parentNode->extents);
00487         TObjectTraits::coord(newExtents, 0, TObjectTraits::coord(newExtents, 0) / 2);
00488         TObjectTraits::coord(newExtents, 1, TObjectTraits::coord(newExtents, 1) / 2);
00489         TObjectTraits::coord(newExtents, 2, TObjectTraits::coord(newExtents, 2) / 2);
00490         
00491         for (size_t i = 0; i < 8; ++i)
00492         {
00493             TPoint newCenter = parentNode->center;
00494             TObjectTraits::coord(newCenter, 0, 
00495                 TObjectTraits::coord(newCenter, 0) + (i & 0x1 ? 1 : -1) * TObjectTraits::coord(newExtents, 0));
00496             TObjectTraits::coord(newCenter, 1, 
00497                 TObjectTraits::coord(newCenter, 1) + (i & 0x2 ? 1 : -1) * TObjectTraits::coord(newExtents, 1));
00498             TObjectTraits::coord(newCenter, 2, 
00499                 TObjectTraits::coord(newCenter, 2) + (i & 0x4 ? 1 : -1) * TObjectTraits::coord(newExtents, 2));
00500             parentNode->node[i] = new QuadNodeType(newCenter, newExtents);
00501         }
00502     }
00503 };
00504 
00505 }
00506 }
00507 }
00508 
00509 #endif
00510 
00511 // 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