SourceXtractorPlusPlus 1.0.3
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) {
41 if (m_is_divided) {
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 for (int i=0; i<4; i++) {
68 if (m_sub_trees[i] != nullptr && m_sub_trees[i]->isContained(c)) {
69 m_sub_trees[i]->remove(data);
70 }
71 }
72 } else {
73 auto it = std::find(m_data.begin(), m_data.end(), data);
74 if (it != m_data.end()) {
75 m_data.erase(it);
76 }
77 }
78}
79
80template<typename T>
82 auto range_sq = range * range;
83 if (m_is_divided) {
84 std::vector<T> points;
85 for (int i=0; i<4; i++) {
86 if (m_sub_trees[i] != nullptr) {
87 // compare range with distance to closest corner of subtree
88 auto dx_sq = std::min((c.x - m_sub_trees[i]->m_min.x) * (c.x - m_sub_trees[i]->m_min.x),
89 (c.x - m_sub_trees[i]->m_max.x) * (c.x - m_sub_trees[i]->m_max.x));
90 auto dy_sq = std::min((c.y - m_sub_trees[i]->m_min.y) * (c.y - m_sub_trees[i]->m_min.y),
91 (c.y - m_sub_trees[i]->m_max.y) * (c.y - m_sub_trees[i]->m_max.y));
92 if (dx_sq + dy_sq <= range_sq) {
93 auto subtree_points = m_sub_trees[i]->getPointsWithinRange(c, range);
94 points.insert(points.end(), subtree_points.begin(), subtree_points.end());
95 }
96 }
97 }
98 return points;
99 } else {
100 std::vector<T> points;
101 std::copy_if(m_data.begin(), m_data.end(), std::back_inserter(points),
102 [c, range_sq](const T& point) {
103 auto pc = Coord { Traits::getCoord(point, 0), Traits::getCoord(point, 1) };
104 return (pc.x - c.x) * (pc.x - c.x) + (pc.y - c.y) * (pc.y - c.y) <= range_sq;
105 });
106 return points;
107 }
108}
109
110template<typename T>
111void QuadTree<T>::addLocally(const T& data) {
112 assert(!m_is_divided);
113
114 auto c = Coord { Traits::getCoord(data, 0), Traits::getCoord(data, 1) };
115
116 if (m_data.empty()) {
117 m_min.x = m_max.x = c.x;
118 m_min.y = m_max.y = c.y;
119 } else {
120 m_min.x = std::min(m_min.x, c.x);
121 m_min.y = std::min(m_min.y, c.y);
122 m_max.x = std::max(m_max.x, c.x);
123 m_max.y = std::max(m_max.y, c.y);
124 }
125
126 m_data.push_back(data);
127}
128
129template<typename T>
131 assert(!m_is_divided);
132
133 m_is_divided = true;
134 // expands to a square
135 m_max.x = std::max(m_max.x, m_min.x + (m_max.y - m_min.y));
136 m_max.y = std::max(m_max.y, m_min.y + (m_max.x - m_min.x));
137
138 for (auto& d : m_data) {
139 add(d);
140 }
141 m_data.clear();
142}
143
144template<typename T>
146 assert(m_is_divided && !isContained(c));
147
148 auto clone = std::make_shared<QuadTree<T>>(*this);
149
150 if (c.x < m_min.x) {
151 m_min.x -= (m_max.x - m_min.x);
152 } else {
153 m_max.x += (m_max.x - m_min.x);
154 }
155 if (c.y < m_min.y) {
156 m_min.y -= (m_max.y - m_min.y);
157 } else {
158 m_max.y += (m_max.y - m_min.y);
159 }
160
161 auto quad = getQuadrant({ (clone->m_min.x + clone->m_max.x) / 2.0, (clone->m_min.y + clone->m_max.y) / 2.0 });
162 m_sub_trees[quad] = clone;
163 for (size_t i=0; i<4; i++) {
164 if (i != quad) {
165 m_sub_trees[i] = nullptr;
166 }
167 }
168}
169
170template<typename T>
172 size_t quadrant = 0;
173 if (c.x >= (m_min.x + m_max.x) / 2.0) {
174 quadrant += 1;
175 }
176 if (c.y >= (m_min.y + m_max.y) / 2.0) {
177 quadrant += 2;
178 }
179 return quadrant;
180}
181
182template<typename T>
184 return c.x >= m_min.x && c.x <= m_max.x && c.y >= m_min.y && c.y <= m_max.y;
185}
186
187template<typename T>
188typename QuadTree<T>::Coord QuadTree<T>::getQuadrantMin(size_t quadrant) const {
189 return {
190 quadrant & 1 ? (m_max.x + m_min.x) / 2.0 : m_min.x,
191 quadrant & 2 ? (m_max.y + m_min.y) / 2.0 : m_min.y
192 };
193}
194
195template<typename T>
196typename QuadTree<T>::Coord QuadTree<T>::getQuadrantMax(size_t quadrant) const {
197 return {
198 quadrant & 1 ? m_max.x : (m_max.x + m_min.x) / 2.0,
199 quadrant & 2 ? m_max.y : (m_max.y + m_min.y) / 2.0
200 };
201}
202
203
204}
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:81
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)