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