├── .gitignore ├── LICENSE.txt ├── README.txt ├── build-gcc ├── build-vc.bat ├── component ├── Array.cpp ├── Array.hpp ├── Octree.cpp ├── Octree.hpp ├── OctreeAuxiliary.cpp ├── OctreeAuxiliary.hpp ├── OctreeImplementation.cpp ├── OctreeImplementation.hpp ├── Primitives.hpp ├── Vector3r.cpp └── Vector3r.hpp ├── docs ├── octree-general-cpp_hxa7241_2005.html ├── ogc-class-relations-diagram.png └── ogc-visit-sequence-diagram.png └── samples ├── OctreeExample.cpp ├── OctreeStreamOut.cpp ├── OctreeStreamOut.hpp ├── OctreeTest.cpp └── OctreeTest.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | /_dev 2 | /temp 3 | /obj 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Harrison Ainsworth / HXA7241 : 2004-2007. 2 | 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products derived 13 | from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 16 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 18 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 20 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 24 | OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | HXA7241 Octree Component C++ v2.1 4 | ====================================================================== 5 | 6 | 7 | Harrison Ainsworth / HXA7241 : 2004-2007. 8 | http://wwww.hxa7241.org/ 9 | 10 | 2007-08-13 11 | 12 | 13 | 14 | 15 | Contents 16 | -------- 17 | 18 | * Description 19 | * Usage 20 | * Acknowledgements 21 | * License 22 | 23 | 24 | 25 | 26 | Description 27 | ----------- 28 | 29 | This is a C++ octree source-code component. It can be used with any stored-item 30 | type and inspection/search algorithm. 31 | 32 | The core interface is like this: 33 | * construction 34 | * create with size and limits 35 | * commands 36 | * insert item 37 | * remove item 38 | * queries 39 | * visit with user-defined operation 40 | 41 | Its features are: 42 | * non-intrusive (doesn't limit or oblige stored-item particularly) 43 | * strongly typed (doesn't accept void pointers) 44 | * doesn't manage item storage (just indexes them) 45 | * minimal in storage space 46 | * numerically sound (no gaps/overlaps between cells) 47 | * moderately-strongly exception-safe (always maintains basic validity) 48 | * moderately easy to use 49 | 50 | Also included are source for: a test application, and an example application. 51 | 52 | Code size is: core 1000 lines, support 400 lines, samples 900 lines. Exception 53 | handling is used for standard storage exceptions. RTTI is not used. Only basic 54 | use is made of templates. Standard C library dependencies are: limits.h, 55 | float.h, and math.h. 56 | 57 | There is an article on its technical-design: 58 | http://www.hxa7241.org/articles/content/octree-general-cpp_hxa7241_2005.html 59 | 60 | 61 | 62 | 63 | Usage 64 | ----- 65 | 66 | The file OctreeExample.cpp contains a minimal example of usage. 67 | 68 | 69 | ### Customisation ### 70 | 71 | There are two main things you must do: write derivative classes for 72 | OctreeAgent<> and OctreeVisitor<>. 73 | 74 | The OctreeAgent<> derivative requires one method override. This will have to 75 | query your item and return whether it overlaps the supplied cell bound. There is 76 | an optional override for multiple overlap tests at once -- this could be more 77 | efficient since cell boundaries are shared. 78 | 79 | The OctreeVisitor<> derivative(s) require three method overrides. These will 80 | have to decide how to traverse and how to react. Any number of derivatives can 81 | be written, one for each kind of search/inspection on the octree. 82 | 83 | Both of these definitions, and any use of Octree, require you to #include 84 | "Octree.hpp". 85 | 86 | 87 | ### Use ### 88 | 89 | 1. instantiate some items and instantiate an Octree 90 | 2. instantiate an OctreeAgentDerivative 91 | 3. insert/remove items into the Octree 92 | 4. instantiate various OctreeVisitorDerivatives, and use them to visit the 93 | Octree 94 | 5. maybe repeat 3. and 4. in any order 95 | 96 | 97 | ### Building ### 98 | 99 | #### Component 100 | 101 | Add these files to your source directories: 102 | * Octree .hpp/.cpp 103 | * OctreeImplementation .hpp/.cpp 104 | * OctreeAuxiliary .hpp/.cpp 105 | * Array .hpp/.cpp 106 | * Vector3r .hpp/.cpp 107 | * Primitives .hpp 108 | Add the .cpp ones to your compile scripts, and the .obj ones produced from the 109 | .cpp ones to your link scripts. 110 | 111 | Vector3r could probably easily be replaced by your own equivalent. 112 | Primitives.hpp too maybe. 113 | 114 | #### Samples 115 | 116 | For Windows, try the build-vc.bat script for MS VC++ 2005. For Linux, try the 117 | build-gcc script for GCC 3.3.5 (or later). Everything needed is in the supplied 118 | archive (assuming the build environment and tools are already prepared). The 119 | result is two programs: octreeexample and octreetest. 120 | 121 | 122 | 123 | 124 | Acknowledgements 125 | ---------------- 126 | 127 | ### C++ ### 128 | 129 | * 'The C++ Programming Language' 3rd ed. - Stroustrup (Addison Wesley) 130 | * 'Effective C++' 3rd ed. - Meyers (Addison Wesley) 131 | * 'More Effective C++' - Meyers (Addison Wesley) 132 | * 'Design Patterns' - Gamma, Helm, Johnson, Vlissides (Addison Wesley) 133 | * 'Object Oriented Software Construction' 2nd ed. - Meyer (PrenticeHall) 134 | 135 | ### Tools ### 136 | 137 | * TextPad 4.7.3 editor 138 | http://www.textpad.com/ 139 | * MS Visual C++ 2005 compiler for Microsoft Windows 140 | http://msdn.microsoft.com/vstudio/express/visualc/ 141 | * GCC 3.3.5 compiler for Suse GNU/Linux 142 | http://gcc.gnu.org/ 143 | 144 | 145 | 146 | 147 | License 148 | ------- 149 | 150 | ### (New) BSD ### 151 | 152 | Harrison Ainsworth / HXA7241 : 2004-2007. 153 | 154 | 155 | Redistribution and use in source and binary forms, with or without modification, 156 | are permitted provided that the following conditions are met: 157 | 158 | * Redistributions of source code must retain the above copyright notice, this 159 | list of conditions and the following disclaimer. 160 | * Redistributions in binary form must reproduce the above copyright notice, this 161 | list of conditions and the following disclaimer in the documentation and/or 162 | other materials provided with the distribution. 163 | * The name of the author may not be used to endorse or promote products derived 164 | from this software without specific prior written permission. 165 | 166 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 167 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 168 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 169 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 170 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 171 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 172 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 173 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 174 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 175 | OF SUCH DAMAGE. 176 | -------------------------------------------------------------------------------- /build-gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # --- using: GCC 3.3.5 --- 5 | 6 | 7 | # set constants ---------------------------------------------------------------- 8 | COMPILE="g++ -c -x c++ -ansi -std=c++98 -pedantic -fno-gnu-keywords -fno-enforce-eh-specs -fno-rtti -O3 -ffast-math -Wall -Wold-style-cast -Woverloaded-virtual -Wsign-promo -Wcast-align -Wwrite-strings -Wdisabled-optimization -Icomponent" 9 | 10 | LINKE=g++ 11 | 12 | 13 | mkdir obj 14 | rm obj/* 15 | 16 | 17 | # compile ---------------------------------------------------------------------- 18 | echo 19 | echo "--- compile --" 20 | 21 | # -- compile component -- 22 | $COMPILE component/Array.cpp -o obj/Array.o 23 | $COMPILE component/Vector3r.cpp -o obj/Vector3r.o 24 | $COMPILE component/OctreeAuxiliary.cpp -o obj/OctreeAuxiliary.o 25 | $COMPILE component/OctreeImplementation.cpp -o obj/OctreeImplementation.o 26 | $COMPILE component/Octree.cpp -o obj/Octree.o 27 | 28 | # -- compile samples -- 29 | $COMPILE -Isamples samples/OctreeStreamOut.cpp -o obj/OctreeStreamOut.o 30 | $COMPILE -Isamples samples/OctreeTest.cpp -o obj/OctreeTest.o 31 | $COMPILE -Isamples samples/OctreeExample.cpp -o obj/OctreeExample.o 32 | 33 | 34 | # link ------------------------------------------------------------------------- 35 | echo 36 | echo "--- link --" 37 | 38 | # -- link test sample -- 39 | $LINKE -o octreetest obj/Array.o obj/Vector3r.o obj/OctreeAuxiliary.o obj/OctreeImplementation.o obj/Octree.o obj/OctreeStreamOut.o obj/OctreeTest.o 40 | 41 | # -- link example sample -- 42 | $LINKE -o octreeexample obj/Array.o obj/Vector3r.o obj/OctreeAuxiliary.o obj/OctreeImplementation.o obj/Octree.o obj/OctreeExample.o 43 | 44 | 45 | echo 46 | echo "--- done --" 47 | 48 | 49 | rm obj/* 50 | 51 | 52 | exit 53 | -------------------------------------------------------------------------------- /build-vc.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | 4 | rem --- using: MS VC++ 2005 --- 5 | 6 | 7 | rem -- set constants ----------------------------------------------------------- 8 | set COMPILE=cl /c /O2 /GL /fp:fast /EHsc /GR- /GS- /MT /W4 /WL /nologo /Icomponent 9 | 10 | set LINKE=link /LTCG /OPT:REF /OPT:NOWIN98 /VERSION:2.1 /NOLOGO 11 | set LIBRARIES=kernel32.lib 12 | 13 | 14 | mkdir obj 15 | del /Q obj\* 16 | 17 | 18 | rem -- compile ----------------------------------------------------------------- 19 | @echo. 20 | @echo --- compile -- 21 | 22 | rem -- compile component -- 23 | %COMPILE% component/Array.cpp /Foobj/Array.obj 24 | %COMPILE% component/Vector3r.cpp /Foobj/Vector3r.obj 25 | %COMPILE% component/OctreeAuxiliary.cpp /Foobj/OctreeAuxiliary.obj 26 | %COMPILE% component/OctreeImplementation.cpp /Foobj/OctreeImplementation.obj 27 | %COMPILE% component/Octree.cpp /Foobj/Octree.obj 28 | 29 | rem -- compile samples -- 30 | %COMPILE% /Isamples samples/OctreeStreamOut.cpp /Foobj/OctreeStreamOut.obj 31 | %COMPILE% /Isamples samples/OctreeTest.cpp /Foobj/OctreeTest.obj 32 | %COMPILE% /Isamples samples/OctreeExample.cpp /Foobj/OctreeExample.obj 33 | 34 | 35 | rem -- link -------------------------------------------------------------------- 36 | @echo. 37 | @echo --- link -- 38 | 39 | rem -- link test sample -- 40 | %LINKE% /OUT:octreetest.exe %LIBRARIES% obj/Array.obj obj/Vector3r.obj obj/OctreeAuxiliary.obj obj/OctreeImplementation.obj obj/Octree.obj obj/OctreeStreamOut.obj obj/OctreeTest.obj 41 | 42 | rem -- link example sample -- 43 | %LINKE% /OUT:octreeexample.exe %LIBRARIES% obj/Array.obj obj/Vector3r.obj obj/OctreeAuxiliary.obj obj/OctreeImplementation.obj obj/Octree.obj obj/OctreeExample.obj 44 | 45 | 46 | @echo. 47 | @echo --- done -- 48 | 49 | 50 | del /Q obj\* 51 | -------------------------------------------------------------------------------- /component/Array.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #include "Array.hpp" 40 | -------------------------------------------------------------------------------- /component/Array.hpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #ifndef Array_h 40 | #define Array_h 41 | 42 | 43 | #include "Primitives.hpp" 44 | 45 | 46 | 47 | 48 | namespace hxa7241_general 49 | { 50 | using namespace hxa7241; 51 | 52 | 53 | /** 54 | * A simpler, compacter alternative to std::vector.

55 | * 56 | * Length is explicit - there is no hidden reserve.

57 | * 58 | * @invariants 59 | * * pStorage_m is 0 or a valid address
60 | * * length_m is >= 0 and <= getMaxLength() (DWORD_MAX)
61 | */ 62 | template 63 | class Array 64 | { 65 | /// standard object services --------------------------------------------------- 66 | public: 67 | Array(); 68 | explicit Array( dword length ); // throws 69 | 70 | ~Array(); 71 | Array( const Array& ); // throws 72 | Array& operator=( const Array& ); // throws 73 | 74 | 75 | /// commands ------------------------------------------------------------------- 76 | void setLength( dword length ); // throws 77 | 78 | void swap( Array& ); 79 | void append( const TYPE& ); // throws 80 | void remove( int index ); // throws 81 | 82 | void zeroStorage(); 83 | 84 | TYPE* getStorage(); 85 | TYPE& operator[]( int index ); 86 | 87 | 88 | /// queries -------------------------------------------------------------------- 89 | dword getLength() const; 90 | bool isEmpty() const; 91 | static dword getMaxLength(); 92 | 93 | const TYPE* getStorage() const; 94 | const TYPE& operator[]( int index ) const; 95 | 96 | 97 | /// implementation ------------------------------------------------------------- 98 | protected: 99 | void assign( const Array& ); 100 | 101 | void acquireStorage( dword length, 102 | bool isCopied ); 103 | 104 | static void copyObjects( TYPE* lValStart, 105 | const TYPE* rValStart, 106 | dword length ); 107 | 108 | 109 | /// fields --------------------------------------------------------------------- 110 | private: 111 | TYPE* pStorage_m; 112 | dword length_m; 113 | }; 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | /// standard object services --------------------------------------------------- 123 | template 124 | Array::Array() 125 | : pStorage_m( 0 ) 126 | , length_m ( 0 ) 127 | { 128 | } 129 | 130 | 131 | template 132 | Array::Array 133 | ( 134 | const dword length 135 | ) 136 | : pStorage_m( 0 ) 137 | , length_m ( 0 ) 138 | { 139 | Array::setLength( length ); 140 | } 141 | 142 | 143 | template 144 | Array::~Array() 145 | { 146 | delete[] pStorage_m; 147 | } 148 | 149 | 150 | template 151 | Array::Array 152 | ( 153 | const Array& other 154 | ) 155 | : pStorage_m( 0 ) 156 | , length_m ( 0 ) 157 | { 158 | Array::assign( other ); 159 | } 160 | 161 | 162 | template 163 | Array& Array::operator= 164 | ( 165 | const Array& other 166 | ) 167 | { 168 | assign( other ); 169 | 170 | return *this; 171 | } 172 | 173 | 174 | 175 | 176 | /// commands ------------------------------------------------------------------- 177 | template 178 | void Array::setLength 179 | ( 180 | const dword length 181 | ) 182 | { 183 | acquireStorage( length, false ); 184 | } 185 | 186 | 187 | template 188 | void Array::swap 189 | ( 190 | Array& other 191 | ) 192 | { 193 | TYPE*const tmpM = pStorage_m; 194 | pStorage_m = other.pStorage_m; 195 | other.pStorage_m = tmpM; 196 | 197 | const dword tmpL = length_m; 198 | length_m = other.length_m; 199 | other.length_m = tmpL; 200 | } 201 | 202 | 203 | template 204 | void Array::append 205 | ( 206 | const TYPE& element 207 | ) 208 | { 209 | // expand storage, duplicating elements 210 | acquireStorage( length_m + 1, true ); 211 | 212 | // write new element into last position 213 | *(pStorage_m + length_m - 1) = element; 214 | 215 | 216 | // // make larger storage 217 | // Array newArray( length_m + 1 ); 218 | // 219 | // // duplicate elements, and append new element 220 | // copyObjects( newArray.pStorage_m, pStorage_m, length_m ); 221 | // *(newArray.pStorage_m + length_m) = element; 222 | // 223 | // // swap new storage with this 224 | // swap( newArray ); 225 | } 226 | 227 | 228 | template 229 | void Array::remove 230 | ( 231 | const int index 232 | ) 233 | { 234 | // check index is within range 235 | if( (index >= 0) & (index < length_m) ) 236 | { 237 | // make smaller storage 238 | Array newArray( length_m - 1 ); 239 | 240 | // copy elements, skipping element at index 241 | { 242 | TYPE* pDestination = newArray.pStorage_m; 243 | TYPE* pEnd = pDestination + newArray.length_m; 244 | const TYPE* pSource = pStorage_m; 245 | const TYPE* pIndex = pSource + index; 246 | while( pDestination < pEnd ) 247 | { 248 | pSource += static_cast(pSource == pIndex); 249 | *(pDestination++) = *(pSource++); 250 | } 251 | } 252 | 253 | // swap new storage with this 254 | swap( newArray ); 255 | } 256 | } 257 | 258 | 259 | template 260 | void Array::zeroStorage() 261 | { 262 | for( dword i = length_m; i-- > 0; ) 263 | { 264 | pStorage_m[ i ] = TYPE(); 265 | } 266 | } 267 | 268 | 269 | template 270 | inline 271 | TYPE* Array::getStorage() 272 | { 273 | return pStorage_m; 274 | } 275 | 276 | 277 | template 278 | inline 279 | TYPE& Array::operator[] 280 | ( 281 | const int index 282 | ) 283 | { 284 | return pStorage_m[ index ]; 285 | } 286 | 287 | 288 | 289 | 290 | /// queries -------------------------------------------------------------------- 291 | template 292 | inline 293 | dword Array::getLength() const 294 | { 295 | return length_m; 296 | } 297 | 298 | 299 | template 300 | inline 301 | bool Array::isEmpty() const 302 | { 303 | return 0 == length_m; 304 | } 305 | 306 | 307 | template 308 | inline 309 | dword Array::getMaxLength() 310 | { 311 | return DWORD_MAX; 312 | } 313 | 314 | 315 | template 316 | inline 317 | const TYPE* Array::getStorage() const 318 | { 319 | return pStorage_m; 320 | } 321 | 322 | 323 | template 324 | inline 325 | const TYPE& Array::operator[] 326 | ( 327 | const int index 328 | ) const 329 | { 330 | return pStorage_m[ index ]; 331 | } 332 | 333 | 334 | 335 | 336 | /// implementation ------------------------------------------------------------- 337 | template 338 | void Array::assign 339 | ( 340 | const Array& other 341 | ) 342 | { 343 | if( &other != this ) 344 | { 345 | acquireStorage( other.getLength(), false ); 346 | 347 | copyObjects( getStorage(), other.getStorage(), other.getLength() ); 348 | } 349 | } 350 | 351 | 352 | template 353 | void Array::acquireStorage 354 | ( 355 | dword newLength, 356 | const bool isCopied 357 | ) 358 | { 359 | // clamp to 0 min 360 | newLength = (newLength >= 0) ? newLength : 0; 361 | 362 | // only allocate if different length 363 | if( newLength != length_m ) 364 | { 365 | // allocate new storage 366 | TYPE* pNewStorage = new TYPE[ newLength ]; 367 | 368 | // copy elements to new storage 369 | if( isCopied ) 370 | { 371 | copyObjects( pNewStorage, pStorage_m, 372 | (length_m <= newLength ? length_m : newLength) ); 373 | } 374 | 375 | // delete old storage and set the members 376 | delete[] pStorage_m; 377 | pStorage_m = pNewStorage; 378 | length_m = newLength; 379 | } 380 | } 381 | 382 | 383 | template 384 | void Array::copyObjects 385 | ( 386 | TYPE*const pDestination, 387 | const TYPE*const pSource, 388 | const dword length 389 | ) 390 | { 391 | if( length >= 0 ) 392 | { 393 | TYPE* pDestinationCursor = pDestination + length; 394 | const TYPE* pSourceCursor = pSource + length; 395 | 396 | while( pDestinationCursor > pDestination ) 397 | { 398 | *(--pDestinationCursor) = *(--pSourceCursor); 399 | } 400 | } 401 | } 402 | 403 | 404 | }//namespace 405 | 406 | 407 | 408 | 409 | #endif//Array_h 410 | -------------------------------------------------------------------------------- /component/Octree.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #include "Octree.hpp" 40 | 41 | 42 | using namespace hxa7241_graphics; 43 | -------------------------------------------------------------------------------- /component/Octree.hpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #ifndef Octree_h 40 | #define Octree_h 41 | 42 | 43 | #include "OctreeImplementation.hpp" 44 | 45 | 46 | 47 | 48 | namespace hxa7241_graphics 49 | { 50 | 51 | 52 | /** 53 | * Agent abstract base, for client use with Octree.

54 | * 55 | * Client of Octree must define a concrete derivative of 56 | * OctreeAgent.

57 | * 58 | * This is similar to a proxy: it is an intermediary for an Octree to query 59 | * its typeless subject items, when inserting or removing.

60 | * 61 | * The overlap methods are to determine an item's relation to a cell or cells, 62 | * for insertion or removal. The parameters supply the bounds of the cell. 63 | *

64 | * 65 | * Return value of getSubcellOverlaps is 8 bits, each bit is a bool 66 | * corresponding to a subcell, the high bit for subcell 7, the low bit for 67 | * subcell 0.

68 | * 69 | * Subcell numbering: 70 | *
 71 |  *    y z       6 7
 72 |  *    |/   2 3  4 5
 73 |  *     -x  0 1
 74 |  * 
75 | * in binary: 76 | *
 77 |  *    y z           110 111
 78 |  *    |/   010 011  100 101
 79 |  *     -x  000 001
 80 |  * 
81 | * 82 | * @implementation 83 | * The ___V methods simply apply a type-cast to void*s and forward to their 84 | * abstract counterparts.

85 | * 86 | * An Octree requires its contained items to provide positional info. But 87 | * requiring the item classes to implement an OctreeItem interface would 88 | * impose a direct interface change on every prospective item type, and enlarge 89 | * their instances with a vptr.

90 | * 91 | * Instead, this agent transfers the Octree-related interface/implementation 92 | * away from the item type into a separate class. The Octree can now hold void 93 | * pointers to items and call the agent to query them indirectly.

94 | */ 95 | template 96 | class OctreeAgent 97 | : public OctreeAgentV 98 | { 99 | /// standard object services --------------------------------------------------- 100 | protected: 101 | OctreeAgent() {} 102 | public: 103 | virtual ~OctreeAgent() {} 104 | private: 105 | OctreeAgent( const OctreeAgent& ); 106 | OctreeAgent& operator=( const OctreeAgent& ); 107 | 108 | 109 | /// void-to-type forwarders 110 | public: 111 | /// queries -------------------------------------------------------------------- 112 | virtual bool isOverlappingCellV ( const void* pItem, 113 | const Vector3r& lowerCorner, 114 | const Vector3r& upperCorner ) const; 115 | virtual dword getSubcellOverlapsV( const void* pItem, 116 | const Vector3r& lower, 117 | const Vector3r& middle, 118 | const Vector3r& upper ) const; 119 | 120 | 121 | /// abstract interface 122 | protected: 123 | /// queries -------------------------------------------------------------------- 124 | /** 125 | * Called by Octree to get relation of item to cell. 126 | */ 127 | virtual bool isOverlappingCell ( const TYPE& item, 128 | const Vector3r& lowerCorner, 129 | const Vector3r& upperCorner ) const =0; 130 | /** 131 | * Called by Octree to get relation of item to subcell octants.

132 | * Override to make a more efficent calculation (boundary testing can be 133 | * shared). 134 | * @return 135 | * 8 bits, each a bool corresponding to a subcell, the high bit for subcell 136 | * 7, the low bit for subcell 0.

137 | * Subcell numbering: 138 | *
139 |     *    y z       6 7
140 |     *    |/   2 3  4 5
141 |     *     -x  0 1
142 |     * 
143 | * in binary: 144 | *
145 |     *    y z           110 111
146 |     *    |/   010 011  100 101
147 |     *     -x  000 001
148 |     * 
149 | */ 150 | virtual dword getSubcellOverlaps( const TYPE& item, 151 | const Vector3r& lowerCorner, 152 | const Vector3r& middlePoint, 153 | const Vector3r& upperCorner ) const; 154 | }; 155 | 156 | 157 | 158 | 159 | /// void-to-type forwarders 160 | template 161 | inline 162 | bool OctreeAgent::isOverlappingCellV 163 | ( 164 | const void* pItem, 165 | const Vector3r& lowerCorner, 166 | const Vector3r& upperCorner 167 | ) const 168 | { 169 | bool is = false; 170 | 171 | // null check unnecessary because Octree interface disallows nulls 172 | //if( pItem ) 173 | { 174 | is = isOverlappingCell( *reinterpret_cast( pItem ), 175 | lowerCorner, upperCorner ); 176 | } 177 | 178 | return is; 179 | } 180 | 181 | 182 | template 183 | inline 184 | dword OctreeAgent::getSubcellOverlapsV 185 | ( 186 | const void* pItem, 187 | const Vector3r& lower, 188 | const Vector3r& middle, 189 | const Vector3r& upper 190 | ) const 191 | { 192 | dword ov = ALL_OUTSIDE; 193 | 194 | // null check unnecessary because Octree interface disallows nulls 195 | //if( pItem ) 196 | { 197 | ov = getSubcellOverlaps( *reinterpret_cast( pItem ), 198 | lower, middle, upper ); 199 | } 200 | 201 | return ov; 202 | } 203 | 204 | 205 | /// default implementation 206 | template 207 | dword OctreeAgent::getSubcellOverlaps 208 | ( 209 | const TYPE& item, 210 | const Vector3r& lowerCorner, 211 | const Vector3r& middlePoint, 212 | const Vector3r& upperCorner 213 | ) const 214 | { 215 | dword flags = ALL_OUTSIDE; 216 | 217 | const Vector3r* lowMidPoints[] = { &lowerCorner, &middlePoint }; 218 | const Vector3r* midHighPoints[] = { &middlePoint, &upperCorner }; 219 | 220 | // step through each subcell 221 | for( dword i = 8; i-- > 0; ) 222 | { 223 | const Vector3r cellLowerCorner( lowMidPoints[ i & 1]->getX(), 224 | lowMidPoints[(i >> 1) & 1]->getY(), 225 | lowMidPoints[(i >> 2) & 1]->getZ() ); 226 | const Vector3r cellUpperCorner( midHighPoints[ i & 1]->getX(), 227 | midHighPoints[(i >> 1) & 1]->getY(), 228 | midHighPoints[(i >> 2) & 1]->getZ() ); 229 | // delegate to single-cell test 230 | flags |= static_cast(isOverlappingCell( item, cellLowerCorner, 231 | cellUpperCorner )) << i; 232 | } 233 | 234 | return flags; 235 | } 236 | 237 | 238 | 239 | 240 | /** 241 | * Visitor abstract base, for client use with Octree.

242 | * 243 | * Client of Octree must define a concrete derivative of 244 | * OctreeVisitor.

245 | * 246 | * This is a reversal of the Visitor pattern: it allows an operation to be 247 | * performed with the Octree, except the Octree is merely read from and it is 248 | * the visitor that is modified.

249 | * 250 | * The visit methods are called by the tree nodes during the visit operation. 251 | * The parameters supply the cell and boundary info. The implementation can 252 | * call visit on the supplied cell.

253 | * 254 | * The implementation of visitBranch needs to make the OctreeData to be given 255 | * in each call of visit. 256 | * 257 | * Subcell numbering: 258 | *
259 |  *    y z       6 7
260 |  *    |/   2 3  4 5
261 |  *     -x  0 1
262 |  * 
263 | * in binary: 264 | *
265 |  *    y z           110 111
266 |  *    |/   010 011  100 101
267 |  *     -x  000 001
268 |  * 
269 | * 270 | * @implementation 271 | * The ___V methods simply apply a type-cast to void*s and forward to their 272 | * abstract counterparts.

273 | */ 274 | template 275 | class OctreeVisitor 276 | : public OctreeVisitorV 277 | { 278 | /// standard object services --------------------------------------------------- 279 | protected: 280 | OctreeVisitor() {} 281 | public: 282 | virtual ~OctreeVisitor() {} 283 | private: 284 | OctreeVisitor( const OctreeVisitor& ); 285 | OctreeVisitor& operator=( const OctreeVisitor& ); 286 | 287 | 288 | /// void-to-type forwarders 289 | public: 290 | /// commands ------------------------------------------------------------------- 291 | virtual void visitRootV ( const OctreeCell* pRootCell, 292 | const OctreeData& octreeData ); 293 | virtual void visitBranchV( const OctreeCell* subCells[8], 294 | const OctreeData& octreeData ); 295 | virtual void visitLeafV ( const Array& items, 296 | const OctreeData& octreeData ); 297 | 298 | 299 | /// abstract interface 300 | protected: 301 | /// commands ------------------------------------------------------------------- 302 | /** 303 | * Called by Octree when visit traversal is at the root.

304 | * To continue deeper, implementation calls OctreeRoot::continueVisit( 305 | * pRootCell, octreeData, *this ). pRootCell can be null.

306 | * @see OctreeData 307 | */ 308 | virtual void visitRoot ( const OctreeCell* pRootCell, 309 | const OctreeData& octreeData ) =0; 310 | /** 311 | * Called by Octree when visit traversal is at a branch.

312 | * To continue deeper, implementation calls OctreeBranch::continueVisit( 313 | * subCells, octreeData, subCellIndex, *this ) for any/all subCellIndex 314 | * values. subCells elements can be null.

315 | * @see OctreeData 316 | */ 317 | virtual void visitBranch( const OctreeCell* subCells[8], 318 | const OctreeData& octreeData ) =0; 319 | /** 320 | * Called by Octree when visit traversal is at a leaf.

321 | * @see OctreeData 322 | */ 323 | virtual void visitLeaf ( const Array& items, 324 | const OctreeData& octreeData ) =0; 325 | }; 326 | 327 | 328 | 329 | 330 | /// void-to-type forwarders 331 | template 332 | inline 333 | void OctreeVisitor::visitRootV 334 | ( 335 | const OctreeCell* pRootCell, 336 | const OctreeData& octreeData 337 | ) 338 | { 339 | visitRoot( pRootCell, octreeData ); 340 | } 341 | 342 | 343 | template 344 | inline 345 | void OctreeVisitor::visitBranchV 346 | ( 347 | const OctreeCell* subCells[8], 348 | const OctreeData& octreeData 349 | ) 350 | { 351 | visitBranch( subCells, octreeData ); 352 | } 353 | 354 | 355 | template 356 | inline 357 | void OctreeVisitor::visitLeafV 358 | ( 359 | const Array& items, 360 | const OctreeData& octreeData 361 | ) 362 | { 363 | visitLeaf( reinterpret_cast&>( items ), 364 | octreeData ); 365 | } 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | /** 375 | * Octree based spatial index.

376 | * 377 | * Client must define concrete derivatives of OctreeAgent and 378 | * OctreeVisitor.

379 | * 380 | * maxItemCountPerCell is ignored where maxLevelCount or minCellSize is reached. 381 | *

382 | * 383 | * The octree is cubical and axis aligned, partitions are axis aligned, 384 | * partitions divide in half, each level partitions the previous level in all 385 | * three axiss.

386 | * 387 | * Storage is contracted or expanded as needed by item insertion and removal. 388 | *

389 | * 390 | * (Occupies, very approximately, 20 bytes per point item. maybe...)

391 | * 392 | * Octree is only an index: it points to client items, it does not manage 393 | * storage of items themselves.

394 | * 395 | * @see OctreeAgent 396 | * @see OctreeVisitor 397 | * 398 | * @implementation 399 | * The octree structure follows the Composite pattern.

400 | * 401 | * This template wrapper ensures the items indexed by the octree, and the agents 402 | * and visitors used when accessing them are, of matching types. All algorithmic 403 | * work is delegated to OctreeRoot and OctreeCell derivatives in 404 | * OctreeImplementation, which work with abstract base interfaces and void 405 | * pointers.

406 | * 407 | * For the insertion and removal commands, the agent provides an interface for 408 | * the octree to query the typeless item, and for the visit query, the visitor 409 | * provides callbacks to read tree nodes for carrying out the visit operation. 410 | */ 411 | template 412 | class Octree 413 | { 414 | /// standard object services --------------------------------------------------- 415 | public: 416 | /** 417 | * Constructs a particular format of octree.

418 | * @parameters 419 | * * sizeOfCube is desired length along a side
420 | * * maxItemCountPerCell is desired max item pointers per leaf
421 | * * maxLevelCount is desired max depth of tree
422 | * * minCellSize is desired min size of cells
423 | */ 424 | Octree( const Vector3r& positionOfLowerCorner, 425 | real sizeOfCube, 426 | dword maxItemCountPerCell, 427 | dword maxLevelCount, 428 | real minCellSize ); 429 | 430 | ~Octree(); 431 | Octree( const Octree& ); 432 | /** 433 | * @exceptions 434 | * Can throw storage allocation exceptions. In such cases the octree is 435 | * unmodified. 436 | */ 437 | Octree& operator=( const Octree& ); 438 | 439 | 440 | /// commands ------------------------------------------------------------------- 441 | /** 442 | * Add pointer(s) to the item to the octree.

443 | * (If an item has non-zero volume, it may have pointers in multiple 444 | * cells.)

445 | * @return is the item inserted -- false if item not inside root bound 446 | * @exceptions 447 | * Can throw storage allocation exceptions. In such cases the octree remains 448 | * structurally ok, but the item will not be fully added, -- call this 449 | * method again or the remove method. 450 | * @see remove, OctreeAgent 451 | */ 452 | bool insert( const TYPE& item, 453 | const OctreeAgent& agent ); 454 | /** 455 | * Removes pointer(s) to the item from the octree.

456 | * (If an item has non-zero volume, it may have pointers in multiple 457 | * cells.)

458 | * @return is the item removed -- false if item wasn't present 459 | * @exceptions 460 | * Can throw storage allocation exceptions. In such cases the octree remains 461 | * structurally ok, but the item will not be fully removed, -- call this 462 | * method again or the insert method. 463 | * @see insert, OctreeAgent 464 | */ 465 | bool remove( const TYPE& item, 466 | const OctreeAgent& agent ); 467 | 468 | 469 | /// queries -------------------------------------------------------------------- 470 | /** 471 | * Execute a visit query operation. 472 | * @see OctreeVisitor 473 | */ 474 | void visit( OctreeVisitor& visitor ) const; 475 | 476 | /** 477 | * Reports if the octree is empty. 478 | */ 479 | bool isEmpty() const; 480 | /** 481 | * Provides stats on the octree.

482 | * @parameters 483 | * * byteSize is size in bytes
484 | * * leafCount is number of leafs
485 | * * itemRefCount is total number of item pointers in all leafs
486 | * * maxDepth is deepest depth of tree
487 | */ 488 | void getInfo( dword& byteSize, 489 | dword& leafCount, 490 | dword& itemRefCount, 491 | dword& maxDepth ) const; 492 | 493 | /** 494 | * Gives the position supplied at construction. 495 | */ 496 | const Vector3r& getPosition() const; 497 | /** 498 | * Gives the size supplied at construction. 499 | */ 500 | real getSize() const; 501 | /** 502 | * Gives the leaf pointer limit supplied at construction. 503 | */ 504 | dword getMaxItemCountPerCell() const; 505 | /** 506 | * Gives the depth limit supplied at construction. 507 | */ 508 | dword getMaxLevelCount() const; 509 | /** 510 | * Gives the size limit supplied at construction. 511 | */ 512 | real getMinCellSize() const; 513 | 514 | 515 | /// fields --------------------------------------------------------------------- 516 | private: 517 | OctreeRoot root_m; 518 | }; 519 | 520 | 521 | 522 | 523 | /// templates /// 524 | 525 | /// standard object services --------------------------------------------------- 526 | template 527 | inline 528 | Octree::Octree 529 | ( 530 | const Vector3r& position, 531 | const real sizeOfCube, 532 | const dword maxItemCountPerCell, 533 | const dword maxLevelCount, 534 | const real minCellSize 535 | ) 536 | : root_m( position, sizeOfCube, maxItemCountPerCell, maxLevelCount, 537 | minCellSize ) 538 | { 539 | } 540 | 541 | 542 | template 543 | inline 544 | Octree::~Octree() 545 | { 546 | } 547 | 548 | 549 | template 550 | inline 551 | Octree::Octree 552 | ( 553 | const Octree& other 554 | ) 555 | : root_m( other.root_m ) 556 | { 557 | } 558 | 559 | 560 | template 561 | inline 562 | Octree& Octree::operator= 563 | ( 564 | const Octree& other 565 | ) 566 | { 567 | root_m = other.root_m; 568 | 569 | return *this; 570 | } 571 | 572 | 573 | 574 | 575 | /// commands ------------------------------------------------------------------- 576 | template 577 | inline 578 | bool Octree::insert 579 | ( 580 | const TYPE& item, 581 | const OctreeAgent& agent 582 | ) 583 | { 584 | return root_m.insert( &item, agent ); 585 | } 586 | 587 | 588 | template 589 | inline 590 | bool Octree::remove 591 | ( 592 | const TYPE& item, 593 | const OctreeAgent& agent 594 | ) 595 | { 596 | return root_m.remove( &item, agent ); 597 | } 598 | 599 | 600 | 601 | 602 | /// queries -------------------------------------------------------------------- 603 | template 604 | inline 605 | void Octree::visit 606 | ( 607 | OctreeVisitor& visitor 608 | ) const 609 | { 610 | root_m.visit( visitor ); 611 | } 612 | 613 | 614 | template 615 | inline 616 | bool Octree::isEmpty() const 617 | { 618 | return root_m.isEmpty(); 619 | } 620 | 621 | 622 | template 623 | inline 624 | void Octree::getInfo 625 | ( 626 | dword& byteSize, 627 | dword& leafCount, 628 | dword& itemRefCount, 629 | dword& maxDepth 630 | ) const 631 | { 632 | root_m.getInfo( sizeof(*this), byteSize, leafCount, itemRefCount, maxDepth ); 633 | } 634 | 635 | 636 | template 637 | inline 638 | const Vector3r& Octree::getPosition() const 639 | { 640 | return root_m.getPosition(); 641 | } 642 | 643 | 644 | template 645 | inline 646 | real Octree::getSize() const 647 | { 648 | return root_m.getSize(); 649 | } 650 | 651 | 652 | template 653 | inline 654 | dword Octree::getMaxItemCountPerCell() const 655 | { 656 | return root_m.getMaxItemCountPerCell(); 657 | } 658 | 659 | 660 | template 661 | inline 662 | dword Octree::getMaxLevelCount() const 663 | { 664 | return root_m.getMaxLevelCount(); 665 | } 666 | 667 | 668 | template 669 | inline 670 | real Octree::getMinCellSize() const 671 | { 672 | return root_m.getMinCellSize(); 673 | } 674 | 675 | 676 | }//namespace 677 | 678 | 679 | 680 | 681 | #endif//Octree_h 682 | -------------------------------------------------------------------------------- /component/OctreeAuxiliary.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #include "OctreeAuxiliary.hpp" 40 | 41 | 42 | using namespace hxa7241_graphics; 43 | 44 | 45 | 46 | 47 | /// OctreeDimensions /////////////////////////////////////////////////////////// 48 | 49 | 50 | // accommodates scene including sun and earth, down to cm cells (use 47 for mm 51 | // cells) 52 | const dword OctreeDimensions::MAX_LEVEL = 44; 53 | // resolves to nanometre scale 54 | const real OctreeDimensions::MIN_SIZE = 1.0f / static_cast(0x40000000); 55 | 56 | 57 | /// standard object services --------------------------------------------------- 58 | OctreeDimensions::OctreeDimensions 59 | ( 60 | const Vector3r& positionOfLowerCorner, 61 | const real size, 62 | const dword maxItemsPerCell, 63 | const dword maxLevelCount, 64 | const real minCellSize 65 | ) 66 | : positionOfLowerCorner_m( positionOfLowerCorner ) 67 | , size_m ( size >= 0.0f ? size : -size ) 68 | , maxItemsPerCell_m ( maxItemsPerCell > 0 ? maxItemsPerCell : 1 ) 69 | , maxLevel_m ( maxLevelCount > 0 ? maxLevelCount - 1 : 0 ) 70 | , minSize_m ( minCellSize <= size_m ? minCellSize : size_m ) 71 | { 72 | if( maxLevel_m > MAX_LEVEL ) 73 | { 74 | maxLevel_m = MAX_LEVEL; 75 | } 76 | if( minSize_m < MIN_SIZE ) 77 | { 78 | minSize_m = MIN_SIZE; 79 | } 80 | } 81 | 82 | 83 | OctreeDimensions::~OctreeDimensions() 84 | { 85 | } 86 | 87 | 88 | OctreeDimensions::OctreeDimensions 89 | ( 90 | const OctreeDimensions& other 91 | ) 92 | : positionOfLowerCorner_m( other.positionOfLowerCorner_m ) 93 | , size_m ( other.size_m ) 94 | , maxItemsPerCell_m ( other.maxItemsPerCell_m ) 95 | , maxLevel_m ( other.maxLevel_m ) 96 | , minSize_m ( other.minSize_m ) 97 | { 98 | } 99 | 100 | 101 | OctreeDimensions& OctreeDimensions::operator= 102 | ( 103 | const OctreeDimensions& other 104 | ) 105 | { 106 | if( &other != this ) 107 | { 108 | positionOfLowerCorner_m = other.positionOfLowerCorner_m; 109 | size_m = other.size_m; 110 | maxItemsPerCell_m = other.maxItemsPerCell_m; 111 | maxLevel_m = other.maxLevel_m; 112 | minSize_m = other.minSize_m; 113 | } 114 | 115 | return *this; 116 | } 117 | 118 | 119 | 120 | 121 | /// queries -------------------------------------------------------------------- 122 | bool OctreeDimensions::isSubdivide 123 | ( 124 | const dword itemCount, 125 | const dword level, 126 | const real size 127 | ) const 128 | { 129 | return (itemCount > maxItemsPerCell_m) & 130 | (level < maxLevel_m) & (size > (minSize_m * 2.0f)); 131 | } 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | /// OctreeBound //////////////////////////////////////////////////////////////// 141 | 142 | 143 | /// standard object services --------------------------------------------------- 144 | OctreeBound::OctreeBound() 145 | : positionOfLowerCorner_m( Vector3r::ZERO() ) 146 | , positionOfUpperCorner_m( Vector3r::ONE() ) 147 | , center_m ( Vector3r::HALF() ) 148 | , circumSphereRadius_m ( Vector3r::HALF().length() ) 149 | { 150 | } 151 | 152 | 153 | OctreeBound::OctreeBound 154 | ( 155 | const Vector3r& positionOfLowerCorner, 156 | const real size 157 | ) 158 | : positionOfLowerCorner_m( positionOfLowerCorner ) 159 | , positionOfUpperCorner_m( positionOfLowerCorner + Vector3r(size, size, size) ) 160 | , center_m ( (positionOfLowerCorner_m + positionOfUpperCorner_m) 161 | *= 0.5f ) 162 | , circumSphereRadius_m ( (Vector3r::HALF() * size).length() ) 163 | { 164 | } 165 | 166 | 167 | OctreeBound::OctreeBound 168 | ( 169 | const OctreeBound& parentCellBound, 170 | const dword subCellIndex 171 | ) 172 | { 173 | { 174 | const Vector3r* lowMidHigh[] = 175 | { 176 | &(parentCellBound.positionOfLowerCorner_m), 177 | &(parentCellBound.center_m), 178 | &(parentCellBound.positionOfUpperCorner_m) 179 | }; 180 | 181 | positionOfLowerCorner_m.set( 182 | lowMidHigh[ subCellIndex & 1]->getX(), 183 | lowMidHigh[(subCellIndex >> 1) & 1]->getY(), 184 | lowMidHigh[(subCellIndex >> 2) & 1]->getZ() ); 185 | positionOfUpperCorner_m.set( 186 | (lowMidHigh+1)[ subCellIndex & 1]->getX(), 187 | (lowMidHigh+1)[(subCellIndex >> 1) & 1]->getY(), 188 | (lowMidHigh+1)[(subCellIndex >> 2) & 1]->getZ() ); 189 | } 190 | 191 | ((center_m = positionOfLowerCorner_m) += positionOfUpperCorner_m) *= 0.5f; 192 | circumSphereRadius_m = parentCellBound.circumSphereRadius_m * 0.5f; 193 | } 194 | 195 | 196 | OctreeBound::~OctreeBound() 197 | { 198 | } 199 | 200 | 201 | OctreeBound::OctreeBound 202 | ( 203 | const OctreeBound& other 204 | ) 205 | : positionOfLowerCorner_m( other.positionOfLowerCorner_m ) 206 | , positionOfUpperCorner_m( other.positionOfUpperCorner_m ) 207 | , center_m ( other.center_m ) 208 | , circumSphereRadius_m ( other.circumSphereRadius_m ) 209 | { 210 | } 211 | 212 | 213 | OctreeBound& OctreeBound::operator= 214 | ( 215 | const OctreeBound& other 216 | ) 217 | { 218 | if( &other != this ) 219 | { 220 | positionOfLowerCorner_m = other.positionOfLowerCorner_m; 221 | positionOfUpperCorner_m = other.positionOfUpperCorner_m; 222 | center_m = other.center_m; 223 | circumSphereRadius_m = other.circumSphereRadius_m; 224 | } 225 | 226 | return *this; 227 | } 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | /// OctreeData ///////////////////////////////////////////////////////////////// 237 | 238 | 239 | /// standard object services --------------------------------------------------- 240 | OctreeData::OctreeData 241 | ( 242 | const OctreeDimensions& dimensions 243 | ) 244 | : bound_m ( dimensions.getPosition(), dimensions.getSize() ) 245 | , level_m ( 0 ) 246 | , pDimensions_m( &dimensions ) 247 | { 248 | } 249 | 250 | 251 | OctreeData::OctreeData 252 | ( 253 | const OctreeData& parentCellData, 254 | const dword subCellIndex 255 | ) 256 | : bound_m ( parentCellData.bound_m, subCellIndex ) 257 | , level_m ( parentCellData.level_m + 1 ) 258 | , pDimensions_m( parentCellData.pDimensions_m ) 259 | { 260 | } 261 | 262 | 263 | OctreeData::OctreeData 264 | ( 265 | const OctreeData& other, 266 | const OctreeDimensions& dimensions 267 | ) 268 | : bound_m ( other.bound_m ) 269 | , level_m ( other.level_m ) 270 | , pDimensions_m( &dimensions ) 271 | { 272 | } 273 | 274 | 275 | OctreeData::~OctreeData() 276 | { 277 | } 278 | 279 | 280 | OctreeData::OctreeData 281 | ( 282 | const OctreeData& other 283 | ) 284 | : bound_m ( other.bound_m ) 285 | , level_m ( other.level_m ) 286 | , pDimensions_m( other.pDimensions_m ) 287 | { 288 | } 289 | 290 | 291 | OctreeData& OctreeData::operator= 292 | ( 293 | const OctreeData& other 294 | ) 295 | { 296 | if( &other != this ) 297 | { 298 | bound_m = other.bound_m; 299 | level_m = other.level_m; 300 | pDimensions_m = other.pDimensions_m; 301 | } 302 | 303 | return *this; 304 | } 305 | -------------------------------------------------------------------------------- /component/OctreeAuxiliary.hpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #ifndef OctreeAuxiliary_h 40 | #define OctreeAuxiliary_h 41 | 42 | 43 | #include "Array.hpp" 44 | #include "Vector3r.hpp" 45 | 46 | 47 | 48 | 49 | namespace hxa7241_graphics 50 | { 51 | using namespace hxa7241; 52 | using hxa7241_general::Array; 53 | class OctreeCell; 54 | 55 | 56 | /** 57 | * Global octree data -- one instance for whole octree.

58 | * 59 | * Constant. 60 | * 61 | * @invariants 62 | * size_m >= 0
63 | * maxItemsPerCell_m >= 1
64 | * maxLevel_m >= 0 and <= MAX_LEVEL
65 | * minSize_m >= MIN_SIZE and <= size_m
66 | */ 67 | class OctreeDimensions 68 | { 69 | /// standard object services --------------------------------------------------- 70 | public: 71 | OctreeDimensions( const Vector3r& positionOfLowerCorner, 72 | real size, 73 | dword maxItemCountPerCell, 74 | dword maxLevelCount, 75 | real minCellSize ); 76 | 77 | ~OctreeDimensions(); 78 | OctreeDimensions( const OctreeDimensions& ); 79 | OctreeDimensions& operator=( const OctreeDimensions& ); 80 | 81 | 82 | /// queries -------------------------------------------------------------------- 83 | const Vector3r& getPosition() const; 84 | real getSize() const; 85 | dword getMaxItemCountPerCell() const; 86 | dword getMaxLevelCount() const; 87 | real getMinCellSize() const; 88 | 89 | bool isSubdivide( dword itemCount, 90 | dword level, 91 | real size ) const; 92 | 93 | 94 | /// fields --------------------------------------------------------------------- 95 | private: 96 | Vector3r positionOfLowerCorner_m; 97 | real size_m; 98 | dword maxItemsPerCell_m; 99 | dword maxLevel_m; 100 | real minSize_m; 101 | 102 | static const dword MAX_LEVEL; 103 | static const real MIN_SIZE; 104 | }; 105 | 106 | 107 | 108 | 109 | /** 110 | * Geometric data for the bound of an octree cell.

111 | * 112 | * Constant.

113 | * 114 | * Radius is that of the circumsphere.

115 | * 116 | * Subcell numbering: 117 | *
118 |  *    y z       6 7
119 |  *    |/   2 3  4 5
120 |  *     -x  0 1
121 |  * 
122 | * in binary: 123 | *
124 |  *    y z           110 111
125 |  *    |/   010 011  100 101
126 |  *     -x  000 001
127 |  * 
128 | */ 129 | class OctreeBound 130 | { 131 | /// standard object services --------------------------------------------------- 132 | public: 133 | OctreeBound(); 134 | OctreeBound( const Vector3r& positionOfLowerCorner, 135 | real size ); 136 | OctreeBound( const OctreeBound& parentCellBound, 137 | dword subCellIndex ); 138 | 139 | ~OctreeBound(); 140 | OctreeBound( const OctreeBound& ); 141 | OctreeBound& operator=( const OctreeBound& ); 142 | 143 | 144 | /// queries -------------------------------------------------------------------- 145 | const Vector3r& getLowerCorner() const; 146 | const Vector3r& getUpperCorner() const; 147 | const Vector3r& getCenter() const; 148 | real getRadius() const; 149 | real getSize() const; 150 | 151 | 152 | /// fields --------------------------------------------------------------------- 153 | private: 154 | Vector3r positionOfLowerCorner_m; 155 | Vector3r positionOfUpperCorner_m; 156 | Vector3r center_m; 157 | real circumSphereRadius_m; 158 | }; 159 | 160 | 161 | 162 | 163 | /** 164 | * Octree cell data during traversal.

165 | * 166 | * Constant.

167 | * 168 | * To be made during each level of tree descent, so storage is avoided, except 169 | * to hold one at the root.

170 | * 171 | * Subcell numbering: 172 | *
173 |  *    y z       6 7
174 |  *    |/   2 3  4 5
175 |  *     -x  0 1
176 |  * 
177 | * in binary: 178 | *
179 |  *    y z           110 111
180 |  *    |/   010 011  100 101
181 |  *     -x  000 001
182 |  * 
183 | * 184 | * @see OctreeBound 185 | * @see OctreeDimensions 186 | */ 187 | class OctreeData 188 | { 189 | /// standard object services --------------------------------------------------- 190 | public: 191 | explicit OctreeData( const OctreeDimensions& dimensions ); 192 | OctreeData( const OctreeData& parentCellData, 193 | dword subCellIndex ); 194 | OctreeData( const OctreeData&, 195 | const OctreeDimensions& ); 196 | 197 | ~OctreeData(); 198 | OctreeData( const OctreeData& ); 199 | OctreeData& operator=( const OctreeData& ); 200 | 201 | 202 | /// queries -------------------------------------------------------------------- 203 | const OctreeBound& getBound() const; 204 | dword getLevel() const; 205 | const OctreeDimensions& getDimensions() const; 206 | 207 | bool isSubdivide( dword itemCount ) const; 208 | 209 | 210 | /// fields --------------------------------------------------------------------- 211 | private: 212 | // local to cell 213 | OctreeBound bound_m; 214 | dword level_m; 215 | 216 | // global for octree 217 | const OctreeDimensions* pDimensions_m; 218 | }; 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | /** 228 | * Agent abstract base, for Octree implementation use.

229 | * 230 | * Return value of getSubcellOverlapsV is 8 bits, each bit is a bool 231 | * corresponding to a subcell, the high bit for subcell 7, the low bit for 232 | * subcell 0.

233 | * 234 | * Subcell numbering: 235 | *
236 |  *    y z       6 7
237 |  *    |/   2 3  4 5
238 |  *     -x  0 1
239 |  * 
240 | * in binary: 241 | *
242 |  *    y z           110 111
243 |  *    |/   010 011  100 101
244 |  *     -x  000 001
245 |  * 
246 | * 247 | * @see OctreeCell 248 | * @see OctreeBranch 249 | * @see OctreeLeaf 250 | */ 251 | class OctreeAgentV 252 | { 253 | /// standard object services --------------------------------------------------- 254 | protected: 255 | OctreeAgentV() {} 256 | public: 257 | virtual ~OctreeAgentV() {} 258 | private: 259 | OctreeAgentV( const OctreeAgentV& ); 260 | OctreeAgentV& operator=( const OctreeAgentV& ); 261 | public: 262 | 263 | 264 | /// queries -------------------------------------------------------------------- 265 | virtual bool isOverlappingCellV ( const void* pItem, 266 | const Vector3r& lowerCorner, 267 | const Vector3r& upperCorner ) const =0; 268 | virtual dword getSubcellOverlapsV( const void* pItem, 269 | const Vector3r& lower, 270 | const Vector3r& middle, 271 | const Vector3r& upper ) const =0; 272 | 273 | 274 | /// constants ------------------------------------------------------------------ 275 | static const dword ALL_INSIDE = 0x0000FFFF; 276 | static const dword ALL_OUTSIDE = 0x00000000; 277 | }; 278 | 279 | 280 | 281 | 282 | /** 283 | * Visitor abstract base, for Octree implementation use.

284 | * 285 | * Subcell numbering: 286 | *
287 |  *    y z       6 7
288 |  *    |/   2 3  4 5
289 |  *     -x  0 1
290 |  * 
291 | * in binary: 292 | *
293 |  *    y z           110 111
294 |  *    |/   010 011  100 101
295 |  *     -x  000 001
296 |  * 
297 | * 298 | * @see OctreeCell 299 | * @see OctreeBranch 300 | * @see OctreeLeaf 301 | */ 302 | class OctreeVisitorV 303 | { 304 | /// standard object services --------------------------------------------------- 305 | protected: 306 | OctreeVisitorV() {} 307 | public: 308 | virtual ~OctreeVisitorV() {} 309 | private: 310 | OctreeVisitorV( const OctreeVisitorV& ); 311 | OctreeVisitorV& operator=( const OctreeVisitorV& ); 312 | public: 313 | 314 | 315 | /// commands ------------------------------------------------------------------- 316 | virtual void visitRootV ( const OctreeCell* pRootCell, 317 | const OctreeData& octreeData ) =0; 318 | virtual void visitBranchV( const OctreeCell* subCells[8], 319 | const OctreeData& octreeData ) =0; 320 | virtual void visitLeafV ( const Array& items, 321 | const OctreeData& octreeData ) =0; 322 | }; 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | /// inlines /// 332 | 333 | /// OctreeDimensions ----------------------------------------------------------- 334 | inline 335 | const Vector3r& OctreeDimensions::getPosition() const 336 | { 337 | return positionOfLowerCorner_m; 338 | } 339 | 340 | 341 | inline 342 | real OctreeDimensions::getSize() const 343 | { 344 | return size_m; 345 | } 346 | 347 | 348 | inline 349 | dword OctreeDimensions::getMaxItemCountPerCell() const 350 | { 351 | return maxItemsPerCell_m; 352 | } 353 | 354 | 355 | inline 356 | dword OctreeDimensions::getMaxLevelCount() const 357 | { 358 | return maxLevel_m + 1; 359 | } 360 | 361 | 362 | inline 363 | real OctreeDimensions::getMinCellSize() const 364 | { 365 | return minSize_m; 366 | } 367 | 368 | 369 | 370 | 371 | /// OctreeBound ---------------------------------------------------------------- 372 | inline 373 | const Vector3r& OctreeBound::getLowerCorner() const 374 | { 375 | return positionOfLowerCorner_m; 376 | } 377 | 378 | 379 | inline 380 | const Vector3r& OctreeBound::getUpperCorner() const 381 | { 382 | return positionOfUpperCorner_m; 383 | } 384 | 385 | 386 | inline 387 | const Vector3r& OctreeBound::getCenter() const 388 | { 389 | return center_m; 390 | } 391 | 392 | 393 | inline 394 | real OctreeBound::getRadius() const 395 | { 396 | return circumSphereRadius_m; 397 | } 398 | 399 | 400 | inline 401 | real OctreeBound::getSize() const 402 | { 403 | return positionOfUpperCorner_m.getX() - positionOfLowerCorner_m.getX(); 404 | } 405 | 406 | 407 | 408 | 409 | /// OctreeData ----------------------------------------------------------------- 410 | inline 411 | const OctreeBound& OctreeData::getBound() const 412 | { 413 | return bound_m; 414 | } 415 | 416 | 417 | inline 418 | dword OctreeData::getLevel() const 419 | { 420 | return level_m; 421 | } 422 | 423 | 424 | inline 425 | const OctreeDimensions& OctreeData::getDimensions() const 426 | { 427 | return *pDimensions_m; 428 | } 429 | 430 | 431 | inline 432 | bool OctreeData::isSubdivide 433 | ( 434 | const dword itemCount 435 | ) const 436 | { 437 | return pDimensions_m->isSubdivide( itemCount, level_m, bound_m.getSize() ); 438 | } 439 | 440 | 441 | }//namespace 442 | 443 | 444 | 445 | 446 | #endif//OctreeAuxiliary_h 447 | -------------------------------------------------------------------------------- /component/OctreeImplementation.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #include "OctreeImplementation.hpp" 40 | 41 | 42 | using namespace hxa7241_graphics; 43 | 44 | 45 | 46 | 47 | /// OctreeRoot ///////////////////////////////////////////////////////////////// 48 | 49 | 50 | /// standard object services --------------------------------------------------- 51 | OctreeRoot::OctreeRoot 52 | ( 53 | const Vector3r& position, 54 | const real sizeOfCube, 55 | const dword maxItemsPerCell, 56 | const dword maxLevelCount, 57 | const real minCellSize 58 | ) 59 | : dimensions_m( position, sizeOfCube, maxItemsPerCell, maxLevelCount, 60 | minCellSize ) 61 | , pRootCell_m ( 0 ) 62 | { 63 | } 64 | 65 | 66 | OctreeRoot::~OctreeRoot() 67 | { 68 | delete pRootCell_m; 69 | } 70 | 71 | 72 | OctreeRoot::OctreeRoot 73 | ( 74 | const OctreeRoot& other 75 | ) 76 | : dimensions_m( other.dimensions_m ) 77 | , pRootCell_m ( OctreeCell::cloneNonZero( other.pRootCell_m ) ) 78 | { 79 | } 80 | 81 | 82 | OctreeRoot& OctreeRoot::operator= 83 | ( 84 | const OctreeRoot& other 85 | ) 86 | { 87 | if( &other != this ) 88 | { 89 | // make new data before deleting old 90 | OctreeCell* pRootCell = OctreeCell::cloneNonZero( other.pRootCell_m ); 91 | delete pRootCell_m; 92 | pRootCell_m = pRootCell; 93 | 94 | dimensions_m = other.dimensions_m; 95 | } 96 | 97 | return *this; 98 | } 99 | 100 | 101 | 102 | 103 | /// commands ------------------------------------------------------------------- 104 | bool OctreeRoot::insert 105 | ( 106 | const void* const pItem, 107 | const OctreeAgentV& agent 108 | ) 109 | { 110 | bool isInserted = false; 111 | 112 | const OctreeData data( dimensions_m ); 113 | 114 | // check if item overlaps root cell 115 | if( agent.isOverlappingCellV( pItem, data.getBound().getLowerCorner(), 116 | data.getBound().getUpperCorner() ) ) 117 | { 118 | OctreeLeaf::insertMaybeCreate( data, pRootCell_m, pItem, agent ); 119 | 120 | isInserted = true; 121 | } 122 | 123 | return isInserted; 124 | } 125 | 126 | 127 | bool OctreeRoot::remove 128 | ( 129 | const void* const pItem, 130 | const OctreeAgentV& //agent 131 | ) 132 | { 133 | bool isRemoved = false; 134 | 135 | if( pRootCell_m ) 136 | { 137 | dword unusedBranchItemCount = 0; 138 | isRemoved = pRootCell_m->remove( pRootCell_m, pItem, 139 | dimensions_m.getMaxItemCountPerCell(), unusedBranchItemCount ); 140 | } 141 | 142 | return isRemoved; 143 | } 144 | 145 | 146 | 147 | 148 | /// queries -------------------------------------------------------------------- 149 | void OctreeRoot::visit 150 | ( 151 | OctreeVisitorV& visitor 152 | ) const 153 | { 154 | const OctreeData data( dimensions_m ); 155 | 156 | visitor.visitRootV( pRootCell_m, data ); 157 | } 158 | 159 | 160 | bool OctreeRoot::isEmpty() const 161 | { 162 | return !pRootCell_m; 163 | } 164 | 165 | 166 | void OctreeRoot::getInfo 167 | ( 168 | const dword rootWrapperByteSize, 169 | dword& byteSize, 170 | dword& leafCount, 171 | dword& itemCount, 172 | dword& maxDepth 173 | ) const 174 | { 175 | byteSize = 0; 176 | leafCount = 0; 177 | itemCount = 0; 178 | maxDepth = 0; 179 | 180 | if( pRootCell_m ) 181 | { 182 | pRootCell_m->getInfo( byteSize, leafCount, itemCount, maxDepth ); 183 | } 184 | 185 | byteSize += rootWrapperByteSize; 186 | } 187 | 188 | 189 | const Vector3r& OctreeRoot::getPosition() const 190 | { 191 | return dimensions_m.getPosition(); 192 | } 193 | 194 | 195 | real OctreeRoot::getSize() const 196 | { 197 | return dimensions_m.getSize(); 198 | } 199 | 200 | 201 | dword OctreeRoot::getMaxItemCountPerCell() const 202 | { 203 | return dimensions_m.getMaxItemCountPerCell(); 204 | } 205 | 206 | 207 | dword OctreeRoot::getMaxLevelCount() const 208 | { 209 | return dimensions_m.getMaxLevelCount(); 210 | } 211 | 212 | 213 | real OctreeRoot::getMinCellSize() const 214 | { 215 | return dimensions_m.getMinCellSize(); 216 | } 217 | 218 | 219 | 220 | 221 | /// statics -------------------------------------------------------------------- 222 | void OctreeRoot::continueVisit 223 | ( 224 | const OctreeCell* pRootCell, 225 | const OctreeData& octreeData, 226 | OctreeVisitorV& visitor 227 | ) 228 | { 229 | if( pRootCell ) 230 | { 231 | pRootCell->visit( octreeData, visitor ); 232 | } 233 | } 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | /// OctreeCell ///////////////////////////////////////////////////////////////// 243 | 244 | 245 | /// statics -------------------------------------------------------------------- 246 | OctreeCell* OctreeCell::cloneNonZero 247 | ( 248 | const OctreeCell* pOriginal 249 | ) 250 | { 251 | return pOriginal ? pOriginal->clone() : 0; 252 | } 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | /// OctreeBranch /////////////////////////////////////////////////////////////// 262 | 263 | 264 | /// standard object services --------------------------------------------------- 265 | OctreeBranch::OctreeBranch() 266 | { 267 | OctreeBranch::zeroSubCells(); 268 | } 269 | 270 | 271 | OctreeBranch::OctreeBranch 272 | ( 273 | const OctreeData& thisData, 274 | const Array& items, 275 | const void* const pItem, 276 | const OctreeAgentV& agent 277 | ) 278 | { 279 | OctreeBranch::zeroSubCells(); 280 | 281 | try 282 | { 283 | OctreeCell* pNotUsed = 0; 284 | 285 | // insert items 286 | for( int j = items.getLength(); j-- > 0; ) 287 | { 288 | OctreeBranch::insert( thisData, pNotUsed, items[j], agent ); 289 | } 290 | 291 | // insert last item 292 | OctreeBranch::insert( thisData, pNotUsed, pItem, agent ); 293 | } 294 | catch( ... ) 295 | { 296 | // delete any allocated cells 297 | this->~OctreeBranch(); 298 | 299 | throw; 300 | } 301 | } 302 | 303 | 304 | OctreeBranch::~OctreeBranch() 305 | { 306 | for( int i = 8; i-- > 0; ) 307 | { 308 | delete subCells_m[i]; 309 | } 310 | } 311 | 312 | 313 | OctreeBranch::OctreeBranch 314 | ( 315 | const OctreeBranch& other 316 | ) 317 | { 318 | OctreeBranch::zeroSubCells(); 319 | 320 | try 321 | { 322 | for( int i = 8; i-- > 0; ) 323 | { 324 | subCells_m[i] = OctreeCell::cloneNonZero( other.subCells_m[i] ); 325 | } 326 | } 327 | catch( ... ) 328 | { 329 | // delete any allocated cells 330 | this->~OctreeBranch(); 331 | 332 | throw; 333 | } 334 | } 335 | 336 | 337 | OctreeBranch& OctreeBranch::operator= 338 | ( 339 | const OctreeBranch& other 340 | ) 341 | { 342 | if( &other != this ) 343 | { 344 | OctreeBranch copy( other ); 345 | 346 | // 'move' subCells copies to this (leaving copy empty) 347 | for( int i = 8; i-- > 0; ) 348 | { 349 | delete subCells_m[i]; 350 | subCells_m[i] = copy.subCells_m[i]; 351 | 352 | copy.subCells_m[i] = 0; 353 | } 354 | } 355 | 356 | return *this; 357 | } 358 | 359 | 360 | 361 | 362 | /// commands ------------------------------------------------------------------- 363 | void OctreeBranch::insert 364 | ( 365 | const OctreeData& thisData, 366 | OctreeCell*& ,//pThis, 367 | const void* const pItem, 368 | const OctreeAgentV& agent 369 | ) 370 | { 371 | // get subcell-item overlaps flags 372 | const OctreeBound& bound = thisData.getBound(); 373 | const dword overlaps = agent.getSubcellOverlapsV( pItem, 374 | bound.getLowerCorner(), bound.getCenter(), bound.getUpperCorner() ); 375 | 376 | // loop through sub cells 377 | for( int i = 8; i-- > 0; ) 378 | { 379 | // check if sub cell is overlapped by item 380 | if( (overlaps >> i) & 1 ) 381 | { 382 | // make sub cell data 383 | const OctreeData subCellData( thisData, i ); 384 | 385 | // add item to sub cell 386 | OctreeLeaf::insertMaybeCreate( subCellData, subCells_m[i], 387 | pItem, agent ); 388 | } 389 | } 390 | } 391 | 392 | 393 | bool OctreeBranch::remove 394 | ( 395 | OctreeCell*& pThis, 396 | const void* const pItem, 397 | const dword maxItemsPerCell, 398 | dword& itemCount 399 | ) 400 | { 401 | bool isRemoved = false; 402 | dword branchItemCount = 0; 403 | 404 | // loop through sub cells 405 | for( int i = 8; i-- > 0; ) 406 | { 407 | // remove item from non-null sub cell 408 | OctreeCell*& pSubCell = subCells_m[i]; 409 | if( pSubCell ) 410 | { 411 | isRemoved |= pSubCell->remove( pSubCell, pItem, maxItemsPerCell, 412 | branchItemCount ); 413 | } 414 | } 415 | 416 | itemCount += branchItemCount; 417 | 418 | // decide whether to collapse this branch 419 | if( branchItemCount > 0 ) 420 | { 421 | // collapse to leaf 422 | if( branchItemCount <= maxItemsPerCell ) 423 | { 424 | // all subcells *will* be leafs! 425 | // because: 426 | // a) if a branch has below it less item refs than the threshold, 427 | // it collapses to a leaf (this function!) 428 | // b) the total of item refs below this branch in the tree is less 429 | // than the threshold 430 | // c) therefore the total of item refs in any branch below this 431 | // cell will be less than the threshold 432 | // d) branchs below this cell will be collapsed before this branch 433 | // (because the recursive 'remove' call is before the 434 | // collapsing code) 435 | // so: if this branch will collapse to a leaf, then all its sub 436 | // branchs (direct and indirect) will collapse to leafs, and that 437 | // will happen before this branch. 438 | OctreeCell*const pLeaf = new OctreeLeaf( 439 | reinterpret_cast( subCells_m ) ); 440 | 441 | delete pThis; 442 | pThis = pLeaf; 443 | } 444 | } 445 | else 446 | { 447 | // delete this branch 448 | delete pThis; 449 | pThis = 0; 450 | } 451 | 452 | return isRemoved; 453 | } 454 | 455 | 456 | 457 | 458 | /// queries -------------------------------------------------------------------- 459 | void OctreeBranch::visit 460 | ( 461 | const OctreeData& thisData, 462 | OctreeVisitorV& visitor 463 | ) const 464 | { 465 | visitor.visitBranchV( const_cast(subCells_m), thisData ); 466 | } 467 | 468 | 469 | OctreeCell* OctreeBranch::clone() const 470 | { 471 | return new OctreeBranch( *this ); 472 | } 473 | 474 | 475 | void OctreeBranch::getInfo 476 | ( 477 | dword& byteSize, 478 | dword& leafCount, 479 | dword& itemCount, 480 | dword& maxDepth 481 | ) const 482 | { 483 | byteSize += sizeof(*this); 484 | 485 | const dword thisDepth = maxDepth + 1; 486 | 487 | for( int i = 8; i-- > 0; ) 488 | { 489 | const OctreeCell*const pSubCell = subCells_m[i]; 490 | if( pSubCell ) 491 | { 492 | dword depth = thisDepth; 493 | pSubCell->getInfo( byteSize, leafCount, itemCount, depth ); 494 | 495 | if( maxDepth < depth ) 496 | { 497 | maxDepth = depth; 498 | } 499 | } 500 | } 501 | } 502 | 503 | 504 | 505 | 506 | /// statics -------------------------------------------------------------------- 507 | void OctreeBranch::continueVisit 508 | ( 509 | const OctreeCell* subCells[8], 510 | const OctreeData& octreeData, 511 | const dword subCellIndex, 512 | OctreeVisitorV& visitor 513 | ) 514 | { 515 | const OctreeCell*const pSubCell = subCells[ subCellIndex & 0x07 ]; 516 | if( pSubCell ) 517 | { 518 | const OctreeData subCellData( octreeData, subCellIndex ); 519 | pSubCell->visit( subCellData, visitor ); 520 | } 521 | } 522 | 523 | 524 | 525 | 526 | /// implementation ------------------------------------------------------------- 527 | void OctreeBranch::zeroSubCells() 528 | { 529 | for( int i = 8; i-- > 0; ) 530 | { 531 | subCells_m[i] = 0; 532 | } 533 | } 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | /// OctreeLeaf ///////////////////////////////////////////////////////////////// 543 | 544 | 545 | /// standard object services --------------------------------------------------- 546 | OctreeLeaf::OctreeLeaf() 547 | : items_m() 548 | { 549 | } 550 | 551 | 552 | OctreeLeaf::OctreeLeaf 553 | ( 554 | const void* pItem 555 | ) 556 | : items_m() 557 | { 558 | items_m.append( pItem ); 559 | } 560 | 561 | 562 | OctreeLeaf::OctreeLeaf 563 | ( 564 | const OctreeLeaf*const leafs[8] 565 | ) 566 | : items_m() 567 | { 568 | // sum all items lengths 569 | dword totalLength = 0; 570 | for( int i = 8; i-- > 0; ) 571 | { 572 | const OctreeLeaf*const pLeaf = leafs[i]; 573 | if( pLeaf ) 574 | { 575 | totalLength += pLeaf->items_m.getLength(); 576 | } 577 | } 578 | 579 | // prepare items array to hold all other items 580 | items_m.setLength( totalLength ); 581 | 582 | // copy items arrays 583 | const void** pElement = items_m.getStorage(); 584 | for( int i = 0; i < 8; ++i ) 585 | { 586 | const OctreeLeaf*const pLeaf = leafs[i]; 587 | if( pLeaf ) 588 | { 589 | const void* const* pOtherElement = pLeaf->items_m.getStorage(); 590 | const void* const* pOtherEnd = pOtherElement + 591 | pLeaf->items_m.getLength(); 592 | for( ; pOtherElement < pOtherEnd; ++pOtherElement, ++pElement ) 593 | { 594 | *pElement = *pOtherElement; 595 | } 596 | } 597 | } 598 | } 599 | 600 | 601 | OctreeLeaf::~OctreeLeaf() 602 | { 603 | } 604 | 605 | 606 | OctreeLeaf::OctreeLeaf 607 | ( 608 | const OctreeLeaf& other 609 | ) 610 | : items_m( other.items_m ) 611 | { 612 | } 613 | 614 | 615 | OctreeLeaf& OctreeLeaf::operator= 616 | ( 617 | const OctreeLeaf& other 618 | ) 619 | { 620 | items_m = other.items_m; 621 | 622 | return *this; 623 | } 624 | 625 | 626 | 627 | 628 | /// commands ------------------------------------------------------------------- 629 | void OctreeLeaf::insert 630 | ( 631 | const OctreeData& thisData, 632 | OctreeCell*& pThis, 633 | const void* const pItem, 634 | const OctreeAgentV& agent 635 | ) 636 | { 637 | // check if item already present 638 | bool isAlreadyPresent = false; 639 | for( int i = items_m.getLength(); (i-- > 0) & !isAlreadyPresent; ) 640 | { 641 | isAlreadyPresent |= (pItem == items_m[i]); 642 | } 643 | 644 | // only insert if item not already present 645 | if( !isAlreadyPresent ) 646 | { 647 | // check if leaf should be subdivided 648 | if( !thisData.isSubdivide( items_m.getLength() + 1 ) ) 649 | { 650 | // append item to collection 651 | items_m.append( pItem ); 652 | } 653 | else 654 | { 655 | // subdivide by making branch and adding items to it 656 | OctreeCell*const pBranch = new OctreeBranch( thisData, items_m, pItem, 657 | agent ); 658 | 659 | // replace this with branch 660 | delete pThis; 661 | pThis = pBranch; 662 | } 663 | } 664 | } 665 | 666 | 667 | bool OctreeLeaf::remove 668 | ( 669 | OctreeCell*& pThis, 670 | const void* const pItem, 671 | const dword ,//maxItemsPerCell, 672 | dword& itemCount 673 | ) 674 | { 675 | bool isRemoved = false; 676 | 677 | // loop through items 678 | for( int i = 0; i < items_m.getLength(); ) 679 | { 680 | // check if item is present 681 | if( items_m[i] == pItem ) 682 | { 683 | // remove item 684 | items_m.remove( i ); 685 | isRemoved = true; 686 | } 687 | else 688 | { 689 | ++i; 690 | } 691 | } 692 | 693 | itemCount += items_m.getLength(); 694 | 695 | // check if leaf is now empty 696 | if( items_m.isEmpty() ) 697 | { 698 | // remove this leaf 699 | delete pThis; 700 | pThis = 0; 701 | } 702 | 703 | return isRemoved; 704 | } 705 | 706 | 707 | 708 | 709 | /// queries -------------------------------------------------------------------- 710 | void OctreeLeaf::visit 711 | ( 712 | const OctreeData& thisData, 713 | OctreeVisitorV& visitor 714 | ) const 715 | { 716 | visitor.visitLeafV( items_m, thisData ); 717 | } 718 | 719 | 720 | OctreeCell* OctreeLeaf::clone() const 721 | { 722 | return new OctreeLeaf( *this ); 723 | } 724 | 725 | 726 | void OctreeLeaf::getInfo 727 | ( 728 | dword& byteSize, 729 | dword& leafCount, 730 | dword& itemCount, 731 | dword& maxDepth 732 | ) const 733 | { 734 | byteSize += sizeof(*this) + (items_m.getLength() * sizeof(void*)); 735 | ++leafCount; 736 | itemCount += items_m.getLength(); 737 | ++maxDepth; 738 | } 739 | 740 | 741 | 742 | 743 | /// statics -------------------------------------------------------------------- 744 | void OctreeLeaf::insertMaybeCreate 745 | ( 746 | const OctreeData& cellData, 747 | OctreeCell*& pCell, 748 | const void* const pItem, 749 | const OctreeAgentV& agent 750 | ) 751 | { 752 | // check cell exists 753 | if( !pCell ) 754 | { 755 | // make leaf, adding item 756 | OctreeCell*const pLeaf = new OctreeLeaf( pItem ); 757 | 758 | // replace cell with leaf 759 | delete pCell; 760 | pCell = pLeaf; 761 | } 762 | else 763 | { 764 | // forward to existing cell 765 | pCell->insert( cellData, pCell, pItem, agent ); 766 | } 767 | } 768 | -------------------------------------------------------------------------------- /component/OctreeImplementation.hpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #ifndef OctreeImplementation_h 40 | #define OctreeImplementation_h 41 | 42 | 43 | #include "OctreeAuxiliary.hpp" 44 | 45 | 46 | 47 | 48 | namespace hxa7241_graphics 49 | { 50 | 51 | 52 | /** 53 | * Implementation class for the Octree template. 54 | * 55 | * @invariants 56 | * pRootCell_m can be null, or point to an OctreeCell instance.

57 | * 58 | * At construction, pRootCell_m is set to a legal value.
59 | * At destruction, pRootCell_m is deleted.
60 | * Whenever pRootCell_m is modified, it must be deleted then set to a legal 61 | * value.
62 | * A legal value is: either 0, or the value from invocation of 'new'. 63 | */ 64 | class OctreeRoot 65 | { 66 | /// standard object services --------------------------------------------------- 67 | public: 68 | OctreeRoot( const Vector3r& position, 69 | real sizeOfCube, 70 | dword maxItemsPerCell, 71 | dword maxLevelCount, 72 | real minCellSize ); 73 | 74 | ~OctreeRoot(); 75 | OctreeRoot( const OctreeRoot& ); 76 | OctreeRoot& operator=( const OctreeRoot& ); 77 | 78 | 79 | /// commands ------------------------------------------------------------------- 80 | bool insert( const void* pItem, 81 | const OctreeAgentV& agent ); 82 | bool remove( const void* pItem, 83 | const OctreeAgentV& agent ); 84 | 85 | 86 | /// queries -------------------------------------------------------------------- 87 | void visit( OctreeVisitorV& visitor ) const; 88 | 89 | bool isEmpty() const; 90 | void getInfo( dword rootWrapperByteSize, 91 | dword& byteSize, 92 | dword& leafCount, 93 | dword& itemCount, 94 | dword& maxDepth ) const; 95 | 96 | const Vector3r& getPosition() const; 97 | real getSize() const; 98 | dword getMaxItemCountPerCell() const; 99 | dword getMaxLevelCount() const; 100 | real getMinCellSize() const; 101 | 102 | 103 | /// statics -------------------------------------------------------------------- 104 | static void continueVisit( const OctreeCell* pRootCell, 105 | const OctreeData& octreeData, 106 | OctreeVisitorV& visitor ); 107 | 108 | 109 | /// fields --------------------------------------------------------------------- 110 | private: 111 | OctreeDimensions dimensions_m; 112 | OctreeCell* pRootCell_m; 113 | }; 114 | 115 | 116 | 117 | 118 | /** 119 | * Abstract base for Composite types, for implementing Octree nodes. 120 | * 121 | * @implementation 122 | * Subcell numbering: 123 | *
124 |  *    y z       6 7
125 |  *    |/   2 3  4 5
126 |  *     -x  0 1
127 |  * 
128 | * in binary: 129 | *
130 |  *    y z           110 111
131 |  *    |/   010 011  100 101
132 |  *     -x  000 001
133 |  * 
134 | */ 135 | class OctreeCell 136 | { 137 | /// standard object services --------------------------------------------------- 138 | protected: 139 | OctreeCell() {} 140 | public: 141 | virtual ~OctreeCell() {} 142 | private: 143 | OctreeCell( const OctreeCell& ); 144 | OctreeCell& operator=( const OctreeCell& ); 145 | public: 146 | 147 | 148 | /// commands ------------------------------------------------------------------- 149 | virtual void insert( const OctreeData& thisData, 150 | OctreeCell*& pThis, 151 | const void* pItem, 152 | const OctreeAgentV& agent ) =0; 153 | virtual bool remove( OctreeCell*& pThis, 154 | const void* pItem, 155 | const dword maxItemsPerCell, 156 | dword& itemCount ) =0; 157 | 158 | 159 | /// queries -------------------------------------------------------------------- 160 | virtual void visit( const OctreeData& thisData, 161 | OctreeVisitorV& visitor ) const =0; 162 | 163 | virtual OctreeCell* clone() const =0; 164 | 165 | virtual void getInfo( dword& byteSize, 166 | dword& leafCount, 167 | dword& itemCount, 168 | dword& maxDepth ) const =0; 169 | 170 | 171 | /// statics -------------------------------------------------------------------- 172 | static OctreeCell* cloneNonZero( const OctreeCell* ); 173 | }; 174 | 175 | 176 | 177 | 178 | /** 179 | * Inner node implementation of an octree cell.

180 | * 181 | * Stores pointers to eight (at most) child cells. 182 | * 183 | * @invariants 184 | * subCells_m elements can be null, or point to an OctreeCell instance. 185 | */ 186 | class OctreeBranch 187 | : public OctreeCell 188 | { 189 | /// standard object services --------------------------------------------------- 190 | public: 191 | OctreeBranch(); 192 | OctreeBranch( const OctreeData& thisData, 193 | const Array& items, 194 | const void* const pItem, 195 | const OctreeAgentV& agent ); 196 | 197 | virtual ~OctreeBranch(); 198 | OctreeBranch( const OctreeBranch& ); 199 | OctreeBranch& operator=( const OctreeBranch& ); 200 | 201 | 202 | /// commands ------------------------------------------------------------------- 203 | virtual void insert( const OctreeData& thisData, 204 | OctreeCell*& pThis, 205 | const void* pItem, 206 | const OctreeAgentV& agent ); 207 | virtual bool remove( OctreeCell*& pThis, 208 | const void* pItem, 209 | const dword maxItemsPerCell, 210 | dword& itemCount ); 211 | 212 | 213 | /// queries -------------------------------------------------------------------- 214 | virtual void visit( const OctreeData& thisData, 215 | OctreeVisitorV& visitor ) const; 216 | 217 | virtual OctreeCell* clone() const; 218 | 219 | virtual void getInfo( dword& byteSize, 220 | dword& leafCount, 221 | dword& itemCount, 222 | dword& maxDepth ) const; 223 | 224 | 225 | /// statics -------------------------------------------------------------------- 226 | static void continueVisit( const OctreeCell* subCells[8], 227 | const OctreeData& octreeData, 228 | dword subCellIndex, 229 | OctreeVisitorV& visitor ); 230 | 231 | 232 | /// implementation ------------------------------------------------------------- 233 | protected: 234 | virtual void zeroSubCells(); 235 | 236 | 237 | /// fields --------------------------------------------------------------------- 238 | private: 239 | OctreeCell* subCells_m[ 8 ]; 240 | }; 241 | 242 | 243 | 244 | 245 | /** 246 | * Outer node implementation of an octree cell.

247 | * 248 | * Stores pointers to items. 249 | */ 250 | class OctreeLeaf 251 | : public OctreeCell 252 | { 253 | /// standard object services --------------------------------------------------- 254 | public: 255 | OctreeLeaf(); 256 | OctreeLeaf( const OctreeLeaf*const leafs[8] ); 257 | private: 258 | explicit OctreeLeaf( const void* pItem ); 259 | 260 | public: 261 | virtual ~OctreeLeaf(); 262 | OctreeLeaf( const OctreeLeaf& ); 263 | OctreeLeaf& operator=( const OctreeLeaf& ); 264 | 265 | 266 | /// commands ------------------------------------------------------------------- 267 | virtual void insert( const OctreeData& thisData, 268 | OctreeCell*& pThis, 269 | const void* pItem, 270 | const OctreeAgentV& agent ); 271 | virtual bool remove( OctreeCell*& pThis, 272 | const void* pItem, 273 | const dword maxItemsPerCell, 274 | dword& itemCount ); 275 | 276 | 277 | /// queries -------------------------------------------------------------------- 278 | virtual void visit( const OctreeData& thisData, 279 | OctreeVisitorV& visitor ) const; 280 | 281 | virtual OctreeCell* clone() const; 282 | 283 | virtual void getInfo( dword& byteSize, 284 | dword& leafCount, 285 | dword& itemCount, 286 | dword& maxDepth ) const; 287 | 288 | 289 | /// statics -------------------------------------------------------------------- 290 | static void insertMaybeCreate( const OctreeData& cellData, 291 | OctreeCell*& pCell, 292 | const void* pItem, 293 | const OctreeAgentV& agent ); 294 | 295 | 296 | /// fields --------------------------------------------------------------------- 297 | private: 298 | Array items_m; 299 | }; 300 | 301 | 302 | }//namespace 303 | 304 | 305 | 306 | 307 | #endif//OctreeImplementation_h 308 | -------------------------------------------------------------------------------- /component/Primitives.hpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #ifndef Primitives_h 40 | #define Primitives_h 41 | 42 | 43 | #include 44 | #include 45 | 46 | 47 | 48 | 49 | namespace hxa7241 50 | { 51 | 52 | 53 | /// types ---------------------------------------------------------------------- 54 | 55 | // remove definition to set real to double 56 | #define REAL_IS_FLOAT 57 | 58 | typedef signed char byte; 59 | typedef unsigned char ubyte; 60 | 61 | typedef signed short word; 62 | typedef unsigned short uword; 63 | 64 | typedef signed int dword; 65 | typedef unsigned int udword; 66 | 67 | #ifdef REAL_IS_FLOAT 68 | typedef float real; 69 | #else 70 | typedef double real; 71 | #endif 72 | 73 | 74 | /// constants ------------------------------------------------------------------ 75 | 76 | // limits.h version 77 | 78 | const byte BYTE_MIN = SCHAR_MIN; 79 | const byte BYTE_MAX = SCHAR_MAX; 80 | const int BYTE_BITS = 8; 81 | 82 | const ubyte UBYTE_MIN = 0; 83 | const ubyte UBYTE_MAX = UCHAR_MAX; 84 | const int UBYTE_BITS = 8; 85 | 86 | 87 | const word WORD_MIN = SHRT_MIN; 88 | const word WORD_MAX = SHRT_MAX; 89 | const int WORD_BITS = 16; 90 | 91 | const uword UWORD_MIN = 0; 92 | const uword UWORD_MAX = USHRT_MAX; 93 | const int UWORD_BITS = 16; 94 | 95 | 96 | const dword DWORD_MIN = INT_MIN; 97 | const dword DWORD_MAX = INT_MAX; 98 | const int DWORD_BITS = 32; 99 | 100 | const udword UDWORD_MIN = 0; 101 | const udword UDWORD_MAX = UINT_MAX; 102 | const int UDWORD_BITS = 32; 103 | 104 | 105 | const float FLOAT_MIN_POS = static_cast(FLT_MIN); 106 | const float FLOAT_MIN_NEG = static_cast(-FLT_MAX); 107 | const float FLOAT_MAX = static_cast(FLT_MAX); 108 | const float FLOAT_EPSILON = static_cast(FLT_EPSILON); 109 | const float FLOAT_ALMOST_ONE = static_cast(1.0f - FLT_EPSILON); 110 | const float FLOAT_SMALL = static_cast(1.0e-12f); 111 | const float FLOAT_LARGE = static_cast(1.0e+12f); 112 | 113 | const double DOUBLE_MIN_POS = static_cast(DBL_MIN); 114 | const double DOUBLE_MIN_NEG = static_cast(-DBL_MAX); 115 | const double DOUBLE_MAX = static_cast(DBL_MAX); 116 | const double DOUBLE_EPSILON = static_cast(DBL_EPSILON); 117 | const double DOUBLE_ALMOST_ONE = static_cast(1.0 - DBL_EPSILON); 118 | const double DOUBLE_SMALL = static_cast(1.0e-96); 119 | const double DOUBLE_LARGE = static_cast(1.0e+96); 120 | 121 | #ifdef REAL_IS_FLOAT 122 | const float REAL_MIN_POS = FLOAT_MIN_POS; 123 | const float REAL_MIN_NEG = FLOAT_MIN_NEG; 124 | const float REAL_MAX = FLOAT_MAX; 125 | const float REAL_EPSILON = FLOAT_EPSILON; 126 | const float REAL_ALMOST_ONE = FLOAT_ALMOST_ONE; 127 | const float REAL_SMALL = FLOAT_SMALL; 128 | const float REAL_LARGE = FLOAT_LARGE; 129 | #else 130 | const double REAL_MIN_POS = DOUBLE_MIN_POS; 131 | const double REAL_MIN_NEG = DOUBLE_MIN_NEG; 132 | const double REAL_MAX = DOUBLE_MAX; 133 | const double REAL_EPSILON = DOUBLE_EPSILON; 134 | const double REAL_ALMOST_ONE = DOUBLE_ALMOST_ONE; 135 | const double REAL_SMALL = DOUBLE_SMALL; 136 | const double REAL_LARGE = DOUBLE_LARGE; 137 | #endif 138 | 139 | 140 | // limits version 141 | 142 | /* 143 | const byte BYTE_MIN = std::numeric_limits::min(); 144 | const byte BYTE_MAX = std::numeric_limits::max(); 145 | const int BYTE_BITS = 8; 146 | 147 | const ubyte UBYTE_MIN = std::numeric_limits::min(); 148 | const ubyte UBYTE_MAX = std::numeric_limits::max(); 149 | const int UBYTE_BITS = 8; 150 | 151 | 152 | const word WORD_MIN = std::numeric_limits::min(); 153 | const word WORD_MAX = std::numeric_limits::max(); 154 | const int WORD_BITS = 16; 155 | 156 | const uword UWORD_MIN = std::numeric_limits::min(); 157 | const uword UWORD_MAX = std::numeric_limits::max(); 158 | const int UWORD_BITS = 16; 159 | 160 | 161 | const dword DWORD_MIN = std::numeric_limits::min(); 162 | const dword DWORD_MAX = std::numeric_limits::max(); 163 | const int DWORD_BITS = 32; 164 | 165 | const udword UDWORD_MIN = std::numeric_limits::min(); 166 | const udword UDWORD_MAX = std::numeric_limits::max(); 167 | const int UDWORD_BITS = 32; 168 | 169 | 170 | const float FLOAT_MIN_POS = std::numeric_limits::min(); 171 | const float FLOAT_MIN_NEG = 172 | static_cast(-std::numeric_limits::max()); 173 | const float FLOAT_MAX = std::numeric_limits::max(); 174 | const float FLOAT_EPSILON = std::numeric_limits::epsilon(); 175 | const float FLOAT_ALMOST_ONE = 176 | static_cast(1.0f - std::numeric_limits::epsilon()); 177 | const float FLOAT_SMALL = static_cast(1.0e-12f); 178 | const float FLOAT_LARGE = static_cast(1.0e+12f); 179 | 180 | const double DOUBLE_MIN_POS = std::numeric_limits::min(); 181 | const double DOUBLE_MIN_NEG = 182 | static_cast(-std::numeric_limits::max()); 183 | const double DOUBLE_MAX = std::numeric_limits::max(); 184 | const double DOUBLE_EPSILON = std::numeric_limits::epsilon(); 185 | const double DOUBLE_ALMOST_ONE = 186 | static_cast(1.0 - std::numeric_limits::epsilon()); 187 | const double DOUBLE_SMALL = static_cast(1.0e-96); 188 | const double DOUBLE_LARGE = static_cast(1.0e+96); 189 | 190 | #ifdef REAL_IS_FLOAT 191 | const float REAL_MIN_POS = FLOAT_MIN_POS; 192 | const float REAL_MIN_NEG = FLOAT_MIN_NEG; 193 | const float REAL_MAX = FLOAT_MAX; 194 | const float REAL_EPSILON = FLOAT_EPSILON; 195 | const float REAL_ALMOST_ONE = FLOAT_ALMOST_ONE; 196 | const float REAL_SMALL = FLOAT_SMALL; 197 | const float REAL_LARGE = FLOAT_LARGE; 198 | #else 199 | const double REAL_MIN_POS = DOUBLE_MIN_POS; 200 | const double REAL_MIN_NEG = DOUBLE_MIN_NEG; 201 | const double REAL_MAX = DOUBLE_MAX; 202 | const double REAL_EPSILON = DOUBLE_EPSILON; 203 | const double REAL_ALMOST_ONE = DOUBLE_ALMOST_ONE; 204 | const double REAL_SMALL = DOUBLE_SMALL; 205 | const double REAL_LARGE = DOUBLE_LARGE; 206 | #endif 207 | */ 208 | 209 | 210 | }//namespace 211 | 212 | 213 | 214 | 215 | #endif//Primitives_h 216 | -------------------------------------------------------------------------------- /component/Vector3r.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #include 40 | 41 | #include "Vector3r.hpp" 42 | 43 | 44 | using namespace hxa7241_graphics; 45 | 46 | 47 | 48 | 49 | /// standard object services --------------------------------------------------- 50 | Vector3r::Vector3r() 51 | { 52 | xyz_m[0] = real(); 53 | xyz_m[1] = real(); 54 | xyz_m[2] = real(); 55 | } 56 | 57 | 58 | Vector3r::Vector3r 59 | ( 60 | const real x, 61 | const real y, 62 | const real z 63 | ) 64 | { 65 | xyz_m[0] = x; 66 | xyz_m[1] = y; 67 | xyz_m[2] = z; 68 | } 69 | 70 | 71 | //Vector3r::Vector3r 72 | //( 73 | // const real xyz[3] 74 | //) 75 | //{ 76 | // xyz_m[0] = xyz[0]; 77 | // xyz_m[1] = xyz[1]; 78 | // xyz_m[2] = xyz[2]; 79 | //} 80 | // 81 | // 82 | //Vector3r::~Vector3r() 83 | //{ 84 | //} 85 | // 86 | // 87 | //Vector3r::Vector3r 88 | //( 89 | // const Vector3r& other 90 | //) 91 | //{ 92 | // xyz_m[0] = other.xyz_m[0]; 93 | // xyz_m[1] = other.xyz_m[1]; 94 | // xyz_m[2] = other.xyz_m[2]; 95 | //} 96 | 97 | 98 | Vector3r& Vector3r::operator= 99 | ( 100 | const Vector3r& other 101 | ) 102 | { 103 | if( &other != this ) 104 | { 105 | xyz_m[0] = other.xyz_m[0]; 106 | xyz_m[1] = other.xyz_m[1]; 107 | xyz_m[2] = other.xyz_m[2]; 108 | } 109 | 110 | return *this; 111 | } 112 | 113 | 114 | 115 | 116 | /// commands ------------------------------------------------------------------- 117 | Vector3r& Vector3r::set 118 | ( 119 | const real x, 120 | const real y, 121 | const real z 122 | ) 123 | { 124 | xyz_m[0] = x; 125 | xyz_m[1] = y; 126 | xyz_m[2] = z; 127 | 128 | return *this; 129 | } 130 | 131 | 132 | /*Vector3r& Vector3r::set 133 | ( 134 | const real xyz[3] 135 | ) 136 | { 137 | xyz_m[0] = xyz[0]; 138 | xyz_m[1] = xyz[1]; 139 | xyz_m[2] = xyz[2]; 140 | 141 | return *this; 142 | } 143 | 144 | 145 | Vector3r& Vector3r::setX 146 | ( 147 | const real x 148 | ) 149 | { 150 | xyz_m[0] = x; 151 | 152 | return *this; 153 | } 154 | 155 | 156 | Vector3r& Vector3r::setY 157 | ( 158 | const real y 159 | ) 160 | { 161 | xyz_m[1] = y; 162 | 163 | return *this; 164 | } 165 | 166 | 167 | Vector3r& Vector3r::setZ 168 | ( 169 | const real z 170 | ) 171 | { 172 | xyz_m[2] = z; 173 | 174 | return *this; 175 | } 176 | 177 | 178 | real& Vector3r::operator[] 179 | ( 180 | const int i 181 | ) 182 | { 183 | // careful ! 184 | return xyz_m[i]; 185 | }*/ 186 | 187 | 188 | /*Vector3r& Vector3r::negateEq() 189 | { 190 | xyz_m[0] = -xyz_m[0]; 191 | xyz_m[1] = -xyz_m[1]; 192 | xyz_m[2] = -xyz_m[2]; 193 | 194 | return *this; 195 | } 196 | 197 | 198 | Vector3r& Vector3r::absEq() 199 | { 200 | if( xyz_m[0] < real() ) 201 | { 202 | xyz_m[0] = -xyz_m[0]; 203 | } 204 | if( xyz_m[1] < real() ) 205 | { 206 | xyz_m[1] = -xyz_m[1]; 207 | } 208 | if( xyz_m[2] < real() ) 209 | { 210 | xyz_m[2] = -xyz_m[2]; 211 | } 212 | 213 | return *this; 214 | } 215 | 216 | 217 | Vector3r& Vector3r::unitizeEq() 218 | { 219 | const real length = sqrt( 220 | (xyz_m[0] * xyz_m[0]) + 221 | (xyz_m[1] * xyz_m[1]) + 222 | (xyz_m[2] * xyz_m[2]) ); 223 | const real oneOverLength = (length != real()) ? 224 | real(1.0f) / length : real(); 225 | 226 | xyz_m[0] *= oneOverLength; 227 | xyz_m[1] *= oneOverLength; 228 | xyz_m[2] *= oneOverLength; 229 | 230 | return *this; 231 | } 232 | 233 | 234 | Vector3r& Vector3r::crossEq 235 | ( 236 | const Vector3r& v 237 | ) 238 | { 239 | const real x = (xyz_m[1] * v.xyz_m[2]) - (xyz_m[2] * v.xyz_m[1]); 240 | const real y = (xyz_m[2] * v.xyz_m[0]) - (xyz_m[0] * v.xyz_m[2]); 241 | const real z = (xyz_m[0] * v.xyz_m[1]) - (xyz_m[1] * v.xyz_m[0]); 242 | 243 | xyz_m[0] = x; 244 | xyz_m[1] = y; 245 | xyz_m[2] = z; 246 | 247 | return *this; 248 | }*/ 249 | 250 | 251 | Vector3r& Vector3r::operator+= 252 | ( 253 | const Vector3r& v 254 | ) 255 | { 256 | xyz_m[0] += v.xyz_m[0]; 257 | xyz_m[1] += v.xyz_m[1]; 258 | xyz_m[2] += v.xyz_m[2]; 259 | 260 | return *this; 261 | } 262 | 263 | 264 | Vector3r& Vector3r::operator-= 265 | ( 266 | const Vector3r& v 267 | ) 268 | { 269 | xyz_m[0] -= v.xyz_m[0]; 270 | xyz_m[1] -= v.xyz_m[1]; 271 | xyz_m[2] -= v.xyz_m[2]; 272 | 273 | return *this; 274 | } 275 | 276 | 277 | Vector3r& Vector3r::operator*= 278 | ( 279 | const Vector3r& v 280 | ) 281 | { 282 | xyz_m[0] *= v.xyz_m[0]; 283 | xyz_m[1] *= v.xyz_m[1]; 284 | xyz_m[2] *= v.xyz_m[2]; 285 | 286 | return *this; 287 | } 288 | 289 | 290 | Vector3r& Vector3r::operator/= 291 | ( 292 | const Vector3r& v 293 | ) 294 | { 295 | xyz_m[0] /= v.xyz_m[0]; 296 | xyz_m[1] /= v.xyz_m[1]; 297 | xyz_m[2] /= v.xyz_m[2]; 298 | 299 | return *this; 300 | } 301 | 302 | 303 | Vector3r& Vector3r::operator*= 304 | ( 305 | const real r 306 | ) 307 | { 308 | xyz_m[0] *= r; 309 | xyz_m[1] *= r; 310 | xyz_m[2] *= r; 311 | 312 | return *this; 313 | } 314 | 315 | 316 | Vector3r& Vector3r::operator/= 317 | ( 318 | const real r 319 | ) 320 | { 321 | // need to check if this is still faster 322 | 323 | const real oneOverR = real(1.0f) / r; 324 | 325 | xyz_m[0] *= oneOverR; 326 | xyz_m[1] *= oneOverR; 327 | xyz_m[2] *= oneOverR; 328 | 329 | return *this; 330 | } 331 | 332 | 333 | /*Vector3r& Vector3r::clampMinEq 334 | ( 335 | const Vector3r& min 336 | ) 337 | { 338 | if( xyz_m[0] < min.xyz_m[0] ) 339 | { 340 | xyz_m[0] = min.xyz_m[0]; 341 | } 342 | if( xyz_m[1] < min.xyz_m[1] ) 343 | { 344 | xyz_m[1] = min.xyz_m[1]; 345 | } 346 | if( xyz_m[2] < min.xyz_m[2] ) 347 | { 348 | xyz_m[2] = min.xyz_m[2]; 349 | } 350 | 351 | return *this; 352 | } 353 | 354 | 355 | Vector3r& Vector3r::clampMaxEq 356 | ( 357 | const Vector3r& max 358 | ) 359 | { 360 | if( xyz_m[0] > max.xyz_m[0] ) 361 | { 362 | xyz_m[0] = max.xyz_m[0]; 363 | } 364 | if( xyz_m[1] > max.xyz_m[1] ) 365 | { 366 | xyz_m[1] = max.xyz_m[1]; 367 | } 368 | if( xyz_m[2] > max.xyz_m[2] ) 369 | { 370 | xyz_m[2] = max.xyz_m[2]; 371 | } 372 | 373 | return *this; 374 | } 375 | 376 | 377 | Vector3r& Vector3r::clampEq 378 | ( 379 | const Vector3r& min, 380 | const Vector3r& max 381 | ) 382 | { 383 | if( xyz_m[0] < min.xyz_m[0] ) 384 | xyz_m[0] = min.xyz_m[0]; 385 | else 386 | if( xyz_m[0] > max.xyz_m[0] ) 387 | xyz_m[0] = max.xyz_m[0]; 388 | 389 | if( xyz_m[1] < min.xyz_m[1] ) 390 | xyz_m[1] = min.xyz_m[1]; 391 | else 392 | if( xyz_m[1] > max.xyz_m[1] ) 393 | xyz_m[1] = max.xyz_m[1]; 394 | 395 | if( xyz_m[2] < min.xyz_m[2] ) 396 | xyz_m[2] = min.xyz_m[2]; 397 | else 398 | if( xyz_m[2] > max.xyz_m[2] ) 399 | xyz_m[2] = max.xyz_m[2]; 400 | 401 | return *this; 402 | } 403 | 404 | 405 | Vector3r& Vector3r::clamp01Eq() 406 | { 407 | // [0,1) 0 to almost 1 408 | 409 | if( xyz_m[0] < real() ) 410 | xyz_m[0] = real(); 411 | else 412 | if( xyz_m[0] >= real(1.0f) ) 413 | xyz_m[0] = REAL_ALMOST_ONE; 414 | 415 | if( xyz_m[1] < real() ) 416 | xyz_m[1] = real(); 417 | else 418 | if( xyz_m[1] >= real(1.0f) ) 419 | xyz_m[1] = REAL_ALMOST_ONE; 420 | 421 | if( xyz_m[2] < real() ) 422 | xyz_m[2] = real(); 423 | else 424 | if( xyz_m[2] >= real(1.0f) ) 425 | xyz_m[2] = REAL_ALMOST_ONE; 426 | 427 | return *this; 428 | }*/ 429 | 430 | 431 | 432 | 433 | /// queries -------------------------------------------------------------------- 434 | /*void Vector3r::get 435 | ( 436 | real& x, 437 | real& y, 438 | real& z 439 | ) const 440 | { 441 | x = xyz_m[0]; 442 | y = xyz_m[1]; 443 | z = xyz_m[2]; 444 | } 445 | 446 | 447 | void Vector3r::get 448 | ( 449 | real xyz[3] 450 | ) const 451 | { 452 | xyz[0] = xyz_m[0]; 453 | xyz[1] = xyz_m[1]; 454 | xyz[2] = xyz_m[2]; 455 | }*/ 456 | 457 | 458 | /*real Vector3r::sum() const 459 | { 460 | return xyz_m[0] + xyz_m[1] + xyz_m[2]; 461 | } 462 | 463 | 464 | real Vector3r::average() const 465 | { 466 | static const real ONE_OVER_3 = real(1.0f) / real(3.0f); 467 | 468 | return (xyz_m[0] + xyz_m[1] + xyz_m[2]) * ONE_OVER_3; 469 | } 470 | 471 | 472 | real Vector3r::smallest() const 473 | { 474 | real smallest = xyz_m[0] <= xyz_m[1] ? xyz_m[0] : xyz_m[1]; 475 | smallest = smallest <= xyz_m[2] ? smallest : xyz_m[2]; 476 | 477 | return smallest; 478 | } 479 | 480 | 481 | real Vector3r::largest() const 482 | { 483 | real largest = xyz_m[0] >= xyz_m[1] ? xyz_m[0] : xyz_m[1]; 484 | largest = largest >= xyz_m[2] ? largest : xyz_m[2]; 485 | 486 | return largest; 487 | }*/ 488 | 489 | 490 | real Vector3r::length() const 491 | { 492 | return sqrt( 493 | (xyz_m[0] * xyz_m[0]) + 494 | (xyz_m[1] * xyz_m[1]) + 495 | (xyz_m[2] * xyz_m[2]) ); 496 | } 497 | 498 | 499 | /*real Vector3r::dot 500 | ( 501 | const Vector3r& v 502 | ) const 503 | { 504 | return 505 | (xyz_m[0] * v.xyz_m[0]) + 506 | (xyz_m[1] * v.xyz_m[1]) + 507 | (xyz_m[2] * v.xyz_m[2]); 508 | } 509 | 510 | 511 | real Vector3r::distance 512 | ( 513 | const Vector3r& v 514 | ) const 515 | { 516 | const real xDif = xyz_m[0] - v.xyz_m[0]; 517 | const real yDif = xyz_m[1] - v.xyz_m[1]; 518 | const real zDif = xyz_m[2] - v.xyz_m[2]; 519 | 520 | return sqrt( (xDif * xDif) + (yDif * yDif) + (zDif * zDif) ); 521 | } 522 | 523 | 524 | real Vector3r::distance2 525 | ( 526 | const Vector3r& v 527 | ) const 528 | { 529 | const real xDif = xyz_m[0] - v.xyz_m[0]; 530 | const real yDif = xyz_m[1] - v.xyz_m[1]; 531 | const real zDif = xyz_m[2] - v.xyz_m[2]; 532 | 533 | return (xDif * xDif) + (yDif * yDif) + (zDif * zDif); 534 | }*/ 535 | 536 | 537 | /*Vector3r Vector3r::operator-() const 538 | { 539 | return Vector3r( -xyz_m[0], -xyz_m[1], -xyz_m[2] ); 540 | } 541 | 542 | 543 | Vector3r Vector3r::abs() const 544 | { 545 | return Vector3r( 546 | xyz_m[0] >= real() ? xyz_m[0] : -xyz_m[0], 547 | xyz_m[1] >= real() ? xyz_m[1] : -xyz_m[1], 548 | xyz_m[2] >= real() ? xyz_m[2] : -xyz_m[2] ); 549 | } 550 | 551 | 552 | Vector3r Vector3r::unitized() const 553 | { 554 | const real length = sqrt( 555 | (xyz_m[0] * xyz_m[0]) + 556 | (xyz_m[1] * xyz_m[1]) + 557 | (xyz_m[2] * xyz_m[2]) ); 558 | const real oneOverLength = (length != real()) ? 559 | real(1.0) / length : real(); 560 | 561 | return Vector3r( 562 | xyz_m[0] * oneOverLength, 563 | xyz_m[1] * oneOverLength, 564 | xyz_m[2] * oneOverLength ); 565 | } 566 | 567 | 568 | Vector3r Vector3r::cross 569 | ( 570 | const Vector3r& v 571 | ) const 572 | { 573 | return Vector3r( 574 | (xyz_m[1] * v.xyz_m[2]) - (xyz_m[2] * v.xyz_m[1]), 575 | (xyz_m[2] * v.xyz_m[0]) - (xyz_m[0] * v.xyz_m[2]), 576 | (xyz_m[0] * v.xyz_m[1]) - (xyz_m[1] * v.xyz_m[0]) ); 577 | }*/ 578 | 579 | 580 | Vector3r Vector3r::operator+ 581 | ( 582 | const Vector3r& v 583 | ) const 584 | { 585 | return Vector3r( 586 | xyz_m[0] + v.xyz_m[0], 587 | xyz_m[1] + v.xyz_m[1], 588 | xyz_m[2] + v.xyz_m[2] ); 589 | } 590 | 591 | 592 | Vector3r Vector3r::operator- 593 | ( 594 | const Vector3r& v 595 | ) const 596 | { 597 | return Vector3r( 598 | xyz_m[0] - v.xyz_m[0], 599 | xyz_m[1] - v.xyz_m[1], 600 | xyz_m[2] - v.xyz_m[2] ); 601 | } 602 | 603 | 604 | Vector3r Vector3r::operator* 605 | ( 606 | const Vector3r& v 607 | ) const 608 | { 609 | return Vector3r( 610 | xyz_m[0] * v.xyz_m[0], 611 | xyz_m[1] * v.xyz_m[1], 612 | xyz_m[2] * v.xyz_m[2] ); 613 | } 614 | 615 | 616 | Vector3r Vector3r::operator/ 617 | ( 618 | const Vector3r& v 619 | ) const 620 | { 621 | return Vector3r( 622 | xyz_m[0] / v.xyz_m[0], 623 | xyz_m[1] / v.xyz_m[1], 624 | xyz_m[2] / v.xyz_m[2] ); 625 | } 626 | 627 | 628 | Vector3r Vector3r::operator* 629 | ( 630 | const real r 631 | ) const 632 | { 633 | return Vector3r( 634 | xyz_m[0] * r, 635 | xyz_m[1] * r, 636 | xyz_m[2] * r ); 637 | } 638 | 639 | 640 | Vector3r Vector3r::operator/ 641 | ( 642 | const real r 643 | ) const 644 | { 645 | const real oneOverR = real(1.0f) / r; 646 | 647 | return Vector3r( 648 | xyz_m[0] * oneOverR, 649 | xyz_m[1] * oneOverR, 650 | xyz_m[2] * oneOverR ); 651 | } 652 | 653 | 654 | bool Vector3r::operator== 655 | ( 656 | const Vector3r& v 657 | ) const 658 | { 659 | return 660 | (xyz_m[0] == v.xyz_m[0]) & 661 | (xyz_m[1] == v.xyz_m[1]) & 662 | (xyz_m[2] == v.xyz_m[2]); 663 | } 664 | 665 | 666 | bool Vector3r::operator!= 667 | ( 668 | const Vector3r& v 669 | ) const 670 | { 671 | return 672 | (xyz_m[0] != v.xyz_m[0]) | 673 | (xyz_m[1] != v.xyz_m[1]) | 674 | (xyz_m[2] != v.xyz_m[2]); 675 | } 676 | 677 | 678 | bool Vector3r::isZero() const 679 | { 680 | return bool( 681 | (xyz_m[0] == real()) & 682 | (xyz_m[1] == real()) & 683 | (xyz_m[2] == real()) ); 684 | } 685 | 686 | 687 | /*Vector3r Vector3r::sign() const 688 | { 689 | return compare( Vector3r::ZERO() ); 690 | } 691 | 692 | 693 | Vector3r Vector3r::compare 694 | ( 695 | const Vector3r& v 696 | ) const 697 | { 698 | return Vector3r( 699 | xyz_m[0] > v.xyz_m[0] ? 700 | real(+1.0f) : (xyz_m[0] == v.xyz_m[0] ? real() : real(-1.0f)), 701 | xyz_m[1] > v.xyz_m[1] ? 702 | real(+1.0f) : (xyz_m[1] == v.xyz_m[1] ? real() : real(-1.0f)), 703 | xyz_m[2] > v.xyz_m[2] ? 704 | real(+1.0f) : (xyz_m[2] == v.xyz_m[2] ? real() : real(-1.0f)) ); 705 | } 706 | 707 | 708 | Vector3r Vector3r::equal 709 | ( 710 | const Vector3r& v 711 | ) const 712 | { 713 | return Vector3r( 714 | static_cast( xyz_m[0] == v.xyz_m[0] ), 715 | static_cast( xyz_m[1] == v.xyz_m[1] ), 716 | static_cast( xyz_m[2] == v.xyz_m[2] ) ); 717 | } 718 | 719 | 720 | Vector3r Vector3r::operator> 721 | ( 722 | const Vector3r& v 723 | ) const 724 | { 725 | return Vector3r( 726 | static_cast( xyz_m[0] > v.xyz_m[0] ), 727 | static_cast( xyz_m[1] > v.xyz_m[1] ), 728 | static_cast( xyz_m[2] > v.xyz_m[2] ) ); 729 | } 730 | 731 | 732 | Vector3r Vector3r::operator>= 733 | ( 734 | const Vector3r& v 735 | ) const 736 | { 737 | return Vector3r( 738 | static_cast( xyz_m[0] >= v.xyz_m[0] ), 739 | static_cast( xyz_m[1] >= v.xyz_m[1] ), 740 | static_cast( xyz_m[2] >= v.xyz_m[2] ) ); 741 | } 742 | 743 | 744 | Vector3r Vector3r::operator< 745 | ( 746 | const Vector3r& v 747 | ) const 748 | { 749 | return Vector3r( 750 | static_cast( xyz_m[0] < v.xyz_m[0] ), 751 | static_cast( xyz_m[1] < v.xyz_m[1] ), 752 | static_cast( xyz_m[2] < v.xyz_m[2] ) ); 753 | } 754 | 755 | 756 | Vector3r Vector3r::operator<= 757 | ( 758 | const Vector3r& v 759 | ) const 760 | { 761 | return Vector3r( 762 | static_cast( xyz_m[0] <= v.xyz_m[0] ), 763 | static_cast( xyz_m[1] <= v.xyz_m[1] ), 764 | static_cast( xyz_m[2] <= v.xyz_m[2] ) ); 765 | }*/ 766 | 767 | 768 | /*Vector3r Vector3r::clampedMin 769 | ( 770 | const Vector3r& min 771 | ) const 772 | { 773 | Vector3r v( *this ); 774 | 775 | if( v.xyz_m[0] < min.xyz_m[0] ) 776 | { 777 | v.xyz_m[0] = min.xyz_m[0]; 778 | } 779 | if( v.xyz_m[1] < min.xyz_m[1] ) 780 | { 781 | v.xyz_m[1] = min.xyz_m[1]; 782 | } 783 | if( v.xyz_m[2] < min.xyz_m[2] ) 784 | { 785 | v.xyz_m[2] = min.xyz_m[2]; 786 | } 787 | 788 | return v; 789 | } 790 | 791 | 792 | Vector3r Vector3r::clampedMax 793 | ( 794 | const Vector3r& max 795 | ) const 796 | { 797 | Vector3r v( *this ); 798 | 799 | if( v.xyz_m[0] > max.xyz_m[0] ) 800 | { 801 | v.xyz_m[0] = max.xyz_m[0]; 802 | } 803 | if( v.xyz_m[1] > max.xyz_m[1] ) 804 | { 805 | v.xyz_m[1] = max.xyz_m[1]; 806 | } 807 | if( v.xyz_m[2] > max.xyz_m[2] ) 808 | { 809 | v.xyz_m[2] = max.xyz_m[2]; 810 | } 811 | 812 | return v; 813 | } 814 | 815 | 816 | Vector3r Vector3r::clamped 817 | ( 818 | const Vector3r& min, 819 | const Vector3r& max 820 | ) const 821 | { 822 | Vector3r v( *this ); 823 | 824 | if( v.xyz_m[0] < min.xyz_m[0] ) 825 | v.xyz_m[0] = min.xyz_m[0]; 826 | else 827 | if( v.xyz_m[0] > max.xyz_m[0] ) 828 | v.xyz_m[0] = max.xyz_m[0]; 829 | 830 | if( v.xyz_m[1] < min.xyz_m[1] ) 831 | v.xyz_m[1] = min.xyz_m[1]; 832 | else 833 | if( v.xyz_m[1] > max.xyz_m[1] ) 834 | v.xyz_m[1] = max.xyz_m[1]; 835 | 836 | if( v.xyz_m[2] < min.xyz_m[2] ) 837 | v.xyz_m[2] = min.xyz_m[2]; 838 | else 839 | if( v.xyz_m[2] > max.xyz_m[2] ) 840 | v.xyz_m[2] = max.xyz_m[2]; 841 | 842 | return v; 843 | } 844 | 845 | 846 | Vector3r Vector3r::clamped01() const 847 | { 848 | // [0,1) 0 to almost 1 849 | 850 | Vector3r v( *this ); 851 | 852 | if( v.xyz_m[0] < real() ) 853 | v.xyz_m[0] = real(); 854 | else 855 | if( v.xyz_m[0] >= real(1.0f) ) 856 | v.xyz_m[0] = REAL_ALMOST_ONE; 857 | 858 | if( v.xyz_m[1] < real() ) 859 | v.xyz_m[1] = real(); 860 | else 861 | if( v.xyz_m[1] >= real(1.0f) ) 862 | v.xyz_m[1] = REAL_ALMOST_ONE; 863 | 864 | if( v.xyz_m[2] < real() ) 865 | v.xyz_m[2] = real(); 866 | else 867 | if( v.xyz_m[2] >= real(1.0f) ) 868 | v.xyz_m[2] = REAL_ALMOST_ONE; 869 | 870 | return v; 871 | }*/ 872 | 873 | 874 | 875 | 876 | /// constants ------------------------------------------------------------------ 877 | const Vector3r& Vector3r::ZERO() 878 | { 879 | static const Vector3r k( real(0.0f), real(0.0f), real(0.0f) ); 880 | return k; 881 | } 882 | 883 | 884 | const Vector3r& Vector3r::HALF() 885 | { 886 | static const Vector3r k( real(0.5f), real(0.5f), real(0.5f) ); 887 | return k; 888 | } 889 | 890 | 891 | const Vector3r& Vector3r::ONE() 892 | { 893 | static const Vector3r k( real(1.0f), real(1.0f), real(1.0f) ); 894 | return k; 895 | } 896 | 897 | 898 | /*const Vector3r& Vector3r::EPSILON() 899 | { 900 | static const Vector3r k( REAL_EPSILON, REAL_EPSILON, REAL_EPSILON ); 901 | return k; 902 | } 903 | 904 | 905 | const Vector3r& Vector3r::ALMOST_ONE() 906 | { 907 | static const Vector3r k( REAL_ALMOST_ONE, REAL_ALMOST_ONE, REAL_ALMOST_ONE ); 908 | return k; 909 | } 910 | 911 | 912 | const Vector3r& Vector3r::MIN() 913 | { 914 | static const Vector3r k( REAL_MIN_NEG, REAL_MIN_NEG, REAL_MIN_NEG ); 915 | return k; 916 | } 917 | 918 | 919 | const Vector3r& Vector3r::MAX() 920 | { 921 | static const Vector3r k( REAL_MAX, REAL_MAX, REAL_MAX ); 922 | return k; 923 | } 924 | 925 | 926 | const Vector3r& Vector3r::SMALL() 927 | { 928 | static const Vector3r k( REAL_SMALL, REAL_SMALL, REAL_SMALL ); 929 | return k; 930 | } 931 | 932 | 933 | const Vector3r& Vector3r::LARGE() 934 | { 935 | static const Vector3r k( REAL_LARGE, REAL_LARGE, REAL_LARGE ); 936 | return k; 937 | } 938 | 939 | 940 | const Vector3r& Vector3r::X() 941 | { 942 | static const Vector3r k( real(1.0f), real(0.0f), real(0.0f) ); 943 | return k; 944 | } 945 | 946 | 947 | const Vector3r& Vector3r::Y() 948 | { 949 | static const Vector3r k( real(0.0f), real(1.0f), real(0.0f) ); 950 | return k; 951 | } 952 | 953 | 954 | const Vector3r& Vector3r::Z() 955 | { 956 | static const Vector3r k( real(0.0f), real(0.0f), real(1.0f) ); 957 | return k; 958 | }*/ 959 | 960 | 961 | 962 | 963 | /// friends -------------------------------------------------------------------- 964 | Vector3r hxa7241_graphics::operator* 965 | ( 966 | const real r, 967 | const Vector3r& v 968 | ) 969 | { 970 | return Vector3r( 971 | r * v.xyz_m[0], 972 | r * v.xyz_m[1], 973 | r * v.xyz_m[2] ); 974 | } 975 | 976 | 977 | Vector3r hxa7241_graphics::operator/ 978 | ( 979 | const real r, 980 | const Vector3r& v 981 | ) 982 | { 983 | return Vector3r( 984 | r / v.xyz_m[0], 985 | r / v.xyz_m[1], 986 | r / v.xyz_m[2] ); 987 | } 988 | -------------------------------------------------------------------------------- /component/Vector3r.hpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #ifndef Vector3r_h 40 | #define Vector3r_h 41 | 42 | 43 | #include "Primitives.hpp" 44 | 45 | 46 | 47 | 48 | namespace hxa7241_graphics 49 | { 50 | using namespace hxa7241; 51 | 52 | 53 | /** 54 | * Yes, its the 3D vector class!.

55 | * 56 | * If you write some 3D graphics software, then you MUST write your OWN vector 57 | * class -- it is the law. So here is mine.

58 | * 59 | * (Unused stuff commented-out) 60 | */ 61 | class Vector3r 62 | { 63 | /// standard object services --------------------------------------------------- 64 | public: 65 | Vector3r(); 66 | Vector3r( real x, 67 | real y, 68 | real z ); 69 | // explicit Vector3r( const real xyz[3] ); 70 | 71 | ~Vector3r(); 72 | Vector3r( const Vector3r& ); 73 | Vector3r& operator=( const Vector3r& ); 74 | 75 | 76 | /// commands ------------------------------------------------------------------- 77 | Vector3r& set( real x, 78 | real y, 79 | real z ); 80 | // Vector3r& set( const real xyz[3] ); 81 | // 82 | // Vector3r& setX( real ); 83 | // Vector3r& setY( real ); 84 | // Vector3r& setZ( real ); 85 | // real& operator[]( int ); 86 | 87 | // Vector3r& negateEq (); 88 | // Vector3r& absEq (); 89 | // Vector3r& unitizeEq(); 90 | // Vector3r& crossEq ( const Vector3r& ); 91 | 92 | Vector3r& operator+=( const Vector3r& ); 93 | Vector3r& operator-=( const Vector3r& ); 94 | Vector3r& operator*=( const Vector3r& ); 95 | Vector3r& operator/=( const Vector3r& ); 96 | Vector3r& operator*=( real ); 97 | Vector3r& operator/=( real ); 98 | 99 | // Vector3r& clampMinEq( const Vector3r& ); 100 | // Vector3r& clampMaxEq( const Vector3r& ); 101 | // Vector3r& clampEq ( const Vector3r& min, 102 | // const Vector3r& max ); 103 | // Vector3r& clamp01Eq (); 104 | 105 | 106 | /// queries -------------------------------------------------------------------- 107 | // void get( real& x, 108 | // real& y, 109 | // real& z ) const; 110 | // void get( real xyz[3] ) const; 111 | 112 | real getX() const; 113 | real getY() const; 114 | real getZ() const; 115 | real operator[]( int ) const; 116 | 117 | // real sum() const; 118 | // real average() const; 119 | // real smallest() const; 120 | // real largest() const; 121 | 122 | real length() const; 123 | // real dot( const Vector3r& ) const; 124 | // real distance ( const Vector3r& ) const; 125 | // real distance2( const Vector3r& ) const; 126 | 127 | // Vector3r operator-() const; 128 | // Vector3r abs() const; 129 | // Vector3r unitized() const; 130 | // Vector3r cross( const Vector3r& ) const; 131 | 132 | Vector3r operator+( const Vector3r& ) const; 133 | Vector3r operator-( const Vector3r& ) const; 134 | Vector3r operator*( const Vector3r& ) const; 135 | Vector3r operator/( const Vector3r& ) const; 136 | Vector3r operator*( real ) const; 137 | Vector3r operator/( real ) const; 138 | 139 | bool operator==( const Vector3r& ) const; 140 | bool operator!=( const Vector3r& ) const; 141 | bool isZero() const; 142 | 143 | // // returning vectors of -1.0 or 0.0 or +1.0 144 | // Vector3r sign () const; 145 | // Vector3r compare( const Vector3r& ) const; 146 | // 147 | // // returning vectors of static_cast(bool) 148 | // Vector3r equal ( const Vector3r& ) const; 149 | // Vector3r operator> ( const Vector3r& ) const; 150 | // Vector3r operator>=( const Vector3r& ) const; 151 | // Vector3r operator< ( const Vector3r& ) const; 152 | // Vector3r operator<=( const Vector3r& ) const; 153 | 154 | // Vector3r clampedMin( const Vector3r& ) const; 155 | // Vector3r clampedMax( const Vector3r& ) const; 156 | // Vector3r clamped ( const Vector3r& min, 157 | // const Vector3r& max ) const; 158 | // Vector3r clamped01 () const; 159 | 160 | friend Vector3r operator*( real, const Vector3r& ); 161 | friend Vector3r operator/( real, const Vector3r& ); 162 | 163 | 164 | /// constants ------------------------------------------------------------------ 165 | static const Vector3r& ZERO(); 166 | static const Vector3r& HALF(); 167 | static const Vector3r& ONE(); 168 | // static const Vector3r& EPSILON(); 169 | // static const Vector3r& ALMOST_ONE(); 170 | // static const Vector3r& MIN(); 171 | // static const Vector3r& MAX(); 172 | // static const Vector3r& SMALL(); 173 | // static const Vector3r& LARGE(); 174 | // static const Vector3r& X(); 175 | // static const Vector3r& Y(); 176 | // static const Vector3r& Z(); 177 | 178 | 179 | /// fields --------------------------------------------------------------------- 180 | private: 181 | real xyz_m[3]; 182 | }; 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | /// friends 192 | Vector3r operator*( real, const Vector3r& ); 193 | Vector3r operator/( real, const Vector3r& ); 194 | 195 | 196 | 197 | 198 | /// INLINES /// 199 | /* 200 | * These are certain. Leave others to the compiler. 201 | */ 202 | 203 | 204 | /// standard object services --------------------------------------------------- 205 | /*inline 206 | Vector3r::Vector3r 207 | ( 208 | const real xyz[3] 209 | ) 210 | { 211 | Vector3r::set( xyz ); 212 | }*/ 213 | 214 | 215 | inline 216 | Vector3r::~Vector3r() 217 | { 218 | } 219 | 220 | 221 | inline 222 | Vector3r::Vector3r 223 | ( 224 | const Vector3r& other 225 | ) 226 | { 227 | Vector3r::operator=( other ); 228 | } 229 | 230 | 231 | 232 | 233 | /// queries -------------------------------------------------------------------- 234 | inline 235 | real Vector3r::getX() const 236 | { 237 | return xyz_m[0]; 238 | } 239 | 240 | 241 | inline 242 | real Vector3r::getY() const 243 | { 244 | return xyz_m[1]; 245 | } 246 | 247 | 248 | inline 249 | real Vector3r::getZ() const 250 | { 251 | return xyz_m[2]; 252 | } 253 | 254 | 255 | inline 256 | real Vector3r::operator[] 257 | ( 258 | const int i 259 | ) const 260 | { 261 | // careful ! 262 | return xyz_m[i]; 263 | } 264 | 265 | 266 | }//namespace 267 | 268 | 269 | 270 | 271 | #endif//Vector3r_h 272 | -------------------------------------------------------------------------------- /docs/ogc-class-relations-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hxa7241/octree-cpp/a8e40b0d0a55bdc293a4848170f43daf42c926e3/docs/ogc-class-relations-diagram.png -------------------------------------------------------------------------------- /docs/ogc-visit-sequence-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hxa7241/octree-cpp/a8e40b0d0a55bdc293a4848170f43daf42c926e3/docs/ogc-visit-sequence-diagram.png -------------------------------------------------------------------------------- /samples/OctreeExample.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #include 40 | #include 41 | 42 | #include "Octree.hpp" 43 | 44 | 45 | using namespace hxa7241_graphics; 46 | 47 | 48 | 49 | 50 | /** 51 | * Step 1:
52 | * Check your item class provides access to its 3D properties.

53 | * 54 | * Step 2:
55 | * Implement a derivative of OctreeAgent, to calculate if an item 56 | * overlaps a cell, or subcells.

57 | * 58 | * Step 3:
59 | * Implement derivatives of OctreeVisitor, to perform operations 60 | * on an octree.

61 | * 62 | * Step 4:
63 | * Write code to create items, octrees, and visitors, add/remove items 64 | * to octrees, and execute operations on octrees. 65 | */ 66 | 67 | 68 | /** 69 | * File contents:

70 | 71 | * Classes
72 | * * Block class: an example item
73 | * * OctreeAgentBlock class: an agent for the example item
74 | * * OctreeVisitorExample class: an example visitor using the item
75 | * Functions
76 | * * main function: code to make some items, make an octree, and use the 77 | * visitor.
78 | */ 79 | 80 | 81 | 82 | 83 | /// Vector3r stream out 84 | 85 | std::ostream& operator<<( std::ostream&, const Vector3r& ); 86 | 87 | std::ostream& operator<< 88 | ( 89 | std::ostream& out, 90 | const Vector3r& obj 91 | ) 92 | { 93 | return out << '(' << obj[0] << ' ' << obj[1] << ' ' << obj[2] << ')'; 94 | } 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | /// Block ////////////////////////////////////////////////////////////////////// 104 | 105 | /** 106 | * An example item: a minimal axis-aligned 3D block.

107 | * 108 | * You write this class, however you want. Though it will have some primitive 109 | * access to its 3D properties. 110 | */ 111 | class Block 112 | { 113 | /// standard object services --------------------------------------------------- 114 | public: 115 | Block(); 116 | Block( const Vector3r& position, 117 | const Vector3r& dimension ); 118 | 119 | ~Block(); 120 | Block( const Block& ); 121 | Block& operator=( const Block& ); 122 | 123 | 124 | /// queries -------------------------------------------------------------------- 125 | const Vector3r& getPosition() const; 126 | const Vector3r& getDimensions() const; 127 | 128 | 129 | /// fields --------------------------------------------------------------------- 130 | private: 131 | Vector3r position_m; 132 | Vector3r dimensions_m; 133 | }; 134 | 135 | 136 | 137 | 138 | /// standard object services --------------------------------------------------- 139 | Block::Block() 140 | : position_m () 141 | , dimensions_m() 142 | { 143 | } 144 | 145 | 146 | Block::Block 147 | ( 148 | const Vector3r& position, 149 | const Vector3r& dimensions 150 | ) 151 | : position_m ( position ) 152 | , dimensions_m( dimensions ) 153 | { 154 | } 155 | 156 | 157 | Block::~Block() 158 | { 159 | } 160 | 161 | 162 | Block::Block 163 | ( 164 | const Block& other 165 | ) 166 | : position_m ( other.position_m ) 167 | , dimensions_m( other.dimensions_m ) 168 | { 169 | } 170 | 171 | 172 | Block& Block::operator= 173 | ( 174 | const Block& other 175 | ) 176 | { 177 | if( &other != this ) 178 | { 179 | position_m = other.position_m; 180 | dimensions_m = other.dimensions_m; 181 | } 182 | 183 | return *this; 184 | } 185 | 186 | 187 | /// queries -------------------------------------------------------------------- 188 | const Vector3r& Block::getPosition() const 189 | { 190 | return position_m; 191 | } 192 | 193 | 194 | const Vector3r& Block::getDimensions() const 195 | { 196 | return dimensions_m; 197 | } 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | /// OctreeAgentBlock /////////////////////////////////////////////////////////// 207 | 208 | /** 209 | * An example Octree agent, for Block item class.

210 | * 211 | * You must write this class, as a concrete derivative of OctreeAgent<>. It 212 | * provides the Octree with a way to interact with your item class. 213 | */ 214 | class OctreeAgentBlock 215 | : public OctreeAgent 216 | { 217 | /// standard object services --------------------------------------------------- 218 | public: 219 | OctreeAgentBlock() {}; 220 | 221 | virtual ~OctreeAgentBlock() {}; 222 | private: 223 | OctreeAgentBlock( const OctreeAgentBlock& ); 224 | OctreeAgentBlock& operator=( const OctreeAgentBlock& ); 225 | 226 | 227 | /// queries -------------------------------------------------------------------- 228 | /// octree agent overrides 229 | protected: 230 | virtual bool isOverlappingCell ( const Block& item, 231 | const Vector3r& lowerCorner, 232 | const Vector3r& upperCorner ) const; 233 | 234 | // could also override getSubcellOverlaps to provide more efficent 235 | // calculation (boundary testing can be shared). 236 | }; 237 | 238 | 239 | 240 | 241 | /// queries -------------------------------------------------------------------- 242 | bool OctreeAgentBlock::isOverlappingCell 243 | ( 244 | const Block& item, 245 | const Vector3r& lowerCorner, 246 | const Vector3r& upperCorner 247 | ) const 248 | { 249 | const Vector3r& itemLower( item.getPosition() ); 250 | const Vector3r itemUpper = item.getPosition() + item.getDimensions(); 251 | 252 | // check the two ranges overlap in every dimension 253 | bool isOverlap = true; 254 | for( int i = 3; i-- > 0; ) 255 | { 256 | isOverlap &= (itemLower[i] < upperCorner[i]) & 257 | (itemUpper[i] > lowerCorner[i]); 258 | } 259 | 260 | return isOverlap; 261 | } 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | /// OctreeVisitorExample /////////////////////////////////////////////////////// 271 | 272 | /** 273 | * An example Octree visitor, for writing out leaf content.

274 | * 275 | * You must write this class, as a concrete derivative of OctreeVisitor<>. It 276 | * defines an search/inspection operation on your items in an octree. Any number 277 | * of different ones can be written and used on the same octree. 278 | */ 279 | class OctreeVisitorExample 280 | : public OctreeVisitor 281 | { 282 | /// standard object services --------------------------------------------------- 283 | public: 284 | OctreeVisitorExample(); 285 | 286 | virtual ~OctreeVisitorExample(); 287 | private: 288 | OctreeVisitorExample( const OctreeVisitorExample& ); 289 | OctreeVisitorExample& operator=( const OctreeVisitorExample& ); 290 | 291 | 292 | /// commands ------------------------------------------------------------------- 293 | /// octree visitor overrides 294 | protected: 295 | virtual void visitRoot ( const OctreeCell* pRootCell, 296 | const OctreeData& octreeData ); 297 | virtual void visitBranch( const OctreeCell* subCells[8], 298 | const OctreeData& octreeData ); 299 | virtual void visitLeaf ( const Array& items, 300 | const OctreeData& octreeData ); 301 | 302 | // any other commands ... 303 | 304 | 305 | /// queries -------------------------------------------------------------------- 306 | // any queries ... 307 | 308 | 309 | /// fields --------------------------------------------------------------------- 310 | private: 311 | // any fields ... 312 | }; 313 | 314 | 315 | 316 | 317 | /// standard object services --------------------------------------------------- 318 | OctreeVisitorExample::OctreeVisitorExample() 319 | { 320 | } 321 | 322 | 323 | OctreeVisitorExample::~OctreeVisitorExample() 324 | { 325 | } 326 | 327 | 328 | /// commands ------------------------------------------------------------------- 329 | void OctreeVisitorExample::visitRoot 330 | ( 331 | const OctreeCell* pRootCell, 332 | const OctreeData& octreeData 333 | ) 334 | { 335 | // continue visit traversal 336 | OctreeRoot::continueVisit( pRootCell, octreeData, *this ); 337 | } 338 | 339 | 340 | void OctreeVisitorExample::visitBranch 341 | ( 342 | const OctreeCell* subCells[8], 343 | const OctreeData& octreeData 344 | ) 345 | { 346 | // subcell numbering: 347 | // y z 6 7 348 | // |/ 2 3 4 5 349 | // -x 0 1 350 | // 351 | // (in binary:) 352 | // y z 110 111 353 | // |/ 010 011 100 101 354 | // -x 000 001 355 | // 356 | 357 | // step through subcells (can be in any order...) 358 | for( dword i = 0; i < 8; ++i ) 359 | { 360 | // maybe do something here... 361 | 362 | // continue visit traversal 363 | OctreeBranch::continueVisit( subCells, octreeData, i, *this ); 364 | 365 | // maybe do something here... 366 | } 367 | } 368 | 369 | 370 | void OctreeVisitorExample::visitLeaf 371 | ( 372 | const Array& items, 373 | const OctreeData& octreeData 374 | ) 375 | { 376 | // write out cell and items data: 377 | 378 | // make some short aliases 379 | const Vector3r& lower( octreeData.getBound().getLowerCorner() ); 380 | const Vector3r& upper( octreeData.getBound().getUpperCorner() ); 381 | 382 | // write leaf bound 383 | std::cout << "leaf: level(" << octreeData.getLevel() << ") "; 384 | std::cout << "lower" << lower << " " << "upper" << upper << "\n"; 385 | 386 | // write items 387 | for( dword i = 0, end = items.getLength(); i < end; ++i ) 388 | { 389 | // make some short aliases 390 | const Vector3r& lower( items[i]->getPosition() ); 391 | const Vector3r upper( items[i]->getPosition() + items[i]->getDimensions() 392 | ); 393 | 394 | // write item 395 | std::cout << " item: "; 396 | std::cout << "lower" << lower << " " << "upper" << upper << "\n"; 397 | } 398 | 399 | std::cout << "\n"; 400 | } 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | /// main /////////////////////////////////////////////////////////////////////// 410 | 411 | /** 412 | * An example Octree usage, with the previously written classes.

413 | * 414 | * You must write some code to instantiate the items, octree, agent, and 415 | * visitors; and then add/remove items and visit the octree. 416 | */ 417 | int main 418 | ( 419 | int ,//argc, 420 | char*[] //argv[] 421 | ) 422 | { 423 | // write banner 424 | std::cout << "\n HXA Octree Component v2.1 C++ *example*\n" << 425 | " Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241.\n" 426 | " http://www.hxa7241.org/\n\n"; 427 | 428 | 429 | // make some items 430 | std::vector blocks; 431 | for( int i = 0; i < 8; ++i ) 432 | { 433 | // one in the middle of each octant 434 | blocks.push_back( Block( Vector3r( real(i & 1) + 0.25f, 435 | real((i >> 1) & 1) + 0.25f, 436 | real((i >> 2) & 1) + 0.25f ), 437 | Vector3r(0.5f, 0.5f, 0.5f) ) ); 438 | } 439 | 440 | // make an octree: 441 | // position (0,0,0), size 2m, max items per leaf 4, max depth 4, 442 | // min cell size 1mm 443 | Octree octree( Vector3r::ZERO(), 2.0f, 4, 4, 0.001f ); 444 | std::cout << "Octree: position" << octree.getPosition() << 445 | " size(" << octree.getSize() << ")" << "\n\n"; 446 | 447 | 448 | // make an agent (probably a singleton) 449 | OctreeAgentBlock agent; 450 | 451 | // add items to octree, using agent 452 | for( int i = 0, end = blocks.size(); i < end; ++i ) 453 | { 454 | octree.insert( blocks[i], agent ); 455 | } 456 | 457 | 458 | // make a visitor (as many concrete variants and instances as wanted) 459 | OctreeVisitorExample visitor; 460 | 461 | // execute visitor 462 | octree.visit( visitor ); 463 | 464 | 465 | return EXIT_SUCCESS; 466 | } 467 | -------------------------------------------------------------------------------- /samples/OctreeStreamOut.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #include 40 | 41 | #include "OctreeStreamOut.hpp" 42 | 43 | 44 | using namespace hxa7241_graphics; 45 | 46 | 47 | 48 | 49 | /// other ---------------------------------------------------------------------- 50 | static std::ostream& operator<<( std::ostream&, const Vector3r& ); 51 | 52 | std::ostream& operator<< 53 | ( 54 | std::ostream& out, 55 | const Vector3r& v 56 | ) 57 | { 58 | return out << "(" << v.getX() << ", " << v.getY() << ", " << v.getZ() << ")"; 59 | } 60 | 61 | 62 | 63 | 64 | /// standard object services --------------------------------------------------- 65 | OctreeStreamOutImplementation::OctreeStreamOutImplementation 66 | ( 67 | std::ostream& outStream, 68 | const bool isLongFormat 69 | ) 70 | : pOutStream_m ( &outStream ) 71 | , isLongFormat_m( isLongFormat ) 72 | , pCurrentCell_m( 0 ) 73 | , indent_m ( 0 ) 74 | { 75 | } 76 | 77 | 78 | OctreeStreamOutImplementation::~OctreeStreamOutImplementation() 79 | { 80 | } 81 | 82 | 83 | OctreeStreamOutImplementation::OctreeStreamOutImplementation 84 | ( 85 | const OctreeStreamOutImplementation& other 86 | ) 87 | : pOutStream_m ( other.pOutStream_m ) 88 | , isLongFormat_m( other.isLongFormat_m ) 89 | , pCurrentCell_m( 0 ) 90 | , indent_m ( 0 ) 91 | { 92 | } 93 | 94 | 95 | OctreeStreamOutImplementation& OctreeStreamOutImplementation::operator= 96 | ( 97 | const OctreeStreamOutImplementation& other 98 | ) 99 | { 100 | if( &other != this ) 101 | { 102 | pOutStream_m = other.pOutStream_m; 103 | isLongFormat_m = other.isLongFormat_m; 104 | 105 | pCurrentCell_m = 0; 106 | indent_m = 0; 107 | } 108 | 109 | return *this; 110 | } 111 | 112 | 113 | 114 | 115 | /// commands ------------------------------------------------------------------- 116 | void OctreeStreamOutImplementation::visitRoot 117 | ( 118 | const OctreeCell* pRootCell, 119 | const OctreeData& octreeData, 120 | OctreeVisitorV& visitor 121 | ) 122 | { 123 | dword byteSize = 0; 124 | dword leafCount = 0; 125 | dword itemCount = 0; 126 | dword maxDepth = 0; 127 | 128 | if( pRootCell ) 129 | { 130 | pRootCell->getInfo( byteSize, leafCount, itemCount, maxDepth ); 131 | } 132 | 133 | byteSize += sizeof(OctreeRoot); 134 | 135 | const OctreeDimensions& dimensions = octreeData.getDimensions(); 136 | *pOutStream_m << "\nOctree " << 137 | "\nposition: " << dimensions.getPosition() << 138 | " size: " << dimensions.getSize() << 139 | " maxItemsPerCell: " << dimensions.getMaxItemCountPerCell() << 140 | " maxLevelCount: " << dimensions.getMaxLevelCount() << 141 | "\n(bytes: " << byteSize << 142 | ", leafs: " << leafCount << 143 | ", items: " << itemCount << 144 | ", depth: " << maxDepth << 145 | ")\n{ "; 146 | 147 | if( pRootCell ) 148 | { 149 | pCurrentCell_m = pRootCell; 150 | indent_m = 1; 151 | 152 | // continue visit traversal 153 | OctreeRoot::continueVisit( pRootCell, octreeData, visitor ); 154 | } 155 | else 156 | { 157 | *pOutStream_m << "empty "; 158 | } 159 | 160 | *pOutStream_m << "}\n"; 161 | } 162 | 163 | 164 | void OctreeStreamOutImplementation::visitBranch 165 | ( 166 | const OctreeCell* subCells[8], 167 | const OctreeData& octreeData, 168 | OctreeVisitorV& visitor 169 | ) 170 | { 171 | writeDataAndInfo( *pCurrentCell_m, octreeData, *pOutStream_m ); 172 | 173 | // step through subcells 174 | for( int i = 0; i < 8; ++i ) 175 | { 176 | *pOutStream_m << "\n"; 177 | for( dword j = indent_m; j-- > 0; ) 178 | { 179 | *pOutStream_m << "\t"; 180 | } 181 | *pOutStream_m << "[" << i << " "; 182 | 183 | const OctreeCell*const pSubCell = subCells[i]; 184 | if( pSubCell ) 185 | { 186 | pCurrentCell_m = pSubCell; 187 | indent_m += 1; 188 | 189 | // continue visit traversal 190 | OctreeBranch::continueVisit( subCells, octreeData, i, visitor ); 191 | 192 | indent_m -= 1; 193 | } 194 | else 195 | { 196 | *pOutStream_m << "empty "; 197 | } 198 | 199 | *pOutStream_m << "] "; 200 | } 201 | 202 | *pOutStream_m << "\n"; 203 | for( dword i = indent_m - 1; i-- > 0; ) 204 | { 205 | *pOutStream_m << "\t"; 206 | } 207 | } 208 | 209 | 210 | void OctreeStreamOutImplementation::visitLeafBefore 211 | ( 212 | const OctreeData& octreeData 213 | ) 214 | { 215 | writeDataAndInfo( *pCurrentCell_m, octreeData, *pOutStream_m ); 216 | 217 | indentNewline( 0 ); 218 | 219 | if( isLongFormat_m ) 220 | { 221 | *pOutStream_m << "<"; 222 | } 223 | } 224 | 225 | 226 | void OctreeStreamOutImplementation::visitLeafAfter() 227 | { 228 | if( isLongFormat_m ) 229 | { 230 | indentNewline( 0 ); 231 | *pOutStream_m << ">"; 232 | indentNewline( -1 ); 233 | } 234 | } 235 | 236 | 237 | bool OctreeStreamOutImplementation::isLongFormat() const 238 | { 239 | return isLongFormat_m; 240 | } 241 | 242 | 243 | std::ostream& OctreeStreamOutImplementation::getOutStream() const 244 | { 245 | return *pOutStream_m; 246 | } 247 | 248 | 249 | std::ostream& OctreeStreamOutImplementation::indentNewline 250 | ( 251 | const dword extraIndent 252 | ) const 253 | { 254 | *pOutStream_m << "\n"; 255 | for( dword i = indent_m + extraIndent; i-- > 0; ) 256 | { 257 | *pOutStream_m << "\t"; 258 | } 259 | 260 | return *pOutStream_m; 261 | } 262 | 263 | 264 | 265 | 266 | /// implementation ------------------------------------------------------------- 267 | 268 | void OctreeStreamOutImplementation::writeDataAndInfo 269 | ( 270 | const OctreeCell& octreeCell, 271 | const OctreeData& octreeData, 272 | std::ostream& outStream 273 | ) 274 | { 275 | // do octreeData 276 | outStream << "level(" << 277 | octreeData.getLevel() << ") lo" << 278 | octreeData.getBound().getLowerCorner() << " hi" << 279 | octreeData.getBound().getUpperCorner() << " ctr" << 280 | octreeData.getBound().getCenter() << " sph(" << 281 | octreeData.getBound().getRadius() << ") "; 282 | 283 | // do info 284 | dword byteSize = 0; 285 | dword leafCount = 0; 286 | dword itemCount = 0; 287 | dword depthLargest = 0; 288 | octreeCell.getInfo( byteSize, leafCount, itemCount, depthLargest ); 289 | 290 | outStream << 291 | "(bytes: " << byteSize << 292 | ", leafs: " << leafCount << 293 | ", items: " << itemCount << 294 | ", depth: " << depthLargest << ") "; 295 | } 296 | -------------------------------------------------------------------------------- /samples/OctreeStreamOut.hpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #ifndef OctreeStreamOut_h 40 | #define OctreeStreamOut_h 41 | 42 | 43 | #include 44 | 45 | #include "Octree.hpp" 46 | 47 | 48 | 49 | 50 | namespace hxa7241_graphics 51 | { 52 | 53 | 54 | /** 55 | * Implementation for OctreeStreamOut template.

56 | * 57 | * @see OctreeStreamOut 58 | */ 59 | class OctreeStreamOutImplementation 60 | { 61 | /// standard object services --------------------------------------------------- 62 | public: 63 | OctreeStreamOutImplementation( std::ostream& outStream, 64 | bool isLongFormat ); 65 | 66 | ~OctreeStreamOutImplementation(); 67 | OctreeStreamOutImplementation( 68 | const OctreeStreamOutImplementation& ); 69 | OctreeStreamOutImplementation& operator=( 70 | const OctreeStreamOutImplementation& ); 71 | 72 | 73 | /// commands ------------------------------------------------------------------- 74 | void visitRoot ( const OctreeCell* pRootCell, 75 | const OctreeData& octreeData, 76 | OctreeVisitorV& visitor ); 77 | void visitBranch( const OctreeCell* subCells[8], 78 | const OctreeData& octreeData, 79 | OctreeVisitorV& visitor ); 80 | void visitLeafBefore( const OctreeData& octreeData ); 81 | void visitLeafAfter (); 82 | 83 | bool isLongFormat() const; 84 | std::ostream& getOutStream() const; 85 | std::ostream& indentNewline( dword extraIndent ) const; 86 | 87 | 88 | /// implementation ------------------------------------------------------------- 89 | protected: 90 | static void writeDataAndInfo( const OctreeCell& octreeCell, 91 | const OctreeData& octreeData, 92 | std::ostream& outStream ); 93 | 94 | 95 | /// fields --------------------------------------------------------------------- 96 | private: 97 | std::ostream* pOutStream_m; 98 | bool isLongFormat_m; 99 | 100 | // visit state (only used during a visit) 101 | const OctreeCell* pCurrentCell_m; 102 | dword indent_m; 103 | }; 104 | 105 | 106 | 107 | 108 | 109 | /** 110 | * An octree visitor for writing a text representation of an octree and its 111 | * contents.

112 | * 113 | * @see OctreeStreamOutImplementation 114 | */ 115 | template 116 | class OctreeStreamOut 117 | : public OctreeVisitor 118 | { 119 | /// standard object services --------------------------------------------------- 120 | public: 121 | OctreeStreamOut( std::ostream& outStream, 122 | bool isLongFormat ); 123 | 124 | virtual ~OctreeStreamOut(); 125 | OctreeStreamOut( const OctreeStreamOut& ); 126 | OctreeStreamOut& operator=( const OctreeStreamOut& ); 127 | 128 | 129 | /// octree visitor overrides 130 | /// commands ------------------------------------------------------------------- 131 | protected: 132 | virtual void visitRoot ( const OctreeCell* pRootCell, 133 | const OctreeData& octreeData ); 134 | virtual void visitBranch( const OctreeCell* subCells[8], 135 | const OctreeData& octreeData ); 136 | virtual void visitLeaf ( const Array& items, 137 | const OctreeData& octreeData ); 138 | 139 | 140 | /// fields --------------------------------------------------------------------- 141 | private: 142 | OctreeStreamOutImplementation implementation_m; 143 | }; 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | /// TEMPLATES /// 153 | 154 | /// standard object services --------------------------------------------------- 155 | template 156 | inline 157 | OctreeStreamOut::OctreeStreamOut 158 | ( 159 | std::ostream& outStream, 160 | const bool isLongFormat 161 | ) 162 | : OctreeVisitor() 163 | , implementation_m ( outStream, isLongFormat ) 164 | { 165 | } 166 | 167 | 168 | template 169 | inline 170 | OctreeStreamOut::~OctreeStreamOut() 171 | { 172 | } 173 | 174 | 175 | template 176 | inline 177 | OctreeStreamOut::OctreeStreamOut 178 | ( 179 | const OctreeStreamOut& other 180 | ) 181 | : OctreeVisitor() 182 | , implementation_m ( other.implementation_m ) 183 | { 184 | } 185 | 186 | 187 | template 188 | inline 189 | OctreeStreamOut& OctreeStreamOut::operator= 190 | ( 191 | const OctreeStreamOut& other 192 | ) 193 | { 194 | if( &other != this ) 195 | { 196 | implementation_m = other.implementation_m; 197 | } 198 | 199 | return *this; 200 | } 201 | 202 | 203 | 204 | 205 | /// commands ------------------------------------------------------------------- 206 | template 207 | inline 208 | void OctreeStreamOut::visitRoot 209 | ( 210 | const OctreeCell* pRootCell, 211 | const OctreeData& octreeData 212 | ) 213 | { 214 | implementation_m.visitRoot( pRootCell, octreeData, *this ); 215 | } 216 | 217 | 218 | template 219 | inline 220 | void OctreeStreamOut::visitBranch 221 | ( 222 | const OctreeCell* subCells[8], 223 | const OctreeData& octreeData 224 | ) 225 | { 226 | implementation_m.visitBranch( subCells, octreeData, *this ); 227 | } 228 | 229 | 230 | template 231 | void OctreeStreamOut::visitLeaf 232 | ( 233 | const Array& items, 234 | const OctreeData& octreeData 235 | ) 236 | { 237 | implementation_m.visitLeafBefore( octreeData ); 238 | 239 | const TYPE* const* ppItem = items.getStorage(); 240 | const TYPE* const* ppEnd = ppItem + items.getLength(); 241 | 242 | for( ; ppItem < ppEnd; ++ppItem ) 243 | { 244 | if( implementation_m.isLongFormat() ) 245 | { 246 | implementation_m.indentNewline( +1 ); 247 | implementation_m.getOutStream() << "id:" << *ppItem << ": " << 248 | **ppItem; 249 | } 250 | else 251 | { 252 | implementation_m.getOutStream() << "<" << "id:" << *ppItem << 253 | ": " << **ppItem << "> "; 254 | } 255 | } 256 | 257 | implementation_m.visitLeafAfter(); 258 | } 259 | 260 | 261 | }//namespace 262 | 263 | 264 | 265 | 266 | #endif//OctreeStreamOut_h 267 | -------------------------------------------------------------------------------- /samples/OctreeTest.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "Octree.hpp" 49 | 50 | #include "OctreeStreamOut.hpp" 51 | #include "OctreeTest.hpp" 52 | 53 | 54 | using namespace hxa7241_graphics; 55 | 56 | 57 | 58 | 59 | std::ostream& operator<<( std::ostream&, const Vector3r& ); 60 | 61 | std::ostream& operator<< 62 | ( 63 | std::ostream& out, 64 | const Vector3r& v3f 65 | ) 66 | { 67 | out << "(" << v3f.getX() << ", " << v3f.getY() << ", " << v3f.getZ() << ")"; 68 | 69 | return out; 70 | } 71 | 72 | 73 | 74 | 75 | /// OctreeItemTest ///////////////////////////////////////////////////////////// 76 | 77 | class OctreeItemTest 78 | { 79 | /// standard object services --------------------------------------------------- 80 | public: 81 | OctreeItemTest( const Vector3r& position = Vector3r::ZERO(), 82 | const Vector3r& dimension = Vector3r::ZERO(), 83 | dword payload = 0 ); 84 | 85 | virtual ~OctreeItemTest(); 86 | OctreeItemTest( const OctreeItemTest& ); 87 | OctreeItemTest& operator=( const OctreeItemTest& ); 88 | 89 | 90 | /// queries -------------------------------------------------------------------- 91 | virtual const Vector3r& getPosition() const; 92 | virtual const Vector3r& getDimensions() const; 93 | 94 | virtual dword getPayload() const; 95 | 96 | 97 | /// fields --------------------------------------------------------------------- 98 | private: 99 | Vector3r position_m; 100 | Vector3r dimensions_m; 101 | 102 | dword payload_m; 103 | }; 104 | 105 | 106 | 107 | 108 | /// standard object services --------------------------------------------------- 109 | OctreeItemTest::OctreeItemTest 110 | ( 111 | const Vector3r& position, 112 | const Vector3r& dimensions, 113 | const dword payload 114 | ) 115 | : position_m ( position ) 116 | , dimensions_m( dimensions ) 117 | , payload_m ( payload ) 118 | { 119 | } 120 | 121 | 122 | OctreeItemTest::~OctreeItemTest() 123 | { 124 | } 125 | 126 | 127 | OctreeItemTest::OctreeItemTest 128 | ( 129 | const OctreeItemTest& other 130 | ) 131 | : position_m ( other.position_m ) 132 | , dimensions_m( other.dimensions_m ) 133 | , payload_m ( other.payload_m ) 134 | { 135 | } 136 | 137 | 138 | OctreeItemTest& OctreeItemTest::operator= 139 | ( 140 | const OctreeItemTest& other 141 | ) 142 | { 143 | if( &other != this ) 144 | { 145 | position_m = other.position_m; 146 | dimensions_m = other.dimensions_m; 147 | payload_m = other.payload_m; 148 | } 149 | 150 | return *this; 151 | } 152 | 153 | 154 | /// queries -------------------------------------------------------------------- 155 | const Vector3r& OctreeItemTest::getPosition() const 156 | { 157 | return position_m; 158 | } 159 | 160 | 161 | const Vector3r& OctreeItemTest::getDimensions() const 162 | { 163 | return dimensions_m; 164 | } 165 | 166 | 167 | dword OctreeItemTest::getPayload() const 168 | { 169 | return payload_m; 170 | } 171 | 172 | 173 | std::ostream& operator<<( std::ostream&, const OctreeItemTest& ); 174 | 175 | std::ostream& operator<< 176 | ( 177 | std::ostream& out, 178 | const OctreeItemTest& item 179 | ) 180 | { 181 | const Vector3r& position( item.getPosition() ); 182 | const Vector3r& dimensions( item.getDimensions() ); 183 | 184 | out << "{" << position << " " << dimensions << "}"; 185 | 186 | return out; 187 | } 188 | 189 | 190 | 191 | 192 | /// OctreeAgentTest //////////////////////////////////////////////////////////// 193 | 194 | class OctreeAgentTest 195 | : public OctreeAgent 196 | { 197 | /// standard object services --------------------------------------------------- 198 | public: 199 | OctreeAgentTest() {}; 200 | 201 | virtual ~OctreeAgentTest() {}; 202 | private: 203 | OctreeAgentTest( const OctreeAgentTest& ); 204 | OctreeAgentTest& operator=( const OctreeAgentTest& ); 205 | 206 | 207 | /// queries -------------------------------------------------------------------- 208 | /// octree agent overrides 209 | protected: 210 | virtual bool isOverlappingCell ( const OctreeItemTest& item, 211 | const Vector3r& lowerCorner, 212 | const Vector3r& upperCorner ) const; 213 | 214 | 215 | /// implementation ------------------------------------------------------------- 216 | public: 217 | static bool isOverlapping( const Vector3r& itemLower, 218 | const Vector3r& itemUpper, 219 | const Vector3r& cellLower, 220 | const Vector3r& cellUpper ); 221 | }; 222 | 223 | 224 | 225 | 226 | /// queries -------------------------------------------------------------------- 227 | /// octree agent overrides 228 | bool OctreeAgentTest::isOverlappingCell 229 | ( 230 | const OctreeItemTest& item, 231 | const Vector3r& lowerCorner, 232 | const Vector3r& upperCorner 233 | ) const 234 | { 235 | return isOverlapping( item.getPosition(), 236 | item.getPosition() + item.getDimensions(), lowerCorner, upperCorner ); 237 | } 238 | 239 | 240 | bool OctreeAgentTest::isOverlapping 241 | ( 242 | const Vector3r& itemLower, 243 | const Vector3r& itemUpper, 244 | const Vector3r& cellLower, 245 | const Vector3r& cellUpper 246 | ) 247 | { 248 | // check the two ranges overlap in every dimension 249 | bool isOverlap = true; 250 | for( int i = 3; i-- > 0; ) 251 | { 252 | isOverlap &= (itemLower[i] < cellUpper[i]) & 253 | (itemUpper[i] > cellLower[i]); 254 | } 255 | 256 | return isOverlap; 257 | } 258 | 259 | 260 | 261 | 262 | /// OctreeVisitorTest ////////////////////////////////////////////////////////// 263 | 264 | class OctreeVisitorTest 265 | : public OctreeVisitor 266 | { 267 | /// standard object services --------------------------------------------------- 268 | public: 269 | OctreeVisitorTest( const Octree& ); 270 | 271 | virtual ~OctreeVisitorTest(); 272 | private: 273 | OctreeVisitorTest( const OctreeVisitorTest& ); 274 | OctreeVisitorTest& operator=( const OctreeVisitorTest& ); 275 | 276 | 277 | /// commands ------------------------------------------------------------------- 278 | protected: 279 | virtual void visitRoot ( const OctreeCell* pRootCell, 280 | const OctreeData& octreeData ); 281 | virtual void visitBranch( const OctreeCell* subCells[8], 282 | const OctreeData& octreeData ); 283 | virtual void visitLeaf ( const Array& items, 284 | const OctreeData& octreeData ); 285 | 286 | 287 | /// queries -------------------------------------------------------------------- 288 | public: 289 | typedef std::pair > LeafData; 290 | 291 | const std::vector& getIds() const; 292 | const std::vector& getLeafs() const; 293 | 294 | 295 | /// fields --------------------------------------------------------------------- 296 | private: 297 | std::vector ids_m; 298 | std::vector leafs_m; 299 | }; 300 | 301 | 302 | 303 | 304 | /// standard object services --------------------------------------------------- 305 | OctreeVisitorTest::OctreeVisitorTest 306 | ( 307 | const Octree& octree 308 | ) 309 | : ids_m () 310 | , leafs_m() 311 | { 312 | ids_m.push_back( static_cast(&octree) ); 313 | } 314 | 315 | 316 | OctreeVisitorTest::~OctreeVisitorTest() 317 | { 318 | } 319 | 320 | 321 | OctreeVisitorTest::OctreeVisitorTest 322 | ( 323 | const OctreeVisitorTest& other 324 | ) 325 | : OctreeVisitor() 326 | , ids_m ( other.ids_m ) 327 | , leafs_m( other.leafs_m ) 328 | { 329 | } 330 | 331 | 332 | OctreeVisitorTest& OctreeVisitorTest::operator= 333 | ( 334 | const OctreeVisitorTest& other 335 | ) 336 | { 337 | if( &other != this ) 338 | { 339 | ids_m = other.ids_m; 340 | leafs_m = other.leafs_m; 341 | } 342 | 343 | return *this; 344 | } 345 | 346 | 347 | /// commands ------------------------------------------------------------------- 348 | void OctreeVisitorTest::visitRoot 349 | ( 350 | const OctreeCell* pRootCell, 351 | const OctreeData& octreeData 352 | ) 353 | { 354 | if( pRootCell ) 355 | { 356 | ids_m.push_back( static_cast(pRootCell) ); 357 | 358 | pRootCell->visit( octreeData, *this ); 359 | } 360 | } 361 | 362 | 363 | void OctreeVisitorTest::visitBranch 364 | ( 365 | const OctreeCell* subCells[8], 366 | const OctreeData& octreeData 367 | ) 368 | { 369 | ids_m.push_back( subCells ); 370 | 371 | // step through subcells 372 | for( dword i = 8; i-- > 0; ) 373 | { 374 | const OctreeCell* pSubCell = subCells[i]; 375 | if( pSubCell ) 376 | { 377 | ids_m.push_back( static_cast(pSubCell) ); 378 | 379 | // continue visit traversal 380 | OctreeBranch::continueVisit( subCells, octreeData, i, *this ); 381 | } 382 | } 383 | } 384 | 385 | 386 | void OctreeVisitorTest::visitLeaf 387 | ( 388 | const Array& items, 389 | const OctreeData& octreeData 390 | ) 391 | { 392 | ids_m.push_back( static_cast(&items) ); 393 | 394 | leafs_m.push_back( LeafData( octreeData, items ) ); 395 | } 396 | 397 | 398 | /// queries -------------------------------------------------------------------- 399 | const std::vector& OctreeVisitorTest::getIds() const 400 | { 401 | return ids_m; 402 | } 403 | 404 | 405 | const std::vector& OctreeVisitorTest::getLeafs() 406 | const 407 | { 408 | return leafs_m; 409 | } 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | /// declarations /////////////////////////////////////////////////////////////// 419 | 420 | static bool testConstruction 421 | ( 422 | std::ostream* out = 0, 423 | const bool isVerbose = false, 424 | const dword seed = 0 425 | ); 426 | static bool testCommands 427 | ( 428 | std::ostream* out = 0, 429 | const bool isVerbose = false, 430 | const dword seed = 0 431 | ); 432 | static bool testCommands1 433 | ( 434 | std::ostream* out = 0, 435 | const bool isVerbose = false, 436 | const dword seed = 0 437 | ); 438 | static bool testCommands2 439 | ( 440 | std::ostream* out = 0, 441 | const bool isVerbose = false, 442 | const dword seed = 0 443 | ); 444 | static bool testCommands3 445 | ( 446 | std::ostream* out = 0, 447 | const bool isVerbose = false, 448 | const dword seed = 0 449 | ); 450 | 451 | 452 | class RandomFast 453 | { 454 | public: 455 | /// standard object services --------------------------------------------------- 456 | explicit RandomFast( const dword seed =0 ) 457 | : random_m( seed ) 458 | { 459 | } 460 | 461 | ~RandomFast() 462 | { 463 | } 464 | 465 | RandomFast( const RandomFast& other ) 466 | : random_m( other.random_m ) 467 | { 468 | } 469 | 470 | RandomFast& operator=( const RandomFast& other ) 471 | { 472 | random_m = other.random_m; 473 | 474 | return *this; 475 | } 476 | 477 | 478 | /// commands ------------------------------------------------------------------- 479 | RandomFast& setSeed( const dword seed ) 480 | { 481 | random_m = seed; 482 | 483 | return *this; 484 | } 485 | 486 | RandomFast& next() 487 | { 488 | random_m = static_cast(1664525) * random_m + 489 | static_cast(1013904223); 490 | 491 | return *this; 492 | } 493 | 494 | 495 | /// queries -------------------------------------------------------------------- 496 | dword getDword() const 497 | { 498 | return random_m; 499 | } 500 | 501 | udword getUdword() const 502 | { 503 | return static_cast(random_m); 504 | } 505 | 506 | float getFloat() const 507 | { 508 | dword itemp = static_cast(0x3F800000) | 509 | (static_cast(0x007FFFFF) & random_m); 510 | return *(reinterpret_cast(&itemp)) - 1.0f; 511 | } 512 | 513 | float getFloat( const float scale, 514 | const float displace = 0.0f ) const 515 | { 516 | return getFloat() * scale + displace; 517 | } 518 | 519 | 520 | /// fields --------------------------------------------------------------------- 521 | private: 522 | // current value of sequence and seed of the following part of the sequence 523 | dword random_m; 524 | }; 525 | 526 | 527 | static void makeRandomFilledOctree 528 | ( 529 | RandomFast& rand, 530 | const dword howManyItems, 531 | std::auto_ptr >& pOctree, 532 | std::vector& items 533 | ); 534 | static void makeRandomOctree 535 | ( 536 | RandomFast& rand, 537 | std::auto_ptr >& pOctree 538 | ); 539 | static void makeRandomItems 540 | ( 541 | RandomFast& rand, 542 | dword howMany, 543 | const Vector3r& position, 544 | real size, 545 | std::vector& items 546 | ); 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | /// test functions ///////////////////////////////////////////////////////////// 556 | 557 | void hxa7241_graphics::preTest() 558 | { 559 | // make items 560 | OctreeItemTest item1( Vector3r( 1, 1, 1 ) ); 561 | OctreeItemTest item2( Vector3r( 3, 3, 3 ) ); 562 | OctreeItemTest item3( Vector3r( 4, 4, 4 ) ); 563 | 564 | // make octree 565 | Vector3r position( 0, 0, 0 ); 566 | real size = 5.0f; 567 | dword maxItems = 1; 568 | dword maxLevels = 4; 569 | 570 | Octree o1( position, size, maxItems, maxLevels, 0.001f ); 571 | 572 | // insert items into octree 573 | OctreeAgentTest a; 574 | o1.insert( item1, a ); 575 | o1.insert( item2, a ); 576 | o1.insert( item3, a ); 577 | 578 | // stream out octree 579 | OctreeStreamOut vso( std::cout, true ); 580 | o1.visit( vso ); 581 | } 582 | 583 | 584 | 585 | 586 | bool hxa7241_graphics::test_Octree 587 | ( 588 | std::ostream* pOut, 589 | const bool isVerbose, 590 | dword seed 591 | ) 592 | { 593 | if( 0 == seed ) 594 | { 595 | seed = static_cast(::time(0)); 596 | } 597 | 598 | if( pOut ) 599 | { 600 | pOut->flags( std::ios_base::boolalpha );// | std::ios_base::uppercase ); 601 | } 602 | 603 | return testConstruction( pOut, isVerbose, seed ) && 604 | testCommands( pOut, isVerbose, seed ); 605 | } 606 | 607 | 608 | 609 | 610 | bool testConstruction 611 | ( 612 | std::ostream* pOut, 613 | const bool isVerbose, 614 | const dword seed 615 | ) 616 | { 617 | // Copying: 618 | // 619 | // Generate some random octrees. Copy each and check it is identical to 620 | // its original in value, and check all octree object ids are different. 621 | 622 | bool isOk = true; 623 | 624 | RandomFast rand( seed ); 625 | if( pOut ) 626 | { 627 | *pOut << "\nseed= " << rand.getDword() << "\n"; 628 | } 629 | 630 | // loop 631 | for( dword i = 0; i < 10; ++i ) 632 | { 633 | std::auto_ptr > po1; 634 | std::vector items; 635 | makeRandomFilledOctree( rand, 30, po1, items ); 636 | 637 | if( (*pOut != 0) && isVerbose ) 638 | { 639 | OctreeStreamOut so( *pOut, true ); 640 | po1->visit( so ); 641 | *pOut << "\n"; 642 | } 643 | 644 | // make copy octree 645 | Octree o2( *po1 ); 646 | 647 | { 648 | // stream out each to string 649 | std::ostringstream ss1; 650 | OctreeStreamOut so1( ss1, false ); 651 | po1->visit( so1 ); 652 | std::ostringstream ss2; 653 | OctreeStreamOut so2( ss2, false ); 654 | o2.visit( so2 ); 655 | 656 | // compare strings 657 | isOk &= (ss1.str() == ss2.str()); 658 | } 659 | 660 | { 661 | // make arrays of octree object ids 662 | OctreeVisitorTest v1( *po1 ); 663 | po1->visit( v1 ); 664 | OctreeVisitorTest v2( o2 ); 665 | o2.visit( v2 ); 666 | 667 | isOk &= (v1.getIds().size() == v2.getIds().size()); 668 | 669 | // check set intersection of ids is empty 670 | std::vector ids1( v1.getIds() ); 671 | std::vector ids2( v2.getIds() ); 672 | std::sort( ids1.begin(), ids1.end() ); 673 | std::sort( ids2.begin(), ids2.end() ); 674 | std::vector intersect; 675 | std::set_intersection( ids1.begin(), ids1.end(), 676 | ids2.begin(), ids2.end(), 677 | intersect.begin() ); 678 | isOk &= intersect.empty(); 679 | } 680 | 681 | if( pOut ) 682 | { 683 | *pOut << i << " " << isOk << "\n"; 684 | } 685 | } 686 | 687 | if( pOut ) 688 | { 689 | *pOut << "\n--- testConstruction: " << isOk << "\n"; 690 | } 691 | 692 | return isOk; 693 | } 694 | 695 | 696 | bool testCommands 697 | ( 698 | std::ostream* pOut, 699 | const bool isVerbose, 700 | const dword seed 701 | ) 702 | { 703 | return testCommands1( pOut, isVerbose, seed ) && 704 | testCommands2( pOut, isVerbose, seed ) && 705 | testCommands3( pOut, isVerbose, seed ); 706 | } 707 | 708 | 709 | bool testCommands1 710 | ( 711 | std::ostream* pOut, 712 | const bool isVerbose, 713 | const dword //seed 714 | ) 715 | { 716 | // simple structural test: 717 | // 718 | // 1) make octree with four item per leaf limit 719 | // 2) add an item in each octant 720 | // 3) check each item is in the correct octant 721 | 722 | bool isOk = true; 723 | 724 | if( pOut ) 725 | { 726 | *pOut << "\n\n"; 727 | } 728 | 729 | 730 | // make octree 731 | Octree o1( Vector3r::ZERO(), 2, 4, 4, 0.0001f ); 732 | 733 | // make items 734 | std::vector i1(8); 735 | OctreeAgentTest a; 736 | for( dword i = 0; i < 8; ++i ) 737 | { 738 | // add item in each octant 739 | const Vector3r position( static_cast(i & 1) + 0.25f, 740 | static_cast((i >> 1) & 1) + 0.25f, 741 | static_cast((i >> 2) & 1) + 0.25f ); 742 | i1[i] = OctreeItemTest( position, Vector3r::HALF(), i ); 743 | o1.insert( i1[i], a ); 744 | 745 | if( pOut && isVerbose ) 746 | { 747 | *pOut << "item " << i << " : " << i1[i] << "\n"; 748 | } 749 | } 750 | if( pOut && isVerbose ) 751 | { 752 | *pOut << "\n"; 753 | } 754 | 755 | if( pOut && isVerbose ) 756 | { 757 | OctreeStreamOut so( *pOut, true ); 758 | o1.visit( so ); 759 | *pOut << "\n"; 760 | } 761 | 762 | // make info from octree 763 | OctreeVisitorTest v1( o1 ); 764 | o1.visit( v1 ); 765 | 766 | // step through leafs 767 | const std::vector& leafs( v1.getLeafs() ); 768 | for( udword j = leafs.size(); j-- > 0; ) 769 | { 770 | const OctreeVisitorTest::LeafData& leaf( leafs[j] ); 771 | 772 | const Vector3r& cellLower( leaf.first.getBound().getLowerCorner() ); 773 | const Vector3r& cellUpper( leaf.first.getBound().getUpperCorner() ); 774 | 775 | // step through items 776 | const Array& items( leaf.second ); 777 | for( int i = 0; i < items.getLength(); ++i ) 778 | { 779 | const OctreeItemTest* pItem = items[i]; 780 | 781 | const Vector3r itemLower( pItem->getPosition() ); 782 | const Vector3r itemUpper( itemLower + pItem->getDimensions() ); 783 | 784 | // check item is overlapping its leaf cell 785 | const bool is = 786 | OctreeAgentTest::isOverlapping( itemLower, itemUpper, 787 | cellLower, cellUpper ); 788 | isOk &= is; 789 | if( pOut && isVerbose ) 790 | { 791 | *pOut << "overlap " << is << " : " << 792 | itemLower << " " << itemUpper << " " << 793 | cellLower << " " << cellUpper << "\n"; 794 | } 795 | 796 | // check item is in correct leaf cell 797 | const dword octantIndex = pItem->getPayload(); 798 | const Vector3r octantLower( static_cast(octantIndex & 1), 799 | static_cast((octantIndex >> 1) & 1), 800 | static_cast((octantIndex >> 2) & 1) ); 801 | const Vector3r octantUpper( octantLower + Vector3r::ONE() ); 802 | isOk &= (cellLower == octantLower); 803 | isOk &= (cellUpper == octantUpper); 804 | 805 | if( pOut ) 806 | { 807 | if( isVerbose ) 808 | { 809 | *pOut << "\toctant match " << (cellLower == octantLower) << 810 | " : " << cellLower << " " << octantLower << "\n"; 811 | *pOut << "\toctant match " << (cellUpper == octantUpper) << 812 | " : " << cellUpper << " " << octantUpper << "\n"; 813 | } 814 | else 815 | { 816 | *pOut << isOk << "\n"; 817 | } 818 | } 819 | } 820 | } 821 | 822 | if( pOut ) 823 | { 824 | *pOut << "\n--- testCommands1: " << isOk << "\n"; 825 | } 826 | 827 | return isOk; 828 | } 829 | 830 | 831 | bool testCommands2 832 | ( 833 | std::ostream* pOut, 834 | const bool ,//isVerbose, 835 | const dword seed 836 | ) 837 | { 838 | // basic insert/remove test: 839 | // 840 | // insert a lot, visit to collect all items, check they are all there 841 | // remove them all, get counts to check they all came out 842 | 843 | bool isOk = true; 844 | 845 | 846 | if( pOut ) 847 | { 848 | *pOut << "\n\n"; 849 | } 850 | 851 | RandomFast rand( seed ); 852 | if( pOut ) 853 | { 854 | *pOut << "\nseed= " << rand.getDword() << "\n\n"; 855 | } 856 | 857 | for( dword j = 0; j < 10; ++j ) 858 | { 859 | // make octree with items 860 | std::auto_ptr > po1; 861 | std::vector i1; 862 | makeRandomFilledOctree( rand, 100, po1, i1 ); 863 | 864 | // // only for 10 or so items (otherwise > 14MB of output) 865 | // if( pOut && isVerbose ) 866 | // { 867 | // OctreeStreamOut so( *pOut, false ); 868 | // po1->visit( so ); 869 | // *pOut << "\n"; 870 | // for( udword i = 0; i < i1.size(); ++i ) 871 | // { 872 | // *pOut << i1[i] << "\n"; 873 | // } 874 | // } 875 | 876 | // collect leafs items 877 | OctreeVisitorTest v1( *po1 ); 878 | po1->visit( v1 ); 879 | 880 | dword byteSize, leafCount, itemRefCount, maxDepth; 881 | po1->getInfo( byteSize, leafCount, itemRefCount, maxDepth ); 882 | 883 | // check collection length equals info leaf count 884 | isOk &= (v1.getLeafs().size() == static_cast(leafCount)); 885 | 886 | // compare items list to leafs collection 887 | { 888 | const std::vector& leafs( v1.getLeafs() ); 889 | 890 | std::set i2s; 891 | for( udword k = 0; k < leafs.size(); ++k ) 892 | { 893 | const Array& items( leafs[k].second ); 894 | for( dword m = 0; m < items.getLength(); ++m ) 895 | { 896 | i2s.insert( items[m] ); 897 | } 898 | } 899 | std::set i1s; 900 | for( udword k = 0; k < i1.size(); ++k ) 901 | { 902 | i1s.insert( &(i1[k]) ); 903 | } 904 | 905 | isOk &= (i1s == i2s); 906 | } 907 | 908 | // remove items 909 | OctreeAgentTest a; 910 | for( udword i = 0; i < i1.size(); ++i ) 911 | { 912 | po1->remove( i1[i], a ); 913 | 914 | // // only for 10 or so items (otherwise > 14MB of output) 915 | // if( pOut && isVerbose ) 916 | // { 917 | // OctreeStreamOut so( *pOut, false ); 918 | // po1->visit( so ); 919 | // } 920 | } 921 | 922 | // check octree info data is all 'zero' 923 | //dword byteSize, leafCount, itemRefCount, maxDepth; 924 | po1->getInfo( byteSize, leafCount, itemRefCount, maxDepth ); 925 | isOk &= (leafCount == 0); 926 | isOk &= (itemRefCount == 0); 927 | isOk &= (maxDepth == 0); 928 | isOk &= po1->isEmpty(); 929 | 930 | if( pOut ) 931 | { 932 | *pOut << j << " " << isOk << "\n"; 933 | } 934 | } 935 | 936 | if( pOut ) 937 | { 938 | *pOut << "\n--- testCommands2: " << isOk << "\n"; 939 | } 940 | 941 | 942 | return isOk; 943 | } 944 | 945 | 946 | bool testCommands3 947 | ( 948 | std::ostream* ,//pOut, 949 | const bool ,//isVerbose, 950 | const dword //seed 951 | ) 952 | { 953 | // Structural conformance postconditions: 954 | // 955 | // Randomly insert and remove many random points, one at a time. 956 | // After each command, check structure of octree: 957 | // * after insertion, the octree is (one of): 958 | // * same, or 959 | // * one leaf holding one more item, or 960 | // * one leaf has changed to a branch containing 1-8 leafs and 0-7 nils, 961 | // or 962 | // * one leaf has changed to 0-n levels of branchs of one subcell, and 963 | // either 2-8 leafs, or one leaf at max level 964 | // * after removal, the octree is (one of): 965 | // * same, or 966 | // * one leaf holding one less item, or 967 | // * one leaf has changed to nil, or 968 | // * eight leafs have disappeared, and their direct parent branch has 969 | // changed to a leaf, or 970 | // * one leaf has disappeared, one of its parent branchs has changed to 971 | // nil, and any branchs between have disappeared 972 | 973 | bool isOk = true; 974 | /* 975 | if( pOut ) 976 | { 977 | *pOut << "\n\n"; 978 | } 979 | 980 | RandomFast rand( seed ); 981 | if( pOut ) 982 | { 983 | *pOut << "\nseed= " << rand.getDword() << "\n\n"; 984 | } 985 | 986 | 987 | if( pOut ) 988 | { 989 | *pOut << "\n--- testCommands3: " << isOk << "\n"; 990 | } 991 | */ 992 | return isOk; 993 | } 994 | 995 | 996 | 997 | 998 | ///----------------------------------------------------------------------------- 999 | 1000 | void makeRandomFilledOctree 1001 | ( 1002 | RandomFast& rand, 1003 | const dword howManyItems, 1004 | std::auto_ptr >& pOctree, 1005 | std::vector& items 1006 | ) 1007 | { 1008 | makeRandomOctree( rand, pOctree ); 1009 | makeRandomItems( rand, howManyItems, 1010 | pOctree->getPosition(), pOctree->getSize(), 1011 | items ); 1012 | 1013 | OctreeAgentTest a; 1014 | for( int i = 0, end = items.size(); i < end; ++i ) 1015 | { 1016 | pOctree->insert( items[i], a ); 1017 | } 1018 | } 1019 | 1020 | 1021 | void makeRandomOctree 1022 | ( 1023 | RandomFast& rand, 1024 | std::auto_ptr >& pOctree 1025 | ) 1026 | { 1027 | // position: random between -/+100 1028 | // (making sure x,y,z are defined in order) 1029 | const real x = rand.next().getFloat(200.0f, -100.0f); 1030 | const real y = rand.next().getFloat(200.0f, -100.0f); 1031 | const real z = rand.next().getFloat(200.0f, -100.0f); 1032 | const Vector3r position( x, y, z ); 1033 | 1034 | // size: random between 0.5 and 50 1035 | const real size = rand.next().getFloat(49.5f, 0.5f); 1036 | 1037 | // max items: random between 1 and 8 1038 | const dword maxItems = (rand.next().getUdword() >> 29) + 1; 1039 | 1040 | // max levels: random between bounds 1041 | const dword maxLevels = (rand.next().getUdword() >> 30) + 3; 1042 | 1043 | // construct 1044 | pOctree.reset( new Octree( position, size, maxItems, 1045 | maxLevels, 0.0001f ) ); 1046 | } 1047 | 1048 | 1049 | void makeRandomItems 1050 | ( 1051 | RandomFast& rand, 1052 | const dword howMany, 1053 | const Vector3r& position, 1054 | const real size, 1055 | std::vector& items 1056 | ) 1057 | { 1058 | items.resize( howMany ); 1059 | 1060 | for( dword i = 0; i < howMany; ++i ) 1061 | { 1062 | // make random item 1063 | const real x = rand.next().getFloat(); 1064 | const real y = rand.next().getFloat(); 1065 | const real z = rand.next().getFloat(); 1066 | Vector3r itemPosition( x, y, z ); 1067 | itemPosition *= (size * 0.99f); 1068 | itemPosition += (Vector3r::ONE() * (size * 0.005f)); 1069 | itemPosition += position; 1070 | 1071 | // add item 1072 | if( rand.next().getDword() >= 0 ) 1073 | { 1074 | items[i] = OctreeItemTest( itemPosition, Vector3r::ZERO() ); 1075 | } 1076 | else 1077 | { 1078 | const real x = rand.next().getFloat(); 1079 | const real y = rand.next().getFloat(); 1080 | const real z = rand.next().getFloat(); 1081 | Vector3r dimensions( x, y, z ); 1082 | dimensions *= 0.175f; 1083 | dimensions += Vector3r(0.025f, 0.025f, 0.025f); 1084 | dimensions *= (size / 3.0f); 1085 | items[i] = OctreeItemTest( itemPosition, dimensions ); 1086 | } 1087 | } 1088 | } 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | /// main /////////////////////////////////////////////////////////////////////// 1098 | 1099 | int main 1100 | ( 1101 | int argc, 1102 | char* argv[] 1103 | ) 1104 | { 1105 | bool isVerbose = false; 1106 | dword seed = 0; 1107 | 1108 | if( argc >= 2 ) 1109 | { 1110 | const std::string a1( argv[1] ); 1111 | isVerbose = (a1 == std::string("true")); 1112 | } 1113 | if( argc >= 3 ) 1114 | { 1115 | std::istringstream iss( argv[2] ); 1116 | iss >> seed; 1117 | } 1118 | 1119 | const bool isOk = hxa7241_graphics::test_Octree( &std::cout, isVerbose, seed 1120 | ); 1121 | 1122 | std::cout << "\n\n" << (isOk ? "---" : "***") << " test_Octree: " << isOk << 1123 | "\n"; 1124 | 1125 | 1126 | return isOk ? EXIT_SUCCESS : EXIT_FAILURE; 1127 | } 1128 | -------------------------------------------------------------------------------- /samples/OctreeTest.hpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | 3 | Octree Component, version 2.1 4 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 5 | 6 | http://www.hxa7241.org/ 7 | 8 | ------------------------------------------------------------------------------*/ 9 | 10 | /*------------------------------------------------------------------------------ 11 | 12 | Copyright (c) 2004-2007, Harrison Ainsworth / HXA7241. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, 15 | are permitted provided that the following conditions are met: 16 | 17 | * Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this 20 | list of conditions and the following disclaimer in the documentation and/or 21 | other materials provided with the distribution. 22 | * The name of the author may not be used to endorse or promote products derived 23 | from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 26 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | OF SUCH DAMAGE. 35 | 36 | ------------------------------------------------------------------------------*/ 37 | 38 | 39 | #ifndef OctreeTest_h 40 | #define OctreeTest_h 41 | 42 | 43 | #include 44 | 45 | 46 | 47 | 48 | namespace hxa7241_graphics 49 | { 50 | 51 | 52 | void preTest(); 53 | 54 | 55 | bool test_Octree 56 | ( 57 | std::ostream* out = 0, 58 | const bool verbose = false, 59 | const dword seed = 0 60 | ); 61 | 62 | 63 | }//namespace 64 | 65 | 66 | 67 | 68 | #endif//OctreeTest_h 69 | --------------------------------------------------------------------------------