kdtree.h

Go to the documentation of this file.
00001 /*
00002  * kdtree.h
00003  * 
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Simple kd-tree library.h
00032  */
00033 
00034 #ifndef WAVEPACKET_KDTREE_H__
00035 #define WAVEPACKET_KDTREE_H__
00036 
00037 
00038 // includes --------------------------------------------------------------------
00039 #include "common/common.h"
00040 #include "geometry/geometry_3d.h"
00041 #include "threadsafe/smart_ptr.h"
00042 
00043 
00044 /// \ingroup geometric
00045 /*@{*/
00046 
00047 ////////////////////////////////////////////////////////////////////////////////
00048 ///
00049 /// \defgroup kdtree kd-tree Library
00050 ///
00051 /// \n
00052 /// API for creating kd trees.  Only supports 3D for now.
00053 /// See http://en.wikipedia.org/wiki/Kd-tree
00054 ///
00055 /// \n
00056 /// This library is optimized for use caess where a lot of objects are added
00057 /// and only a few are removed.  In particular, the tree isn't rebalanced nor
00058 /// are empty nodes removed.
00059 ///
00060 /// \n
00061 /// \b WARNING: This API is \e not threadsafe.
00062 ///
00063 ////////////////////////////////////////////////////////////////////////////////
00064 
00065 /*@{*/
00066 
00067 
00068 namespace kdtree {
00069 
00070 
00071 // basic sorting (move this to geometry library?)
00072 enum eSort {
00073         eSort_Left      = 1, ///< "left" of sort plane, negative distance
00074         eSort_Right     = 2, ///< "right" of sort plane, positive distance
00075         eSort_Straddle  = 3, ///< in sort plane, or spans both sides
00076 
00077         // keep this last!
00078         eSort_Invalid   = 0
00079 };
00080 
00081 
00082 
00083 enum eAxis {
00084         eAxis_X         = 1,
00085         eAxis_Y         = 2,
00086         eAxis_Z         = 3,
00087 
00088         // keep this last!
00089         eAxis_Invalid   = 0
00090 };
00091 
00092 
00093 /// a kdtree plane is always axis-aligned
00094 struct plane_t {
00095         void clear(void) throw() {
00096                         axis = eAxis_Invalid;
00097                         value = 0.0;
00098                 }
00099         bool isValid(void) const throw() { return (axis > 0 && axis < 4); }
00100         void dump(IN const char * title) const throw() {
00101                         DPRINTF("%s: axis[%d] value=%f", title, axis, value);
00102                 }
00103 
00104         // data fields
00105         eAxis           axis;   ///< which axis is normal to this plane
00106         float           value;  ///< coordinate value along axis
00107 };
00108 
00109 
00110 /// say which side of a given sort plane the provided test point is on
00111 eSort sortPoint(IN const plane_t& plane, IN const point3d_t& point) throw();
00112 
00113 
00114 /// say how the given rectangle sorts against the given sorting plane
00115 eSort sortRect(IN const plane_t& plane, IN const rect3d_t& rect) throw();
00116 
00117 
00118 // forward declaration
00119 class Node;
00120 
00121 
00122 /// base class for kd-tree entries.  Clients can inherit from this.
00123 class Entry {
00124 public:
00125         // virtual destructor (main purpose of this class) ---------------------
00126         virtual ~Entry(void) throw();
00127 };
00128 
00129 
00130 
00131 enum eAction {
00132         eAction_Continue                = 0x001,        // keep iterating
00133         eAction_Halt                    = 0x002,        // stop iterating
00134 
00135         eAction_Remove                  = 0x010,        // remove this item
00136 
00137         eAction_Invalid                 = 0             // keep this last!
00138 };
00139 
00140 
00141 typedef eAction (*iteration_callback)(IN void * context,
00142                                 IN Entry * entry,
00143                                 IN const rect3d_t& entry_rect);
00144 
00145 
00146 /// strategies used for space partitioning
00147 enum eStrategy {
00148         eStrategy_Naive         =  1, ///< simple strategy based on bounding box
00149         eStrategy_Balance       =  2, ///< strategy that aims to balance nodes
00150 
00151         // keep this last!
00152         eStrategy_Invalid       =  0
00153 };
00154 
00155 
00156 
00157 /// root (and node!) of a kd-tree
00158 /// This class is expected to be used as the core object for rendering and other
00159 ///     CPU-intensive tasks, so it therefore has no virtual methods.
00160 class Node {
00161 public:
00162         // public typedefs -----------------------------------------------------
00163         struct entry_rec_t {
00164                 smart_ptr<Entry>        entry;
00165                 rect3d_t                rect;
00166         };
00167         struct dynamic_entry_t {
00168                 // data fields
00169                 smart_ptr<Entry>        entry;
00170                 rect3d_t                rect;
00171                 smart_ptr<dynamic_entry_t> next;
00172         };
00173 
00174         typedef std::vector<entry_rec_t> vec_entries_t;
00175 
00176         // constructor, destructor ---------------------------------------------
00177         ~Node(void) throw();
00178 
00179         // kdtree::Node class interface methods --------------------------------
00180 
00181         /// static entries are expensive to add and remove--do so rarely (such
00182         ///     as when constructing the tree).
00183         void addStaticEntry(IN smart_ptr<Entry>& entry,
00184                                 IN const rect3d_t& r);
00185 
00186         /// dynamic entries are fast to add and remove, but are not used for
00187         ///     partitioning and are not affected by subdividing.
00188         void addDynamicEntry(IN smart_ptr<dynamic_entry_t>& de);
00189 
00190         bool removeStaticEntry(IN Entry * entry) throw();
00191         smart_ptr<dynamic_entry_t> popDynamicEntry(void) throw();
00192         int getTreeDepth(void) const throw();
00193         int getNodeCount(void) const throw();
00194         int getStaticEntryCount(void) const throw();
00195 
00196         /// here you tell the kd-tree to subdivide (recursively), using the
00197         ///     given strategy.  The param use depends on the strategy.
00198         ///
00199         /// - For the naive strategy, the param is the max number of nodes per
00200         ///     entity.
00201         void subdivide(IN eStrategy strategy,
00202                                 IN float param);
00203 
00204         /// client can iterate over all entries in the given rect
00205         eAction iterateStaticEntries(IN const rect3d_t& r,
00206                                 IN iteration_callback callback,
00207                                 IN void * context);
00208 
00209         // raw accessors for clients needing to walk directly
00210         const Node * getLeftChild(void) const throw() { return m_left; }
00211         const Node * getRightChild(void) const throw() { return m_right; }
00212         Node * getLeftChild(void) throw() { return m_left; }
00213         Node * getRightChild(void) throw() { return m_right; }
00214 
00215         const rect3d_t& getRect(void) const throw() { return m_bounds; }
00216         const plane_t& getSortPlane(void) const throw() { return m_sortPlane; }
00217 
00218         const vec_entries_t& getStaticEntries(void) const throw() { return m_entries; }
00219         vec_entries_t& getStaticEntries(void) throw() { return m_entries; }
00220 
00221         void setUserPointer(IN void * context) throw() { m_user = context; }
00222         void * getUserPointer(void) const throw() { return m_user; }
00223 
00224         // public static methods (factory methods) -----------------------------
00225 
00226         /// when you create a kd-tree node (especially the root!) you had better
00227         ///     know the overall boundaries.  Anything you add to the node must
00228         ///     be contained by these bounds.
00229         static smart_ptr<Node> create(IN const rect3d_t& bounds);
00230 
00231 private:
00232         // require clients to use the public factory methods to create ---------
00233         Node(void) throw();
00234 
00235         // private helper methods ----------------------------------------------
00236         void initialize(IN const rect3d_t& bounds);
00237         void subdivideInternal(IN eStrategy strategy,
00238                                 IN float param);
00239 
00240         // private member data -------------------------------------------------
00241         smart_ptr<Node> m_left; // left child (for some definition of "left")
00242         smart_ptr<Node> m_right;// right child
00243         plane_t         m_sortPlane;// left/right divide
00244         rect3d_t        m_bounds;// boundary
00245         vec_entries_t   m_entries; // unsorted or spanning entries
00246         smart_ptr<dynamic_entry_t> m_dynamic;   // dynamic entries
00247         void *          m_user; // user context
00248 };
00249 
00250 
00251 
00252 };      // kdtree namespace
00253 
00254 #endif  // WAVEPACKET_KDTREE_H__
00255