-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOctree.cpp
180 lines (157 loc) · 5.35 KB
/
Octree.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtx/hash.hpp>
#include <vector>
#include <utility>
#include <stdexcept>
#include "Util.hpp"
#include "AABB.hpp"
#include "Octree.hpp"
#include <iterator>
#include <unordered_map>
// copy constructor
Octree::Octree(const Octree& o) :
boundary(o.boundary),
points(o.points),
kids(o.kids),
haveKids(o.haveKids),
depth(o.depth)
{
}
Octree::Octree(const AABB& boundary, const int& depth) :
boundary(boundary),
haveKids(false),
depth(depth)
{
kids.reserve(8);
}
Octree::Octree(const v3& center, const float& halfDimension, const int& depth) :
Octree(AABB(center,halfDimension),depth)
{}
Octree::Octree(const v3& center, const float& halfDimension) :
Octree(center,halfDimension,1) {}
int Octree::size() const {
int acc = points.size();
for (const auto& kid: kids) {
acc += kid.size();
}
return acc;
}
bool Octree::del(const v3& p) {
// Ignore objects that do not belong in this quad tree
if (!boundary.containsPoint(p)) {
return false; // object cannot be added
}
//std::cout << "del - My center is " << printV(boundary.center) << " with range " << boundary.halfDimension << "\n";
//std::cout << "and I'm looking to delete " << printV(p) << "\n";
if (haveKids) {
//std::cout << "Have kids depth " << depth << "\n";
for (auto& kid: kids) {
const bool removed = kid.del(p);
if (removed) {
return true;
}
}
//std::cout << "Could not erase " << printV(p) << "\n";
} else {
//std::cout << "Don't have kids\n";
//std::cout << "My map size is " << points.size() << "\n";
//std::cout << "Look here for " << printV(p) << "\n";
if (points.find(p) != points.end()) {
//std::cout << "I do contain " << printV(p) << "\n";
points.erase(p);
return true;
} else {
//std::cout << "I don't contain " << printV(p) << "\n";
return false;
}
}
throw std::runtime_error("Error: could not delete ele from octree");
return false;
}
bool Octree::insert(const v3&p, const Id& id) {
return insert(std::make_pair(p,id));
}
bool Octree::insert(const v3Id& p) {
// Ignore objects that do not belong in this quad tree
if (!boundary.containsPoint(p.first)) {
return false; // object cannot be added
}
if (haveKids) {
for (auto& kid: kids) {
const bool worked = kid.insert(p);
if (worked) {
return true;
}
}
} else {
if (points.size() < node_capacity) {
//std::cout << "Trying to insert " << printV(p.first) << " with id " << p.second << "\n";
const auto ret = points.insert(p);
bool worked = ret.second;
if (worked) {
return true;
} else {
throw std::runtime_error("Error: insert into this octree level failed");
}
} else {
// Otherwise, makeKids and then add the point to whichever node will accept it
makeKids();
return insert(p);
}
}
throw std::runtime_error("Octree - Error: could not insert into tree?");
// Otherwise, the point cannot be inserted for some unknown reason (this should never happen)
return false;
}
vId Octree::queryRange(const v3& center, const float& halfDimension) const {
return queryRange(AABB(center,halfDimension));
}
vId Octree::queryRange(const AABB& range) const {
// Prepare an array of results
vId idsInRange;
//idsInRange.reserve(4);
// Automatically abort if the range does not intersect this quad
if (!boundary.intersectsAABB(range)) {
return idsInRange; // empty list
}
if (haveKids) {
for (const auto& kid: kids) {
concat(idsInRange, kid.queryRange(range));
}
// return all kids ids that are valid
} else {
// Check objects at this quad level
for (const auto& p: points) {
if (range.containsPoint(p.first)) {
idsInRange.emplace_back(p.second);
}
}
}
return idsInRange;
}
void Octree::makeKids() {
if (haveKids) {
throw std::runtime_error("Error: shouldn't be calling makeKids on something that has already done so");
}
haveKids = true;
auto c = boundary.center;
auto h = boundary.halfDimension / 2.0f;
int i = 0;
kids.emplace_back(Octree( v3(c.x + h, c.y + h, c.z + h),h,depth+1 ));
kids.emplace_back( Octree(v3(c.x - h, c.y - h, c.z - h),h,depth+1 ));
kids.emplace_back( Octree(v3(c.x - h, c.y + h, c.z + h),h,depth+1 ));
kids.emplace_back( Octree(v3(c.x + h, c.y - h, c.z + h),h,depth+1 ));
kids.emplace_back( Octree(v3(c.x + h, c.y + h, c.z - h),h,depth+1 ));
kids.emplace_back( Octree(v3(c.x - h, c.y - h, c.z + h),h,depth+1 ));
kids.emplace_back( Octree(v3(c.x - h, c.y + h, c.z - h),h,depth+1 ));
kids.emplace_back( Octree(v3(c.x + h, c.y - h, c.z - h),h,depth+1 ));
// remove all objects at this level, insert into kids...
for (const auto& p: points) {
const bool worked = insert(p);
if (!worked) {
throw std::runtime_error("Error: when making kids, could not move elements from parent to child nodes");
}
}
points.clear();
}