Tramway SDK
octree.h
Go to the documentation of this file.
1// TRAMWAY DRIFT AND DUNGEON EXPLORATION SIMULATOR 2022
2// All rights reserved.
3
4#ifndef TRAM_SDK_TEMPLATES_OCTREE_H
5#define TRAM_SDK_TEMPLATES_OCTREE_H
6
7#include <vector>
8#include <algorithm>
9#include <framework/math.h>
10#include <templates/pool.h>
11
12namespace tram {
13
14template <typename T>
15class Octree {
16public:
17 Octree(std::string name, size_t size) : nodes(name, size) {
18 root = nodes.AddNew();
19 root->mid_point = {0.0f, 0.0f, 0.0f};
20 root->half_extent = 100.0f;
21 }
22
23 uint32_t Insert(vec3 point, T data) {
24 Node* new_leaf = nodes.AddNew(Node {.point = point, .data = data});
25 Insert(root, new_leaf);
26 return nodes.index(new_leaf);
27 }
28
29 void Remove(uint32_t node) {
30 Remove(&nodes[node]);
31 }
32
33 size_t Find(T* array, vec3 point) {
34 NearestSearch search = {.point = point};
35 search.point = point;
36
37 //std::cout << "search start " << std::endl;
38 FindNearest(&search, root);
39 //std::cout << " " << std::endl;
40
41 for (int i = 0 ; i < search.found ; i++) {
42 array[i] = search.nearest[i]->data;
43 }
44
45 return search.found;
46 }
47
48 void Draw() {
49 Draw(root);
50 }
51
52
53 // temporary compatibility methods
54 // TODO: remove
55 uint32_t AddLeaf(T type, float x, float y, float z){
56 return Insert({x, y, z}, type);
57 }
58
59 void RemoveLeaf(uint32_t leaf_id){
60 Remove(leaf_id);
61 }
62
63 size_t FindNearest(T result[], float x, float y, float z){
64 return Find(result, {x, y, z});
65 }
66
67protected:
68 enum Octant {
77 };
78
79 struct Node {
80 Node* octants[8] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
81
82 Node* parent = nullptr;
83
85
86 float half_extent = 1.0f;
87
89
91
92 inline bool IsLeaf() {
93 return !IsNode();
94 }
95
96 inline bool IsNode() {
97 for (int i = 0; i < 8; i++) if (octants[i]) return true;
98 return false;
99 }
100 };
101
103
104 Node* root = nullptr;
105
106
107
108 void Insert(Node* parent, Node* leaf) {
109 Octant octant_type = GetOctant(parent->mid_point, leaf->point);
110 Node*& octant = parent->octants[octant_type];
111
112 if (octant) {
113 if (octant->IsNode()) {
114 Insert(octant, leaf);
115 } else {
116 Node* existing_leaf = octant;
117
118 if (glm::distance(existing_leaf->point, leaf->point) == 0.0f) {
119 std::cout << "Point " << leaf->point.x << " " << leaf->point.y << " " << leaf->point.z << " already in tree!" << std::endl;
120 return;
121 }
122
123 octant = NewNode(octant_type, parent);
124
125 Insert(octant, existing_leaf);
126 Insert(octant, leaf);
127 }
128 } else {
129 octant = leaf;
130 leaf->parent = parent;
131 }
132 }
133
134
135
136 void Remove(Node* node) {
137
138 // don't allow removing root node
139 if (!node->parent) return;
140
141 // remove node from parent
142 for (int i = 0; i < 8; i++) {
143 if (node->parent->octants[i] == node) {
144 node->parent->octants[i] = nullptr;
145 break;
146 }
147 }
148
149 // remove parent if it has no other children
150 //if (node->parent->IsLeaf()) Remove(node->parent);
151
152 //delete node;
153 nodes.Remove(node);
154 }
155
157 Node* nearest[4] = {nullptr, nullptr, nullptr, nullptr};
158 float distance[4] = {INFINITY, INFINITY, INFINITY, INFINITY};
160 float farthest_distance = -INFINITY;
162 int found = 0;
163 };
164
165 /*struct NearestSearch {
166 vec3 nearest;
167 float nearest_distance = INFINITY;
168
169 vec3 point;
170 bool found = false;
171 };*/
172
173
174
175 void FindNearest(NearestSearch* search, Node* parent_node) {
176 int first_octant = GetOctant(parent_node->mid_point, search->point);
177
178 FindNearest(search, parent_node, first_octant);
179
180 for (int i = 0 ; i < 8; i++) {
181 if (i != first_octant) FindNearest(search, parent_node, i);
182 }
183 }
184
185 void FindNearest(NearestSearch* search, Node* parent_node, int octant) {
186 Node* search_node = parent_node->octants[octant];
187
188 if (!search_node) return;
189
190 if (search_node->IsNode()) {
191 // do the nearest check
192 if (search->found >= 4) {
193 float nearest_possible = glm::distance(search->point, search_node->mid_point) - 1.73205f * search_node->half_extent;
194 if (nearest_possible > search->farthest_distance) return;
195 }
196
197 FindNearest(search, search_node);
198 } else {
199 if (search->found < 4) {
200 float distance = glm::distance(search_node->point, search->point);
201
202 //std::cout << "packed " << distance << std::endl;
203
204 search->nearest[search->found] = search_node;
205 search->distance[search->found] = distance;
206
207 if (search->farthest_distance < distance) {
208 search->farthest_distance = distance;
209 search->farthest_index = search->found;
210 }
211
212 search->found++;
213 } else {
214 float distance = glm::distance(search_node->point, search->point);
215
216 //if (search->farthest_distance < distance) return;
217 if (search->farthest_distance < distance) {
218 //std::cout << "ignore " << distance << "\t" << search->farthest_distance << std::endl;
219 return;
220 } else {
221 //std::cout << "replace " << distance << "\t" << search->farthest_distance << std::endl;
222 }
223
224 search->distance[search->farthest_index] = distance;
225 search->nearest[search->farthest_index] = search_node;
226
227 search->farthest_distance = -INFINITY;
228 for (int i = 0; i < 4; i++) {
229 if (search->farthest_distance < search->distance[i]) {
230 search->farthest_distance = search->distance[i];
231 search->farthest_index = i;
232 }
233 }
234 }
235 }
236 }
237
238 /*void Find(NearestSearch* search, Node* node) {
239 if (node->IsNode()) {
240 float nearest_possible = glm::distance(search->point, node->mid_point) - 1.73205f * node->half_extent;
241 if (nearest_possible > search->nearest_distance) return;
242
243 for (int i = 0 ; i < 8; i++) {
244 if (node->octants[i]) Find(search, node->octants[i]);
245 }
246 } else {
247 float distance = glm::distance(search->point, node->point);
248 if (search->nearest_distance > distance) {
249 search->nearest_distance = distance;
250 search->nearest = node->point;
251 search->found = true;
252 }
253 }
254 }*/
255
256 Node* NewNode(Octant octant, Node* parent) {
257 Node* node = nodes.AddNew();
258
259 node->parent = parent;
260
261 node->half_extent = parent->half_extent / 2.0f;
262 node->mid_point = parent->mid_point;
263
264 switch (octant) {
266 node->mid_point.x -= node->half_extent;
267 node->mid_point.y += node->half_extent;
268 node->mid_point.z -= node->half_extent;
269 break;
271 node->mid_point.x -= node->half_extent;
272 node->mid_point.y += node->half_extent;
273 node->mid_point.z += node->half_extent;
274 break;
276 node->mid_point.x += node->half_extent;
277 node->mid_point.y += node->half_extent;
278 node->mid_point.z -= node->half_extent;
279 break;
281 node->mid_point.x += node->half_extent;
282 node->mid_point.y += node->half_extent;
283 node->mid_point.z += node->half_extent;
284 break;
286 node->mid_point.x -= node->half_extent;
287 node->mid_point.y -= node->half_extent;
288 node->mid_point.z -= node->half_extent;
289 break;
291 node->mid_point.x -= node->half_extent;
292 node->mid_point.y -= node->half_extent;
293 node->mid_point.z += node->half_extent;
294 break;
296 node->mid_point.x += node->half_extent;
297 node->mid_point.y -= node->half_extent;
298 node->mid_point.z -= node->half_extent;
299 break;
301 node->mid_point.x += node->half_extent;
302 node->mid_point.y -= node->half_extent;
303 node->mid_point.z += node->half_extent;
304 break;
305 }
306
307 return node;
308 }
309
310 Octant GetOctant(vec3 mid, vec3 point) {
311 if (point.y < mid.y) {
312 if (point.x < mid.x) {
313 if (point.z < mid.z) {
315 } else {
317 }
318 } else {
319 if (point.z < mid.z) {
321 } else {
323 }
324 }
325 } else {
326 if (point.x < mid.x) {
327 if (point.z < mid.z) {
329 } else {
331 }
332 } else {
333 if (point.z < mid.z) {
335 } else {
337 }
338 }
339 }
340
341 }
342
343 void Draw(Node * node) {
344 if (node->IsNode()) {
345 /*vec3 p00 = node->mid_point + vec3(node->width, node->width, node->width);
346 vec3 p01 = node->mid_point + vec3(-node->width, node->width, node->width);
347 vec3 p02 = node->mid_point + vec3(node->width, node->width, -node->width);
348 vec3 p03 = node->mid_point + vec3(-node->width, node->width, -node->width);
349 vec3 p10 = node->mid_point + vec3(node->width, -node->width, node->width);
350 vec3 p11 = node->mid_point + vec3(-node->width, -node->width, node->width);
351 vec3 p12 = node->mid_point + vec3(node->width, -node->width, -node->width);
352 vec3 p13 = node->mid_point + vec3(-node->width, -node->width, -node->width);
353
354 AddLine(p00, p01, COLOR_YELLOW);
355 AddLine(p00, p02, COLOR_YELLOW);
356 AddLine(p03, p01, COLOR_YELLOW);
357 AddLine(p03, p02, COLOR_YELLOW);
358
359 AddLine(p10, p11, COLOR_YELLOW);
360 AddLine(p10, p12, COLOR_YELLOW);
361 AddLine(p13, p11, COLOR_YELLOW);
362 AddLine(p13, p12, COLOR_YELLOW);
363
364 AddLine(p00, p10, COLOR_YELLOW);
365 AddLine(p01, p11, COLOR_YELLOW);
366 AddLine(p02, p12, COLOR_YELLOW);
367 AddLine(p03, p13, COLOR_YELLOW);*/
368
369 for (int i = 0 ; i < 8; i++) {
370 if (node->octants[i]) Draw (node->octants[i]);
371 }
372 } else {
373 //AddLineMarker(node->point, COLOR_GREEN);
374 }
375 }
376
377};
378
379
380/*
381template <typename T>
382class Octree {
383 // TODO: actually implement the octree
384 struct Node {
385 uint32_t id;
386 float x, y, z;
387 T type;
388 };
389
390 std::vector<Node> nodevec;
391 uint32_t last_id = 1;
392public:
393
394 uint32_t AddLeaf(T type, float x, float y, float z){
395 //Node n = {last_id, x, y, z, type};
396 nodevec.push_back(Node{last_id, x, y, z, type});
397 last_id++;
398 return last_id - 1;
399 }
400
401 void RemoveLeaf(uint32_t leaf_id){
402 nodevec.erase(std::find_if(nodevec.begin(), nodevec.end(), [=](Node& n){return n.id == leaf_id;}));
403 }
404
405 size_t FindNearest(T result[], float x, float y, float z){
406 std::sort(nodevec.begin(), nodevec.end(), [=](const Node& a, const Node& b){return glm::distance(vec3(x, y, z), vec3(a.x, a.y, a.z)) < glm::distance(vec3(x, y, z), vec3(b.x, b.y, b.z));});
407 for (size_t i = 0; i < 4 && i < nodevec.size(); i++){
408 result[i] = nodevec[i].type;
409 }
410 return nodevec.size() > 4 ? 4 : nodevec.size();
411 }
412};
413*/
414
415}
416
417#endif // TRAM_SDK_TEMPLATES_OCTREE_H
Definition: octree.h:15
void Insert(Node *parent, Node *leaf)
Definition: octree.h:108
void Draw()
Definition: octree.h:48
Pool< Node > nodes
Definition: octree.h:102
Node * root
Definition: octree.h:104
void Draw(Node *node)
Definition: octree.h:343
void FindNearest(NearestSearch *search, Node *parent_node, int octant)
Definition: octree.h:185
Node * NewNode(Octant octant, Node *parent)
Definition: octree.h:256
void Remove(Node *node)
Definition: octree.h:136
size_t Find(T *array, vec3 point)
Definition: octree.h:33
Octant
Definition: octree.h:68
@ OCTANT_BOTTOM_RIGHT_FRONT
Definition: octree.h:76
@ OCTANT_BOTTOM_LEFT_BACK
Definition: octree.h:73
@ OCTANT_TOP_RIGHT_FRONT
Definition: octree.h:72
@ OCTANT_TOP_RIGHT_BACK
Definition: octree.h:71
@ OCTANT_TOP_LEFT_BACK
Definition: octree.h:69
@ OCTANT_BOTTOM_LEFT_FRONT
Definition: octree.h:74
@ OCTANT_BOTTOM_RIGHT_BACK
Definition: octree.h:75
@ OCTANT_TOP_LEFT_FRONT
Definition: octree.h:70
void Remove(uint32_t node)
Definition: octree.h:29
Octant GetOctant(vec3 mid, vec3 point)
Definition: octree.h:310
Octree(std::string name, size_t size)
Definition: octree.h:17
void RemoveLeaf(uint32_t leaf_id)
Definition: octree.h:59
uint32_t AddLeaf(T type, float x, float y, float z)
Definition: octree.h:55
size_t FindNearest(T result[], float x, float y, float z)
Definition: octree.h:63
void FindNearest(NearestSearch *search, Node *parent_node)
Definition: octree.h:175
uint32_t Insert(vec3 point, T data)
Definition: octree.h:23
Definition: pool.h:14
Definition: api.h:9
glm::vec3 vec3
Definition: math.h:12
Definition: octree.h:156
int found
Definition: octree.h:162
Node * nearest[4]
Definition: octree.h:157
float distance[4]
Definition: octree.h:158
float farthest_distance
Definition: octree.h:160
int farthest_index
Definition: octree.h:159
vec3 point
Definition: octree.h:161
Definition: octree.h:79
Node * parent
Definition: octree.h:82
bool IsNode()
Definition: octree.h:96
float half_extent
Definition: octree.h:86
vec3 point
Definition: octree.h:88
Node * octants[8]
Definition: octree.h:80
vec3 mid_point
Definition: octree.h:84
bool IsLeaf()
Definition: octree.h:92
T data
Definition: octree.h:90