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