Gamedev Framework (gf)  0.12.0
A C++14 framework for 2D games
Spatial.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016-2019 Julien Bernard
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 #ifndef GF_SPATIAL_H
22 #define GF_SPATIAL_H
23 
24 #include <cassert>
25 #include <cmath>
26 #include <algorithm>
27 #include <functional>
28 #include <iterator>
29 #include <map>
30 #include <memory>
31 #include <numeric>
32 #include <vector>
33 
34 #include <boost/container/static_vector.hpp>
35 
36 #include "Box.h"
37 #include "Math.h"
38 #include "Unused.h"
39 
40 #include "Log.h"
41 
42 namespace gf {
43 #ifndef DOXYGEN_SHOULD_SKIP_THIS
44 inline namespace v1 {
45 #endif
46 
47  enum class SpatialStructureType {
48  Object,
49  Node,
50  };
51 
52  template<typename U, std::size_t N>
56  int level;
57  };
58 
63  enum class SpatialQuery {
64  Contain,
65  Intersect,
66  };
67 
72  template<typename T>
73  using SpatialQueryCallback = std::function<void(const T&)>;
74 
82  template<typename T, typename U = float, std::size_t Size = 16>
83  class QuadTree {
84  static_assert(Size > 0, "Size can not be 0");
85  public:
91  QuadTree(const Box<U, 2>& bounds)
92  : m_root(bounds)
93  {
94 
95  }
96 
104  bool insert(T value, const Box<U, 2>& bounds) {
105  Node *node = m_root.chooseNode(bounds);
106 
107  if (node == nullptr) {
108  return false;
109  }
110 
111  return node->insert(std::move(value), bounds);
112  }
113 
122  std::size_t query(const Box<U, 2>& bounds, SpatialQueryCallback<T> callback, SpatialQuery kind = SpatialQuery::Intersect) const {
123  return m_root.query(bounds, callback, kind);
124  }
125 
129  void clear() {
130  m_root.clear();
131  }
132 
133 
134  std::vector<SpatialStructure<U, 2>> getStructure() const {
135  std::vector<SpatialStructure<U, 2>> structures;
136  m_root.appendToStructure(structures, 0);
137  return structures;
138  }
139 
140  private:
141  struct Entry {
142  T value;
143  Box<U, 2> bounds;
144  };
145 
146  class Node {
147  public:
148  Node()
149  : m_children(nullptr)
150  {
151  m_entries.reserve(Size);
152  }
153 
154  Node(const Box<U, 2>& bounds)
155  : m_bounds(bounds)
156  , m_children(nullptr)
157  {
158  m_entries.reserve(Size);
159  }
160 
161  bool isLeaf() const {
162  return m_children == nullptr;
163  }
164 
165  Node *chooseNode(const Box<U, 2>& bounds) {
166  if (!m_bounds.contains(bounds)) {
167  return nullptr;
168  }
169 
170  if (isLeaf()) {
171  if (m_entries.size() < Size) {
172  return this;
173  }
174 
175  subdivide();
176 
177  // try again
178  if (m_entries.size() < Size) {
179  return this;
180  }
181  }
182 
183  for (std::size_t i = 0; i < 4; ++i) {
184  if (m_children[i].chooseNode(bounds) != nullptr) {
185  return &m_children[i];
186  }
187  }
188 
189  clearChildrenIfEmpty();
190 
191  return this;
192  }
193 
194  bool insert(T&& value, const Box<U, 2>& bounds) {
195  m_entries.push_back({ std::move(value), bounds });
196  return true;
197  }
198 
199  std::size_t query(const Box<U, 2>& bounds, SpatialQueryCallback<T>& callback, SpatialQuery kind) const {
200  if (!m_bounds.intersects(bounds)) {
201  return 0;
202  }
203 
204  std::size_t found = 0;
205 
206  for (auto& entry : m_entries) {
207  switch (kind) {
209  if (bounds.contains(entry.bounds)) {
210  callback(entry.value);
211  ++found;
212  }
213  break;
214 
216  if (bounds.intersects(entry.bounds)) {
217  callback(entry.value);
218  ++found;
219  }
220  break;
221  }
222  }
223 
224  if (!isLeaf()) {
225  for (std::size_t i = 0; i < 4; ++i) {
226  found += m_children[i].query(bounds, callback, kind);
227  }
228  }
229 
230  return found;
231  }
232 
233  void clear() {
234  m_entries.clear();
235 
236  // no need to explicitly clear children
237  m_children = nullptr;
238  }
239 
240  void appendToStructure(std::vector<SpatialStructure<U, 2>>& structures, int level) const {
241  structures.push_back({ m_bounds, SpatialStructureType::Node, level });
242 
243  for (auto& entry : m_entries) {
244  structures.push_back( { entry.bounds, SpatialStructureType::Object, level });
245  }
246 
247  if (m_children) {
248  for (std::size_t i = 0; i < 4; ++i) {
249  m_children[i].appendToStructure(structures, level + 1);
250  }
251  }
252  }
253 
254  private:
255  void subdivide() {
256  m_children = std::make_unique<Node[]>(4);
257 
258  m_children[0].m_bounds = computeBoxQuadrant(m_bounds, Quadrant::UpperLeft);
259  m_children[1].m_bounds = computeBoxQuadrant(m_bounds, Quadrant::UpperRight);
260  m_children[2].m_bounds = computeBoxQuadrant(m_bounds, Quadrant::LowerRight);
261  m_children[3].m_bounds = computeBoxQuadrant(m_bounds, Quadrant::LowerLeft);
262 
263  std::vector<Entry> entries;
264 
265  for (auto& entry : m_entries) {
266  bool inserted = false;
267 
268  for (std::size_t i = 0; i < 4; ++i) {
269  if (m_children[i].m_bounds.contains(entry.bounds)) {
270  m_children[i].m_entries.push_back(std::move(entry));
271  inserted = true;
272  break;
273  }
274  }
275 
276  if (!inserted) {
277  entries.push_back(std::move(entry));
278  }
279  }
280 
281  std::swap(m_entries, entries);
282  }
283 
284  void clearChildrenIfEmpty() {
285  assert(!isLeaf());
286 
287  for (std::size_t i = 0; i < 4; ++i) {
288  if (!m_children[i].m_entries.empty()) {
289  return;
290  }
291  }
292 
293  m_children = nullptr;
294  }
295 
296  private:
297  Box<U, 2> m_bounds;
298  std::vector<Entry> m_entries;
299  std::unique_ptr<Node[]> m_children;
300  };
301 
302  private:
303  Node m_root;
304  };
305 
315  template<typename T, typename U = float, std::size_t N = 2, std::size_t MaxSize = 16, std::size_t MinSize = 4>
316  class RStarTree {
317  static_assert(N > 0, "N can not be 0");
318  static_assert(2 <= MinSize, "MinSize must be at least 2");
319  static_assert(MinSize <= MaxSize / 2, "MinSize must be less than MaxSize/2");
320  public:
325  : m_root(new Leaf)
326  {
327 
328  }
329 
333  RStarTree(const RStarTree&) = delete;
334 
338  RStarTree& operator=(const RStarTree&) = delete;
339 
343  RStarTree(RStarTree&& other) noexcept
344  {
345  m_root = std::exchange(other.m_root, nullptr);
346  }
347 
351  RStarTree& operator=(RStarTree&& other) noexcept {
352  std::swap(m_root, other.m_root);
353  return *this;
354  }
355 
360  delete m_root;
361  }
362 
370  bool insert(T value, const Box<U, N>& bounds) {
371  Leaf *leaf = m_root->chooseSubtree(bounds);
372 
373  Node *splitted = leaf->tryInsert(std::move(value), bounds);
374  Node *current = leaf;
375 
376  while (splitted != nullptr) {
377  auto splittedBounds = splitted->computeBounds();
378  splitted->updateOriginalBounds(splittedBounds);
379 
380  auto currentBounds = current->computeBounds();
381  current->updateOriginalBounds(currentBounds);
382 
383  if (current == m_root) {
384  auto branch = new Branch;
385 
386  current->setParent(branch);
387  branch->tryInsert(current, currentBounds);
388 
389  splitted->setParent(branch);
390  branch->tryInsert(splitted, splittedBounds);
391 
392  branch->updateOriginalBounds(branch->computeBounds());
393 
394  m_root = branch;
395  current = m_root;
396  splitted = nullptr;
397  } else {
398  Branch *parent = current->getParent();
399  assert(parent != nullptr);
400 
401  parent->updateBoundsForChild(currentBounds, current);
402 
403  splitted->setParent(parent);
404  splitted = parent->tryInsert(splitted, splittedBounds);
405 
406  current = parent;
407  }
408  }
409 
410  while (current != m_root) {
411  auto currentBounds = current->computeBounds();
412 
413  Branch *parent = current->getParent();
414  assert(parent != nullptr);
415 
416  parent->updateBoundsForChild(currentBounds, current);
417 
418  current = parent;
419  }
420 
421  return true;
422  }
423 
432  std::size_t query(const Box<U, N>& bounds, SpatialQueryCallback<T> callback, SpatialQuery kind = SpatialQuery::Intersect) const {
433  return m_root->query(bounds, callback, kind);
434  }
435 
439  void clear() {
440  delete m_root;
441  m_root = new Leaf;
442  }
443 
444  std::vector<SpatialStructure<U, N>> getStructure() const {
445  std::vector<SpatialStructure<U, N>> structures;
446  m_root->appendToStructure(structures, 0);
447  return structures;
448  }
449 
450  private:
451  static constexpr std::size_t Size = MaxSize + 1;
452 
453  enum SplitOrder {
454  Min,
455  Max,
456  };
457 
458  struct SplitResult {
459  std::size_t index;
460  std::size_t axis;
461  SplitOrder order;
462  };
463 
464  class Leaf;
465  class Branch;
466 
467  /*
468  * Node
469  */
470 
471  struct Entry {
472  Box<U, N> bounds;
473  };
474 
475  class Node {
476  public:
477  Node()
478  : m_parent(nullptr)
479  {
480 
481  }
482 
483  Branch *getParent() noexcept {
484  return m_parent;
485  }
486 
487  void setParent(Branch *parent) {
488  m_parent = parent;
489  }
490 
491  bool hasOriginalBounds() const {
492  return !m_orig.isEmpty();
493  }
494 
495  U getOriginalCenterAxisValue(std::size_t axis) const {
496  return (m_orig.min[axis] + m_orig.max[axis]) / 2;
497  }
498 
499  void updateOriginalBounds(Box<U, N> orig) {
500  m_orig = orig;
501  }
502 
503  virtual ~Node() = default;
504  virtual std::size_t query(const Box<U, N>& bounds, SpatialQueryCallback<T>& callback, SpatialQuery kind) const = 0;
505  virtual Leaf *chooseSubtree(const Box<U, N>& bounds) = 0;
506 
507  virtual Box<U, N> computeBounds() const = 0;
508 
509  virtual void appendToStructure(std::vector<SpatialStructure<U, N>>& structures, int level) const = 0;
510 
511  private:
512  Branch *m_parent;
513  Box<U, N> m_orig;
514  };
515 
516  /*
517  * Leaf
518  */
519 
520  struct LeafEntry : Entry {
521  T value;
522  };
523 
524  class Leaf : public Node {
525  public:
526  virtual std::size_t query(const Box<U, N>& bounds, SpatialQueryCallback<T>& callback, SpatialQuery kind) const override {
527  std::size_t found = 0;
528 
529  switch (kind) {
531  for (auto& entry : m_entries) {
532  if (bounds.contains(entry.bounds)) {
533  callback(entry.value);
534  ++found;
535  }
536  }
537  break;
538 
540  for (auto& entry : m_entries) {
541  if (bounds.intersects(entry.bounds)) {
542  callback(entry.value);
543  ++found;
544  }
545  }
546  break;
547  }
548 
549  return found;
550  }
551 
552 
553  virtual Leaf *chooseSubtree(const Box<U, N>& bounds) override {
554  gf::unused(bounds);
555  return this;
556  }
557 
558  virtual Box<U,N> computeBounds() const override {
559  assert(!m_entries.empty());
560  Box<U,N> res(m_entries[0].bounds);
561 
562  for (auto& entry : m_entries) {
563  res.extend(entry.bounds);
564  }
565 
566  return res;
567  }
568 
569  virtual void appendToStructure(std::vector<SpatialStructure<U, N>>& structures, int level) const override {
570  for (auto& entry : m_entries) {
571  structures.push_back({ entry.bounds, SpatialStructureType::Object, level });
572  }
573  }
574 
575  Leaf *tryInsert(T&& value, const Box<U, N>& bounds) {
576  LeafEntry entry;
577  entry.bounds = bounds;
578  entry.value = std::move(value);
579  m_entries.push_back(std::move(entry));
580 
581  if (m_entries.size() < Size) {
582  return nullptr;
583  }
584 
585  std::vector<Box<U, N>> boxes;
586 
587  std::transform(m_entries.begin(), m_entries.end(), std::back_inserter(boxes), [](const Entry& entry) {
588  return entry.bounds;
589  });
590 
591  SplitResult split = computeSplit(boxes);
592 
593  switch (split.order) {
594  case SplitOrder::Min:
595  std::sort(m_entries.begin(), m_entries.end(), EntryMinAxisComparator<LeafEntry>(split.axis));
596  break;
597  case SplitOrder::Max:
598  std::sort(m_entries.begin(), m_entries.end(), EntryMaxAxisComparator<LeafEntry>(split.axis));
599  break;
600  }
601 
602  auto leaf = new Leaf;
603 
604  auto splitIteratorBegin = std::next(m_entries.begin(), split.index + 1);
605  auto splitIteratorEnd = m_entries.end();
606 
607  std::move(splitIteratorBegin, splitIteratorEnd, std::back_inserter(leaf->m_entries));
608  m_entries.erase(splitIteratorBegin, splitIteratorEnd);
609 
610  return leaf;
611  }
612 
613  private:
614  SplitResult computeSplit(std::vector<Box<U, N>>& boxes) {
615  SplitResult split;
616  std::tie(split.axis, split.order) = computeSplitAxis(boxes);
617 
618  switch (split.order) {
619  case SplitOrder::Min:
620  std::sort(boxes.begin(), boxes.end(), MinAxisComparator(split.axis));
621  break;
622  case SplitOrder::Max:
623  std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(split.axis));
624  break;
625  }
626 
627  split.index = computeSplitIndex(boxes, split.axis);
628  return split;
629  }
630 
631  std::tuple<std::size_t, SplitOrder> computeSplitAxis(std::vector<Box<U, N>>& boxes) {
632  std::size_t currentAxis = 0;
633  U currentValue = std::numeric_limits<U>::max();
634  SplitOrder currentOrder = SplitOrder::Min;
635 
636  for (std::size_t axis = 0; axis < N; ++axis) {
637  std::sort(boxes.begin(), boxes.end(), MinAxisComparator(axis));
638 
639  U value = computeAxisValue(boxes);
640 
641  if (value < currentValue) {
642  currentAxis = axis;
643  currentValue = value;
644  currentOrder = SplitOrder::Min;
645  }
646 
647  std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(axis));
648 
649  value = computeAxisValue(boxes);
650 
651  if (value < currentValue) {
652  currentAxis = axis;
653  currentValue = value;
654  currentOrder = SplitOrder::Max;
655  }
656  }
657 
658  return std::make_tuple(currentAxis, currentOrder);
659  }
660 
661  U computeAxisValue(const std::vector<Box<U, N>>& boxes) {
662  std::vector<Box<U, N>> firstBounds;
663 
664  std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](const Box<U, N>& lhs, const Box<U, N>& rhs) {
665  return lhs.getExtended(rhs);
666  });
667 
668  std::vector<Box<U, N>> secondBounds;
669 
670  std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](const Box<U, N>& lhs, const Box<U, N>& rhs) {
671  return lhs.getExtended(rhs);
672  });
673 
674  U value = { };
675 
676  for (std::size_t j = MinSize; j <= MaxSize - MinSize + 1; ++j) {
677  value += firstBounds[j].getExtentDistance() + secondBounds[Size - j].getExtentDistance();
678  }
679 
680  return value;
681  }
682 
683  std::size_t computeSplitIndex(const std::vector<Box<U, N>>& boxes, std::size_t axis) {
684  std::vector<Box<U, N>> firstBounds;
685 
686  std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](const Box<U, N>& lhs, const Box<U, N>& rhs) {
687  return lhs.getExtended(rhs);
688  });
689 
690  std::vector<Box<U, N>> secondBounds;
691 
692  std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](const Box<U, N>& lhs, const Box<U, N>& rhs) {
693  return lhs.getExtended(rhs);
694  });
695 
696 
697  // define wf
698 
699  const auto& bounds = firstBounds.back();
700  float asym = 0.0f;
701 
702  if (Node::hasOriginalBounds()) {
703  asym = 2.0f * ((bounds.max[axis] + bounds.min[axis]) / 2 - Node::getOriginalCenterAxisValue(axis)) / (bounds.max[axis] - bounds.min[axis]);
704  }
705 
706  assert(-1.0f <= asym && asym <= 1.0f);
707 
708  static constexpr float S = 0.5f;
709  const float mu = (1 - 2.0f * MinSize / (MaxSize + 1)) * asym;
710  const float rho = S * (1 + std::abs(mu));
711  const float y1 = std::exp(- 1 / (S * S));
712  const float ys = 1 / (1 - y1);
713 
714  auto wf = [mu,rho,y1,ys](std::size_t i) {
715  const float xi = 2.0f * i / (MaxSize + 1.0f) - 1.0f;
716  return ys * (std::exp(- gf::square((xi - mu) / rho) - y1));
717  };
718 
719  // compute weight
720 
721  std::size_t currentIndex = 0;
722  U currentValue = std::numeric_limits<U>::max();
723 
724  U (Box<U,N>::* overlapFn)(const Box<U, N>&) const noexcept = nullptr;
725 
726  if (firstBounds[MinSize].getVolume() == 0 || secondBounds[MinSize].getVolume() == 0) {
727  // perimeter based strategy
729  } else {
730  // volume based strategy
731  overlapFn = &Box<U,N>::getIntersectionVolume;
732  }
733 
734  bool overlapFree = false;
735 
736  U perimeterMax = 2 * bounds.getExtentDistance() - bounds.getMinimumEdge();
737 
738  for (std::size_t index = MinSize; index <= MaxSize - MinSize + 1; ++index) {
739  auto weight = (firstBounds[index].*overlapFn)(secondBounds[Size - index - 1]);
740 
741  if (!overlapFree) {
742  if (weight == 0) {
743  overlapFree = true;
744  } else {
745  auto value = weight * wf(index);
746 
747  if (value < currentValue) {
748  currentValue = value;
749  currentIndex = index;
750  }
751  }
752  }
753 
754  if (overlapFree && weight == 0) {
755  weight = firstBounds[index].getExtentDistance() + secondBounds[Size - index - 1].getExtentDistance() - perimeterMax;
756  assert(weight <= 0);
757 
758  auto value = weight / wf(index);
759 
760  if (value < currentValue) {
761  currentValue = value;
762  currentIndex = index;
763  }
764  }
765  }
766 
767  return currentIndex;
768  }
769 
770  private:
771  boost::container::static_vector<LeafEntry, Size> m_entries;
772  };
773 
774  /*
775  * Branch
776  */
777 
778  struct BranchEntry : Entry {
779  Node *child;
780  };
781 
782  class Branch : public Node {
783  public:
784  virtual ~Branch() {
785  for (auto& entry : m_entries) {
786  delete entry.child;
787  }
788  }
789 
790  virtual std::size_t query(const Box<U, N>& bounds, SpatialQueryCallback<T>& callback, SpatialQuery kind) const override {
791  std::size_t found = 0;
792 
793  for (auto& entry : m_entries) {
794  if (bounds.intersects(entry.bounds)) {
795  found += entry.child->query(bounds, callback, kind);
796  }
797  }
798 
799  return found;
800  }
801 
802  virtual Leaf *chooseSubtree(const Box<U, N>& bounds) override {
803  return chooseNode(bounds)->chooseSubtree(bounds);
804  }
805 
806  Node *searchForCoveringNode(const Box<U, N>& bounds) {
807  Node *bestNodeForVolume = nullptr;
808  U bestVolume = std::numeric_limits<U>::max();
809 
810  Node *bestNodeForExtentDistance = nullptr;
811  U bestExtentDistance = std::numeric_limits<U>::max();
812 
813  for (auto& entry : m_entries) {
814  if (entry.bounds.getIntersection(bounds) == bounds) {
815  U volume = entry.bounds.getVolume();
816 
817  if (bestNodeForVolume == nullptr || volume < bestVolume) {
818  bestVolume = volume;
819  bestNodeForVolume = entry.child;
820  }
821 
822  U extentDistance = entry.bounds.getExtentDistance();
823 
824  if (bestNodeForExtentDistance == nullptr || extentDistance < bestExtentDistance) {
825  bestExtentDistance = extentDistance;
826  bestNodeForExtentDistance = entry.child;
827  }
828  }
829  }
830 
831  if (bestNodeForVolume != nullptr) {
832  if (bestVolume > 0) {
833  return bestNodeForVolume;
834  }
835 
836  assert(bestNodeForExtentDistance);
837  return bestNodeForExtentDistance;
838  }
839 
840  return nullptr;
841  }
842 
843  Node *chooseNode(const Box<U, N>& bounds) {
844  Node *covering = searchForCoveringNode(bounds);
845 
846  if (covering != nullptr) {
847  return covering;
848  }
849 
850  std::sort(m_entries.begin(), m_entries.end(), ExtentDistanceEnlargement(bounds));
851 
852  OverlapExtentDistanceEnlargement extentDistanceEnlargement(bounds, m_entries.front());
853 
854  std::size_t p;
855 
856  for (p = m_entries.size() - 1; p > 0; --p) {
857  if (extentDistanceEnlargement(m_entries[p]) != 0) {
858  break;
859  }
860  }
861 
862  if (p == 0) {
863  return m_entries[0].child;
864  }
865 
866  std::vector<Candidate> candidates(p + 1, { 0, false, U() });
867  Node *node = nullptr;
868 
869  if (existsEmptyVolumeExtension(bounds)) {
870  node = findCandidates<OverlapExtentDistanceEnlargement>(0, p, bounds, candidates);
871  } else {
872  node = findCandidates<OverlapVolumeEnlargement>(0, p, bounds, candidates);
873  }
874 
875  if (node != nullptr) {
876  return node;
877  }
878 
879  candidates.erase(std::remove_if(candidates.begin(), candidates.end(), [](const Candidate& candidate) {
880  return !candidate.isCandidate;
881  }), candidates.end());
882 
883  assert(!candidates.empty());
884 
885  auto it = std::min_element(candidates.begin(), candidates.end(), [](const Candidate& lhs, const Candidate& rhs) {
886  return lhs.overlap < rhs.overlap;
887  });
888 
889  return m_entries[it->index].child;
890  }
891 
892  virtual Box<U,N> computeBounds() const override {
893  assert(!m_entries.empty());
894  Box<U,N> res(m_entries[0].bounds);
895 
896  for (auto& entry : m_entries) {
897  res.extend(entry.bounds);
898  }
899 
900  return res;
901  }
902 
903  virtual void appendToStructure(std::vector<SpatialStructure<U, N>>& structures, int level) const override {
904  for (auto& entry : m_entries) {
905  structures.push_back({ entry.bounds, SpatialStructureType::Node, level });
906  entry.child->appendToStructure(structures, level + 1);
907  }
908  }
909 
910  void updateBoundsForChild(const Box<U, N>& bounds, Node *child) {
911  for (auto& entry : m_entries) {
912  if (entry.child == child) {
913  entry.bounds = bounds;
914  return;
915  }
916  }
917 
918  assert(false);
919  }
920 
921  Branch *tryInsert(Node * node, const Box<U, N>& bounds) {
922  BranchEntry entry;
923  entry.bounds = bounds;
924  entry.child = node;
925  m_entries.push_back(std::move(entry));
926 
927  if (m_entries.size() < Size) {
928  return nullptr;
929  }
930 
931  std::vector<Box<U, N>> boxes;
932 
933  std::transform(m_entries.begin(), m_entries.end(), std::back_inserter(boxes), [](const Entry& entry) {
934  return entry.bounds;
935  });
936 
937  SplitResult split = computeSplit(boxes);
938 
939  switch (split.order) {
940  case SplitOrder::Min:
941  std::sort(m_entries.begin(), m_entries.end(), EntryMinAxisComparator<BranchEntry>(split.axis));
942  break;
943  case SplitOrder::Max:
944  std::sort(m_entries.begin(), m_entries.end(), EntryMaxAxisComparator<BranchEntry>(split.axis));
945  break;
946  }
947 
948  auto branch = new Branch;
949 
950  auto splitIteratorBegin = std::next(m_entries.begin(), split.index + 1);
951  auto splitIteratorEnd = m_entries.end();
952 
953  std::move(splitIteratorBegin, splitIteratorEnd, std::back_inserter(branch->m_entries));
954  m_entries.erase(splitIteratorBegin, splitIteratorEnd);
955 
956  for (auto& entry : branch->m_entries) {
957  entry.child->setParent(branch);
958  }
959 
960  return branch;
961  }
962 
963  private:
964  struct Candidate {
965  std::size_t index;
966  bool isCandidate;
967  U overlap;
968  };
969 
970  bool existsEmptyVolumeExtension(const Box<U, N>& bounds) {
971  for (auto& entry : m_entries) {
972  if (entry.bounds.getExtended(bounds).getVolume() == 0) {
973  return true;
974  }
975  }
976 
977  return false;
978  }
979 
980  template<typename OverlapEnlargement>
981  Node *findCandidates(std::size_t t, std::size_t p, const Box<U, N>& bounds, std::vector<Candidate>& candidates) {
982  candidates[t].index = t;
983  candidates[t].isCandidate = true;
984 
985  OverlapEnlargement enlargement(bounds, m_entries[t]);
986 
987  U overlap = { };
988 
989  for (std::size_t i = 0; i <= p; ++i) {
990  if (i == t) {
991  continue;
992  }
993 
994  U localOverlap = enlargement(m_entries[i]);
995  overlap += localOverlap;
996 
997  if (localOverlap == 0 && !candidates[i].isCandidate) {
998  Node *node = findCandidates<OverlapEnlargement>(i, p, bounds, candidates);
999 
1000  if (node != nullptr) {
1001  return node;
1002  }
1003  }
1004  }
1005 
1006  if (overlap == 0) {
1007  return m_entries[t].child;
1008  }
1009 
1010  candidates[t].overlap = overlap;
1011  return nullptr;
1012  }
1013 
1014  struct SplitStatus {
1015  bool overlapFree = false;
1016  U currentValue = std::numeric_limits<U>::max();
1017  };
1018 
1019  SplitResult computeSplit(std::vector<Box<U, N>>& boxes) {
1020  SplitResult result;
1021  SplitStatus status;
1022 
1023  for (std::size_t axis = 0; axis < N; ++axis) {
1024  std::sort(boxes.begin(), boxes.end(), MinAxisComparator(axis));
1025  computeBestSplitValue(boxes, result, status, axis, SplitOrder::Min);
1026 
1027  std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(axis));
1028  computeBestSplitValue(boxes, result, status, axis, SplitOrder::Max);
1029  }
1030 
1031  return result;
1032  }
1033 
1034  void computeBestSplitValue(std::vector<Box<U, N>>& boxes, SplitResult& result, SplitStatus& status, std::size_t axis, SplitOrder order) {
1035  std::vector<Box<U, N>> firstBounds;
1036 
1037  std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](const Box<U, N>& lhs, const Box<U, N>& rhs) {
1038  return lhs.getExtended(rhs);
1039  });
1040 
1041  std::vector<Box<U, N>> secondBounds;
1042 
1043  std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](const Box<U, N>& lhs, const Box<U, N>& rhs) {
1044  return lhs.getExtended(rhs);
1045  });
1046 
1047  // define wf
1048 
1049  const auto& bounds = firstBounds.back();
1050  float asym = 0.0f;
1051 
1052  if (Node::hasOriginalBounds()) {
1053  asym = 2.0f * ((bounds.max[axis] + bounds.min[axis]) / 2 - Node::getOriginalCenterAxisValue(axis)) / (bounds.max[axis] - bounds.min[axis]);
1054  }
1055 
1056  assert(-1.0f <= asym && asym <= 1.0f);
1057 
1058  static constexpr float S = 0.5f;
1059  const float mu = (1 - 2.0f * MinSize / (MaxSize + 1)) * asym;
1060  const float rho = S * (1 + std::abs(mu));
1061  const float y1 = std::exp(- 1 / (S * S));
1062  const float ys = 1 / (1 - y1);
1063 
1064  auto wf = [mu,rho,y1,ys](std::size_t i) {
1065  const float xi = 2.0f * i / (MaxSize + 1.0f) - 1.0f;
1066  return ys * (std::exp(- gf::square((xi - mu) / rho) - y1));
1067  };
1068 
1069  // compute weight
1070 
1071  U (Box<U,N>::* overlapFn)(const Box<U, N>&) const noexcept = nullptr;
1072 
1073  if (firstBounds[MinSize].getVolume() == 0 || secondBounds[MinSize].getVolume() == 0) {
1074  // perimeter based strategy
1076  } else {
1077  // volume based strategy
1078  overlapFn = &Box<U,N>::getIntersectionVolume;
1079  }
1080 
1081  U perimeterMax = 2 * bounds.getExtentDistance() - bounds.getMinimumEdge();
1082 
1083  for (std::size_t index = MinSize; index <= MaxSize - MinSize + 1; ++index) {
1084  auto weight = (firstBounds[index].*overlapFn)(secondBounds[Size - index - 1]);
1085 
1086  if (!status.overlapFree) {
1087  if (weight == 0) {
1088  status.overlapFree = true;
1089  } else {
1090  auto value = weight * wf(index);
1091 
1092  if (value < status.currentValue) {
1093  status.currentValue = value;
1094  result.index = index;
1095  result.axis = axis;
1096  result.order = order;
1097  }
1098  }
1099  }
1100 
1101  if (status.overlapFree && weight == 0) {
1102  weight = firstBounds[index].getExtentDistance() + secondBounds[Size - index - 1].getExtentDistance() - perimeterMax;
1103  assert(weight <= 0);
1104 
1105  auto value = weight / wf(index);
1106 
1107  if (value < status.currentValue) {
1108  status.currentValue = value;
1109  result.index = index;
1110  result.axis = axis;
1111  result.order = order;
1112  }
1113  }
1114  }
1115  }
1116 
1117  private:
1118  boost::container::static_vector<BranchEntry, Size> m_entries;
1119  };
1120 
1121  /*
1122  * Comparators and Functors
1123  */
1124 
1125  class ExtentDistanceEnlargement {
1126  public:
1127  ExtentDistanceEnlargement(const Box<U, N>& bounds)
1128  : m_bounds(bounds)
1129  {
1130 
1131  }
1132 
1133  bool operator()(const Entry& lhs, const Entry& rhs) const {
1134  return getExtentDistanceEnlargement(lhs) < getExtentDistanceEnlargement(rhs);
1135  }
1136 
1137  U getExtentDistanceEnlargement(const Entry& entry) const {
1138  return entry.bounds.getExtended(m_bounds).getExtentDistance() - entry.bounds.getExtentDistance();
1139  }
1140 
1141  private:
1142  const Box<U, N>& m_bounds;
1143  };
1144 
1145  class OverlapExtentDistanceEnlargement {
1146  public:
1147  OverlapExtentDistanceEnlargement(const Box<U, N>& bounds, const Entry& reference)
1148  : m_bounds(bounds)
1149  , m_reference(reference)
1150  , m_extended(reference.bounds.getExtended(bounds))
1151  {
1152 
1153  }
1154 
1155  U operator()(const Entry& entry) const {
1156  return getOverlapExtentDistanceEnlargement(entry);
1157  }
1158 
1159  U getOverlapExtentDistanceEnlargement(const Entry& entry) const {
1160  return m_extended.getIntersectionExtentDistance(entry.bounds) - m_reference.bounds.getIntersectionExtentDistance(entry.bounds);
1161  }
1162 
1163  private:
1164  const Box<U, N>& m_bounds;
1165  const Entry& m_reference;
1166  Box<U, N> m_extended;
1167  };
1168 
1169 
1170  class OverlapVolumeEnlargement {
1171  public:
1172  OverlapVolumeEnlargement(const Box<U, N>& bounds, const Entry& reference)
1173  : m_bounds(bounds)
1174  , m_reference(reference)
1175  , m_extended(reference.bounds.getExtended(bounds))
1176  {
1177 
1178  }
1179 
1180  U operator()(const Entry& entry) const {
1181  return getOverlapVolumeEnlargement(entry);
1182  }
1183 
1184  U getOverlapVolumeEnlargement(const Entry& entry) const {
1185  return m_extended.getIntersectionVolume(entry.bounds) - m_reference.bounds.getIntersectionVolume(entry.bounds);
1186  }
1187 
1188  private:
1189  const Box<U, N>& m_bounds;
1190  const Entry& m_reference;
1191  Box<U, N> m_extended;
1192  };
1193 
1194  class MinAxisComparator {
1195  public:
1196  MinAxisComparator(std::size_t axis)
1197  : m_axis(axis)
1198  {
1199 
1200  }
1201 
1202  bool operator()(const Box<U, N>& lhs, const Box<U, N>& rhs) {
1203  return std::make_tuple(lhs.min[m_axis], lhs.max[m_axis]) < std::make_tuple(rhs.min[m_axis], rhs.max[m_axis]);
1204  }
1205 
1206  private:
1207  std::size_t m_axis;
1208  };
1209 
1210  template<typename Entry>
1211  class EntryMinAxisComparator {
1212  public:
1213  EntryMinAxisComparator(std::size_t axis)
1214  : m_axis(axis)
1215  {
1216 
1217  }
1218 
1219  bool operator()(const Entry& lhs, const Entry& rhs) {
1220  return std::make_tuple(lhs.bounds.min[m_axis], lhs.bounds.max[m_axis]) < std::make_tuple(rhs.bounds.min[m_axis], rhs.bounds.max[m_axis]);
1221  }
1222 
1223  private:
1224  std::size_t m_axis;
1225  };
1226 
1227  class MaxAxisComparator {
1228  public:
1229  MaxAxisComparator(std::size_t axis)
1230  : m_axis(axis)
1231  {
1232 
1233  }
1234 
1235  bool operator()(const Box<U, N>& lhs, const Box<U, N>& rhs) {
1236  return std::make_tuple(lhs.max[m_axis], lhs.min[m_axis]) < std::make_tuple(rhs.max[m_axis], rhs.min[m_axis]);
1237  }
1238 
1239  private:
1240  std::size_t m_axis;
1241  };
1242 
1243  template<typename Entry>
1244  class EntryMaxAxisComparator {
1245  public:
1246  EntryMaxAxisComparator(std::size_t axis)
1247  : m_axis(axis)
1248  {
1249 
1250  }
1251 
1252  bool operator()(const Entry& lhs, const Entry& rhs) {
1253  return std::make_tuple(lhs.bounds.max[m_axis], lhs.bounds.min[m_axis]) < std::make_tuple(rhs.bounds.max[m_axis], rhs.bounds.min[m_axis]);
1254  }
1255 
1256  private:
1257  std::size_t m_axis;
1258  };
1259 
1260  private:
1261  void updateBounds(Node *node) {
1262  while (node != nullptr) {
1263  Box<U, N> bounds = node->computeBounds();
1264 
1265  Branch *parent = node->getParent();
1266 
1267  if (parent != nullptr) {
1268  parent->updateBoundsForChild(bounds, node);
1269  }
1270 
1271  node = parent;
1272  }
1273  }
1274 
1275  private:
1276  Node *m_root;
1277  };
1278 
1279 
1280 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1281 }
1282 #endif
1283 }
1284 
1285 #endif // GF_SPATIAL_H
constexpr Box< T, N > getExtended(const Box< T, N > &other) const noexcept
Definition: Box.h:196
bool insert(T value, const Box< U, N > &bounds)
Insert an object in the tree.
Definition: Spatial.h:370
constexpr bool intersects(const Box< T, N > &other) const noexcept
Definition: Box.h:118
void clear()
Remove all the objects from the tree.
Definition: Spatial.h:129
std::size_t query(const Box< U, N > &bounds, SpatialQueryCallback< T > callback, SpatialQuery kind=SpatialQuery::Intersect) const
Query objects in the tree.
Definition: Spatial.h:432
std::function< void(const T &)> SpatialQueryCallback
A callback for spatial query.
Definition: Spatial.h:73
std::vector< SpatialStructure< U, N > > getStructure() const
Definition: Spatial.h:444
constexpr Vector2f transform(const Matrix3f &mat, Vector2f point)
Apply an affine transformation to a 2D point.
Definition: Transform.h:331
SpatialStructureType type
Definition: Spatial.h:55
Box< U, N > bounds
Definition: Spatial.h:54
Vector< T, N > min
Definition: Box.h:49
Search for all objects that contain the given bounds.
~RStarTree()
Destructor.
Definition: Spatial.h:359
Definition: Spatial.h:53
std::vector< SpatialStructure< U, 2 > > getStructure() const
Definition: Spatial.h:134
constexpr T square(T val)
Square function.
Definition: Math.h:275
SpatialStructureType
Definition: Spatial.h:47
std::size_t query(const Box< U, 2 > &bounds, SpatialQueryCallback< T > callback, SpatialQuery kind=SpatialQuery::Intersect) const
Query objects in the tree.
Definition: Spatial.h:122
Search for all objects that intersect the given bounds.
RStarTree & operator=(RStarTree &&other) noexcept
Move assignement.
Definition: Spatial.h:351
void clear()
Remove all the objects from the tree.
Definition: Spatial.h:439
The namespace for gf classes.
Definition: Action.h:35
QuadTree(const Box< U, 2 > &bounds)
Constructor.
Definition: Spatial.h:91
RStarTree()
Constructor.
Definition: Spatial.h:324
An implementation of quadtree.
Definition: Spatial.h:83
Vector< T, N > max
Definition: Box.h:50
Box< T, 2 > computeBoxQuadrant(const Box< T, 2 > &box, Quadrant quadrant)
Definition: Box.h:263
int level
Definition: Spatial.h:56
RStarTree(RStarTree &&other) noexcept
Move constructor.
Definition: Spatial.h:343
An implemntation of a R* tree.
Definition: Spatial.h:316
SpatialQuery
A kind of spatial query.
Definition: Spatial.h:63
bool insert(T value, const Box< U, 2 > &bounds)
Insert an object in the tree.
Definition: Spatial.h:104
constexpr bool contains(Vector< T, N > point) const noexcept
Definition: Box.h:98
constexpr void unused(Args &&...)
A simple way to avoid warnings about unused variables.
Definition: Unused.h:35