OGS
OctTree-impl.h
Go to the documentation of this file.
1 
13 namespace GeoLib
14 {
15 template <typename POINT, std::size_t MAX_POINTS>
17  Eigen::Vector3d ll, Eigen::Vector3d ur, double eps)
18 {
19  // compute an axis aligned cube around the points ll and ur
20  const double dx(ur[0] - ll[0]);
21  const double dy(ur[1] - ll[1]);
22  const double dz(ur[2] - ll[2]);
23  if (dx >= dy && dx >= dz)
24  {
25  ll[1] -= (dx - dy) / 2.0;
26  ur[1] += (dx - dy) / 2.0;
27  ll[2] -= (dx - dz) / 2.0;
28  ur[2] += (dx - dz) / 2.0;
29  }
30  else
31  {
32  if (dy >= dx && dy >= dz)
33  {
34  ll[0] -= (dy - dx) / 2.0;
35  ur[0] += (dy - dx) / 2.0;
36  ll[2] -= (dy - dz) / 2.0;
37  ur[2] += (dy - dz) / 2.0;
38  }
39  else
40  {
41  ll[0] -= (dz - dx) / 2.0;
42  ur[0] += (dz - dx) / 2.0;
43  ll[1] -= (dz - dy) / 2.0;
44  ur[1] += (dz - dy) / 2.0;
45  }
46  }
47  if (eps == 0.0)
48  {
49  eps = std::numeric_limits<double>::epsilon();
50  }
51  for (std::size_t k(0); k < 3; ++k)
52  {
53  if (ur[k] - ll[k] > 0.0)
54  {
55  ur[k] += (ur[k] - ll[k]) * 1e-6;
56  }
57  else
58  {
59  ur[k] += eps;
60  }
61  }
62  Eigen::Vector3d lower_left{ll[0], ll[1], ll[2]};
63  Eigen::Vector3d upper_right{ur[0], ur[1], ur[2]};
64  return new OctTree<POINT, MAX_POINTS>(lower_left, upper_right, eps);
65 }
66 
67 template <typename POINT, std::size_t MAX_POINTS>
69 {
70  for (auto c : _children)
71  {
72  delete c;
73  }
74 }
75 
76 template <typename POINT, std::size_t MAX_POINTS>
77 bool OctTree<POINT, MAX_POINTS>::addPoint(POINT* pnt, POINT*& ret_pnt)
78 {
79  // first do a range query using a epsilon box around the point pnt
80  std::vector<POINT*> query_pnts;
81  Eigen::Vector3d const min =
82  Eigen::Map<Eigen::Vector3d>(pnt->getCoords()).array() - _eps;
83  Eigen::Vector3d const max =
84  Eigen::Map<Eigen::Vector3d>(pnt->getCoords()).array() + _eps;
85  getPointsInRange(min, max, query_pnts);
86  auto const it = std::find_if(
87  query_pnts.begin(), query_pnts.end(),
88  [pnt, this](auto const* p)
89  {
90  return (Eigen::Map<Eigen::Vector3d const>(p->getCoords()) -
91  Eigen::Map<Eigen::Vector3d const>(pnt->getCoords()))
92  .squaredNorm() < _eps * _eps;
93  });
94  if (it != query_pnts.end())
95  {
96  ret_pnt = *it;
97  return false;
98  }
99 
100  // the point pnt is not yet in the OctTree
101  if (isOutside(pnt))
102  {
103  ret_pnt = nullptr;
104  return false;
105  }
106 
107  // at this place it holds true that the point is within [_ll, _ur]
108  if (!_is_leaf)
109  {
110  for (auto c : _children)
111  {
112  if (c->addPoint_(pnt, ret_pnt))
113  {
114  return true;
115  }
116  if (ret_pnt != nullptr)
117  {
118  return false;
119  }
120  }
121  }
122 
123  ret_pnt = pnt;
124 
125  if (_pnts.size() < MAX_POINTS)
126  {
127  _pnts.push_back(pnt);
128  }
129  else
130  { // i.e. _pnts.size () == MAX_POINTS
131  splitNode(pnt);
132  _pnts.clear();
133  }
134  return true;
135 }
136 
137 template <typename POINT, std::size_t MAX_POINTS>
138 template <typename T>
140  T const& min, T const& max, std::vector<POINT*>& pnts) const
141 {
142  if (_ur[0] < min[0] || _ur[1] < min[1] || _ur[2] < min[2])
143  {
144  return;
145  }
146 
147  if (max[0] < _ll[0] || max[1] < _ll[1] || max[2] < _ll[2])
148  {
149  return;
150  }
151 
152  if (_is_leaf)
153  {
154  std::copy_if(_pnts.begin(), _pnts.end(), std::back_inserter(pnts),
155  [&min, &max](auto const* p)
156  {
157  return (min[0] <= (*p)[0] && (*p)[0] < max[0] &&
158  min[1] <= (*p)[1] && (*p)[1] < max[1] &&
159  min[2] <= (*p)[2] && (*p)[2] < max[2]);
160  });
161  }
162  else
163  {
164  for (std::size_t k(0); k < 8; k++)
165  {
166  _children[k]->getPointsInRange(min, max, pnts);
167  }
168  }
169 }
170 
171 template <typename POINT, std::size_t MAX_POINTS>
172 OctTree<POINT, MAX_POINTS>::OctTree(Eigen::Vector3d const& ll,
173  Eigen::Vector3d const& ur, double eps)
174  : _ll(ll), _ur(ur), _is_leaf(true), _eps(eps)
175 {
176  _children.fill(nullptr);
177 }
178 
179 template <typename POINT, std::size_t MAX_POINTS>
180 bool OctTree<POINT, MAX_POINTS>::addPoint_(POINT* pnt, POINT*& ret_pnt)
181 {
182  if (isOutside(pnt))
183  {
184  ret_pnt = nullptr;
185  return false;
186  }
187 
188  // at this place it holds true that the point is within [_ll, _ur]
189  if (!_is_leaf)
190  {
191  for (auto c : _children)
192  {
193  if (c->addPoint_(pnt, ret_pnt))
194  {
195  return true;
196  }
197  if (ret_pnt != nullptr)
198  {
199  return false;
200  }
201  }
202  }
203 
204  ret_pnt = pnt;
205  if (_pnts.size() < MAX_POINTS)
206  {
207  _pnts.push_back(pnt);
208  }
209  else
210  { // i.e. _pnts.size () == MAX_POINTS
211  splitNode(pnt);
212  _pnts.clear();
213  }
214  return true;
215 }
216 
217 template <typename POINT, std::size_t MAX_POINTS>
219 {
220  if (isOutside(pnt))
221  {
222  return false;
223  }
224 
225  if (_pnts.size() < MAX_POINTS)
226  {
227  _pnts.push_back(pnt);
228  }
229  else
230  { // i.e. _pnts.size () == MAX_POINTS
231  splitNode(pnt);
232  _pnts.clear();
233  }
234  return true;
235 }
236 
237 template <typename POINT, std::size_t MAX_POINTS>
239 {
240  const double x_mid((_ur[0] + _ll[0]) / 2.0);
241  const double y_mid((_ur[1] + _ll[1]) / 2.0);
242  const double z_mid((_ur[2] + _ll[2]) / 2.0);
243  Eigen::Vector3d p0{x_mid, y_mid, _ll[2]};
244  Eigen::Vector3d p1{_ur[0], _ur[1], z_mid};
245 
246  // create child NEL
247  _children[static_cast<std::int8_t>(Quadrant::NEL)] =
248  new OctTree<POINT, MAX_POINTS>(p0, p1, _eps);
249 
250  // create child NWL
251  p0[0] = _ll[0];
252  p1[0] = x_mid;
253  _children[static_cast<std::int8_t>(Quadrant::NWL)] =
254  new OctTree<POINT, MAX_POINTS>(p0, p1, _eps);
255 
256  // create child SWL
257  p0[1] = _ll[1];
258  p1[1] = y_mid;
259  _children[static_cast<std::int8_t>(Quadrant::SWL)] =
260  new OctTree<POINT, MAX_POINTS>(_ll, p1, _eps);
261 
262  // create child NEU
263  _children[static_cast<std::int8_t>(Quadrant::NEU)] =
264  new OctTree<POINT, MAX_POINTS>(p1, _ur, _eps);
265 
266  // create child SEL
267  p0[0] = x_mid;
268  p1[0] = _ur[0];
269  _children[static_cast<std::int8_t>(Quadrant::SEL)] =
270  new OctTree<POINT, MAX_POINTS>(p0, p1, _eps);
271 
272  // create child NWU
273  p0[0] = _ll[0];
274  p0[1] = y_mid;
275  p0[2] = z_mid;
276  p1[0] = x_mid;
277  p1[1] = _ur[1];
278  p1[2] = _ur[2];
279  _children[static_cast<std::int8_t>(Quadrant::NWU)] =
280  new OctTree<POINT, MAX_POINTS>(p0, p1, _eps);
281 
282  // create child SWU
283  p0[1] = _ll[1];
284  p1[1] = y_mid;
285  _children[static_cast<std::int8_t>(Quadrant::SWU)] =
286  new OctTree<POINT, MAX_POINTS>(p0, p1, _eps);
287 
288  // create child SEU
289  p0[0] = x_mid;
290  p1[0] = _ur[0];
291  p1[1] = y_mid;
292  p1[2] = _ur[2];
293  _children[static_cast<std::int8_t>(Quadrant::SEU)] =
294  new OctTree<POINT, MAX_POINTS>(p0, p1, _eps);
295 
296  // add the passed point pnt to the children at first
297  for (std::size_t k(0); k < 8; k++)
298  {
299  if (_children[k]->addPointToChild(pnt))
300  {
301  break;
302  }
303  }
304 
305  // distribute points to sub quadtrees
306  const std::size_t n_pnts(_pnts.size());
307  for (std::size_t j(0); j < n_pnts; j++)
308  {
309  for (auto c : _children)
310  {
311  if (c->addPointToChild(_pnts[j]))
312  {
313  break;
314  }
315  }
316  }
317  _is_leaf = false;
318 }
319 
320 template <typename POINT, std::size_t MAX_POINTS>
322 {
323  if ((*pnt)[0] < _ll[0] || (*pnt)[1] < _ll[1] || (*pnt)[2] < _ll[2])
324  {
325  return true;
326  }
327  if ((*pnt)[0] >= _ur[0] || (*pnt)[1] >= _ur[1] || (*pnt)[2] >= _ur[2])
328  {
329  return true;
330  }
331  return false;
332 }
333 } // end namespace GeoLib
bool addPoint(POINT *pnt, POINT *&ret_pnt)
Definition: OctTree-impl.h:77
bool addPointToChild(POINT *pnt)
Definition: OctTree-impl.h:218
bool addPoint_(POINT *pnt, POINT *&ret_pnt)
Definition: OctTree-impl.h:180
void splitNode(POINT *pnt)
Definition: OctTree-impl.h:238
void getPointsInRange(T const &min, T const &max, std::vector< POINT * > &pnts) const
Definition: OctTree-impl.h:139
OctTree(Eigen::Vector3d const &ll, Eigen::Vector3d const &ur, double eps)
Definition: OctTree-impl.h:172
std::array< OctTree< POINT, MAX_POINTS > *, 8 > _children
Definition: OctTree.h:139
bool isOutside(POINT *pnt) const
Definition: OctTree-impl.h:321
static OctTree< POINT, MAX_POINTS > * createOctTree(Eigen::Vector3d ll, Eigen::Vector3d ur, double eps=std::numeric_limits< double >::epsilon())
Definition: OctTree-impl.h:16
virtual ~OctTree()
Definition: OctTree-impl.h:68