API Documentation
Loading...
Searching...
No Matches
RTree.hpp
Go to the documentation of this file.
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Tree
28File: RTree
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/TreeIterator.h>
34#include <NDEVR/Node.h>
35#include <NDEVR/Tree.h>
36#include <NDEVR/TreeSorter.h>
37#include <NDEVR/BaseValues.h>
38#include <NDEVR/Buffer.h>
39#include <NDEVR/Bounds.h>
40#include <NDEVR/Median.h>
41#include <NDEVR/OpenMP.h>
42#include <NDEVR/ProgressInfo.h>
43#include <NDEVR/Vector.h>
44#include <NDEVR/VectorFunctions.h>
45#include <NDEVR/Intersection.h>
46#include <NDEVR/Distance.h>
47#include <NDEVR/BinaryHeap.h>
48#include <NDEVR/BinaryFile.h>
49#include <functional>
50namespace NDEVR
51{
52 template<uint01 t_dims, class t_type>
53 class RNode : public TreeNode
54 {
55 public:
58 , m_cache_bounds(Constant<Bounds<t_dims, t_type>>::Invalid)
59 {}
60 explicit RNode(uint04 index_start)
61 : TreeNode(index_start)
62 , m_cache_bounds(Constant<Bounds<t_dims, t_type>>::Min)
63 {}
64 void clear(uint04 index_start)
65 {
66 setBegin(index_start);
69 }
70 void clear(uint04 index_start, const Bounds<t_dims, t_type>& bounds)
71 {
72 setBegin(index_start);
75 }
76
77 uint04 left() const
78 {
79 return uint04(m_child_start);
80 }
81 uint04 right() const
82 {
83 return uint04(m_child_start) + 1;
84 }
85
87 {
88 return m_cache_bounds;
89 }
98
99 protected:
101 };
102
103
104
105 template<uint01 t_dims, class t_type>
106 class RTreeBase : public TreeBase<RNode<t_dims, t_type>, t_type, 2>
107 {
108 public:
113 explicit RTreeBase<t_dims, t_type>(uint04 bucket_size)
114 : TreeBase<RNode<t_dims, t_type>, t_type, 2>(bucket_size)
115 {}
117 : TreeBase<RNode<t_dims, t_type>, t_type, 2>(tree)
118 {}
120 : TreeBase<RNode<t_dims, t_type>, t_type, 2>(std::move(tree))
121 {}
122 protected:
123 RTreeBase<t_dims, t_type>(const Buffer<RNode<t_dims, t_type>>& nodes, const Buffer<uint04>& indices, bool is_read_only)
124 : TreeBase<RNode<t_dims, t_type>, t_type, 2>(nodes, indices, is_read_only)
125 {}
126 public:
127 template<class t_buffer_type>
128 bool validate(const t_buffer_type& elements)
129 {
130 TreeIterator iterator(root_node);
131
132 Buffer<uint04> values;
133 values.setSize(elements.size());
134 if (elements.size() == 0)
135 return true;
136 uint04 i = 0;
137 while (iterator.valid())
138 {
139 if (i++ > m_nodes.size())
140 {
141 lib_assert(false, "invalid tree");
142 return false;
143 }
144 const uint04 node_index = iterator.get();
145 RNode<t_dims, t_type>& node = m_nodes[node_index];
146 iterator.pop();
147
148 values.clear();
149 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAll<false>(node_index, values);
150 if (node.size() != values.size())
151 {
152 lib_assert(false, "invalid tree");
153 return false;
154 }
155 if (!IsInvalid(node.bounds()))
156 {
157 if (node.size() != 0 && !node.bounds().validate())
158 {
159 lib_assert(false, "invalid tree");
160 return false;
161 }
162 }
163 if (node.isLeaf())
164 {
165 const uint04 end = node.begin() + node.size();
166 for (uint04 idx = node.begin(); idx < end; idx++)
167 {
168 const auto& element = elements[m_indices[idx]];
169 if (!IsInvalid(element) && classify(node.bounds(), element.template as<t_dims, t_type>()) != inside)
170 {
171 lib_assert(false, "invalid tree");
172 return false;
173 }
174 }
175 }
176 else
177 {
178 if (node.size() != m_nodes[node.left()].size() + m_nodes[node.right()].size())
179 {
180 lib_assert(false, "invalid tree");
181 return false;
182 }
183 if(!IsInvalid(node.bounds()) && !IsInvalid(m_nodes[node.left()].bounds()))
184 if (classify(node.bounds(), m_nodes[node.left()].bounds()) != inside)
185 {
186 lib_assert(false, "invalid tree");
187 return false;
188 }
189 if (!IsInvalid(node.bounds()) && !IsInvalid(m_nodes[node.right()].bounds()))
190 if (classify(node.bounds(), m_nodes[node.right()].bounds()) != inside)
191 {
192 lib_assert(false, "invalid tree");
193 return false;
194 }
195
196 iterator.addAndGoToIndex(node.left(), node.right());
197 }
198 }
199 return true;
200 }
201 void traverse(const std::function<void(uint04 node_index, const Buffer<RNode<t_dims, t_type>, uint04, ObjectAllocator<true>>& node, const Buffer<uint04>& indices)>& callback) const
202 {
203 TreeIterator iterator(root_node);
204 while (iterator.valid())
205 {
206 const uint04 node_index = iterator.get();
207 const RNode<t_dims, t_type>& node = m_nodes[node_index];
208 iterator.pop();
209 callback(node_index, m_nodes, m_indices);
210 if (!node.isLeaf())
211 {
212 iterator.addAndGoToIndex(node.left(), node.right());
213 }
214 }
215 }
216 protected:
217
218 template<class t_buffer_type>
219 uint04 _calculateAndSplit(uint04 node_index, TreeBoundarySorter<t_dims, t_type>& sorter, const t_buffer_type& elements, uint04 start, uint04 end, bool is_precise)
220 {
221 UNUSED(is_precise);
222 Vector<t_dims, t_type> d_size;//The difference between the right and left size if a given node is chosen
223 for (uint01 dim = 0; dim < t_dims; ++dim)
224 {
225 if (m_nodes[node_index].bounds().span()[dim] != 0)
226 {
227 Vector<2, Bounds<t_dims, t_type>> potential_bounds = sorter.getMedianBounds(dim, start, end, elements);
228 d_size[dim] = potential_bounds[0].surfaceArea() + potential_bounds[1].surfaceArea();
229 }
230
231 }
232 const uint01 split_dim = d_size.template dimensionalIndex<MIN>();//maximize our smallest split dimension
233
234 sorter.getMedian(split_dim, start, end);
235 const uint04 median_location = ((end - start) / 2) + start;
236
237 TreeBase<RNode<t_dims, t_type>, t_type, 2>::splitLeafNode(node_index);
238 auto left = sorter.getBounds(start, median_location, elements);
239 auto right = sorter.getBounds(median_location, end, elements);
240#ifdef _DEBUG
241 if (!IsInvalid(m_nodes[node_index].bounds()) && !IsInvalid(left))
242 if (classify(m_nodes[node_index].bounds(), left) != inside)
243 lib_assert(false, "bad bounds creation");
244 if (!IsInvalid(m_nodes[node_index].bounds()) && !IsInvalid(right))
245 if (classify(m_nodes[node_index].bounds(), right) != inside)
246 lib_assert(false, "bad bounds creation");
247#endif
248 m_nodes[m_nodes[node_index].left()].setBounds(left);
249 m_nodes[m_nodes[node_index].right()].setBounds(right);
250
251 return median_location;
252 }
253 template<bool t_has_nans, bool t_uses_boundary, class t_buffer_type>
254 bool _balanceLeafNode(uint04 top_index, const t_buffer_type& elements, Buffer<uint04>& indices, uint04 top_start, uint04 top_end, bool is_precise, ProgressInfo* progress = nullptr)
255 {
257 if constexpr (t_uses_boundary)
258 {
259 sorter.template createBoundarySortList<t_has_nans>(indices, elements, progress);
260 }
261 else
262 {
263 sorter.template createCenterSortList<t_has_nans>(indices, elements, progress);
264 }
265 m_nodes[top_index].setBounds(sorter.getBounds(0, (top_end - top_start), elements));
266 uint04 start_stack[256];
267 uint04 end_stack[256];
268 start_stack[0] = top_start;
269 end_stack[0] = top_end;
270 TreeIterator iterator(top_index);
271 while (iterator.valid())
272 {
273 uint01 level = iterator.depth();
274 uint04 start = start_stack[level];
275 uint04 end = end_stack[level];
276 uint04 node_index = iterator.get();
277 iterator.pop();
278 m_nodes[node_index].setSize(end - start);
279
280 if ((end - start) > m_bucket_size)
281 {
282 const uint04 new_left = _calculateAndSplit(node_index, sorter, elements, start, end, is_precise);
283
284 iterator.addAndGoToIndex(m_nodes[node_index].right());
285 start_stack[iterator.depth()] = new_left;
286 end_stack[iterator.depth()] = end;
287
288 iterator.addAndGoToIndex(m_nodes[node_index].left());
289 start_stack[iterator.depth()] = start;
290 end_stack[iterator.depth()] = new_left;
291 }
292 else
293 {
294 sorter.getList(0, start, end, m_indices, m_nodes[node_index].begin());
295 }
296 }
297 return true;
298 }
299 template<class t_location_type>
300 bool predictBranch(uint04& index, const RNode<t_dims, t_type>& node, const t_location_type& selector, MaxHeap<t_type, uint04>& node_heap, t_type min_distance_squared) const
301 {
302 t_type left_distance = distanceSquared(selector, m_nodes[node.left()].bounds());
303 if(left_distance <= t_type(0))
304 left_distance = -(cast<t_type>(1) / distanceSquared(selector, m_nodes[node.left()].bounds().center()));
305 t_type right_distance = distanceSquared(selector, m_nodes[node.right()].bounds());
306 if (right_distance <= t_type(0))
307 right_distance = -(cast<t_type>(1) / distanceSquared(selector, m_nodes[node.right()].bounds().center()));
308 if (left_distance < right_distance)
309 {
310 if (left_distance >= min_distance_squared)
311 {
312 if (node_heap.size() == 0 || node_heap.extremeComp() >= min_distance_squared)
313 return false;
314 index = node_heap.popExtreme();
315 }
316 else if(node_heap.size() > 0 && node_heap.extremeComp() < left_distance)
317 {
318 index = node_heap.popExtreme();
319 node_heap.insert(left_distance, node.left());
320 if (right_distance < min_distance_squared)
321 node_heap.insert(right_distance, node.right());
322 }
323 else
324 {
325 index = node.left();
326 if (right_distance < min_distance_squared)
327 node_heap.insert(right_distance, node.right());
328 }
329 }
330 else
331 {
332 if (right_distance >= min_distance_squared)
333 {
334 if (node_heap.size() == 0 || node_heap.extremeComp() >= min_distance_squared)
335 return false;
336 index = node_heap.popExtreme();
337 }
338 else if (node_heap.size() > 0 && node_heap.extremeComp() < right_distance)
339 {
340 index = node_heap.popExtreme();
341 node_heap.insert(right_distance, node.right());
342 if (left_distance < min_distance_squared)
343 node_heap.insert(left_distance, node.right());
344 }
345 else
346 {
347 index = node.right();
348 if (left_distance < min_distance_squared)
349 node_heap.insert(left_distance, node.left());
350 }
351 }
352 return true;
353 }
354 template<bool t_presorted, class t_location_type, class t_buffer_type>
355 void _getClosestElement(uint04 top_index, const t_location_type& selector, const t_buffer_type& elements, t_type& min_distance_squared, const t_type& epsilon, uint04& min_index) const
356 {
357 t_type root_distance = distanceSquared(selector, m_nodes[top_index].bounds());
358 lib_assert(min_distance_squared >= 0.0f, "Cannot search for 0.0 distance. Use epsilon");
359 if (root_distance >= min_distance_squared)
360 return;
362 uint04 index = top_index;
363 for(;;)
364 {
365 const RNode<t_dims, t_type>& node = m_nodes[index];
366 if (node.isLeaf())
367 {
368 const uint04 end = node.end();
369 const uint04 start_index = node.begin();
370 for(uint04 i = start_index; i < end; ++i)
371 {
372 uint04 check_index;
373 if constexpr(t_presorted)
374 check_index = i;
375 else
376 check_index = m_indices[i];
377 t_type distance = distanceSquared(selector, elements[check_index].template as<t_dims, t_type>());
378 if (distance < min_distance_squared)
379 {
380 min_distance_squared = distance;
381 min_index = check_index;
382 if (min_distance_squared <= epsilon)
383 return;
384 }
385 }
386 if (node_heap.size() == 0 || node_heap.extremeComp() >= min_distance_squared)
387 return;
388 index = node_heap.popExtreme();
389 }
390 else
391 {
392 if (!predictBranch(index, node, selector, node_heap, min_distance_squared))
393 return;
394 }
395 }
396 }
397
398 template<bool t_presorted, class t_buffer_type, class t_reference_type>
399 void _getClosestElements(uint04 top_index, const t_reference_type& selector, const t_buffer_type& elements, t_type& min_distance_squared, const t_type& epsilon, MinHeap<t_type, uint04>& value_heap, uint04 size) const
400 {
402 t_type root_distance = distanceSquared(selector, m_nodes[top_index].bounds());
403 if (root_distance >= min_distance_squared)
404 return;
405 uint04 index = top_index;
406 for(;;)
407 {
408 const RNode<t_dims, t_type>& node = m_nodes[index];
409 if (node.isLeaf())
410 {
411 const uint04 end = node.end();
412 for (uint04 i = node.begin(); i < end; ++i)
413 {
414 uint04 check_index;
415 if constexpr (t_presorted)
416 check_index = i;
417 else
418 check_index = m_indices[i];
419 t_type distance = distanceSquared(selector, elements[check_index]);
420 if (distance < min_distance_squared)
421 {
422 value_heap.insert(distance, check_index);
423 if (value_heap.size() > size)
424 {
425 value_heap.deleteExtreme();
426 min_distance_squared = value_heap.extremeComp();
427 if (min_distance_squared <= epsilon)
428 return;
429 }
430 }
431 }
432 if (node_heap.size() == 0 || node_heap.extremeComp() >= min_distance_squared)
433 return;
434 index = node_heap.popExtreme();
435 }
436 else
437 {
438 if (!predictBranch(index, node, selector, node_heap, min_distance_squared))
439 return;
440 }
441 }
442 }
443 template<class t_area_type, class t_buffer_type>
444 void _getEnclosedElements(uint04 top_node, t_area_type area, Buffer<bool>& indices, const t_buffer_type& elements) const
445 {
446 TreeIterator iterator(top_node);
447 while (iterator.valid())
448 {
449 uint04 index = iterator.get();
450 const RNode<t_dims, t_type>& node = m_nodes[index];
451 iterator.pop();
452 switch (classify(area, node.bounds()))
453 {
455 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAllT<true>(index, indices);
456 break;
458 break;
460 if (node.isLeaf())
461 {
462 const uint04 end = node.begin() + node.size();
463 for (uint04 i = node.begin(); i < end; i++)
464 {
465 if (classify(area, elements[m_indices[i]]) != outside)
466 {
467 indices[m_indices[i]] = true;
468 }
469 }
470 }
471 else
472 {
473 iterator.addAndGoToIndex(node.left(), node.right());
474 }
475 break;
476 }
477 }
478 }
479
480 template<bool t_is_presorted, class t_area_type, class t_buffer_type>
481 void _getEnclosedElements(uint04 top_node, t_area_type area, Buffer<uint04>& indices, const t_buffer_type& elements) const
482 {
483 TreeIterator iterator(top_node);
484 while (iterator.valid())
485 {
486 uint04 index = iterator.get();
487 const RNode<t_dims, t_type>& node = m_nodes[index];
488 iterator.pop();
489 switch (classify(area, node.bounds()))
490 {
493 break;
495 if (node.isLeaf())
496 {
497 const uint04 end = node.begin() + node.size();
498 for (uint04 i = node.begin(); i < end; ++i)
499 {
500 uint04 local_index;
501 if constexpr (t_is_presorted)
502 local_index = i;
503 else
504 local_index = m_indices[i];
505 if (classify(area, elements[local_index]) != outside)
506 {
507 indices.add(local_index);
508 }
509 }
510 }
511 else
512 {
513 iterator.addAndGoToIndex(node.left(), node.right());
514 }
515 break;
517 break;
518 }
519 }
520 }
521
522 template<class t_area_type, class t_buffer_type>
523 uint04 _getNumberOfEnclosedElements(uint04 top_node, const t_area_type& area, const t_buffer_type& elements) const
524 {
525 TreeIterator iterator(top_node);
526 uint04 size = 0;
527 while (iterator.valid())
528 {
529 uint04 index = iterator.get();
530 const RNode<t_dims, t_type>& node = m_nodes[index];
531 iterator.pop();
532 switch (TreeBase<RNode<t_dims, t_type>, t_type, 2>::classify(area, node.bounds()))
533 {
535 size += node.size();
536 break;
538 break;
540 if (node.isLeaf())
541 {
542 const uint04 end = node.begin() + node.size();
543 for (int i = node.begin(); i < end; i++)
544 {
545 if (TreeBase<RNode<t_dims, t_type>, t_type, 2>::classify(area, elements[m_indices[i]]) != outside)
546 {
547 ++size;
548 }
549 }
550 }
551 else
552 {
553 iterator.addAndGoToIndex(node.left(), node.right());
554 }
555 break;
556 }
557 }
558 return size;
559 }
560
561 template<class t_area_type, class t_buffer_type>
562 void _getNearElements(uint04 top_node, t_type max_distance, const t_area_type& area, Buffer<bool>& indices, const t_buffer_type& elements) const
563 {
564 TreeIterator iterator(top_node);
565 while (iterator.valid())
566 {
567 const uint04 index = iterator.get();
568 const RNode<t_dims, t_type>& node = m_nodes[index];
569 iterator.pop();
570 Bounds<t_dims, t_type> bounds = node.bounds();
571 bounds.expand(max_distance);
572 switch (classify(bounds, area))
573 {
574#if __clang__
575 #pragma clang diagnostic push
576 #pragma clang diagnostic ignored "-Wunused-value"//It makes no sense this error is being reported?
577#endif
579 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAll<false>(index, indices);
580 break;
581#if __clang__
582 #pragma clang diagnostic pop
583#endif
585 break;
587 if (node.isLeaf())
588 {
589 const uint04 end = node.begin() + node.size();
590 for (uint04 i = node.begin(); i < end; i++)
591 {
592 if (distanceSqaured(area, elements[m_indices[i]]) < max_distance)
593 {
594 indices[m_indices[i]] = true;
595 }
596 }
597 }
598 else
599 {
600 iterator.addAndGoToIndex(node.left(), node.right());
601 }
602 break;
603 }
604 }
605 }
606 template<class t_area_type, class t_buffer_type>
607 void _getChangedElements(uint04 top_node, const t_area_type& new_area, const t_area_type& old_area, Buffer<bool>& indices, const t_buffer_type& elements, bool allow_enable, bool allow_disable) const
608 {
609 TreeIterator iterator(top_node);
610 while (iterator.valid())
611 {
612 bool is_mixed = false;
613 uint04 index = iterator.get();
614 const RNode<t_dims, t_type>& node = m_nodes[index];
615 iterator.pop();
616 switch (classify(new_area, node.bounds()))
617 {
619 switch (classify(old_area, node.bounds()))
620 {
622 break;
624 if(allow_enable)
625 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAllT<true>(index, indices);
626 break;
628 is_mixed = true;
629 break;
630 }
631 break;
633 switch (classify(old_area, node.bounds()))
634 {
636 if(allow_disable)
637 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAllT<false>(index, indices);
638 break;
640 break;
642 is_mixed = true;
643 break;
644 }
645 break;
647 is_mixed = true;
648 break;
649 }
650 if (is_mixed)
651 {
652 if (node.isLeaf())
653 {
654 const uint04 end = node.begin() + node.size();
655 for (uint04 i = node.begin(); i < end; i++)
656 {
657 if (allow_disable && indices[m_indices[i]])
658 {
659 if(classify(new_area, elements[m_indices[i]]) == outside)
660 indices[m_indices[i]] = false;
661 }
662 else if (allow_enable && !indices[m_indices[i]])
663 {
664 if(classify(new_area, elements[m_indices[i]]) != outside)
665 indices[m_indices[i]] = true;
666 }
667 }
668 }
669 else
670 {
671 iterator.addAndGoToIndex(node.left(), node.right());
672 }
673 }
674 }
675 }
676
677 template<class t_buffer_type>
678 void _removeValue(uint04 top_node, uint04 index, const t_buffer_type& elements)
679 {
680 bool recalculate_bounds = false;
681 TreeIterator iterator(top_node);
682 while (iterator.valid())
683 {
684 const uint04 node_index = iterator.get();
685 RNode<t_dims, t_type>& node = m_nodes[node_index];
686 if (node.isLeaf())
687 {
688 uint04 end = node.end();
690 uint04 index_location = Constant<uint04>::Invalid;
691 for (uint04 i = node.begin(); i < end; i++)
692 {
693 uint04 check_index = m_indices[i];
694 if (index != check_index)
695 bounds.addToBounds(elements[check_index].template as<t_dims, t_type>());
696 else
697 index_location = i;
698 }
699 node.setSize(node.size() - 1);
700 if (node.size() != 0)
701 m_indices.swapIndices(index_location, node.end());
702 if (classify(node.bounds(), bounds) == inside)
703 recalculate_bounds = true;
704 node.setBounds(bounds);
705 iterator.pop();
706 break;
707 }
708 else
709 {
710
711 bool needs_rebalance = false;
712 if (classify(m_nodes[node.left()].bounds(), elements[index]) == inside)
713 {
714 if (needsRebalance(m_nodes[node.left()].size() - 1, m_nodes[node.right()].size()))
715 needs_rebalance = true;
716 else
717 iterator.addAndGoToIndex(node.left());
718 }
719 else
720 {
721 if (needsRebalance(m_nodes[node.left()].size(), m_nodes[node.right()].size() - 1))
722 needs_rebalance = true;
723 else
724 iterator.addAndGoToIndex(node.right());
725 }
726 if (needs_rebalance || node.size() - 1 == m_bucket_size)
727 {
729 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAll<false>(node_index, indices);
730 node.setSize(node.size() - 1);
731 indices.removeElement(index);
733 //TreeBase<RNode<t_dims, t_type>, t_type, 2>::_balanceLeafNode(node_index, elements, indices, 0, indices.size(), false);
734 recalculate_bounds = true;
735 break;
736 }
737 else
738 {
739 node.setSize(node.size() - 1);
740 }
741 }
742 }
743 if (recalculate_bounds)
744 {
745 while (iterator.valid())
746 {
747 if (!recalculateBounds(iterator.get(), elements))
748 return;
749 iterator.pop();
750 }
751 }
752 }
753
754
755 template<class t_node_type, class t_buffer_type>
756 void _moveValue(uint04 top_node, uint04 index, const t_node_type& old_location, const t_buffer_type& elements, bool rebalance)
757 {
758 TreeIterator iterator(top_node);
759 bool recalculate_bounds = false;
760 while (iterator.valid())
761 {
762 const uint04 node_index = iterator.get();
763 RNode<t_dims, t_type>& node = m_nodes[node_index];
764 if (node.isLeaf())
765 {
766 //If the bounds of the node don't change, no need to do anything
767 if (classify(m_nodes[node.left()].bounds(), elements[index]) == inside)
768 return;
769 uint04 end = node.end();
770 //Recalculate Node Bounds
772 uint04 index_location = Constant<uint04>::Invalid;
773 for (uint04 i = node.begin(); i < end; i++)
774 {
775 uint04 check_index = m_indices[i];
776 if (index != check_index)
777 bounds.addToBounds(elements[check_index]);
778 else
779 index_location = i;
780 }
781 //Check to see if bounding box is smaller
782 switch (classify(node.bounds(), bounds))
783 {
784 case inside:
785 recalculate_bounds = true;//Node boundary made smaller
786 node.setBounds(bounds);
787 break;
788 case mixed:
789 case outside:
790 lib_assert(node.bounds() == bounds, "Unexpected Node Resize behavior: Removing object should not increase bounds");
791 recalculate_bounds = false;
792 break;
793 }
794
795 //reset Node Size
796 node.setSize(node.size() - 1);
797 if (node.size() != 0)
798 m_indices.swapIndices(index_location, node.end());
799
800 iterator.pop();
801 break;//Break to begin resetting bounds
802 }
803 else
804 {
805 if (classify(m_nodes[node.left()].bounds(), old_location) == inside)
806 {
807 iterator.addAndGoToIndex(node.left());
808 }
809 else
810 {
811 lib_assert(classify(m_nodes[node.right()].bounds(), old_location) == inside, "Original Element not in either bounds");
812 iterator.addAndGoToIndex(node.right());
813 }
814 }
815 }
816 bool added_in = false;
817 while (iterator.valid() && (!added_in || recalculate_bounds))
818 {
819 const uint04 node_index = iterator.get();
820 if (recalculate_bounds)
821 {
822 recalculate_bounds = recalculateBounds(node_index, elements);
823 }
824 if (!added_in)
825 {
826 RNode<t_dims, t_type>& node = m_nodes[node_index];
827 if (classify(node.bounds(), elements[index]) == inside)
828 {
829 TreeBase<RNode<t_dims, t_type>, t_type, 2>::_addValue(node_index, index, elements, rebalance);
830 added_in = true;
831 }
832 }
833 iterator.pop();
834 }
835 if (!added_in)
836 {
837 TreeBase<RNode<t_dims, t_type>, t_type, 2>::_addValue(top_node, index, elements, rebalance);
838 }
839 }
840
841 bool needsRebalance(uint04 left_size, uint04 right_size)
842 {
843 const uint04 total_size = left_size + right_size;
844 return (left_size < total_size / 3 || right_size < total_size / 3);
845 }
846
847 bool useBulkResize(uint04 change_size)
848 {
849 return (change_size > TreeBase<RNode<t_dims, t_type>, t_type, 2>::size() / 4);
850 }
851 template<bool t_has_nans, bool t_uses_boundary, class t_buffer_type>
852 void _addValues(uint04 top_node, Buffer<uint04> indices, const t_buffer_type& elements, bool is_precise, ProgressInfo* progress = nullptr)
853 {
854 if (progress) progress->addMessage("RTree: Getting all");
855 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAll<false>(top_node, indices);
856 if (progress) progress->addMessage("RTree: reclaiming children");
859
860 uint04 max_node_size = 1;
861 uint04 max_index_size = m_bucket_size;
862 uint04 load_size = indices.size();
863 uint04 level = 1;
864 while (load_size >= m_bucket_size)
865 {
866 load_size = cast<uint04>(ceil(load_size / 2));
867 max_index_size = 2 * max_index_size;
868 max_node_size = cast<uint04>(pow(2, level++)) + max_node_size;
869 }
870 m_indices.ensureCapacity(max_index_size);
871 m_nodes.ensureCapacity(max_node_size);
872 if (progress) progress->addMessage("RTree: Balancing Node");
873 _balanceLeafNode<t_has_nans, t_uses_boundary>(top_node, elements, indices, 0, indices.size(), is_precise, progress);
874 if (progress) progress->setProgress(1.0f);
875 if (progress) progress->addMessage("RTree: Finished Adding values");
876 }
877
878
879 template<bool t_has_nans, bool t_uses_boundary, class t_buffer_type>
880 void _addValue(uint04 node_index, uint04 index, const t_buffer_type& elements, bool balance)
881 {
882 Bounds<t_dims, t_type> bounds = m_nodes[node_index].bounds();
883 const auto value = elements[index].template as<t_dims, t_type>();
884 bounds.addToBounds(value);
885 for (;;)
886 {
887 RNode<t_dims, t_type>& node = m_nodes[node_index];
888 node.setBounds(bounds);
889 if (node.isLeaf())
890 {
891 if (node.size() == m_bucket_size)
892 {
894 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAll<false>(node_index, indices);
896 indices.add(index);
897 _balanceLeafNode<t_has_nans, t_uses_boundary>(node_index, elements, indices, 0, m_bucket_size + 1, false);
898 }
899 else
900 {
901 m_indices[node.begin() + node.size()] = index;
902 node.setSize(node.size() + 1);
903 }
904 return;
905 }
906 else
907 {
908 Bounds<t_dims, t_type> left = m_nodes[node.left()].bounds();
909 Bounds<t_dims, t_type> right = m_nodes[node.right()].bounds();
910
911 left.addToBounds(value);
912 right.addToBounds(value);
913 bool needs_rebalance = false;
914 t_type surface_diff =
915 (left.surfaceArea() - m_nodes[node.left()].bounds().surfaceArea())
916 - (right.surfaceArea() - m_nodes[node.right()].bounds().surfaceArea());
917 if(surface_diff == 0)//Volumes are equal, insert to least full.
918 {
919 if (m_nodes[node.left()].size() < m_nodes[node.right()].size())
920 {
921 node_index = node.left();
922 bounds = left;
923 }
924 else
925 {
926 node_index = node.right();
927 bounds = right;
928 }
929 }
930 else if (surface_diff < 0)//better to add it to left side
931 {
932 if (balance && needsRebalance(
933 m_nodes[node.left()].size() + 1
934 , m_nodes[node.right()].size()))
935 needs_rebalance = true;
936 else
937 node_index = node.left();
938 bounds = left;
939 }
940 else//better to add it to right side
941 {
942 if (balance && needsRebalance(
943 m_nodes[node.left()].size()
944 , m_nodes[node.right()].size() + 1))
945 needs_rebalance = true;
946 else
947 node_index = node.right();
948 bounds = right;
949 }
950 if (needs_rebalance)
951 {
952 Buffer<uint04> indices(node.size() + 1);
953 TreeBase<RNode<t_dims, t_type>, t_type, 2>::template _getAll<false>(node_index, indices);
954 indices.add(index);
956 _balanceLeafNode<t_has_nans, t_uses_boundary>(node_index, elements, indices, 0, indices.size(), false);
957 return;
958 }
959 else
960 {
961 node.setSize(node.size() + 1);
962 }
963 }
964 }
965 }
966 //Returns true if bounds changed, false if stayed the same
967 template<class t_buffer_type>
968 bool recalculateBounds(uint04 node_index, const t_buffer_type& elements)
969 {
971 RNode<t_dims, t_type>& node = m_nodes[node_index];
972 if (node.isLeaf())
973 {
974 uint04 end = node.end();
975 for (uint04 i = node.begin(); i < end; i++)
976 {
977 bounds.addToBounds(elements[m_indices[i]]);
978 }
979 }
980 else
981 {
982 bounds = Bounds<t_dims, t_type>(m_nodes[node.left()].bounds(), m_nodes[node.right()].bounds());
983 }
984 if (classify(node.bounds(), bounds) == inside)
985 return false;
986 node.setBounds(bounds);
987 return true;
988 }
989
991 {
993
994 TreeIterator iterator(root_node);
995 while (iterator.valid())
996 {
997 RNode<t_dims, t_type>& node = m_nodes[iterator.get()];
998 iterator.pop();
999 if (node.isLeaf())
1000 {
1001 node.setBegin(iterator.get());
1002 indices.addAll(m_indices.begin(node.begin()), node.size());
1003 }
1004 else
1005 iterator.addAndGoToIndex(node.left(), node.right());
1006 }
1008 }
1009 };
1010
1011
1012 template<uint01 t_dims, class t_type>
1013 class RTree : public Tree<t_dims, t_type, RTreeBase<t_dims, t_type>>
1014 {
1015 public:
1016 using TreeBase<RNode<t_dims, t_type>, t_type, 2>::m_nodes;
1022 {}
1023 explicit RTree<t_dims, t_type>(uint04 bucket_size)
1025 {}
1028 {}
1031 {}
1034 {
1036 m_indices = value.m_indices;
1037 m_nodes = value.m_nodes;
1040 }
1043 {
1045 std::swap(m_indices, value.m_indices);
1046 std::swap(m_nodes, value.m_nodes);
1049 }
1051 {
1053 return node.bounds();
1054 }
1055 protected:
1056 RTree<t_dims, t_type>(const Buffer<RNode<t_dims, t_type>>& nodes, const Buffer<uint04>& indices, bool is_read_only)
1057 : Tree<t_dims, t_type, RTreeBase<t_dims, t_type>>(nodes, indices, is_read_only)
1058 {}
1059 public:
1069 inline RTree& operator=(RTree&& value)
1070 {
1072 std::swap(m_indices, value.m_indices);
1073 std::swap(m_nodes, value.m_nodes);
1076 return (*this);
1077 }
1078 void mapToFile(BinaryFile& file, Buffer<BinaryCompressionObject>& objects, uint04 compression_index = 0)
1079 {
1080 file.write(m_bucket_size);
1081 bool placeholder = false;
1082 file.write(placeholder);
1083 file.writeCompression(objects[compression_index + 0]);
1084 file.writeCompression(objects[compression_index + 1]);
1085 file.writeCompression(objects[compression_index + 2]);
1086 file.writeCompression(objects[compression_index + 3]);
1087 }
1088 void compress(Buffer<BinaryCompressionObject>& objects, Buffer<Buffer<uint01>>& compressed_data, uint04 compression_index, uint04 internal_index)
1089 {
1090 switch (internal_index)
1091 {
1092 case 0:
1093 Compressor::Compress(objects[compression_index]
1094 , compressed_data[compression_index]
1095 , m_indices);
1096 break;
1097 case 1:
1098 Compressor::Compress(objects[compression_index]
1099 , compressed_data[compression_index]
1100 , m_nodes);
1101 break;
1102 case 2:
1103 Compressor::Compress(objects[compression_index]
1104 , compressed_data[compression_index]
1106 break;
1107 case 3:
1108 Compressor::Compress(objects[compression_index]
1109 , compressed_data[compression_index]
1111 break;
1112 }
1113
1114 }
1116 {
1117 file.write(m_bucket_size);
1118 bool placeholder = false;
1119 file.write(placeholder);
1120 file.write(m_indices, mode);
1121 file.write(m_nodes, mode);
1124 }
1126 {
1127 m_bucket_size = file.read<uint04>();
1128 file.read<bool>();//placeholder
1129 file.read(m_indices);
1130 file.read(m_nodes);
1133 }
1134 virtual const char* getTreeType() const override
1135 {
1136 return "R Tree";
1137 }
1138 };
1139}
#define UNUSED(expr)
Definition BaseValues.hpp:406
#define lib_assert(expression, message)
Asserts some logic in the code. Disabled in non debug mode by default. Can be re-enabled in release u...
Definition LibAssert.h:68
Logic for reading or writing to a binary file including logic for.
Definition BinaryFile.h:59
void write(const t_type &data)
Definition BinaryFile.h:123
void writeCompression(BinaryCompressionObject &compression_object)
t_type read()
Definition BinaryFile.h:233
A heap data structure that takes the form of a binary tree which is a common way of.
Definition BinaryHeap.hpp:42
void insert(t_comp_type comparison, t_value_type value)
Definition BinaryHeap.hpp:47
uint04 size() const
Definition BinaryHeap.hpp:74
t_value_type popExtreme()
Definition BinaryHeap.hpp:115
void deleteExtreme()
Definition BinaryHeap.hpp:121
t_comp_type extremeComp() const
Definition BinaryHeap.hpp:62
A specification of upper and lower bounds in N-dimensions.
Definition Bounds.hpp:52
constexpr t_type surfaceArea() const
The surface area of the shape. This is defined as the area between internal space and non-internal sp...
Definition Bounds.hpp:171
constexpr void addToBounds(const t_vertex &vector)
Adds to the bounds such that the new bounds fully encompasses the argument.
Definition Bounds.hpp:461
constexpr void expand(const t_type &expansion_scaler)
Expands the given expansion scaler. such that max and min are both expanded outward from the center b...
Definition Bounds.hpp:200
The equivelent of std::vector but with a bit more control. The basic array unit of the library.
Definition Buffer.hpp:59
void add(t_type &&object)
Definition Buffer.hpp:212
constexpr t_index_type size() const
Definition Buffer.hpp:1395
void addAll(const Buffer< t_type, t_other_index_type, t_other_memory_allocator, t_other_memory_manager > &buffer)
Definition Buffer.hpp:278
void setSize(t_index_type new_size)
Definition Buffer.hpp:1351
void swapIndices(t_index_type index_1, t_index_type index_2)
Definition Buffer.hpp:1478
void ensureCapacity(t_index_type new_capacity, bool ensure_not_greater=false, bool ensure_not_less=true)
Definition Buffer.hpp:791
decltype(auto) begin()
Definition Buffer.hpp:518
void clear()
Definition Buffer.hpp:578
bool removeElement(const t_type &element)
Definition Buffer.hpp:1040
static std::enable_if<!ObjectInfo< t_type >::Buffer >::type Compress(BinaryCompressionObject &object, Buffer< uint01 > &compression_data, const Buffer< t_type, t_index_type, t_memory_allocator, t_memory_manager > &data)
Definition Compressor.h:117
Definition MemoryManager.h:265
A light-weight base class for Log that allows processes to update, without the need for.
Definition ProgressInfo.hpp:48
Definition RTree.hpp:54
void clear(uint04 index_start)
Definition RTree.hpp:64
Bounds< t_dims, t_type > & bounds()
Definition RTree.hpp:90
RNode()
Definition RTree.hpp:56
uint04 right() const
Definition RTree.hpp:81
const Bounds< t_dims, t_type > & bounds() const
Definition RTree.hpp:86
void setBounds(const Bounds< t_dims, t_type > &bounds)
Definition RTree.hpp:94
RNode(uint04 index_start)
Definition RTree.hpp:60
uint04 left() const
Definition RTree.hpp:77
void clear(uint04 index_start, const Bounds< t_dims, t_type > &bounds)
Definition RTree.hpp:70
Bounds< t_dims, t_type > m_cache_bounds
Definition RTree.hpp:100
Definition RTree.hpp:107
void _getClosestElement(uint04 top_index, const t_location_type &selector, const t_buffer_type &elements, t_type &min_distance_squared, const t_type &epsilon, uint04 &min_index) const
Definition RTree.hpp:355
uint04 _getNumberOfEnclosedElements(uint04 top_node, const t_area_type &area, const t_buffer_type &elements) const
Definition RTree.hpp:523
bool validate(const t_buffer_type &elements)
Definition RTree.hpp:128
bool _balanceLeafNode(uint04 top_index, const t_buffer_type &elements, Buffer< uint04 > &indices, uint04 top_start, uint04 top_end, bool is_precise, ProgressInfo *progress=nullptr)
Definition RTree.hpp:254
uint04 _calculateAndSplit(uint04 node_index, TreeBoundarySorter< t_dims, t_type > &sorter, const t_buffer_type &elements, uint04 start, uint04 end, bool is_precise)
Definition RTree.hpp:219
void _makeWriteable()
Definition RTree.hpp:990
void _getChangedElements(uint04 top_node, const t_area_type &new_area, const t_area_type &old_area, Buffer< bool > &indices, const t_buffer_type &elements, bool allow_enable, bool allow_disable) const
Definition RTree.hpp:607
void _removeValue(uint04 top_node, uint04 index, const t_buffer_type &elements)
Definition RTree.hpp:678
bool recalculateBounds(uint04 node_index, const t_buffer_type &elements)
Definition RTree.hpp:968
void _getEnclosedElements(uint04 top_node, t_area_type area, Buffer< bool > &indices, const t_buffer_type &elements) const
Definition RTree.hpp:444
void _moveValue(uint04 top_node, uint04 index, const t_node_type &old_location, const t_buffer_type &elements, bool rebalance)
Definition RTree.hpp:756
bool needsRebalance(uint04 left_size, uint04 right_size)
Definition RTree.hpp:841
bool useBulkResize(uint04 change_size)
Definition RTree.hpp:847
void _getClosestElements(uint04 top_index, const t_reference_type &selector, const t_buffer_type &elements, t_type &min_distance_squared, const t_type &epsilon, MinHeap< t_type, uint04 > &value_heap, uint04 size) const
Definition RTree.hpp:399
void _addValue(uint04 node_index, uint04 index, const t_buffer_type &elements, bool balance)
Definition RTree.hpp:880
void _addValues(uint04 top_node, Buffer< uint04 > indices, const t_buffer_type &elements, bool is_precise, ProgressInfo *progress=nullptr)
Definition RTree.hpp:852
void _getEnclosedElements(uint04 top_node, t_area_type area, Buffer< uint04 > &indices, const t_buffer_type &elements) const
Definition RTree.hpp:481
void traverse(const std::function< void(uint04 node_index, const Buffer< RNode< t_dims, t_type >, uint04, ObjectAllocator< true > > &node, const Buffer< uint04 > &indices)> &callback) const
Definition RTree.hpp:201
void _getNearElements(uint04 top_node, t_type max_distance, const t_area_type &area, Buffer< bool > &indices, const t_buffer_type &elements) const
Definition RTree.hpp:562
RTreeBase(uint04 bucket_size)
Definition RTree.hpp:113
bool predictBranch(uint04 &index, const RNode< t_dims, t_type > &node, const t_location_type &selector, MaxHeap< t_type, uint04 > &node_heap, t_type min_distance_squared) const
Definition RTree.hpp:300
Definition RTree.hpp:1014
RTree & operator=(const RTree &value)
Definition RTree.hpp:1060
RTree & operator=(RTree &&value)
Definition RTree.hpp:1069
virtual const char * getTreeType() const override
Definition RTree.hpp:1134
void mapToFile(BinaryFile &file, Buffer< BinaryCompressionObject > &objects, uint04 compression_index=0)
Definition RTree.hpp:1078
void mapToFile(BinaryFile &file, CompressionMode mode)
Definition RTree.hpp:1115
void mapFromFile(BinaryFile &file)
Definition RTree.hpp:1125
RTree()
Definition RTree.hpp:1020
void compress(Buffer< BinaryCompressionObject > &objects, Buffer< Buffer< uint01 > > &compressed_data, uint04 compression_index, uint04 internal_index)
Definition RTree.hpp:1088
Bounds< t_dims, t_type > bounds() const
Definition RTree.hpp:1050
Definition Tree.hpp:54
Buffer< RNode< t_dims, t_type >, uint04, ObjectAllocator< true > > m_nodes
Definition Tree.hpp:480
void reclaimChildren(uint04 index)
Definition Tree.hpp:397
const Buffer< uint04 > & indices() const
Definition Tree.hpp:287
Buffer< uint04 > m_available_node_positions
Definition Tree.hpp:481
void _getAllT(const uint04 &node_index, Buffer< bool > &indices) const
Definition Tree.hpp:423
void _getAll(const uint04 &node_index, Buffer< uint04 > &indices) const
Definition Tree.hpp:445
uint04 size() const
Definition Tree.hpp:229
Buffer< uint04 > m_indices
Definition Tree.hpp:479
static const uint04 root_node
Definition Tree.hpp:483
void splitLeafNode(uint04 index)
Definition Tree.hpp:353
Buffer< uint04 > m_available_indexed_positions
Definition Tree.hpp:482
Definition TreeSorter.h:94
uint04 getMedian(uint01 dimension, uint04 start, uint04 end)
Definition TreeSorter.h:386
Bounds< t_dims, t_type > getBounds(uint04 start, uint04 finish, const t_list_type &locations) const
Definition TreeSorter.h:244
Vector< 2, Bounds< t_dims, t_type > > getMedianBounds(uint01 dimension, uint04 start, uint04 end, const t_list_type &locations)
Definition TreeSorter.h:266
Definition Tree.hpp:489
Definition TreeIterator.hpp:38
void pop()
Definition TreeIterator.hpp:53
bool valid() const
Definition TreeIterator.hpp:49
uint01 depth()
Definition TreeIterator.hpp:57
void addAndGoToIndex(uint04 index)
Definition TreeIterator.hpp:61
uint04 get() const
Definition TreeIterator.hpp:45
Definition Node.hpp:37
uint04 begin() const
Definition Node.hpp:54
bool isLeaf() const
Definition Node.hpp:87
void setSize(uint04 bucket_size)
Definition Node.hpp:82
uint04 end() const
Definition Node.hpp:59
uint04 size() const
Definition Node.hpp:78
uint04 m_element_size
Definition Node.hpp:92
void setBegin(uint04 index_start)
Definition Node.hpp:50
sint04 m_child_start
Definition Node.hpp:93
void getList(uint01 dimension, uint04 start, uint04 end, Buffer< uint04 > &values, uint04 index_offset)
Definition TreeSorter.h:60
A fixed-size array with better performance compared to dynamic containers.
Definition Vector.hpp:60
Definition ACIColor.h:37
constexpr bool IsInvalid(const t_type &value)
Query if 'value' is valid or invalid. Invalid values should return invalid if used for calculations o...
Definition BaseFunctions.hpp:177
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:78
CompressionMode
Logical information about the type of compression implemented or requested.
Definition Compressor.h:15
t_type distanceSquared(const Bounds< t_dims, t_type, t_vertex > &bounds, const Vector< t_dims, t_type > &vertex)
Definition Distance.hpp:45
@ inside
Definition BaseValues.hpp:207
@ mixed
Definition BaseValues.hpp:208
@ outside
Definition BaseValues.hpp:206
IntersectionTypes classify(const Vector< t_dims, t_type > &v1, const Vector< t_dims, t_type > &v2)
Definition Intersection.hpp:326
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:94
t_type sqrt(const t_type &value)
Definition VectorFunctions.hpp:1225
constexpr t_to cast(const Angle< t_from > &value)
Definition Angle.h:379
constexpr t_type distance(const t_vertex &vertex, const LineSegment< t_dims, t_type, t_vertex > &line)
Definition Distance.hpp:243
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved.
Definition BaseValues.hpp:230