├── LICENSE
├── Makefile
├── README.md
└── src
├── Octree.cpp
├── Octree.hpp
├── Pool.cpp
├── Pool.hpp
└── main.cpp
/LICENSE:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |
117 |
118 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | CFLAGS = -O3
3 |
4 | .PHONY: main clean
5 |
6 | main: clean
7 | $(CXX) $(CFLAGS) src/main.cpp src/Octree.cpp src/Pool.cpp -o main
8 |
9 | clean:
10 | rm -f main
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Simple Octree
2 |
3 | WARNING: There is currently a bug present that needs to be fixed (#1)!
4 |
5 | A simple and very fast Octree implementation that supports Nearest Neigbour Search.
6 | The code uses a pool allocator, but it is easy to swap it out for malloc/free.
7 |
8 | The code is licensed under CC0 / released into Public Domain.
9 |
--------------------------------------------------------------------------------
/src/Octree.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "Octree.hpp"
3 |
--------------------------------------------------------------------------------
/src/Octree.hpp:
--------------------------------------------------------------------------------
1 |
2 | #ifndef OCTREE_H
3 | #define OCTREE_H
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include //for sqrt
11 |
12 | #include "Pool.hpp"
13 |
14 | /*
15 | * This is an Octree implementation for quick point
16 | * insertion, retrival and nearest neighbour search.
17 | * There is no support for removing a Leaf or Branch;
18 | * but that makes the code easier and faster.
19 | */
20 |
21 |
22 | inline bool isPow2(unsigned i) {
23 | return ((i - 1) & i) == 0;
24 | }
25 |
26 | inline unsigned log2(unsigned n) {
27 | assert(n != 0);
28 | assert(isPow2(n));
29 |
30 | unsigned log = 0;
31 | while(true) {
32 | n >>= 1;
33 | if (n == 0) {
34 | break;
35 | }
36 | log++;
37 | }
38 | return log;
39 | }
40 |
41 |
42 | //set bits in mask to 1 (not 0, no toggle) if i has bit [1,2,3] set
43 | #define set1_if_bit1(value, i, mask) ((i&1) ? ((value) | (mask)) : (value))
44 | #define set1_if_bit2(value, i, mask) ((i&2) ? ((value) | (mask)) : (value))
45 | #define set1_if_bit3(value, i, mask) ((i&4) ? ((value) | (mask)) : (value))
46 |
47 |
48 | template
49 | class Octree
50 | {
51 | public:
52 |
53 | class Node {};
54 |
55 | // Branch must have at least one child.
56 | struct Branch : public Node
57 | {
58 | Node *children[8];
59 |
60 | Branch() : children() {
61 | }
62 |
63 | void *operator new(size_t num_bytes, Pool *mem) {
64 | assert(sizeof(Branch) == num_bytes);
65 | return mem->alloc_item();
66 | }
67 |
68 | Node* operator[](unsigned i) const {
69 | assert(i < 8);
70 | return children[i];
71 | }
72 | };
73 |
74 | struct Leaf : public Node
75 | {
76 | T m_value;
77 |
78 | Leaf(T value) : m_value(value) {
79 | }
80 |
81 | void *operator new(size_t num_bytes, Pool *mem) {
82 | assert(sizeof(Leaf) == num_bytes);
83 | return mem->alloc_item();
84 | }
85 |
86 | T& value() {
87 | return m_value;
88 | }
89 |
90 | void value(T& v) {
91 | m_value = v;
92 | }
93 | };
94 |
95 |
96 | typedef typename Pool::iterator leaves_iterator;
97 | typedef typename Pool::iterator branches_iterator;
98 |
99 | Octree(unsigned size) :
100 | m_root(0), m_depth(log2(size)),
101 | leaf_count(0), branch_count(0) {
102 | assert(isPow2(size));
103 | assert(size > 2);
104 | }
105 |
106 | ~Octree() {
107 | }
108 |
109 | /*
110 | * Size of the bounding box.
111 | * Always a power of two.
112 | */
113 | unsigned width() const {
114 | return (1 << depth());
115 | }
116 |
117 | /*
118 | * Maximum depth of the tree.
119 | */
120 | unsigned depth() const {
121 | return m_depth;
122 | }
123 |
124 | /*
125 | * Maximum number of leaves.
126 | */
127 | unsigned capacity() const {
128 | auto w = width();
129 | return w * w * w;
130 | }
131 |
132 | /*
133 | * Get value at given position if Leaf exists.
134 | * Otherwise return a null pointer.
135 | */
136 | Leaf* at(const unsigned x, const unsigned y, const unsigned z) const {
137 | Node* n = m_root;
138 | unsigned size = width();
139 |
140 | assert(x <= size);
141 | assert(y <= size);
142 | assert(z <= size);
143 |
144 | while(size != 1 && n)
145 | {
146 | size /= 2;
147 |
148 | n = reinterpret_cast(n)->children[
149 | !!(x & size) * 1 + !!(y & size) * 2 + !!(z & size) * 4
150 | ];
151 | }
152 |
153 | return reinterpret_cast(n);
154 | }
155 |
156 | /*
157 | * Insert a new Leaf and initialize it using the given value.
158 | * If the Leaf exists, just return the leaf.
159 | */
160 | Leaf* insert(const unsigned x, const unsigned y, const unsigned z, const T &value) {
161 | assert(x < width());
162 | assert(y < width());
163 | assert(z < width());
164 |
165 | Node** n = &m_root;
166 | Node** parent = &m_root;
167 | unsigned i = 0;
168 | unsigned depth = m_depth;
169 |
170 | while (depth) {
171 | if (*n == nullptr) {
172 | *n = new(&branch_pool) Branch();
173 | ++branch_count;
174 | parent = n;
175 | } else {
176 | --depth;
177 | parent = n;
178 |
179 | // The nth bit of x, y and z is encoded in the index.
180 | // Since size is always a power of two, size has always
181 | // only one bit set and it is used as bit mask to check the nth bit.
182 |
183 | const unsigned size = (1 << depth);
184 | // Same as: i = ((x & size) ? 1 : 0) + ((y & size) ? 2 : 0) + ((z & size) ? 4 : 0);
185 | i = !!(x & size) * 1 + !!(y & size) * 2 + !!(z & size) * 4;
186 | n = &reinterpret_cast(*n)->children[i];
187 | }
188 | }
189 |
190 | if (*n == nullptr) {
191 | assert(depth == 0);
192 | *n = new(&leaf_pool) Leaf(value);
193 | ++leaf_count;
194 | }
195 |
196 | return reinterpret_cast(*n);
197 | }
198 |
199 | //search for the nearest neighbour to coordiantes x/y/z
200 | Leaf* findNearestNeighbour(unsigned x, unsigned y, unsigned z) const {
201 | unsigned found_x;
202 | unsigned found_y;
203 | unsigned found_z;
204 |
205 | return findNearestNeighbour(x, y, z, found_x, found_y, found_z);
206 | }
207 |
208 | Leaf* findNearestNeighbour(unsigned x, unsigned y, unsigned z, unsigned &found_x, unsigned &found_y, unsigned &found_z) const {
209 | assert(x <= width());
210 | assert(y <= width());
211 | assert(z <= width());
212 |
213 | if (root() == nullptr) {
214 | return nullptr;
215 | }
216 |
217 | NearestNeighbourSearchFull nns(x, y, z);
218 |
219 | nns.search(root(), 0, 0, 0, width() / 2);
220 |
221 | found_x = nns.nn_x;
222 | found_y = nns.nn_y;
223 | found_z = nns.nn_z;
224 |
225 | return nns.nn_leaf;
226 | }
227 |
228 | typedef void (*Func)(unsigned x, unsigned y, unsigned z, T& value);
229 |
230 | void traverse(Func func) {
231 | if (m_root) {
232 | traverse(m_root, width(), 0, 0, 0, func);
233 | }
234 | }
235 |
236 | Branch* root() const {
237 | return reinterpret_cast(m_root);
238 | }
239 |
240 | /*
241 | * Iterate leaves flollowing memory chunks.
242 | * The order is not defined.
243 | */
244 | leaves_iterator leaf_begin() {
245 | return leaf_pool.begin();
246 | }
247 |
248 | leaves_iterator leaf_end() {
249 | return leaf_pool.end();
250 | }
251 |
252 | /*
253 | * Iterate over all Branch elements.
254 | * Uses the allocated memory chunks.
255 | */
256 | branches_iterator branch_begin() {
257 | return branch_pool.begin();
258 | }
259 |
260 | branches_iterator branch_end() {
261 | return branch_pool.end();
262 | }
263 |
264 | unsigned countLeaves() {
265 | return leaf_count;
266 | }
267 |
268 | unsigned countBranches() {
269 | return branch_count;
270 | }
271 |
272 | private:
273 |
274 | void traverse(Node* n, unsigned m, const unsigned x, const unsigned y, const unsigned z, Func func) {
275 | assert(n != nullptr);
276 | assert(m != 0);
277 |
278 | if (m == 1) {
279 | (*func)(x, y, z, reinterpret_cast(n)->m_value);
280 | } else {
281 | m >>= 1;
282 | Node* tmp;
283 | for (unsigned i = 0; i < 8; i++) {
284 | tmp = reinterpret_cast(n)->children[i];
285 | if (tmp == nullptr) {
286 | continue;
287 | }
288 |
289 | traverse(tmp, m, set1_if_bit1(x, i, m), set1_if_bit2(y, i, m), set1_if_bit3(z, i, m), func);
290 | }
291 | }
292 | }
293 |
294 | // Nearest Neighbor Search in the Octree using bounding boxes.
295 | struct NearestNeighbourSearchFull
296 | {
297 | // Search for nearest neighbour to this position.
298 | const int pos_x;
299 | const int pos_y;
300 | const int pos_z;
301 |
302 | // Search box volume.
303 | int x_min, x_max;
304 | int y_min, y_max;
305 | int z_min, z_max;
306 |
307 | // Nearest neighbour.
308 | Leaf* nn_leaf;
309 | unsigned nn_sq_distance;
310 | unsigned nn_x;
311 | unsigned nn_y;
312 | unsigned nn_z;
313 |
314 | NearestNeighbourSearchFull(unsigned x, unsigned y, unsigned z) :
315 | pos_x(x), pos_y(y), pos_z(z),
316 | x_min(0), x_max(std::numeric_limits::max()),
317 | y_min(0), y_max(std::numeric_limits::max()),
318 | z_min(0), z_max(std::numeric_limits::max()),
319 | nn_leaf(0), nn_sq_distance(std::numeric_limits::max()),
320 | nn_x(0), nn_y(0), nn_z(0) {
321 | }
322 |
323 | // Check if the leaf at position x/y/z is nearer then the current leaf
324 | void check_leaf(Leaf* leaf, int x, int y, int z) {
325 | const long dx = pos_x - x;
326 | const long dy = pos_y - y;
327 | const long dz = pos_z - z;
328 | const unsigned sq_distance = (dx * dx) + (dy * dy) + (dz * dz);
329 |
330 | if (sq_distance < nn_sq_distance)
331 | {
332 | nn_leaf = leaf;
333 | nn_sq_distance = sq_distance;
334 | nn_x = x;
335 | nn_y = y;
336 | nn_z = z;
337 |
338 | const int r = std::sqrt(sq_distance) + 1.0;
339 |
340 | x_min = pos_x - r;
341 | x_max = pos_x + r;
342 | y_min = pos_y - r;
343 | y_max = pos_y + r;
344 | z_min = pos_z - r;
345 | z_max = pos_z + r;
346 | }
347 | }
348 |
349 | // Check if any point of the position is in the search box.
350 | bool check_branch(const unsigned x, const unsigned int y, const unsigned int z, const unsigned w) const {
351 | return !(x_max < x || x_min > x+w || y_max < y || y_min > y+w || z_max < z || z_min > z+w);
352 | }
353 |
354 | void search(const Branch* b, const unsigned x, const unsigned y, const unsigned z, const unsigned size) {
355 | assert(b != nullptr);
356 | assert(isPow2(size));
357 |
358 | // Try the path to the destined position first
359 | const unsigned start_i = !!(pos_x & size) * 1 + !!(pos_y & size) * 2 + !!(pos_z & size) * 4;
360 |
361 | for (unsigned i = start_i; i < (start_i + 8); ++i) {
362 | // Limit index to range [0-7].
363 | Node* n = b->children[i & 7];
364 |
365 | if (n == nullptr) {
366 | continue;
367 | }
368 |
369 | const unsigned child_x = set1_if_bit1(x, i, size);
370 | const unsigned child_y = set1_if_bit2(y, i, size);
371 | const unsigned child_z = set1_if_bit3(z, i, size);
372 |
373 | if (size == 1) {
374 | check_leaf(reinterpret_cast(n), child_x, child_y, child_z);
375 | } else if (check_branch(child_x, child_y, child_z, size)) {
376 | search(reinterpret_cast(n), child_x, child_y, child_z, (size / 2));
377 | }
378 | }
379 | }
380 | };
381 |
382 | Node* m_root;
383 | unsigned m_depth;
384 | unsigned leaf_count;
385 | unsigned branch_count;
386 |
387 | Pool leaf_pool;
388 | Pool branch_pool;
389 | };
390 |
391 | #endif
392 |
--------------------------------------------------------------------------------
/src/Pool.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "Pool.hpp"
3 |
--------------------------------------------------------------------------------
/src/Pool.hpp:
--------------------------------------------------------------------------------
1 | #ifndef POOL_H
2 | #define POOL_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | /*
11 | * This is a simple block based allocator
12 | * that allocates lists of memory blocks.
13 | */
14 |
15 | template
16 | struct Pool
17 | {
18 | struct Chunk
19 | {
20 | T items[LEN];
21 | Chunk* next;
22 | };
23 |
24 | class iterator : public std::iterator
25 | {
26 | public:
27 |
28 | Chunk *chunk;
29 | unsigned pos;
30 |
31 | public:
32 |
33 | iterator() {
34 | }
35 |
36 | iterator(Chunk* chunk, unsigned pos)
37 | : chunk(chunk), pos(pos) {
38 | }
39 |
40 | ~iterator()
41 | {}
42 |
43 | inline iterator(const iterator& it) : chunk(it.chunk), pos(it.pos) {}
44 | inline iterator& operator++() {
45 | ++pos;
46 | if (pos == LEN && chunk->next) {
47 | pos = 0;
48 | chunk = chunk->next;
49 | }
50 | return *this;
51 | }
52 |
53 | inline iterator operator++(int) {
54 | iterator tmp(*this);
55 | operator++();
56 | return tmp;
57 | }
58 |
59 | inline bool operator==(const iterator& rhs) {
60 | return chunk == rhs.chunk && pos == rhs.pos;
61 | }
62 |
63 | inline bool operator!=(const iterator& rhs) {
64 | return !(chunk == rhs.chunk && pos == rhs.pos);
65 | }
66 |
67 | inline T& operator*() {
68 | return chunk->items[pos];
69 | }
70 |
71 | inline T& operator->() {
72 | return chunk->items[pos];
73 | }
74 | };
75 |
76 | Pool() : pos_m(0) {
77 | init_resources();
78 | }
79 |
80 | ~Pool() {
81 | free_resources();
82 | }
83 |
84 | void clear() {
85 | free_resources();
86 | init_resources();
87 | }
88 |
89 | unsigned countElements() {
90 | unsigned count = 0;
91 | Chunk* cur = beg_m;
92 | while(cur != end_m) {
93 | cur = cur->next;
94 | count += LEN;
95 | }
96 |
97 | return count + pos_m;
98 | }
99 |
100 | iterator begin() {
101 | return iterator(beg_m, 0);
102 | }
103 |
104 | iterator end() {
105 | return iterator(end_m, pos_m);
106 | }
107 |
108 | void* alloc_item() {
109 | assert(pos_m <= LEN);
110 |
111 | if (pos_m == LEN) {
112 | Chunk* chunk = (Chunk*) malloc(sizeof(Chunk));
113 | assert(chunk != NULL);
114 |
115 | chunk->next = NULL;
116 | end_m->next = chunk;
117 | end_m = chunk;
118 | pos_m = 0;
119 | }
120 |
121 | T* mem = &end_m->items[pos_m];
122 | ++pos_m;
123 |
124 | return mem;
125 | }
126 |
127 | private:
128 |
129 | void init_resources() {
130 | beg_m = (Chunk*) malloc(sizeof(Chunk));
131 | beg_m->next = NULL;
132 | end_m = beg_m;
133 | }
134 |
135 | //free all resources
136 | void free_resources() {
137 | Chunk* cur = beg_m;
138 | while(cur != end_m)
139 | {
140 | Chunk* tmp = cur->next;
141 | free(cur);
142 | cur = tmp;
143 | }
144 | }
145 |
146 | Chunk* beg_m;
147 | Chunk* end_m;
148 | unsigned pos_m;
149 | };
150 |
151 | #endif
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #include "Octree.hpp"
5 |
6 |
7 | // pseudo random number generator
8 | unsigned rand(unsigned seed) {
9 | const unsigned a = 16807;
10 | const unsigned m = 2147483647;
11 | return ((a * seed) % m);
12 | }
13 |
14 | void test1() {
15 | // Cube side span of 2048 units.
16 | unsigned width = 2048;
17 |
18 | // Create an Octree.
19 | Octree octree(width);
20 |
21 | // Insert elements at random locations.
22 | for (unsigned i = 0; i < 1000; i++) {
23 | unsigned x = rand() % width;
24 | unsigned y = rand() % width;
25 | unsigned z = rand() % width;
26 | octree.insert(x, y, z, i);
27 | }
28 |
29 | //std::cout << "Branches: " << octree.countBranches() << std::endl;
30 | //std::cout << "Leaves: " << octree.countLeaves() << std::endl;
31 |
32 | // Find leaf nearest to [444, 23, 1333]
33 | const unsigned find_x = 444;
34 | const unsigned find_y = 23;
35 | const unsigned find_z = 1333;
36 |
37 | unsigned found_x;
38 | unsigned found_y;
39 | unsigned found_z;
40 |
41 | auto leaf = octree.findNearestNeighbour(find_x, find_y, find_z, found_x, found_y, found_z);
42 | if (leaf && found_x == 204 && found_y == 469 && found_z == 1301 && leaf->value() == 452) {
43 | std::cout << "Test1 [success]" << std::endl;
44 | } else {
45 | std::cout << "Test1 [failed]" << std::endl;
46 | }
47 | }
48 |
49 | void test2() {
50 | Octree octree(8);
51 |
52 | octree.insert(0, 2, 3, 23);
53 | octree.insert(0, 4, 5, 42);
54 |
55 | unsigned found_x;
56 | unsigned found_y;
57 | unsigned found_z;
58 | auto leaf = octree.findNearestNeighbour(0, 2, 4, found_x, found_y, found_z);
59 |
60 | if (leaf && found_x == 0 && found_y == 2 && found_z == 3 && leaf->value() == 23) {
61 | std::cout << "Test2: [success]" << std::endl;
62 | } else {
63 | std::cout << "Test2: [failed]" << std::endl;
64 | }
65 | }
66 |
67 | int main(int argc, char **argv) {
68 | test1();
69 | test2();
70 | return 0;
71 | }
72 |
--------------------------------------------------------------------------------