Tramway SDK
octree.h
Go to the documentation of this file.
1// Tramway Drifting and Dungeon Exploration Simulator SDK Runtime
2
3#ifndef TRAM_SDK_TEMPLATES_OCTREE_H
4#define TRAM_SDK_TEMPLATES_OCTREE_H
5
6#include <vector>
7#include <algorithm>
8#include <framework/math.h>
9#include <templates/pool.h>
10
11namespace tram {
12
13template <typename T>
14class Octree {
15public:
16 Octree(std::string name, size_t size) : nodes(name, size) {
17 root = nodes.AddNew();
18 root->mid_point = {0.0f, 0.0f, 0.0f};
19 root->half_extent = 100.0f;
20 }
21
22 uint32_t Insert(vec3 point, T data) {
23 Node* new_leaf = nodes.AddNew(Node {.point = point, .data = data});
24 Insert(root, new_leaf);
25 return nodes.index(new_leaf);
26 }
27
28 void Remove(uint32_t node) {
29 Remove(&nodes[node]);
30 }
31
32 size_t Find(T* array, vec3 point) {
33 NearestSearch search = {.point = point};
34 search.point = point;
35
36 FindNearest(&search, root);
37
38 for (int i = 0 ; i < search.found ; i++) {
39 array[i] = search.nearest[i]->data;
40 }
41
42 return search.found;
43 }
44
45 void Draw() {
46 Draw(root);
47 }
48
49 // temporary compatibility methods
50 // TODO: remove
51 uint32_t AddLeaf(T type, float x, float y, float z){
52 return Insert({x, y, z}, type);
53 }
54
55 void RemoveLeaf(uint32_t leaf_id){
56 Remove(leaf_id);
57 }
58
59 size_t FindNearest(T result[], float x, float y, float z){
60 return Find(result, {x, y, z});
61 }
62
63protected:
64 enum Octant {
73 };
74
75 struct Node {
76 Node* octants[8] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
77
78 Node* parent = nullptr;
79
81
82 float half_extent = 1.0f;
83
85
87
88 inline bool IsLeaf() {
89 return !IsNode();
90 }
91
92 inline bool IsNode() {
93 for (int i = 0; i < 8; i++) if (octants[i]) return true;
94 return false;
95 }
96 };
97
99
100 Node* root = nullptr;
101
102 void Insert(Node* parent, Node* leaf) {
103 Octant octant_type = GetOctant(parent->mid_point, leaf->point);
104 Node*& octant = parent->octants[octant_type];
105
106 if (octant) {
107 if (octant->IsNode()) {
108 Insert(octant, leaf);
109 } else {
110 Node* existing_leaf = octant;
111
112 if (glm::distance(existing_leaf->point, leaf->point) == 0.0f) {
113 std::cout << "Point " << leaf->point.x << " " << leaf->point.y << " " << leaf->point.z << " already in tree!" << std::endl;
114 return;
115 }
116
117 octant = NewNode(octant_type, parent);
118
119 Insert(octant, existing_leaf);
120 Insert(octant, leaf);
121 }
122 } else {
123 octant = leaf;
124 leaf->parent = parent;
125 }
126 }
127
128 void Remove(Node* node) {
129 // don't allow removing root node
130 if (!node->parent) return;
131
132 // remove node from parent
133 for (int i = 0; i < 8; i++) {
134 if (node->parent->octants[i] == node) {
135 node->parent->octants[i] = nullptr;
136 break;
137 }
138 }
139
140 //delete node;
141 nodes.Remove(node);
142 }
143
145 Node* nearest[4] = {nullptr, nullptr, nullptr, nullptr};
146 float distance[4] = {INFINITY, INFINITY, INFINITY, INFINITY};
148 float farthest_distance = -INFINITY;
150 int found = 0;
151 };
152
153 void FindNearest(NearestSearch* search, Node* parent_node) {
154 int first_octant = GetOctant(parent_node->mid_point, search->point);
155
156 FindNearest(search, parent_node, first_octant);
157
158 for (int i = 0 ; i < 8; i++) {
159 if (i != first_octant) FindNearest(search, parent_node, i);
160 }
161 }
162
163 void FindNearest(NearestSearch* search, Node* parent_node, int octant) {
164 Node* search_node = parent_node->octants[octant];
165
166 if (!search_node) return;
167
168 if (search_node->IsNode()) {
169 // do the nearest check
170 if (search->found >= 4) {
171 float nearest_possible = glm::distance(search->point, search_node->mid_point) - 1.73205f * search_node->half_extent;
172 if (nearest_possible > search->farthest_distance) return;
173 }
174
175 FindNearest(search, search_node);
176 } else {
177 if (search->found < 4) {
178 float distance = glm::distance(search_node->point, search->point);
179
180 search->nearest[search->found] = search_node;
181 search->distance[search->found] = distance;
182
183 if (search->farthest_distance < distance) {
184 search->farthest_distance = distance;
185 search->farthest_index = search->found;
186 }
187
188 search->found++;
189 } else {
190 float distance = glm::distance(search_node->point, search->point);
191
192 if (search->farthest_distance < distance) {
193 return;
194 }
195
196 search->distance[search->farthest_index] = distance;
197 search->nearest[search->farthest_index] = search_node;
198
199 search->farthest_distance = -INFINITY;
200 for (int i = 0; i < 4; i++) {
201 if (search->farthest_distance < search->distance[i]) {
202 search->farthest_distance = search->distance[i];
203 search->farthest_index = i;
204 }
205 }
206 }
207 }
208 }
209
210 Node* NewNode(Octant octant, Node* parent) {
211 Node* node = nodes.AddNew();
212
213 node->parent = parent;
214
215 node->half_extent = parent->half_extent / 2.0f;
216 node->mid_point = parent->mid_point;
217
218 switch (octant) {
220 node->mid_point.x -= node->half_extent;
221 node->mid_point.y += node->half_extent;
222 node->mid_point.z -= node->half_extent;
223 break;
225 node->mid_point.x -= node->half_extent;
226 node->mid_point.y += node->half_extent;
227 node->mid_point.z += node->half_extent;
228 break;
230 node->mid_point.x += node->half_extent;
231 node->mid_point.y += node->half_extent;
232 node->mid_point.z -= node->half_extent;
233 break;
235 node->mid_point.x += node->half_extent;
236 node->mid_point.y += node->half_extent;
237 node->mid_point.z += node->half_extent;
238 break;
240 node->mid_point.x -= node->half_extent;
241 node->mid_point.y -= node->half_extent;
242 node->mid_point.z -= node->half_extent;
243 break;
245 node->mid_point.x -= node->half_extent;
246 node->mid_point.y -= node->half_extent;
247 node->mid_point.z += node->half_extent;
248 break;
250 node->mid_point.x += node->half_extent;
251 node->mid_point.y -= node->half_extent;
252 node->mid_point.z -= node->half_extent;
253 break;
255 node->mid_point.x += node->half_extent;
256 node->mid_point.y -= node->half_extent;
257 node->mid_point.z += node->half_extent;
258 break;
259 }
260
261 return node;
262 }
263
264 Octant GetOctant(vec3 mid, vec3 point) {
265 if (point.y < mid.y) {
266 if (point.x < mid.x) {
267 if (point.z < mid.z) {
269 } else {
271 }
272 } else {
273 if (point.z < mid.z) {
275 } else {
277 }
278 }
279 } else {
280 if (point.x < mid.x) {
281 if (point.z < mid.z) {
283 } else {
285 }
286 } else {
287 if (point.z < mid.z) {
289 } else {
291 }
292 }
293 }
294
295 }
296
297 void Draw(Node * node) {
298 if (node->IsNode()) {
299 /*vec3 p00 = node->mid_point + vec3(node->width, node->width, node->width);
300 vec3 p01 = node->mid_point + vec3(-node->width, node->width, node->width);
301 vec3 p02 = node->mid_point + vec3(node->width, node->width, -node->width);
302 vec3 p03 = node->mid_point + vec3(-node->width, node->width, -node->width);
303 vec3 p10 = node->mid_point + vec3(node->width, -node->width, node->width);
304 vec3 p11 = node->mid_point + vec3(-node->width, -node->width, node->width);
305 vec3 p12 = node->mid_point + vec3(node->width, -node->width, -node->width);
306 vec3 p13 = node->mid_point + vec3(-node->width, -node->width, -node->width);
307
308 AddLine(p00, p01, COLOR_YELLOW);
309 AddLine(p00, p02, COLOR_YELLOW);
310 AddLine(p03, p01, COLOR_YELLOW);
311 AddLine(p03, p02, COLOR_YELLOW);
312
313 AddLine(p10, p11, COLOR_YELLOW);
314 AddLine(p10, p12, COLOR_YELLOW);
315 AddLine(p13, p11, COLOR_YELLOW);
316 AddLine(p13, p12, COLOR_YELLOW);
317
318 AddLine(p00, p10, COLOR_YELLOW);
319 AddLine(p01, p11, COLOR_YELLOW);
320 AddLine(p02, p12, COLOR_YELLOW);
321 AddLine(p03, p13, COLOR_YELLOW);*/
322
323 for (int i = 0 ; i < 8; i++) {
324 if (node->octants[i]) Draw(node->octants[i]);
325 }
326 } else {
327 //AddLineMarker(node->point, COLOR_GREEN);
328 }
329 }
330
331};
332
333}
334
335#endif // TRAM_SDK_TEMPLATES_OCTREE_H
Definition: octree.h:14
void Insert(Node *parent, Node *leaf)
Definition: octree.h:102
void Draw()
Definition: octree.h:45
Pool< Node > nodes
Definition: octree.h:98
Node * root
Definition: octree.h:100
void Draw(Node *node)
Definition: octree.h:297
void FindNearest(NearestSearch *search, Node *parent_node, int octant)
Definition: octree.h:163
Node * NewNode(Octant octant, Node *parent)
Definition: octree.h:210
void Remove(Node *node)
Definition: octree.h:128
size_t Find(T *array, vec3 point)
Definition: octree.h:32
Octant
Definition: octree.h:64
@ OCTANT_BOTTOM_RIGHT_FRONT
Definition: octree.h:72
@ OCTANT_BOTTOM_LEFT_BACK
Definition: octree.h:69
@ OCTANT_TOP_RIGHT_FRONT
Definition: octree.h:68
@ OCTANT_TOP_RIGHT_BACK
Definition: octree.h:67
@ OCTANT_TOP_LEFT_BACK
Definition: octree.h:65
@ OCTANT_BOTTOM_LEFT_FRONT
Definition: octree.h:70
@ OCTANT_BOTTOM_RIGHT_BACK
Definition: octree.h:71
@ OCTANT_TOP_LEFT_FRONT
Definition: octree.h:66
void Remove(uint32_t node)
Definition: octree.h:28
Octant GetOctant(vec3 mid, vec3 point)
Definition: octree.h:264
Octree(std::string name, size_t size)
Definition: octree.h:16
void RemoveLeaf(uint32_t leaf_id)
Definition: octree.h:55
uint32_t AddLeaf(T type, float x, float y, float z)
Definition: octree.h:51
size_t FindNearest(T result[], float x, float y, float z)
Definition: octree.h:59
void FindNearest(NearestSearch *search, Node *parent_node)
Definition: octree.h:153
uint32_t Insert(vec3 point, T data)
Definition: octree.h:22
Definition: pool.h:21
Serialization, i.e.
glm::vec3 vec3
Definition: math.h:11
Definition: octree.h:144
int found
Definition: octree.h:150
Node * nearest[4]
Definition: octree.h:145
float distance[4]
Definition: octree.h:146
float farthest_distance
Definition: octree.h:148
int farthest_index
Definition: octree.h:147
vec3 point
Definition: octree.h:149
Definition: octree.h:75
Node * parent
Definition: octree.h:78
bool IsNode()
Definition: octree.h:92
float half_extent
Definition: octree.h:82
vec3 point
Definition: octree.h:84
Node * octants[8]
Definition: octree.h:76
vec3 mid_point
Definition: octree.h:80
bool IsLeaf()
Definition: octree.h:88
T data
Definition: octree.h:86