SourceXtractorPlusPlus 0.22
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
QuadTree.icpp
Go to the documentation of this file.
1
17
18#include <cassert>
19#include <algorithm> // For std::find
20
21namespace SourceXtractor {
22
23template<typename T>
24QuadTree<T>::QuadTree(size_t capacity) : m_capacity(capacity), m_is_divided(false) {
25}
26
27template<typename T>
31 m_min = tree.m_min;
32 m_max = tree.m_max;
33 m_data = tree.m_data;
34 for (int i = 0; i<4; i++) {
35 m_sub_trees[i] = tree.m_sub_trees[i];
36 }
37}
38
39template<typename T>
40void QuadTree<T>::add(const T& data) {
42 auto c = Coord { Traits::getCoord(data, 0), Traits::getCoord(data, 1) };
44 while (!isContained(c)) {
46 }
47
48 auto quad = getQuadrant(c);
49 if (m_sub_trees[quad] == nullptr) {
51 m_sub_trees[quad]->m_min = getQuadrantMin(quad);
52 m_sub_trees[quad]->m_max = getQuadrantMax(quad);
53 }
54 m_sub_trees[quad]->add(data);
55 } else {
56 addLocally(data);
57 if (m_data.size() >= m_capacity) {
58 split();
59 }
60 }
61}
62
63template<typename T>
64void QuadTree<T>::remove(const T& data) {
65 if (m_is_divided) {
66 auto c = Coord { Traits::getCoord(data, 0), Traits::getCoord(data, 1) };
67 auto quad = getQuadrant(c);
68 if (m_sub_trees[quad] != nullptr) {
69 m_sub_trees[quad]->remove(data);
70 }
71 } else {
72 auto it = std::find(m_data.begin(), m_data.end(), data);
73 if (it != m_data.end()) {
74 m_data.erase(it);
75 }
76 }
77}
78
79template<typename T>
81 auto range_sq = range * range;
82 if (m_is_divided) {
83 std::vector<T> points;
84 for (int i=0; i<4; i++) {
85 if (m_sub_trees[i] != nullptr) {
86 // compare range with distance to closest corner of subtree
87 auto dx_sq = std::min((c.x - m_sub_trees[i]->m_min.x) * (c.x - m_sub_trees[i]->m_min.x),
88 (c.x - m_sub_trees[i]->m_max.x) * (c.x - m_sub_trees[i]->m_max.x));
89 auto dy_sq = std::min((c.y - m_sub_trees[i]->m_min.y) * (c.y - m_sub_trees[i]->m_min.y),
90 (c.y - m_sub_trees[i]->m_max.y) * (c.y - m_sub_trees[i]->m_max.y));
91 if (dx_sq + dy_sq <= range_sq) {
92 auto subtree_points = m_sub_trees[i]->getPointsWithinRange(c, range);
93 points.insert(points.end(), subtree_points.begin(), subtree_points.end());
94 }
95 }
96 }
97 return points;
98 } else {
99 std::vector<T> points;
100 std::copy_if(m_data.begin(), m_data.end(), std::back_inserter(points),
101 [c, range_sq](const T& point) {
102 auto pc = Coord { Traits::getCoord(point, 0), Traits::getCoord(point, 1) };
103 return (pc.x - c.x) * (pc.x - c.x) + (pc.y - c.y) * (pc.y - c.y) <= range_sq;
104 });
105 return points;
106 }
107}
108
109template<typename T>
110void QuadTree<T>::addLocally(const T& data) {
111 assert(!m_is_divided);
112
113 auto c = Coord { Traits::getCoord(data, 0), Traits::getCoord(data, 1) };
114
115 if (m_data.empty()) {
116 m_min.x = m_max.x = c.x;
117 m_min.y = m_max.y = c.y;
118 } else {
119 m_min.x = std::min(m_min.x, c.x);
120 m_min.y = std::min(m_min.y, c.y);
121 m_max.x = std::max(m_max.x, c.x);
122 m_max.y = std::max(m_max.y, c.y);
123 }
124
125 m_data.push_back(data);
126}
127
128template<typename T>
130 assert(!m_is_divided);
131
132 m_is_divided = true;
133 // expands to a square
134 m_max.x = std::max(m_max.x, m_min.x + (m_max.y - m_min.y));
135 m_max.y = std::max(m_max.y, m_min.y + (m_max.x - m_min.x));
136
137 for (auto& d : m_data) {
138 add(d);
139 }
140 m_data.clear();
141}
142
143template<typename T>
145 assert(m_is_divided && !isContained(c));
146
147 auto clone = std::make_shared<QuadTree<T>>(*this);
148
149 if (c.x < m_min.x) {
150 m_min.x -= (m_max.x - m_min.x);
151 } else {
152 m_max.x += (m_max.x - m_min.x);
153 }
154 if (c.y < m_min.y) {
155 m_min.y -= (m_max.y - m_min.y);
156 } else {
157 m_max.y += (m_max.y - m_min.y);
158 }
159
160 auto quad = getQuadrant({ (clone->m_min.x + clone->m_max.x) / 2.0, (clone->m_min.y + clone->m_max.y) / 2.0 });
161 m_sub_trees[quad] = clone;
162 for (size_t i=0; i<4; i++) {
163 if (i != quad) {
164 m_sub_trees[i] = nullptr;
165 }
166 }
167}
168
169template<typename T>
171 size_t quadrant = 0;
172 if (c.x >= (m_min.x + m_max.x) / 2.0) {
173 quadrant += 1;
174 }
175 if (c.y >= (m_min.y + m_max.y) / 2.0) {
176 quadrant += 2;
177 }
178 return quadrant;
179}
180
181template<typename T>
183 return c.x >= m_min.x && c.x <= m_max.x && c.y >= m_min.y && c.y <= m_max.y;
184}
185
186template<typename T>
187typename QuadTree<T>::Coord QuadTree<T>::getQuadrantMin(size_t quadrant) const {
188 return {
189 quadrant & 1 ? (m_max.x + m_min.x) / 2.0 : m_min.x,
190 quadrant & 2 ? (m_max.y + m_min.y) / 2.0 : m_min.y
191 };
192}
193
194template<typename T>
195typename QuadTree<T>::Coord QuadTree<T>::getQuadrantMax(size_t quadrant) const {
196 return {
197 quadrant & 1 ? m_max.x : (m_max.x + m_min.x) / 2.0,
198 quadrant & 2 ? m_max.y : (m_max.y + m_min.y) / 2.0
199 };
200}
201
202
203}
T back_inserter(T... args)
void remove(const T &data)
Definition QuadTree.icpp:64
std::vector< T > getPointsWithinRange(Coord c, double range) const
Definition QuadTree.icpp:80
std::shared_ptr< QuadTree< T > > m_sub_trees[4]
Definition QuadTree.h:62
void add(const T &data)
Definition QuadTree.icpp:40
void addLocally(const T &data)
QuadTree(size_t capacity=100)
Definition QuadTree.icpp:24
std::vector< T > m_data
Definition QuadTree.h:61
T copy_if(T... args)
T end(T... args)
T find(T... args)
T insert(T... args)
T make_shared(T... args)
T max(T... args)
T min(T... args)
static double getCoord(const T &t, size_t index)