diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-12-04 16:02:24 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-12-04 16:02:24 +0100 |
commit | 9eca02a388e20e4de3beae078bb42be81eabc021 (patch) | |
tree | 12f5bed61c09b122ab45301b4b24b49100813ebd | |
parent | 3d79820261a79ddd06e38c49f8c94db0fe901600 (diff) |
compat/lqt: tabs to spaces
-rw-r--r-- | compat/LooseQuadtree-impl.h | 2012 | ||||
-rw-r--r-- | compat/LooseQuadtree.h | 112 | ||||
-rw-r--r-- | test/quadtree.cpp | 1248 |
3 files changed, 1686 insertions, 1686 deletions
diff --git a/compat/LooseQuadtree-impl.h b/compat/LooseQuadtree-impl.h index 694d04d1..eab448a1 100644 --- a/compat/LooseQuadtree-impl.h +++ b/compat/LooseQuadtree-impl.h @@ -36,85 +36,85 @@ namespace detail { class BlocksAllocator { public: - static constexpr std::size_t kBlockAlign = alignof(long double); - static constexpr std::size_t kBlockSize = 16384; - static constexpr std::size_t kMaxAllowedAlloc = sizeof(void*) * 8; - - BlocksAllocator(); - ~BlocksAllocator(); - BlocksAllocator(const BlocksAllocator&) = delete; - BlocksAllocator& operator=(const BlocksAllocator&) = delete; - - void* Allocate(std::size_t object_size); - void Deallocate(void* p, std::size_t object_size); - void ReleaseFreeBlocks(); - template <typename T, typename... Args> - T* New(Args&&... args); - template <typename T> - void Delete(T* p); + static constexpr std::size_t kBlockAlign = alignof(long double); + static constexpr std::size_t kBlockSize = 16384; + static constexpr std::size_t kMaxAllowedAlloc = sizeof(void*) * 8; + + BlocksAllocator(); + ~BlocksAllocator(); + BlocksAllocator(const BlocksAllocator&) = delete; + BlocksAllocator& operator=(const BlocksAllocator&) = delete; + + void* Allocate(std::size_t object_size); + void Deallocate(void* p, std::size_t object_size); + void ReleaseFreeBlocks(); + template <typename T, typename... Args> + T* New(Args&&... args); + template <typename T> + void Delete(T* p); private: - struct Block { - alignas(kBlockAlign) unsigned char data[kBlockSize]; - }; - - //template <std::size_t kSizeT> - //union Slot { - // Slot* next_empty_slot; - // std::array<char, kSizeT> data; - //}; - - using BlocksAndEmptySlots = std::map<Block*, std::size_t>; - - struct BlocksHead { - BlocksAndEmptySlots address_to_empty_slot_number; - void* first_empty_slot; - std::size_t slots_in_a_block_; - - BlocksHead(std::size_t object_size) { - first_empty_slot = nullptr; - slots_in_a_block_ = kBlockSize / object_size; - } - }; - - std::map<std::size_t, BlocksHead> size_to_blocks_; + struct Block { + alignas(kBlockAlign) unsigned char data[kBlockSize]; + }; + + //template <std::size_t kSizeT> + //union Slot { + // Slot* next_empty_slot; + // std::array<char, kSizeT> data; + //}; + + using BlocksAndEmptySlots = std::map<Block*, std::size_t>; + + struct BlocksHead { + BlocksAndEmptySlots address_to_empty_slot_number; + void* first_empty_slot; + std::size_t slots_in_a_block_; + + BlocksHead(std::size_t object_size) { + first_empty_slot = nullptr; + slots_in_a_block_ = kBlockSize / object_size; + } + }; + + std::map<std::size_t, BlocksHead> size_to_blocks_; }; template <typename T> struct BlocksAllocatorAdaptor { - using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - template<typename U> - struct rebind {using other = BlocksAllocatorAdaptor<U>;}; - - BlocksAllocatorAdaptor(BlocksAllocator& allocator); - template <typename U> - BlocksAllocatorAdaptor(const BlocksAllocatorAdaptor<U>& other); - template <typename U> - BlocksAllocatorAdaptor& operator=(const BlocksAllocatorAdaptor<U>& other); - - pointer address(reference r) const {return &r;} - const_pointer address(const_reference r) const {return &r;} - size_type max_size() const {return std::numeric_limits<size_type>::max();} - template <typename U, typename... Args> - void construct(U* p, Args&&... args) { - new((void*)p) U(std::forward<Args>(args)...); - } - template <typename U> - void destroy(U* p) { - p->~U(); - } - - T* allocate(std::size_t n); - void deallocate(T* p, std::size_t n); - - BlocksAllocator* allocator_; + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + template<typename U> + struct rebind {using other = BlocksAllocatorAdaptor<U>;}; + + BlocksAllocatorAdaptor(BlocksAllocator& allocator); + template <typename U> + BlocksAllocatorAdaptor(const BlocksAllocatorAdaptor<U>& other); + template <typename U> + BlocksAllocatorAdaptor& operator=(const BlocksAllocatorAdaptor<U>& other); + + pointer address(reference r) const {return &r;} + const_pointer address(const_reference r) const {return &r;} + size_type max_size() const {return std::numeric_limits<size_type>::max();} + template <typename U, typename... Args> + void construct(U* p, Args&&... args) { + new((void*)p) U(std::forward<Args>(args)...); + } + template <typename U> + void destroy(U* p) { + p->~U(); + } + + T* allocate(std::size_t n); + void deallocate(T* p, std::size_t n); + + BlocksAllocator* allocator_; }; @@ -122,184 +122,184 @@ BlocksAllocator::BlocksAllocator() {} BlocksAllocator::~BlocksAllocator() { - for (auto& size_block_pair : size_to_blocks_) { - BlocksHead& blocks_head = size_block_pair.second; - for (auto& address_empty_pair : blocks_head.address_to_empty_slot_number) { - assert(address_empty_pair.second == blocks_head.slots_in_a_block_); - Block* block = address_empty_pair.first; - delete block; - } - } + for (auto& size_block_pair : size_to_blocks_) { + BlocksHead& blocks_head = size_block_pair.second; + for (auto& address_empty_pair : blocks_head.address_to_empty_slot_number) { + assert(address_empty_pair.second == blocks_head.slots_in_a_block_); + Block* block = address_empty_pair.first; + delete block; + } + } } void* BlocksAllocator::Allocate(std::size_t object_size) { #ifdef LQT_USE_OWN_ALLOCATOR - if (object_size < sizeof(void*)) object_size = sizeof(void*); - assert(object_size <= kMaxAllowedAlloc); - auto size_blocks_it = size_to_blocks_.find(object_size); - if (size_blocks_it == size_to_blocks_.end()) { - size_blocks_it = size_to_blocks_.emplace(object_size, object_size).first; - } - BlocksHead& blocks_head = size_blocks_it->second; - assert(blocks_head.slots_in_a_block_ == kBlockSize / object_size); - if (blocks_head.first_empty_slot == nullptr) { - Block* new_block = new Block(); - std::size_t empties = blocks_head.slots_in_a_block_; - blocks_head.address_to_empty_slot_number.emplace(new_block, empties); - blocks_head.first_empty_slot = reinterpret_cast<void*>(new_block); - void* current_slot = reinterpret_cast<void*>(new_block); - empties--; - while (empties > 0) { - void* next_slot = - reinterpret_cast<void*>(reinterpret_cast<char*>(current_slot) - + object_size); - *reinterpret_cast<void**>(current_slot) = next_slot; - current_slot = next_slot; - empties--; - } - *reinterpret_cast<void**>(current_slot) = nullptr; - } - assert(blocks_head.first_empty_slot != nullptr); - void* slot = blocks_head.first_empty_slot; - blocks_head.first_empty_slot = *reinterpret_cast<void**>(slot); - auto address_empties_it = - blocks_head.address_to_empty_slot_number.upper_bound(reinterpret_cast<Block*>(slot)); - assert(address_empties_it != blocks_head.address_to_empty_slot_number.begin()); - address_empties_it--; - assert(address_empties_it->first <= reinterpret_cast<Block*>(slot) && - (std::size_t)(reinterpret_cast<char*>(slot) - - reinterpret_cast<char*>(address_empties_it->first)) < kBlockSize); - assert((std::size_t)(reinterpret_cast<char*>(slot) - - reinterpret_cast<char*>(address_empties_it->first)) % object_size == 0); - assert(address_empties_it->second > 0 && - address_empties_it->second <= blocks_head.slots_in_a_block_); - address_empties_it->second--; - return slot; + if (object_size < sizeof(void*)) object_size = sizeof(void*); + assert(object_size <= kMaxAllowedAlloc); + auto size_blocks_it = size_to_blocks_.find(object_size); + if (size_blocks_it == size_to_blocks_.end()) { + size_blocks_it = size_to_blocks_.emplace(object_size, object_size).first; + } + BlocksHead& blocks_head = size_blocks_it->second; + assert(blocks_head.slots_in_a_block_ == kBlockSize / object_size); + if (blocks_head.first_empty_slot == nullptr) { + Block* new_block = new Block(); + std::size_t empties = blocks_head.slots_in_a_block_; + blocks_head.address_to_empty_slot_number.emplace(new_block, empties); + blocks_head.first_empty_slot = reinterpret_cast<void*>(new_block); + void* current_slot = reinterpret_cast<void*>(new_block); + empties--; + while (empties > 0) { + void* next_slot = + reinterpret_cast<void*>(reinterpret_cast<char*>(current_slot) + + object_size); + *reinterpret_cast<void**>(current_slot) = next_slot; + current_slot = next_slot; + empties--; + } + *reinterpret_cast<void**>(current_slot) = nullptr; + } + assert(blocks_head.first_empty_slot != nullptr); + void* slot = blocks_head.first_empty_slot; + blocks_head.first_empty_slot = *reinterpret_cast<void**>(slot); + auto address_empties_it = + blocks_head.address_to_empty_slot_number.upper_bound(reinterpret_cast<Block*>(slot)); + assert(address_empties_it != blocks_head.address_to_empty_slot_number.begin()); + address_empties_it--; + assert(address_empties_it->first <= reinterpret_cast<Block*>(slot) && + (std::size_t)(reinterpret_cast<char*>(slot) - + reinterpret_cast<char*>(address_empties_it->first)) < kBlockSize); + assert((std::size_t)(reinterpret_cast<char*>(slot) - + reinterpret_cast<char*>(address_empties_it->first)) % object_size == 0); + assert(address_empties_it->second > 0 && + address_empties_it->second <= blocks_head.slots_in_a_block_); + address_empties_it->second--; + return slot; #else - return reinterpret_cast<void*>(new char[object_size]); + return reinterpret_cast<void*>(new char[object_size]); #endif } void BlocksAllocator::Deallocate(void* p, std::size_t object_size) { #ifdef LQT_USE_OWN_ALLOCATOR - if (object_size < sizeof(void*)) object_size = sizeof(void*); - assert(object_size <= kMaxAllowedAlloc); - auto size_blocks_it = size_to_blocks_.find(object_size); - assert(size_blocks_it != size_to_blocks_.end()); - BlocksHead& blocks_head = size_blocks_it->second; - assert(blocks_head.slots_in_a_block_ == kBlockSize / object_size); - auto address_empties_it = - blocks_head.address_to_empty_slot_number.upper_bound(reinterpret_cast<Block*>(p)); - assert(address_empties_it != blocks_head.address_to_empty_slot_number.begin()); - address_empties_it--; - assert(address_empties_it->first <= reinterpret_cast<Block*>(p) && - (std::size_t)(reinterpret_cast<char*>(p) - - reinterpret_cast<char*>(address_empties_it->first)) < kBlockSize); - assert((std::size_t)(reinterpret_cast<char*>(p) - - reinterpret_cast<char*>(address_empties_it->first)) % object_size == 0); - assert(address_empties_it->second < blocks_head.slots_in_a_block_); - void* slot = p; - *reinterpret_cast<void**>(slot) = blocks_head.first_empty_slot; - blocks_head.first_empty_slot = slot; - address_empties_it->second++; - assert(address_empties_it->second > 0 && - address_empties_it->second <= blocks_head.slots_in_a_block_); + if (object_size < sizeof(void*)) object_size = sizeof(void*); + assert(object_size <= kMaxAllowedAlloc); + auto size_blocks_it = size_to_blocks_.find(object_size); + assert(size_blocks_it != size_to_blocks_.end()); + BlocksHead& blocks_head = size_blocks_it->second; + assert(blocks_head.slots_in_a_block_ == kBlockSize / object_size); + auto address_empties_it = + blocks_head.address_to_empty_slot_number.upper_bound(reinterpret_cast<Block*>(p)); + assert(address_empties_it != blocks_head.address_to_empty_slot_number.begin()); + address_empties_it--; + assert(address_empties_it->first <= reinterpret_cast<Block*>(p) && + (std::size_t)(reinterpret_cast<char*>(p) - + reinterpret_cast<char*>(address_empties_it->first)) < kBlockSize); + assert((std::size_t)(reinterpret_cast<char*>(p) - + reinterpret_cast<char*>(address_empties_it->first)) % object_size == 0); + assert(address_empties_it->second < blocks_head.slots_in_a_block_); + void* slot = p; + *reinterpret_cast<void**>(slot) = blocks_head.first_empty_slot; + blocks_head.first_empty_slot = slot; + address_empties_it->second++; + assert(address_empties_it->second > 0 && + address_empties_it->second <= blocks_head.slots_in_a_block_); #else - (void)object_size; - delete[] reinterpret_cast<char*>(p); + (void)object_size; + delete[] reinterpret_cast<char*>(p); #endif } void BlocksAllocator::ReleaseFreeBlocks() { - for (auto& size_block_pair : size_to_blocks_) { - BlocksHead& blocks_head = size_block_pair.second; - void** current = &blocks_head.first_empty_slot; - while (*current != nullptr) { - auto address_empties_it = - blocks_head.address_to_empty_slot_number.upper_bound(reinterpret_cast<Block*>(*current)); - assert(address_empties_it != blocks_head.address_to_empty_slot_number.begin()); - address_empties_it--; - assert(address_empties_it->first <= reinterpret_cast<Block*>(*current) && - (std::size_t)(reinterpret_cast<char*>(*current) - - reinterpret_cast<char*>(address_empties_it->first)) < kBlockSize); - assert((std::size_t)(reinterpret_cast<char*>(*current) - - reinterpret_cast<char*>(address_empties_it->first)) % size_block_pair.first == 0); - assert(address_empties_it->second > 0 && - address_empties_it->second <= blocks_head.slots_in_a_block_); - if (address_empties_it->second >= blocks_head.slots_in_a_block_) { - *current = **reinterpret_cast<void***>(current); - } - else { - current = *reinterpret_cast<void***>(current); - } - } - auto address_empties_it = blocks_head.address_to_empty_slot_number.begin(); - while (address_empties_it != blocks_head.address_to_empty_slot_number.end()) { - if (address_empties_it->second >= blocks_head.slots_in_a_block_) { - auto prev_address_empties_it = address_empties_it; - address_empties_it++; - blocks_head.address_to_empty_slot_number.erase(prev_address_empties_it); - } - else { - address_empties_it++; - } - } - } + for (auto& size_block_pair : size_to_blocks_) { + BlocksHead& blocks_head = size_block_pair.second; + void** current = &blocks_head.first_empty_slot; + while (*current != nullptr) { + auto address_empties_it = + blocks_head.address_to_empty_slot_number.upper_bound(reinterpret_cast<Block*>(*current)); + assert(address_empties_it != blocks_head.address_to_empty_slot_number.begin()); + address_empties_it--; + assert(address_empties_it->first <= reinterpret_cast<Block*>(*current) && + (std::size_t)(reinterpret_cast<char*>(*current) - + reinterpret_cast<char*>(address_empties_it->first)) < kBlockSize); + assert((std::size_t)(reinterpret_cast<char*>(*current) - + reinterpret_cast<char*>(address_empties_it->first)) % size_block_pair.first == 0); + assert(address_empties_it->second > 0 && + address_empties_it->second <= blocks_head.slots_in_a_block_); + if (address_empties_it->second >= blocks_head.slots_in_a_block_) { + *current = **reinterpret_cast<void***>(current); + } + else { + current = *reinterpret_cast<void***>(current); + } + } + auto address_empties_it = blocks_head.address_to_empty_slot_number.begin(); + while (address_empties_it != blocks_head.address_to_empty_slot_number.end()) { + if (address_empties_it->second >= blocks_head.slots_in_a_block_) { + auto prev_address_empties_it = address_empties_it; + address_empties_it++; + blocks_head.address_to_empty_slot_number.erase(prev_address_empties_it); + } + else { + address_empties_it++; + } + } + } } template <typename T, typename... Args> T* BlocksAllocator::New(Args&&... args) { - return new(Allocate(sizeof(T))) T(std::forward<Args>(args)...); + return new(Allocate(sizeof(T))) T(std::forward<Args>(args)...); } template <typename T> void BlocksAllocator::Delete(T* p) { - p->~T(); - Deallocate(p, sizeof(T)); + p->~T(); + Deallocate(p, sizeof(T)); } template <typename T> BlocksAllocatorAdaptor<T>::BlocksAllocatorAdaptor(BlocksAllocator& allocator) - : allocator_(&allocator) { + : allocator_(&allocator) { } template <typename T> template <typename U> BlocksAllocatorAdaptor<T>::BlocksAllocatorAdaptor(const BlocksAllocatorAdaptor<U>& other) - : allocator_(other.allocator_) { + : allocator_(other.allocator_) { } template <typename T> template <typename U> BlocksAllocatorAdaptor<T>& BlocksAllocatorAdaptor<T>::operator=(const BlocksAllocatorAdaptor<U>& other) { - allocator_ = other.allocator_; + allocator_ = other.allocator_; } template <typename T> T* BlocksAllocatorAdaptor<T>::allocate(std::size_t n) { - if (sizeof(T) <= BlocksAllocator::kMaxAllowedAlloc && n == 1) { - return reinterpret_cast<T*>(allocator_->Allocate(sizeof(T))); - } - else { - return reinterpret_cast<T*>(new char[sizeof(T) * n]); - } + if (sizeof(T) <= BlocksAllocator::kMaxAllowedAlloc && n == 1) { + return reinterpret_cast<T*>(allocator_->Allocate(sizeof(T))); + } + else { + return reinterpret_cast<T*>(new char[sizeof(T) * n]); + } } template <typename T> void BlocksAllocatorAdaptor<T>::deallocate(T* p, std::size_t n) { - if (sizeof(T) <= BlocksAllocator::kMaxAllowedAlloc && n == 1) { - allocator_->Deallocate(p, sizeof(T)); - } - else { - delete[] reinterpret_cast<char*>(p); - } + if (sizeof(T) <= BlocksAllocator::kMaxAllowedAlloc && n == 1) { + allocator_->Deallocate(p, sizeof(T)); + } + else { + delete[] reinterpret_cast<char*>(p); + } } @@ -322,31 +322,31 @@ struct MakeDistance<long double> { using Type = long double;}; enum class ChildPosition { - kNone, - kTopLeft, - kTopRight, - kBottomRight, - kBottomLeft, + kNone, + kTopLeft, + kTopRight, + kBottomRight, + kBottomLeft, }; template <typename ObjectT> struct TreeNode { - using Object = ObjectT; - using ObjectContainer = - std::forward_list<Object*, BlocksAllocatorAdaptor<Object*>>; - - TreeNode(BlocksAllocator& allocator) : - top_left(nullptr), top_right(nullptr), bottom_right(nullptr), - bottom_left(nullptr), objects(BlocksAllocatorAdaptor<Object*>(allocator)) - {} - - TreeNode<Object>* top_left; - TreeNode<Object>* top_right; - TreeNode<Object>* bottom_right; - TreeNode<Object>* bottom_left; - ObjectContainer objects; + using Object = ObjectT; + using ObjectContainer = + std::forward_list<Object*, BlocksAllocatorAdaptor<Object*>>; + + TreeNode(BlocksAllocator& allocator) : + top_left(nullptr), top_right(nullptr), bottom_right(nullptr), + bottom_left(nullptr), objects(BlocksAllocatorAdaptor<Object*>(allocator)) + {} + + TreeNode<Object>* top_left; + TreeNode<Object>* top_right; + TreeNode<Object>* bottom_right; + TreeNode<Object>* bottom_left; + ObjectContainer objects; }; @@ -354,33 +354,33 @@ struct TreeNode { template <typename NumberT, typename ObjectT> class ForwardTreeTraversal { public: - using Number = NumberT; - using Object = ObjectT; - - struct TreePosition { - TreePosition(const BoundingBox<Number>& _bbox, TreeNode<Object>* _node) : - bounding_box(_bbox), node(_node) { - current_child = ChildPosition::kNone; - } - - BoundingBox<Number> bounding_box; - TreeNode<Object>* node; - ChildPosition current_child; - }; - - ForwardTreeTraversal(); - void StartAt(TreeNode<Object>* root, const BoundingBox<Number>& root_bounds); - int GetDepth() const; ///< starting from 0 - TreeNode<Object>* GetNode() const; - const BoundingBox<Number>& GetNodeBoundingBox() const; - void GoTopLeft(); - void GoTopRight(); - void GoBottomRight(); - void GoBottomLeft(); + using Number = NumberT; + using Object = ObjectT; + + struct TreePosition { + TreePosition(const BoundingBox<Number>& _bbox, TreeNode<Object>* _node) : + bounding_box(_bbox), node(_node) { + current_child = ChildPosition::kNone; + } + + BoundingBox<Number> bounding_box; + TreeNode<Object>* node; + ChildPosition current_child; + }; + + ForwardTreeTraversal(); + void StartAt(TreeNode<Object>* root, const BoundingBox<Number>& root_bounds); + int GetDepth() const; ///< starting from 0 + TreeNode<Object>* GetNode() const; + const BoundingBox<Number>& GetNodeBoundingBox() const; + void GoTopLeft(); + void GoTopRight(); + void GoBottomRight(); + void GoBottomLeft(); protected: - TreePosition position_; - int depth_; + TreePosition position_; + int depth_; }; @@ -388,24 +388,24 @@ protected: template <typename NumberT, typename ObjectT> class FullTreeTraversal : public ForwardTreeTraversal<NumberT, ObjectT> { public: - using Number = NumberT; - using Object = ObjectT; - using typename ForwardTreeTraversal<Number, Object>::TreePosition; - - void StartAt(TreeNode<Object>* root, const BoundingBox<Number>& root_bounds); - ChildPosition GetNodeCurrentChild() const; - void SetNodeCurrentChild(ChildPosition child_position); - void GoUp(); - void GoTopLeft(); - void GoTopRight(); - void GoBottomRight(); - void GoBottomLeft(); + using Number = NumberT; + using Object = ObjectT; + using typename ForwardTreeTraversal<Number, Object>::TreePosition; + + void StartAt(TreeNode<Object>* root, const BoundingBox<Number>& root_bounds); + ChildPosition GetNodeCurrentChild() const; + void SetNodeCurrentChild(ChildPosition child_position); + void GoUp(); + void GoTopLeft(); + void GoTopRight(); + void GoBottomRight(); + void GoBottomLeft(); private: - using ForwardTreeTraversal<Number, Object>::position_; - using ForwardTreeTraversal<Number, Object>::depth_; + using ForwardTreeTraversal<Number, Object>::position_; + using ForwardTreeTraversal<Number, Object>::depth_; - std::vector<TreePosition> position_stack_; + std::vector<TreePosition> position_stack_; }; @@ -416,88 +416,88 @@ private: template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> class - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: Impl { public: - enum class QueryType {kIntersects, kInside, kContains, kEndOfQuery}; + enum class QueryType {kIntersects, kInside, kContains, kEndOfQuery}; - Impl(); - void Acquire(typename LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl* quadtree, - const BoundingBox<Number>* query_region, QueryType query_type); - void Release(); - bool IsAvailable() const; - bool EndOfQuery() const; - Object* GetCurrent() const; - void Next(); + Impl(); + void Acquire(typename LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl* quadtree, + const BoundingBox<Number>* query_region, QueryType query_type); + void Release(); + bool IsAvailable() const; + bool EndOfQuery() const; + Object* GetCurrent() const; + void Next(); private: - enum class FitType {kNoFit = 0, kPartialFit, kFreeRide}; - - bool CurrentObjectFits() const; - FitType CurrentNodeFits() const; - - typename LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl* quadtree_; - detail::FullTreeTraversal<Number, Object> traversal_; - typename detail::TreeNode<Object>::ObjectContainer::iterator object_iterator_; - typename detail::TreeNode<Object>::ObjectContainer::iterator object_iterator_before_; - BoundingBox<Number> query_region_; - QueryType query_type_; - int free_ride_from_level_; + enum class FitType {kNoFit = 0, kPartialFit, kFreeRide}; + + bool CurrentObjectFits() const; + FitType CurrentNodeFits() const; + + typename LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl* quadtree_; + detail::FullTreeTraversal<Number, Object> traversal_; + typename detail::TreeNode<Object>::ObjectContainer::iterator object_iterator_; + typename detail::TreeNode<Object>::ObjectContainer::iterator object_iterator_before_; + BoundingBox<Number> query_region_; + QueryType query_type_; + int free_ride_from_level_; }; template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> class - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: Impl { public: - constexpr static int kInternalMinDepth = 4; - constexpr static int kInternalMaxDepth = (sizeof(long long) * 8 - 1) / 2; - constexpr static Number kMinimalObjectExtent = - std::is_integral<Number>::value ? 1 : - std::numeric_limits<Number>::min() * 16; - - Impl(); - ~Impl(); - Impl(const Impl&) = delete; - Impl& operator=(const Impl&) = delete; - - bool Insert(Object* object); - bool Update(Object* object); - bool Remove(Object* object); - bool Contains(Object* object) const; - Query QueryIntersectsRegion(const BoundingBox<Number>& region); - Query QueryInsideRegion(const BoundingBox<Number>& region); - Query QueryContainsRegion(const BoundingBox<Number>& region); - const BoundingBox<Number>& GetBoundingBox() const; ///< loose sense bounds - int GetSize() const; - void Clear(); - void ForceCleanup(); + constexpr static int kInternalMinDepth = 4; + constexpr static int kInternalMaxDepth = (sizeof(long long) * 8 - 1) / 2; + constexpr static Number kMinimalObjectExtent = + std::is_integral<Number>::value ? 1 : + std::numeric_limits<Number>::min() * 16; + + Impl(); + ~Impl(); + Impl(const Impl&) = delete; + Impl& operator=(const Impl&) = delete; + + bool Insert(Object* object); + bool Update(Object* object); + bool Remove(Object* object); + bool Contains(Object* object) const; + Query QueryIntersectsRegion(const BoundingBox<Number>& region); + Query QueryInsideRegion(const BoundingBox<Number>& region); + Query QueryContainsRegion(const BoundingBox<Number>& region); + const BoundingBox<Number>& GetBoundingBox() const; ///< loose sense bounds + int GetSize() const; + void Clear(); + void ForceCleanup(); private: - friend class Query::Impl; - using ObjectPointerContainer = - std::unordered_map<Object*, Object**, - std::hash<Object*>, std::equal_to<Object*>, - detail::BlocksAllocatorAdaptor<std::pair<Object *const, Object**>>>; - using QueryPoolContainer = - std::deque<typename LooseQuadtree<Number, Object, BoundingBoxExtractor>::Query::Impl>; - - void RecalculateMaximalDepth(); - void DeleteTree(); - Object** InsertIntoTree(Object* object); - typename Query::Impl* GetAvailableQueryFromPool(); - - detail::BlocksAllocator allocator_; - detail::TreeNode<Object>* root_; - BoundingBox<Number> bounding_box_; - ObjectPointerContainer object_pointers_; - int number_of_objects_; - int maximal_depth_; - detail::FullTreeTraversal<Number, Object> internal_traversal_; - QueryPoolContainer query_pool_; - int running_queries_; ///< queries which are opened and not at their end + friend class Query::Impl; + using ObjectPointerContainer = + std::unordered_map<Object*, Object**, + std::hash<Object*>, std::equal_to<Object*>, + detail::BlocksAllocatorAdaptor<std::pair<Object *const, Object**>>>; + using QueryPoolContainer = + std::deque<typename LooseQuadtree<Number, Object, BoundingBoxExtractor>::Query::Impl>; + + void RecalculateMaximalDepth(); + void DeleteTree(); + Object** InsertIntoTree(Object* object); + typename Query::Impl* GetAvailableQueryFromPool(); + + detail::BlocksAllocator allocator_; + detail::TreeNode<Object>* root_; + BoundingBox<Number> bounding_box_; + ObjectPointerContainer object_pointers_; + int number_of_objects_; + int maximal_depth_; + detail::FullTreeTraversal<Number, Object> internal_traversal_; + QueryPoolContainer query_pool_; + int running_queries_; ///< queries which are opened and not at their end }; @@ -507,1026 +507,1026 @@ private: template <typename NumberT> bool - BoundingBox<NumberT>:: + BoundingBox<NumberT>:: Intersects(const BoundingBox<Number>& other) const { - return !( - left + width <= other.left || other.left + other.width <= left || - top + height <= other.top || other.top + other.height <= top - ); + return !( + left + width <= other.left || other.left + other.width <= left || + top + height <= other.top || other.top + other.height <= top + ); } template <typename NumberT> bool - BoundingBox<NumberT>:: + BoundingBox<NumberT>:: Contains(const BoundingBox<Number>& other) const { - return left <= other.left && left + width >= other.left + other.width && - top <= other.top && top + height >= other.top + other.height; + return left <= other.left && left + width >= other.left + other.width && + top <= other.top && top + height >= other.top + other.height; } template <typename NumberT> bool - BoundingBox<NumberT>:: + BoundingBox<NumberT>:: Contains(Number x, Number y) const { - return left <= x && x < left + width && - top <= y && y < top + height; + return left <= x && x < left + width && + top <= y && y < top + height; } template <typename NumberT, typename ObjectT> - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: ForwardTreeTraversal() : - position_(BoundingBox<Number>(0, 0, 0, 0), nullptr), depth_(0) { + position_(BoundingBox<Number>(0, 0, 0, 0), nullptr), depth_(0) { } template <typename NumberT, typename ObjectT> void - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: StartAt(TreeNode<Object>* root, const BoundingBox<Number>& root_bounds) { - position_.bounding_box = root_bounds; - position_.node = root; - depth_ = 0; + position_.bounding_box = root_bounds; + position_.node = root; + depth_ = 0; } template <typename NumberT, typename ObjectT> int - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: GetDepth() const { - return depth_; + return depth_; } template <typename NumberT, typename ObjectT> detail::TreeNode<ObjectT>* - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: GetNode() const { - return position_.node; + return position_.node; } template <typename NumberT, typename ObjectT> const BoundingBox<NumberT>& - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: GetNodeBoundingBox() const { - return position_.bounding_box; + return position_.bounding_box; } template <typename NumberT, typename ObjectT> void - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: GoTopLeft() { - BoundingBox<Number>& bbox = position_.bounding_box; - bbox.width = (Number)((typename MakeDistance<Number>::Type)bbox.width / 2); - bbox.height = (Number)((typename MakeDistance<Number>::Type)bbox.height / 2); - position_.node = position_.node->top_left; - assert(position_.node != nullptr); - depth_++; + BoundingBox<Number>& bbox = position_.bounding_box; + bbox.width = (Number)((typename MakeDistance<Number>::Type)bbox.width / 2); + bbox.height = (Number)((typename MakeDistance<Number>::Type)bbox.height / 2); + position_.node = position_.node->top_left; + assert(position_.node != nullptr); + depth_++; } template <typename NumberT, typename ObjectT> void - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: GoTopRight() { - BoundingBox<Number>& bbox = position_.bounding_box; - Number right = (Number)(bbox.left + bbox.width); - bbox.left = (Number)(bbox.left + - (Number)((typename MakeDistance<Number>::Type)bbox.width / 2)); - bbox.width = (Number)(right - bbox.left); - bbox.height = (Number)((typename MakeDistance<Number>::Type)bbox.height / 2); - position_.node = position_.node->top_right; - assert(position_.node != nullptr); - depth_++; + BoundingBox<Number>& bbox = position_.bounding_box; + Number right = (Number)(bbox.left + bbox.width); + bbox.left = (Number)(bbox.left + + (Number)((typename MakeDistance<Number>::Type)bbox.width / 2)); + bbox.width = (Number)(right - bbox.left); + bbox.height = (Number)((typename MakeDistance<Number>::Type)bbox.height / 2); + position_.node = position_.node->top_right; + assert(position_.node != nullptr); + depth_++; } template <typename NumberT, typename ObjectT> void - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: GoBottomRight() { - BoundingBox<Number>& bbox = position_.bounding_box; - Number right = (Number)(bbox.left + bbox.width); - bbox.left = (Number)(bbox.left + - (Number)((typename MakeDistance<Number>::Type)bbox.width / 2)); - bbox.width = (Number)(right - bbox.left); - Number bottom = (Number)(bbox.top + bbox.height); - bbox.top = (Number)(bbox.top + - (Number)((typename MakeDistance<Number>::Type)bbox.height / 2)); - bbox.height = (Number)(bottom - bbox.top); - position_.node = position_.node->bottom_right; - assert(position_.node != nullptr); - depth_++; + BoundingBox<Number>& bbox = position_.bounding_box; + Number right = (Number)(bbox.left + bbox.width); + bbox.left = (Number)(bbox.left + + (Number)((typename MakeDistance<Number>::Type)bbox.width / 2)); + bbox.width = (Number)(right - bbox.left); + Number bottom = (Number)(bbox.top + bbox.height); + bbox.top = (Number)(bbox.top + + (Number)((typename MakeDistance<Number>::Type)bbox.height / 2)); + bbox.height = (Number)(bottom - bbox.top); + position_.node = position_.node->bottom_right; + assert(position_.node != nullptr); + depth_++; } template <typename NumberT, typename ObjectT> void - detail::ForwardTreeTraversal<NumberT, ObjectT>:: + detail::ForwardTreeTraversal<NumberT, ObjectT>:: GoBottomLeft() { - BoundingBox<Number>& bbox = position_.bounding_box; - bbox.width = (Number)((typename MakeDistance<Number>::Type)bbox.width / 2); - Number bottom = (Number)(bbox.top + bbox.height); - bbox.top = (Number)(bbox.top + - (Number)((typename MakeDistance<Number>::Type)bbox.height / 2)); - bbox.height = (Number)(bottom - bbox.top); - position_.node = position_.node->bottom_left; - assert(position_.node != nullptr); - depth_++; + BoundingBox<Number>& bbox = position_.bounding_box; + bbox.width = (Number)((typename MakeDistance<Number>::Type)bbox.width / 2); + Number bottom = (Number)(bbox.top + bbox.height); + bbox.top = (Number)(bbox.top + + (Number)((typename MakeDistance<Number>::Type)bbox.height / 2)); + bbox.height = (Number)(bottom - bbox.top); + position_.node = position_.node->bottom_left; + assert(position_.node != nullptr); + depth_++; } template <typename NumberT, typename ObjectT> void - detail::FullTreeTraversal<NumberT, ObjectT>:: + detail::FullTreeTraversal<NumberT, ObjectT>:: StartAt(TreeNode<Object>* root, const BoundingBox<Number>& root_bounds) { - ForwardTreeTraversal<Number, Object>::StartAt(root, root_bounds); - position_.current_child = ChildPosition::kNone; - position_stack_.clear(); + ForwardTreeTraversal<Number, Object>::StartAt(root, root_bounds); + position_.current_child = ChildPosition::kNone; + position_stack_.clear(); } template <typename NumberT, typename ObjectT> detail::ChildPosition - detail::FullTreeTraversal<NumberT, ObjectT>:: + detail::FullTreeTraversal<NumberT, ObjectT>:: GetNodeCurrentChild() const { - return position_.current_child; + return position_.current_child; } template <typename NumberT, typename ObjectT> void - detail::FullTreeTraversal<NumberT, ObjectT>:: + detail::FullTreeTraversal<NumberT, ObjectT>:: SetNodeCurrentChild(ChildPosition child_position) { - position_.current_child = child_position; + position_.current_child = child_position; } template <typename NumberT, typename ObjectT> void - detail::FullTreeTraversal<NumberT, ObjectT>:: + detail::FullTreeTraversal<NumberT, ObjectT>:: GoTopLeft() { - assert((size_t)depth_ == position_stack_.size()); - position_.current_child = ChildPosition::kTopLeft; - position_stack_.emplace_back(position_); - ForwardTreeTraversal<Number, Object>::GoTopLeft(); - position_.current_child = ChildPosition::kNone; + assert((size_t)depth_ == position_stack_.size()); + position_.current_child = ChildPosition::kTopLeft; + position_stack_.emplace_back(position_); + ForwardTreeTraversal<Number, Object>::GoTopLeft(); + position_.current_child = ChildPosition::kNone; } template <typename NumberT, typename ObjectT> void - detail::FullTreeTraversal<NumberT, ObjectT>:: + detail::FullTreeTraversal<NumberT, ObjectT>:: GoTopRight() { - assert((size_t)depth_ == position_stack_.size()); - position_.current_child = ChildPosition::kTopRight; - position_stack_.emplace_back(position_); - ForwardTreeTraversal<Number, Object>::GoTopRight(); - position_.current_child = ChildPosition::kNone; + assert((size_t)depth_ == position_stack_.size()); + position_.current_child = ChildPosition::kTopRight; + position_stack_.emplace_back(position_); + ForwardTreeTraversal<Number, Object>::GoTopRight(); + position_.current_child = ChildPosition::kNone; } template <typename NumberT, typename ObjectT> void - detail::FullTreeTraversal<NumberT, ObjectT>:: + detail::FullTreeTraversal<NumberT, ObjectT>:: GoBottomRight() { - assert((size_t)depth_ == position_stack_.size()); - position_.current_child = ChildPosition::kBottomRight; - position_stack_.emplace_back(position_); - ForwardTreeTraversal<Number, Object>::GoBottomRight(); - position_.current_child = ChildPosition::kNone; + assert((size_t)depth_ == position_stack_.size()); + position_.current_child = ChildPosition::kBottomRight; + position_stack_.emplace_back(position_); + ForwardTreeTraversal<Number, Object>::GoBottomRight(); + position_.current_child = ChildPosition::kNone; } template <typename NumberT, typename ObjectT> void - detail::FullTreeTraversal<NumberT, ObjectT>:: + detail::FullTreeTraversal<NumberT, ObjectT>:: GoBottomLeft() { - assert((size_t)depth_ == position_stack_.size()); - position_.current_child = ChildPosition::kBottomLeft; - position_stack_.emplace_back(position_); - ForwardTreeTraversal<Number, Object>::GoBottomLeft(); - position_.current_child = ChildPosition::kNone; + assert((size_t)depth_ == position_stack_.size()); + position_.current_child = ChildPosition::kBottomLeft; + position_stack_.emplace_back(position_); + ForwardTreeTraversal<Number, Object>::GoBottomLeft(); + position_.current_child = ChildPosition::kNone; } template <typename NumberT, typename ObjectT> void - detail::FullTreeTraversal<NumberT, ObjectT>:: + detail::FullTreeTraversal<NumberT, ObjectT>:: GoUp() { - assert((size_t)depth_ == position_stack_.size() && depth_ > 0); - position_ = position_stack_.back(); - depth_--; - position_stack_.pop_back(); + assert((size_t)depth_ == position_stack_.size() && depth_ > 0); + position_ = position_stack_.back(); + depth_--; + position_stack_.pop_back(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: Impl() : quadtree_(nullptr), query_region_(0,0,0,0), - query_type_(QueryType::kEndOfQuery), - free_ride_from_level_(LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl::kInternalMaxDepth) { + query_type_(QueryType::kEndOfQuery), + free_ride_from_level_(LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl::kInternalMaxDepth) { } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: Acquire(typename LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl* quadtree, - const BoundingBox<Number>* query_region, QueryType query_type) { - assert(IsAvailable()); - assert(query_type != QueryType::kEndOfQuery); - quadtree_ = quadtree; - query_region_ = *query_region; - query_type_ = query_type; - free_ride_from_level_ = - LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl::kInternalMaxDepth; - if (quadtree->root_ == nullptr) { - query_type_ = QueryType::kEndOfQuery; - } - else { - quadtree_->running_queries_++; - traversal_.StartAt(quadtree->root_, quadtree->bounding_box_); - object_iterator_ = traversal_.GetNode()->objects.before_begin(); - Next(); - } + const BoundingBox<Number>* query_region, QueryType query_type) { + assert(IsAvailable()); + assert(query_type != QueryType::kEndOfQuery); + quadtree_ = quadtree; + query_region_ = *query_region; + query_type_ = query_type; + free_ride_from_level_ = + LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl::kInternalMaxDepth; + if (quadtree->root_ == nullptr) { + query_type_ = QueryType::kEndOfQuery; + } + else { + quadtree_->running_queries_++; + traversal_.StartAt(quadtree->root_, quadtree->bounding_box_); + object_iterator_ = traversal_.GetNode()->objects.before_begin(); + Next(); + } } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: Release() { - assert(!IsAvailable()); - quadtree_ = nullptr; + assert(!IsAvailable()); + quadtree_ = nullptr; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: IsAvailable() const { - return quadtree_ == nullptr; + return quadtree_ == nullptr; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: EndOfQuery() const { - assert(!IsAvailable()); - return query_type_ == QueryType::kEndOfQuery; + assert(!IsAvailable()); + return query_type_ == QueryType::kEndOfQuery; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> ObjectT* - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: GetCurrent() const { - assert(!IsAvailable()); - assert(!EndOfQuery()); - return *object_iterator_; + assert(!IsAvailable()); + assert(!EndOfQuery()); + return *object_iterator_; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: Next() { - assert(!IsAvailable()); - assert(!EndOfQuery()); - do { - object_iterator_before_ = object_iterator_; - object_iterator_++; - if (object_iterator_ == traversal_.GetNode()->objects.end()) { - do { - switch (traversal_.GetNodeCurrentChild()) { - case detail::ChildPosition::kNone: - if (traversal_.GetNode()->top_left == nullptr) { - traversal_.SetNodeCurrentChild(detail::ChildPosition::kTopLeft); - continue; - } - else { - traversal_.GoTopLeft(); - } - break; - case detail::ChildPosition::kTopLeft: - if (traversal_.GetNode()->top_right == nullptr) { - traversal_.SetNodeCurrentChild(detail::ChildPosition::kTopRight); - continue; - } - else { - traversal_.GoTopRight(); - } - break; - case detail::ChildPosition::kTopRight: - if (traversal_.GetNode()->bottom_right == nullptr) { - traversal_.SetNodeCurrentChild(detail::ChildPosition::kBottomRight); - continue; - } - else { - traversal_.GoBottomRight(); - } - break; - case detail::ChildPosition::kBottomRight: - if (traversal_.GetNode()->bottom_left == nullptr) { - traversal_.SetNodeCurrentChild(detail::ChildPosition::kBottomLeft); - continue; - } - else { - traversal_.GoBottomLeft(); - } - break; - case detail::ChildPosition::kBottomLeft: + assert(!IsAvailable()); + assert(!EndOfQuery()); + do { + object_iterator_before_ = object_iterator_; + object_iterator_++; + if (object_iterator_ == traversal_.GetNode()->objects.end()) { + do { + switch (traversal_.GetNodeCurrentChild()) { + case detail::ChildPosition::kNone: + if (traversal_.GetNode()->top_left == nullptr) { + traversal_.SetNodeCurrentChild(detail::ChildPosition::kTopLeft); + continue; + } + else { + traversal_.GoTopLeft(); + } + break; + case detail::ChildPosition::kTopLeft: + if (traversal_.GetNode()->top_right == nullptr) { + traversal_.SetNodeCurrentChild(detail::ChildPosition::kTopRight); + continue; + } + else { + traversal_.GoTopRight(); + } + break; + case detail::ChildPosition::kTopRight: + if (traversal_.GetNode()->bottom_right == nullptr) { + traversal_.SetNodeCurrentChild(detail::ChildPosition::kBottomRight); + continue; + } + else { + traversal_.GoBottomRight(); + } + break; + case detail::ChildPosition::kBottomRight: + if (traversal_.GetNode()->bottom_left == nullptr) { + traversal_.SetNodeCurrentChild(detail::ChildPosition::kBottomLeft); + continue; + } + else { + traversal_.GoBottomLeft(); + } + break; + case detail::ChildPosition::kBottomLeft: #ifndef NDEBUG - int running_queries = 0; - for (auto& query : quadtree_->query_pool_) { - if (!query.IsAvailable() && !query.EndOfQuery()) running_queries++; - } - assert(running_queries == quadtree_->running_queries_); + int running_queries = 0; + for (auto& query : quadtree_->query_pool_) { + if (!query.IsAvailable() && !query.EndOfQuery()) running_queries++; + } + assert(running_queries == quadtree_->running_queries_); #endif - //only run this if no parallel queries are running - if (traversal_.GetDepth() > quadtree_->maximal_depth_ && - quadtree_->running_queries_ == 1) { - typename detail::TreeNode<Object>::ObjectContainer& objects = - traversal_.GetNode()->objects; - auto iterator = objects.begin(); - while (iterator != objects.end()) { - if (*iterator != nullptr) { - quadtree_->Update(*iterator); - assert(*iterator == nullptr); - } - iterator++; - } - objects.clear(); - } - - if (traversal_.GetDepth() > 0) { - bool remove_node = (traversal_.GetNode()->objects.empty() && - traversal_.GetNode()->top_left == nullptr && - traversal_.GetNode()->top_right == nullptr && - traversal_.GetNode()->bottom_right == nullptr && - traversal_.GetNode()->bottom_left == nullptr); - detail::TreeNode<Object>* node = traversal_.GetNode(); - traversal_.GoUp(); - - // if the node is empty no other queries can be invalidated by deleting - if (remove_node) { - switch (traversal_.GetNodeCurrentChild()) { - case detail::ChildPosition::kTopLeft: - traversal_.GetNode()->top_left = nullptr; - break; - case detail::ChildPosition::kTopRight: - traversal_.GetNode()->top_right = nullptr; - break; - case detail::ChildPosition::kBottomRight: - traversal_.GetNode()->bottom_right = nullptr; - break; - case detail::ChildPosition::kBottomLeft: - traversal_.GetNode()->bottom_left = nullptr; - break; - case detail::ChildPosition::kNone: - assert(false); - } - quadtree_->allocator_.Delete(node); - } - - if (free_ride_from_level_ == traversal_.GetDepth() + 1) { - free_ride_from_level_ = - LooseQuadtree<Number, Object, - BoundingBoxExtractor>::Impl::kInternalMaxDepth; - } - continue; - } - else { - // if the root is empty no other queries can be invalidated by deleting - if (traversal_.GetNode()->objects.empty() && - traversal_.GetNode()->top_left == nullptr && - traversal_.GetNode()->top_right == nullptr && - traversal_.GetNode()->bottom_right == nullptr && - traversal_.GetNode()->bottom_left == nullptr) { - assert(traversal_.GetNode() == quadtree_->root_); - assert(quadtree_->GetSize() == 0); - assert(quadtree_->object_pointers_.size() == 0); - quadtree_->allocator_.Delete(quadtree_->root_); - quadtree_->root_ = nullptr; - quadtree_->bounding_box_ = BoundingBox<Number>(0,0,0,0); - } - - quadtree_->running_queries_--; - query_type_ = QueryType::kEndOfQuery; - return; - } - break; - } - assert(traversal_.GetNodeCurrentChild() == detail::ChildPosition::kNone); - { - FitType fit = FitType::kPartialFit; - if (traversal_.GetDepth() >= free_ride_from_level_ || - (fit = CurrentNodeFits()) != FitType::kNoFit) { - if (fit == FitType::kFreeRide) { - free_ride_from_level_ = traversal_.GetDepth(); - } - } - else { - traversal_.SetNodeCurrentChild(detail::ChildPosition::kBottomLeft); - continue; - } - } - object_iterator_ = traversal_.GetNode()->objects.before_begin(); - break; - } while (true); - } - else if (*object_iterator_ == nullptr) { - // other queries also cannot stop on an empty object, - // so we are not invalidating any iterators/queries with this - traversal_.GetNode()->objects.erase_after(object_iterator_before_); - object_iterator_ = object_iterator_before_; - } - else { - if (traversal_.GetDepth() >= free_ride_from_level_ || - CurrentObjectFits()) { - break; - } - } - } while (true); + //only run this if no parallel queries are running + if (traversal_.GetDepth() > quadtree_->maximal_depth_ && + quadtree_->running_queries_ == 1) { + typename detail::TreeNode<Object>::ObjectContainer& objects = + traversal_.GetNode()->objects; + auto iterator = objects.begin(); + while (iterator != objects.end()) { + if (*iterator != nullptr) { + quadtree_->Update(*iterator); + assert(*iterator == nullptr); + } + iterator++; + } + objects.clear(); + } + + if (traversal_.GetDepth() > 0) { + bool remove_node = (traversal_.GetNode()->objects.empty() && + traversal_.GetNode()->top_left == nullptr && + traversal_.GetNode()->top_right == nullptr && + traversal_.GetNode()->bottom_right == nullptr && + traversal_.GetNode()->bottom_left == nullptr); + detail::TreeNode<Object>* node = traversal_.GetNode(); + traversal_.GoUp(); + + // if the node is empty no other queries can be invalidated by deleting + if (remove_node) { + switch (traversal_.GetNodeCurrentChild()) { + case detail::ChildPosition::kTopLeft: + traversal_.GetNode()->top_left = nullptr; + break; + case detail::ChildPosition::kTopRight: + traversal_.GetNode()->top_right = nullptr; + break; + case detail::ChildPosition::kBottomRight: + traversal_.GetNode()->bottom_right = nullptr; + break; + case detail::ChildPosition::kBottomLeft: + traversal_.GetNode()->bottom_left = nullptr; + break; + case detail::ChildPosition::kNone: + assert(false); + } + quadtree_->allocator_.Delete(node); + } + + if (free_ride_from_level_ == traversal_.GetDepth() + 1) { + free_ride_from_level_ = + LooseQuadtree<Number, Object, + BoundingBoxExtractor>::Impl::kInternalMaxDepth; + } + continue; + } + else { + // if the root is empty no other queries can be invalidated by deleting + if (traversal_.GetNode()->objects.empty() && + traversal_.GetNode()->top_left == nullptr && + traversal_.GetNode()->top_right == nullptr && + traversal_.GetNode()->bottom_right == nullptr && + traversal_.GetNode()->bottom_left == nullptr) { + assert(traversal_.GetNode() == quadtree_->root_); + assert(quadtree_->GetSize() == 0); + assert(quadtree_->object_pointers_.size() == 0); + quadtree_->allocator_.Delete(quadtree_->root_); + quadtree_->root_ = nullptr; + quadtree_->bounding_box_ = BoundingBox<Number>(0,0,0,0); + } + + quadtree_->running_queries_--; + query_type_ = QueryType::kEndOfQuery; + return; + } + break; + } + assert(traversal_.GetNodeCurrentChild() == detail::ChildPosition::kNone); + { + FitType fit = FitType::kPartialFit; + if (traversal_.GetDepth() >= free_ride_from_level_ || + (fit = CurrentNodeFits()) != FitType::kNoFit) { + if (fit == FitType::kFreeRide) { + free_ride_from_level_ = traversal_.GetDepth(); + } + } + else { + traversal_.SetNodeCurrentChild(detail::ChildPosition::kBottomLeft); + continue; + } + } + object_iterator_ = traversal_.GetNode()->objects.before_begin(); + break; + } while (true); + } + else if (*object_iterator_ == nullptr) { + // other queries also cannot stop on an empty object, + // so we are not invalidating any iterators/queries with this + traversal_.GetNode()->objects.erase_after(object_iterator_before_); + object_iterator_ = object_iterator_before_; + } + else { + if (traversal_.GetDepth() >= free_ride_from_level_ || + CurrentObjectFits()) { + break; + } + } + } while (true); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: CurrentObjectFits() const { - BoundingBox<Number> object_bounds(0,0,0,0); - BoundingBoxExtractor::ExtractBoundingBox(GetCurrent(), &object_bounds); - switch (query_type_) { - case QueryType::kIntersects: - return query_region_.Intersects(object_bounds); - case QueryType::kInside: - return query_region_.Contains(object_bounds); - case QueryType::kContains: - return object_bounds.Contains(query_region_); - case QueryType::kEndOfQuery: - assert(false); - } - return false; + BoundingBox<Number> object_bounds(0,0,0,0); + BoundingBoxExtractor::ExtractBoundingBox(GetCurrent(), &object_bounds); + switch (query_type_) { + case QueryType::kIntersects: + return query_region_.Intersects(object_bounds); + case QueryType::kInside: + return query_region_.Contains(object_bounds); + case QueryType::kContains: + return object_bounds.Contains(query_region_); + case QueryType::kEndOfQuery: + assert(false); + } + return false; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query::Impl:: CurrentNodeFits() const -> FitType { - const BoundingBox<Number>& node_bounds = traversal_.GetNodeBoundingBox(); - BoundingBox<Number> extended_bounds = node_bounds; - Number half_width = - (Number)((typename detail::MakeDistance<Number>::Type)node_bounds.width / 2); - Number half_height = - (Number)((typename detail::MakeDistance<Number>::Type)node_bounds.height / 2); - extended_bounds.width = (Number)(extended_bounds.width * 2); - extended_bounds.height = (Number)(extended_bounds.height * 2); - extended_bounds.left = (Number)(extended_bounds.left - half_width); - extended_bounds.top = (Number)(extended_bounds.top - half_height); - switch (query_type_) { - case QueryType::kIntersects: - if (!query_region_.Intersects(extended_bounds)) { - return FitType::kNoFit; - } - else if (query_region_.Contains(node_bounds)) { - return FitType::kFreeRide; - } - return FitType::kPartialFit; - case QueryType::kInside: - if (!query_region_.Intersects(node_bounds)) { - return FitType::kNoFit; - } - else if (query_region_.Contains(extended_bounds)) { - return FitType::kFreeRide; - } - return FitType::kPartialFit; - case QueryType::kContains: - if (!extended_bounds.Contains(query_region_)) { - return FitType::kNoFit; - } - return FitType::kPartialFit; - case QueryType::kEndOfQuery: - assert(false); - } - return FitType::kNoFit; + const BoundingBox<Number>& node_bounds = traversal_.GetNodeBoundingBox(); + BoundingBox<Number> extended_bounds = node_bounds; + Number half_width = + (Number)((typename detail::MakeDistance<Number>::Type)node_bounds.width / 2); + Number half_height = + (Number)((typename detail::MakeDistance<Number>::Type)node_bounds.height / 2); + extended_bounds.width = (Number)(extended_bounds.width * 2); + extended_bounds.height = (Number)(extended_bounds.height * 2); + extended_bounds.left = (Number)(extended_bounds.left - half_width); + extended_bounds.top = (Number)(extended_bounds.top - half_height); + switch (query_type_) { + case QueryType::kIntersects: + if (!query_region_.Intersects(extended_bounds)) { + return FitType::kNoFit; + } + else if (query_region_.Contains(node_bounds)) { + return FitType::kFreeRide; + } + return FitType::kPartialFit; + case QueryType::kInside: + if (!query_region_.Intersects(node_bounds)) { + return FitType::kNoFit; + } + else if (query_region_.Contains(extended_bounds)) { + return FitType::kFreeRide; + } + return FitType::kPartialFit; + case QueryType::kContains: + if (!extended_bounds.Contains(query_region_)) { + return FitType::kNoFit; + } + return FitType::kPartialFit; + case QueryType::kEndOfQuery: + assert(false); + } + return FitType::kNoFit; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: Impl() : - root_(nullptr), bounding_box_(0, 0, 0, 0), - object_pointers_(64, std::hash<Object*>(), std::equal_to<Object*>(), - detail::BlocksAllocatorAdaptor<std::pair<const Object*, Object**>>(allocator_)), - number_of_objects_(0), maximal_depth_(kInternalMinDepth), - running_queries_(0) { - assert(maximal_depth_ < kInternalMaxDepth); - //object_pointers_.reserve(64); + root_(nullptr), bounding_box_(0, 0, 0, 0), + object_pointers_(64, std::hash<Object*>(), std::equal_to<Object*>(), + detail::BlocksAllocatorAdaptor<std::pair<const Object*, Object**>>(allocator_)), + number_of_objects_(0), maximal_depth_(kInternalMinDepth), + running_queries_(0) { + assert(maximal_depth_ < kInternalMaxDepth); + //object_pointers_.reserve(64); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: ~Impl() { - DeleteTree(); + DeleteTree(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: Insert(Object* object) { - bool was_removed = Remove(object); - Object** place = InsertIntoTree(object); - object_pointers_.emplace(object, place); - number_of_objects_++; - RecalculateMaximalDepth(); - return !was_removed; + bool was_removed = Remove(object); + Object** place = InsertIntoTree(object); + object_pointers_.emplace(object, place); + number_of_objects_++; + RecalculateMaximalDepth(); + return !was_removed; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: Update(Object* object) { - return !Insert(object); + return !Insert(object); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: Remove(Object* object) { - auto it = object_pointers_.find(object); - if (it != object_pointers_.end()) { - assert(*(it->second) == it->first); - *(it->second) = nullptr; - object_pointers_.erase(it); - number_of_objects_--; - RecalculateMaximalDepth(); - return true; - } - return false; + auto it = object_pointers_.find(object); + if (it != object_pointers_.end()) { + assert(*(it->second) == it->first); + *(it->second) = nullptr; + object_pointers_.erase(it); + number_of_objects_--; + RecalculateMaximalDepth(); + return true; + } + return false; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: Contains(Object* object) const { - return object_pointers_.find(object) != object_pointers_.end(); + return object_pointers_.find(object) != object_pointers_.end(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: QueryIntersectsRegion(const BoundingBox<Number>& region) -> Query { - typename Query::Impl* query_impl = GetAvailableQueryFromPool(); - query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kIntersects); - return Query(query_impl); + typename Query::Impl* query_impl = GetAvailableQueryFromPool(); + query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kIntersects); + return Query(query_impl); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: QueryInsideRegion(const BoundingBox<Number>& region) -> Query { - typename Query::Impl* query_impl = GetAvailableQueryFromPool(); - query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kInside); - return Query(query_impl); + typename Query::Impl* query_impl = GetAvailableQueryFromPool(); + query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kInside); + return Query(query_impl); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: QueryContainsRegion(const BoundingBox<Number>& region) -> Query { - typename Query::Impl* query_impl = GetAvailableQueryFromPool(); - query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kContains); - return Query(query_impl); + typename Query::Impl* query_impl = GetAvailableQueryFromPool(); + query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kContains); + return Query(query_impl); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> const BoundingBox<NumberT>& - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: GetBoundingBox() const { - return bounding_box_; + return bounding_box_; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: ForceCleanup() { - Query query = QueryIntersectsRegion(bounding_box_); - while (!query.EndOfQuery()) { - query.Next(); - } - allocator_.ReleaseFreeBlocks(); + Query query = QueryIntersectsRegion(bounding_box_); + while (!query.EndOfQuery()) { + query.Next(); + } + allocator_.ReleaseFreeBlocks(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> int - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: GetSize() const { - return number_of_objects_; + return number_of_objects_; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: Clear() { - DeleteTree(); + DeleteTree(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: RecalculateMaximalDepth() { - do { - if (maximal_depth_ < kInternalMaxDepth && - number_of_objects_ > 1ll << (maximal_depth_ << 1)) { - maximal_depth_++; - } - else if (maximal_depth_ > kInternalMinDepth && - number_of_objects_ <= 1ll << ((maximal_depth_ - 1) << 1)) { - maximal_depth_--; - } - else { - break; - } - } while (true); + do { + if (maximal_depth_ < kInternalMaxDepth && + number_of_objects_ > 1ll << (maximal_depth_ << 1)) { + maximal_depth_++; + } + else if (maximal_depth_ > kInternalMinDepth && + number_of_objects_ <= 1ll << ((maximal_depth_ - 1) << 1)) { + maximal_depth_--; + } + else { + break; + } + } while (true); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: DeleteTree() { - object_pointers_.clear(); - detail::FullTreeTraversal<Number, Object>& trav = internal_traversal_; - trav.StartAt(root_, bounding_box_); - while (root_ != nullptr) { - assert(trav.GetDepth() >= 0 && trav.GetDepth() <= kInternalMaxDepth); - detail::TreeNode<Object>* node = trav.GetNode(); - if (node->top_left != nullptr) { - trav.GoTopLeft(); - } - else if (node->top_right != nullptr) { - trav.GoTopRight(); - } - else if (node->bottom_right != nullptr) { - trav.GoBottomRight(); - } - else if (node->bottom_left != nullptr) { - trav.GoBottomLeft(); - } - else { - if (trav.GetDepth() > 0) { - trav.GoUp(); - switch (trav.GetNodeCurrentChild()) { - case detail::ChildPosition::kNone: - assert(false); - break; - case detail::ChildPosition::kTopLeft: - assert(node == trav.GetNode()->top_left); - trav.GetNode()->top_left = nullptr; - break; - case detail::ChildPosition::kTopRight: - assert(node == trav.GetNode()->top_right); - trav.GetNode()->top_right = nullptr; - break; - case detail::ChildPosition::kBottomRight: - assert(node == trav.GetNode()->bottom_right); - trav.GetNode()->bottom_right = nullptr; - break; - case detail::ChildPosition::kBottomLeft: - assert(node == trav.GetNode()->bottom_left); - trav.GetNode()->bottom_left = nullptr; - break; - } - allocator_.Delete(node); - } - else { - assert(node == root_); - allocator_.Delete(root_); - root_ = nullptr; - } - } - } - - bounding_box_ = BoundingBox<Number>(0, 0, 0, 0); - number_of_objects_ = 0; - maximal_depth_ = kInternalMinDepth; + object_pointers_.clear(); + detail::FullTreeTraversal<Number, Object>& trav = internal_traversal_; + trav.StartAt(root_, bounding_box_); + while (root_ != nullptr) { + assert(trav.GetDepth() >= 0 && trav.GetDepth() <= kInternalMaxDepth); + detail::TreeNode<Object>* node = trav.GetNode(); + if (node->top_left != nullptr) { + trav.GoTopLeft(); + } + else if (node->top_right != nullptr) { + trav.GoTopRight(); + } + else if (node->bottom_right != nullptr) { + trav.GoBottomRight(); + } + else if (node->bottom_left != nullptr) { + trav.GoBottomLeft(); + } + else { + if (trav.GetDepth() > 0) { + trav.GoUp(); + switch (trav.GetNodeCurrentChild()) { + case detail::ChildPosition::kNone: + assert(false); + break; + case detail::ChildPosition::kTopLeft: + assert(node == trav.GetNode()->top_left); + trav.GetNode()->top_left = nullptr; + break; + case detail::ChildPosition::kTopRight: + assert(node == trav.GetNode()->top_right); + trav.GetNode()->top_right = nullptr; + break; + case detail::ChildPosition::kBottomRight: + assert(node == trav.GetNode()->bottom_right); + trav.GetNode()->bottom_right = nullptr; + break; + case detail::ChildPosition::kBottomLeft: + assert(node == trav.GetNode()->bottom_left); + trav.GetNode()->bottom_left = nullptr; + break; + } + allocator_.Delete(node); + } + else { + assert(node == root_); + allocator_.Delete(root_); + root_ = nullptr; + } + } + } + + bounding_box_ = BoundingBox<Number>(0, 0, 0, 0); + number_of_objects_ = 0; + maximal_depth_ = kInternalMinDepth; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> ObjectT** - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: InsertIntoTree(Object* object) { - BoundingBox<Number> object_bounds(0,0,0,0); - BoundingBoxExtractor::ExtractBoundingBox(object, &object_bounds); - assert(object_bounds.width >= 0); - assert(object_bounds.height >= 0); - assert(object_bounds.left <= object_bounds.left + object_bounds.width); - assert(object_bounds.top <= object_bounds.top + object_bounds.height); - Number maximal_object_extent = object_bounds.width >= object_bounds.height ? - object_bounds.width : object_bounds.height; - if (maximal_object_extent < kMinimalObjectExtent) { - maximal_object_extent = kMinimalObjectExtent; - } - Number object_center_x = (Number)(object_bounds.left + - (Number)((typename detail::MakeDistance<Number>::Type)object_bounds.width / 2)); - Number object_center_y = (Number)(object_bounds.top + - (Number)((typename detail::MakeDistance<Number>::Type)object_bounds.height / 2)); - - if (root_ != nullptr) { - assert(number_of_objects_ >= 0); - assert(bounding_box_.width > 0); - assert(bounding_box_.width == bounding_box_.height); - - int depth_increase = 0; - while (!bounding_box_.Contains(object_center_x, object_center_y) || - maximal_object_extent > bounding_box_.width) { - Number previous_size = bounding_box_.width; - bounding_box_.width = (Number)(bounding_box_.width * 2); - bounding_box_.height = bounding_box_.width; - Number previous_half = - (Number)((typename detail::MakeDistance<Number>::Type)previous_size / 2); - Number bb_center_x = (Number)(bounding_box_.left + previous_half); - Number bb_center_y = (Number)(bounding_box_.top + previous_half); - detail::TreeNode<Object>* old_root = root_; - root_ = allocator_.New<detail::TreeNode<Object>>(allocator_); - if (object_center_x <= bb_center_x) { - bounding_box_.left = (Number)(bounding_box_.left - previous_size); - if (object_center_y <= bb_center_y) { - bounding_box_.top = (Number)(bounding_box_.top - previous_size); - root_->bottom_right = old_root; - } - else { - root_->top_right = old_root; - } - } - else { - if (object_center_y <= bb_center_y) { - bounding_box_.top = (Number)(bounding_box_.top - previous_size); - root_->bottom_left = old_root; - } - else { - root_->top_left = old_root; - } - } - depth_increase++; - assert(depth_increase < kInternalMaxDepth); - (void)depth_increase; - assert(bounding_box_.left < bounding_box_.left + bounding_box_.width); - assert(bounding_box_.top < bounding_box_.top + bounding_box_.height); - // If this happens with integral types you are close to get out of bounds - // The bounding box of things should be at least 1/8 of the total interval spanned - assert(!std::is_integral<Number>::value || - bounding_box_.width < std::numeric_limits<Number>::max() / 8 * 7); - assert(!std::is_integral<Number>::value || - bounding_box_.height < std::numeric_limits<Number>::max() / 8 * 7); - } - - detail::ForwardTreeTraversal<Number, Object> trav; - trav.StartAt(root_, bounding_box_); - do { - const BoundingBox<Number>& node_bounds = trav.GetNodeBoundingBox(); - assert(node_bounds.Contains(object_center_x, object_center_y)); - Number maximal_bb_extent = - node_bounds.width >= node_bounds.height ? - node_bounds.width : node_bounds.height; - Number half_bb_extent = - (Number)((typename detail::MakeDistance<Number>::Type)maximal_bb_extent / 2); - assert(maximal_object_extent <= maximal_bb_extent); - - if (maximal_object_extent > half_bb_extent || - trav.GetDepth() >= maximal_depth_) { - break; - } - - Number node_center_x = (Number)(node_bounds.left + - (Number)((typename detail::MakeDistance<Number>::Type)node_bounds.width / 2)); - Number node_center_y = (Number)(node_bounds.top + - (Number)((typename detail::MakeDistance<Number>::Type)node_bounds.height / 2)); - - detail::TreeNode<Object>** direction; - if (object_center_x < node_center_x) { - if (object_center_y < node_center_y) { - direction = &trav.GetNode()->top_left; - } - else { - direction = &trav.GetNode()->bottom_left; - } - } - else { - if (object_center_y < node_center_y) { - direction = &trav.GetNode()->top_right; - } - else { - direction = &trav.GetNode()->bottom_right; - } - } - - if (*direction == nullptr) { - *direction = allocator_.New<detail::TreeNode<Object>>(allocator_); - } - - if (*direction == trav.GetNode()->top_left) { - trav.GoTopLeft(); - } - else if (*direction == trav.GetNode()->top_right) { - trav.GoTopRight(); - } - else if (*direction == trav.GetNode()->bottom_right) { - trav.GoBottomRight(); - } - else { - assert(*direction == trav.GetNode()->bottom_left); - trav.GoBottomLeft(); - } - } while (true); + BoundingBox<Number> object_bounds(0,0,0,0); + BoundingBoxExtractor::ExtractBoundingBox(object, &object_bounds); + assert(object_bounds.width >= 0); + assert(object_bounds.height >= 0); + assert(object_bounds.left <= object_bounds.left + object_bounds.width); + assert(object_bounds.top <= object_bounds.top + object_bounds.height); + Number maximal_object_extent = object_bounds.width >= object_bounds.height ? + object_bounds.width : object_bounds.height; + if (maximal_object_extent < kMinimalObjectExtent) { + maximal_object_extent = kMinimalObjectExtent; + } + Number object_center_x = (Number)(object_bounds.left + + (Number)((typename detail::MakeDistance<Number>::Type)object_bounds.width / 2)); + Number object_center_y = (Number)(object_bounds.top + + (Number)((typename detail::MakeDistance<Number>::Type)object_bounds.height / 2)); + + if (root_ != nullptr) { + assert(number_of_objects_ >= 0); + assert(bounding_box_.width > 0); + assert(bounding_box_.width == bounding_box_.height); + + int depth_increase = 0; + while (!bounding_box_.Contains(object_center_x, object_center_y) || + maximal_object_extent > bounding_box_.width) { + Number previous_size = bounding_box_.width; + bounding_box_.width = (Number)(bounding_box_.width * 2); + bounding_box_.height = bounding_box_.width; + Number previous_half = + (Number)((typename detail::MakeDistance<Number>::Type)previous_size / 2); + Number bb_center_x = (Number)(bounding_box_.left + previous_half); + Number bb_center_y = (Number)(bounding_box_.top + previous_half); + detail::TreeNode<Object>* old_root = root_; + root_ = allocator_.New<detail::TreeNode<Object>>(allocator_); + if (object_center_x <= bb_center_x) { + bounding_box_.left = (Number)(bounding_box_.left - previous_size); + if (object_center_y <= bb_center_y) { + bounding_box_.top = (Number)(bounding_box_.top - previous_size); + root_->bottom_right = old_root; + } + else { + root_->top_right = old_root; + } + } + else { + if (object_center_y <= bb_center_y) { + bounding_box_.top = (Number)(bounding_box_.top - previous_size); + root_->bottom_left = old_root; + } + else { + root_->top_left = old_root; + } + } + depth_increase++; + assert(depth_increase < kInternalMaxDepth); + (void)depth_increase; + assert(bounding_box_.left < bounding_box_.left + bounding_box_.width); + assert(bounding_box_.top < bounding_box_.top + bounding_box_.height); + // If this happens with integral types you are close to get out of bounds + // The bounding box of things should be at least 1/8 of the total interval spanned + assert(!std::is_integral<Number>::value || + bounding_box_.width < std::numeric_limits<Number>::max() / 8 * 7); + assert(!std::is_integral<Number>::value || + bounding_box_.height < std::numeric_limits<Number>::max() / 8 * 7); + } + + detail::ForwardTreeTraversal<Number, Object> trav; + trav.StartAt(root_, bounding_box_); + do { + const BoundingBox<Number>& node_bounds = trav.GetNodeBoundingBox(); + assert(node_bounds.Contains(object_center_x, object_center_y)); + Number maximal_bb_extent = + node_bounds.width >= node_bounds.height ? + node_bounds.width : node_bounds.height; + Number half_bb_extent = + (Number)((typename detail::MakeDistance<Number>::Type)maximal_bb_extent / 2); + assert(maximal_object_extent <= maximal_bb_extent); + + if (maximal_object_extent > half_bb_extent || + trav.GetDepth() >= maximal_depth_) { + break; + } + + Number node_center_x = (Number)(node_bounds.left + + (Number)((typename detail::MakeDistance<Number>::Type)node_bounds.width / 2)); + Number node_center_y = (Number)(node_bounds.top + + (Number)((typename detail::MakeDistance<Number>::Type)node_bounds.height / 2)); + + detail::TreeNode<Object>** direction; + if (object_center_x < node_center_x) { + if (object_center_y < node_center_y) { + direction = &trav.GetNode()->top_left; + } + else { + direction = &trav.GetNode()->bottom_left; + } + } + else { + if (object_center_y < node_center_y) { + direction = &trav.GetNode()->top_right; + } + else { + direction = &trav.GetNode()->bottom_right; + } + } + + if (*direction == nullptr) { + *direction = allocator_.New<detail::TreeNode<Object>>(allocator_); + } + + if (*direction == trav.GetNode()->top_left) { + trav.GoTopLeft(); + } + else if (*direction == trav.GetNode()->top_right) { + trav.GoTopRight(); + } + else if (*direction == trav.GetNode()->bottom_right) { + trav.GoBottomRight(); + } + else { + assert(*direction == trav.GetNode()->bottom_left); + trav.GoBottomLeft(); + } + } while (true); #ifndef NDEBUG - BoundingBox<Number> effective_bounds = trav.GetNodeBoundingBox(); - Number half_width = - (Number)((typename detail::MakeDistance<Number>::Type)effective_bounds.width / 2); - Number half_height = - (Number)((typename detail::MakeDistance<Number>::Type)effective_bounds.height / 2); - effective_bounds.width = (Number)(effective_bounds.width * 2); - effective_bounds.height = (Number)(effective_bounds.height * 2); - effective_bounds.left = (Number)(effective_bounds.left - half_width); - effective_bounds.top = (Number)(effective_bounds.top - half_height); - assert(effective_bounds.Contains(object_bounds)); + BoundingBox<Number> effective_bounds = trav.GetNodeBoundingBox(); + Number half_width = + (Number)((typename detail::MakeDistance<Number>::Type)effective_bounds.width / 2); + Number half_height = + (Number)((typename detail::MakeDistance<Number>::Type)effective_bounds.height / 2); + effective_bounds.width = (Number)(effective_bounds.width * 2); + effective_bounds.height = (Number)(effective_bounds.height * 2); + effective_bounds.left = (Number)(effective_bounds.left - half_width); + effective_bounds.top = (Number)(effective_bounds.top - half_height); + assert(effective_bounds.Contains(object_bounds)); #endif - typename detail::TreeNode<Object>::ObjectContainer& objects = - trav.GetNode()->objects; - if (!objects.empty() && objects.front() == nullptr) { - objects.front() = object; - } - else { - objects.emplace_front(object); - } - return &objects.front(); - } - else { - assert(number_of_objects_ == 0); - { - bounding_box_.width = - (Number)((typename detail::MakeDistance<Number>::Type)maximal_object_extent * 2 * 7 / 8); - bounding_box_.height = bounding_box_.width; - Number extent_half = - (Number)((typename detail::MakeDistance<Number>::Type)bounding_box_.width / 2); - bounding_box_.left = (Number)(object_center_x - extent_half); - bounding_box_.top = (Number)(object_center_y - extent_half); - assert(bounding_box_.left < bounding_box_.left + bounding_box_.width); - assert(bounding_box_.top < bounding_box_.top + bounding_box_.height); - } - root_ = allocator_.New<detail::TreeNode<Object>>(allocator_); - root_->objects.emplace_front(object); - return &root_->objects.front(); - } + typename detail::TreeNode<Object>::ObjectContainer& objects = + trav.GetNode()->objects; + if (!objects.empty() && objects.front() == nullptr) { + objects.front() = object; + } + else { + objects.emplace_front(object); + } + return &objects.front(); + } + else { + assert(number_of_objects_ == 0); + { + bounding_box_.width = + (Number)((typename detail::MakeDistance<Number>::Type)maximal_object_extent * 2 * 7 / 8); + bounding_box_.height = bounding_box_.width; + Number extent_half = + (Number)((typename detail::MakeDistance<Number>::Type)bounding_box_.width / 2); + bounding_box_.left = (Number)(object_center_x - extent_half); + bounding_box_.top = (Number)(object_center_y - extent_half); + assert(bounding_box_.left < bounding_box_.left + bounding_box_.width); + assert(bounding_box_.top < bounding_box_.top + bounding_box_.height); + } + root_ = allocator_.New<detail::TreeNode<Object>>(allocator_); + root_->objects.emplace_front(object); + return &root_->objects.front(); + } } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Impl:: GetAvailableQueryFromPool() -> typename Query::Impl* { - for (auto it = query_pool_.begin(); it != query_pool_.end(); it++) { - if (it->IsAvailable()) { - return &*it; - } - } - query_pool_.emplace_back(); - assert(query_pool_.back().IsAvailable()); - return &query_pool_.back(); + for (auto it = query_pool_.begin(); it != query_pool_.end(); it++) { + if (it->IsAvailable()) { + return &*it; + } + } + query_pool_.emplace_back(); + assert(query_pool_.back().IsAvailable()); + return &query_pool_.back(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: Insert(Object* object) { - return impl_.Insert(object); + return impl_.Insert(object); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: Update(Object* object) { - return impl_.Update(object); + return impl_.Update(object); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: Remove(Object* object) { - return impl_.Remove(object); + return impl_.Remove(object); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: Contains(Object* object) const { - return impl_.Contains(object); + return impl_.Contains(object); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: QueryIntersectsRegion(const BoundingBox<Number>& region) -> Query { - return impl_.QueryIntersectsRegion(region); + return impl_.QueryIntersectsRegion(region); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: QueryInsideRegion(const BoundingBox<Number>& region) -> Query { - return impl_.QueryInsideRegion(region); + return impl_.QueryInsideRegion(region); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: QueryContainsRegion(const BoundingBox<Number>& region) -> Query { - return impl_.QueryContainsRegion(region); + return impl_.QueryContainsRegion(region); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> const BoundingBox<NumberT>& - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: GetLooseBoundingBox() const { - return impl_.GetBoundingBox(); + return impl_.GetBoundingBox(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: ForceCleanup() { - impl_.ForceCleanup(); + impl_.ForceCleanup(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> int - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: GetSize() const { - return impl_.GetSize(); + return impl_.GetSize(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: IsEmpty() const { - return impl_.GetSize() == 0; + return impl_.GetSize() == 0; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>:: Clear() { - impl_.Clear(); + impl_.Clear(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: Query(Impl* pimpl) : pimpl_(pimpl) { - assert(pimpl_ != nullptr); - assert(!pimpl_->IsAvailable()); + assert(pimpl_ != nullptr); + assert(!pimpl_->IsAvailable()); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: ~Query() { - if (pimpl_ != nullptr) { - pimpl_->Release(); - assert(pimpl_->IsAvailable()); - pimpl_ = nullptr; - } + if (pimpl_ != nullptr) { + pimpl_->Release(); + assert(pimpl_->IsAvailable()); + pimpl_ = nullptr; + } } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: Query(Query&& other) noexcept : pimpl_(other.pimpl_) { - other.pimpl_ = nullptr; + other.pimpl_ = nullptr; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> auto - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: operator=(Query&& other) noexcept -> Query& { - this->~Query(); - pimpl_ = other.pimpl_; - other.pimpl_ = nullptr; - return *this; + this->~Query(); + pimpl_ = other.pimpl_; + other.pimpl_ = nullptr; + return *this; } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> bool - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: EndOfQuery() const { - return pimpl_->EndOfQuery(); + return pimpl_->EndOfQuery(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> ObjectT* - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: GetCurrent() const { - return pimpl_->GetCurrent(); + return pimpl_->GetCurrent(); } template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> void - LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: + LooseQuadtree<NumberT, ObjectT, BoundingBoxExtractorT>::Query:: Next() { - pimpl_->Next(); + pimpl_->Next(); } diff --git a/compat/LooseQuadtree.h b/compat/LooseQuadtree.h index 90ad0aee..95ebc13f 100644 --- a/compat/LooseQuadtree.h +++ b/compat/LooseQuadtree.h @@ -38,18 +38,18 @@ namespace loose_quadtree { template <typename NumberT> struct BoundingBox { - using Number = NumberT; - - BoundingBox(Number _left, Number _top, Number _width, Number _height) : - left(_left), top(_top), width(_width), height(_height) {} - bool Intersects(const BoundingBox<Number>& other) const ; - bool Contains(const BoundingBox<Number>& other) const; - bool Contains(Number x, Number y) const; - - Number left; - Number top; - Number width; - Number height; + using Number = NumberT; + + BoundingBox(Number _left, Number _top, Number _width, Number _height) : + left(_left), top(_top), width(_width), height(_height) {} + bool Intersects(const BoundingBox<Number>& other) const ; + bool Contains(const BoundingBox<Number>& other) const; + bool Contains(Number x, Number y) const; + + Number left; + Number top; + Number width; + Number height; }; @@ -57,56 +57,56 @@ struct BoundingBox { template <typename NumberT, typename ObjectT, typename BoundingBoxExtractorT> class LooseQuadtree { public: - using Number = NumberT; - using Object = ObjectT; - using BoundingBoxExtractor = BoundingBoxExtractorT; + using Number = NumberT; + using Object = ObjectT; + using BoundingBoxExtractor = BoundingBoxExtractorT; private: - class Impl; + class Impl; public: - class Query { - public: - ~Query(); - Query() = delete; - Query(const Query&) = delete; - Query& operator=(const Query&) = delete; - Query(Query&&) noexcept; - Query& operator=(Query&&) noexcept; - - bool EndOfQuery() const; - Object* GetCurrent() const; - void Next(); - - private: - friend class LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl; - class Impl; - Query(Impl* pimpl); - Impl* pimpl_; - }; - - LooseQuadtree() = default; - ~LooseQuadtree() = default; - LooseQuadtree(const LooseQuadtree&) = delete; - LooseQuadtree& operator=(const LooseQuadtree&) = delete; - - bool Insert(Object* object); ///< true if it was inserted (else updated) - bool Update(Object* object); ///< true if it was updated (else inserted) - bool Remove(Object* object); ///< true if it was removed - bool Contains(Object* object) const; ///< true if object is in tree - Query QueryIntersectsRegion(const BoundingBox<Number>& region); - Query QueryInsideRegion(const BoundingBox<Number>& region); - Query QueryContainsRegion(const BoundingBox<Number>& region); - const BoundingBox<Number>& GetLooseBoundingBox() const; - ///< double its size to get a bounding box including everything contained for sure - int GetSize() const; - bool IsEmpty() const; - void Clear(); - void ForceCleanup(); ///< does a full data structure and memory cleanup - ///< cleanup is semi-automatic during queries so you needn't call this normally + class Query { + public: + ~Query(); + Query() = delete; + Query(const Query&) = delete; + Query& operator=(const Query&) = delete; + Query(Query&&) noexcept; + Query& operator=(Query&&) noexcept; + + bool EndOfQuery() const; + Object* GetCurrent() const; + void Next(); + + private: + friend class LooseQuadtree<Number, Object, BoundingBoxExtractor>::Impl; + class Impl; + Query(Impl* pimpl); + Impl* pimpl_; + }; + + LooseQuadtree() = default; + ~LooseQuadtree() = default; + LooseQuadtree(const LooseQuadtree&) = delete; + LooseQuadtree& operator=(const LooseQuadtree&) = delete; + + bool Insert(Object* object); ///< true if it was inserted (else updated) + bool Update(Object* object); ///< true if it was updated (else inserted) + bool Remove(Object* object); ///< true if it was removed + bool Contains(Object* object) const; ///< true if object is in tree + Query QueryIntersectsRegion(const BoundingBox<Number>& region); + Query QueryInsideRegion(const BoundingBox<Number>& region); + Query QueryContainsRegion(const BoundingBox<Number>& region); + const BoundingBox<Number>& GetLooseBoundingBox() const; + ///< double its size to get a bounding box including everything contained for sure + int GetSize() const; + bool IsEmpty() const; + void Clear(); + void ForceCleanup(); ///< does a full data structure and memory cleanup + ///< cleanup is semi-automatic during queries so you needn't call this normally private: - Impl impl_; + Impl impl_; }; diff --git a/test/quadtree.cpp b/test/quadtree.cpp index 615ab695..5f9d9074 100644 --- a/test/quadtree.cpp +++ b/test/quadtree.cpp @@ -24,572 +24,572 @@ namespace { template <typename NumberT> class TrivialBBExtractor { public: - static void ExtractBoundingBox(const BoundingBox<NumberT> *object, BoundingBox<NumberT> *bbox) { - bbox->left = object->left; - bbox->top = object->top; - bbox->width = object->width; - bbox->height = object->height; - } + static void ExtractBoundingBox(const BoundingBox<NumberT> *object, BoundingBox<NumberT> *bbox) { + bbox->left = object->left; + bbox->top = object->top; + bbox->width = object->width; + bbox->height = object->height; + } }; template <typename NumberT> void TestBoundingBox() { - BoundingBox<NumberT> big(100, 100, 200, 50); - BoundingBox<NumberT> small_inside(200, 125, 5, 5); - BoundingBox<NumberT> edge_inside(110, 110, 190, 40); - BoundingBox<NumberT> edge_outside(300, 150, 20, 5); - BoundingBox<NumberT> intersecting1(290, 90, 29, 25); - BoundingBox<NumberT> intersecting2(290, 110, 29, 25); - BoundingBox<NumberT> outside(290, 210, 29, 25); - - ASSERT(big.Contains(100, 100)); - ASSERT(!big.Contains(300, 150)); - - ASSERT(big.Contains(big)); - ASSERT(big.Contains(small_inside)); - ASSERT(!small_inside.Contains(big)); - ASSERT(big.Contains(edge_inside)); - ASSERT(!edge_inside.Contains(big)); - ASSERT(!big.Contains(edge_outside)); - ASSERT(!edge_outside.Contains(big)); - ASSERT(!big.Contains(intersecting1)); - ASSERT(!intersecting1.Contains(big)); - ASSERT(!big.Contains(intersecting2)); - ASSERT(!intersecting1.Contains(big)); - ASSERT(!intersecting1.Contains(intersecting2)); - ASSERT(!big.Contains(outside)); - ASSERT(!outside.Contains(big)); - - ASSERT(big.Intersects(big)); - ASSERT(big.Intersects(small_inside)); - ASSERT(small_inside.Intersects(big)); - ASSERT(big.Intersects(edge_inside)); - ASSERT(edge_inside.Intersects(big)); - ASSERT(!big.Intersects(edge_outside)); - ASSERT(!edge_outside.Intersects(big)); - ASSERT(big.Intersects(intersecting1)); - ASSERT(intersecting1.Intersects(big)); - ASSERT(big.Intersects(intersecting2)); - ASSERT(intersecting2.Intersects(big)); - ASSERT(intersecting1.Intersects(intersecting2)); - ASSERT(!big.Intersects(outside)); - ASSERT(!outside.Intersects(big)); + BoundingBox<NumberT> big(100, 100, 200, 50); + BoundingBox<NumberT> small_inside(200, 125, 5, 5); + BoundingBox<NumberT> edge_inside(110, 110, 190, 40); + BoundingBox<NumberT> edge_outside(300, 150, 20, 5); + BoundingBox<NumberT> intersecting1(290, 90, 29, 25); + BoundingBox<NumberT> intersecting2(290, 110, 29, 25); + BoundingBox<NumberT> outside(290, 210, 29, 25); + + ASSERT(big.Contains(100, 100)); + ASSERT(!big.Contains(300, 150)); + + ASSERT(big.Contains(big)); + ASSERT(big.Contains(small_inside)); + ASSERT(!small_inside.Contains(big)); + ASSERT(big.Contains(edge_inside)); + ASSERT(!edge_inside.Contains(big)); + ASSERT(!big.Contains(edge_outside)); + ASSERT(!edge_outside.Contains(big)); + ASSERT(!big.Contains(intersecting1)); + ASSERT(!intersecting1.Contains(big)); + ASSERT(!big.Contains(intersecting2)); + ASSERT(!intersecting1.Contains(big)); + ASSERT(!intersecting1.Contains(intersecting2)); + ASSERT(!big.Contains(outside)); + ASSERT(!outside.Contains(big)); + + ASSERT(big.Intersects(big)); + ASSERT(big.Intersects(small_inside)); + ASSERT(small_inside.Intersects(big)); + ASSERT(big.Intersects(edge_inside)); + ASSERT(edge_inside.Intersects(big)); + ASSERT(!big.Intersects(edge_outside)); + ASSERT(!edge_outside.Intersects(big)); + ASSERT(big.Intersects(intersecting1)); + ASSERT(intersecting1.Intersects(big)); + ASSERT(big.Intersects(intersecting2)); + ASSERT(intersecting2.Intersects(big)); + ASSERT(intersecting1.Intersects(intersecting2)); + ASSERT(!big.Intersects(outside)); + ASSERT(!outside.Intersects(big)); } template <typename NumberT> void TestForwardTreeTraversal() { - detail::BlocksAllocator allocator; - detail::ForwardTreeTraversal<NumberT, BoundingBox<NumberT>> fortt; - detail::TreeNode<BoundingBox<NumberT>> root(allocator); - detail::TreeNode<BoundingBox<NumberT>> tl(allocator); - detail::TreeNode<BoundingBox<NumberT>> tr(allocator); - detail::TreeNode<BoundingBox<NumberT>> br(allocator); - detail::TreeNode<BoundingBox<NumberT>> bl(allocator); - root.top_left = &tl; - tl.top_right = &tr; - tr.bottom_right = &br; - root.bottom_left = &bl; - fortt.StartAt(&root, BoundingBox<NumberT>(0, 0, 64, 64)); - ASSERT(fortt.GetDepth() == 0); - ASSERT(fortt.GetNode() == &root); - ASSERT(fortt.GetNodeBoundingBox().left == 0); - ASSERT(fortt.GetNodeBoundingBox().top == 0); - ASSERT(fortt.GetNodeBoundingBox().width == 64); - ASSERT(fortt.GetNodeBoundingBox().height == 64); - fortt.GoTopLeft(); - ASSERT(fortt.GetDepth() == 1); - ASSERT(fortt.GetNode() == &tl); - ASSERT(fortt.GetNodeBoundingBox().left == 0); - ASSERT(fortt.GetNodeBoundingBox().top == 0); - ASSERT(fortt.GetNodeBoundingBox().width == 32); - ASSERT(fortt.GetNodeBoundingBox().height == 32); - fortt.GoTopRight(); - ASSERT(fortt.GetDepth() == 2); - ASSERT(fortt.GetNode() == &tr); - ASSERT(fortt.GetNodeBoundingBox().left == 16); - ASSERT(fortt.GetNodeBoundingBox().top == 0); - ASSERT(fortt.GetNodeBoundingBox().width == 16); - ASSERT(fortt.GetNodeBoundingBox().height == 16); - fortt.GoBottomRight(); - ASSERT(fortt.GetDepth() == 3); - ASSERT(fortt.GetNode() == &br); - ASSERT(fortt.GetNodeBoundingBox().left == 24); - ASSERT(fortt.GetNodeBoundingBox().top == 8); - ASSERT(fortt.GetNodeBoundingBox().width == 8); - ASSERT(fortt.GetNodeBoundingBox().height == 8); - fortt.StartAt(&root, BoundingBox<NumberT>(0, 0, 64, 64)); - ASSERT(fortt.GetDepth() == 0); - ASSERT(fortt.GetNode() == &root); - ASSERT(fortt.GetNodeBoundingBox().left == 0); - ASSERT(fortt.GetNodeBoundingBox().top == 0); - ASSERT(fortt.GetNodeBoundingBox().width == 64); - ASSERT(fortt.GetNodeBoundingBox().height == 64); - fortt.GoBottomLeft(); - ASSERT(fortt.GetDepth() == 1); - ASSERT(fortt.GetNode() == &bl); - ASSERT(fortt.GetNodeBoundingBox().left == 0); - ASSERT(fortt.GetNodeBoundingBox().top == 32); - ASSERT(fortt.GetNodeBoundingBox().width == 32); - ASSERT(fortt.GetNodeBoundingBox().height == 32); + detail::BlocksAllocator allocator; + detail::ForwardTreeTraversal<NumberT, BoundingBox<NumberT>> fortt; + detail::TreeNode<BoundingBox<NumberT>> root(allocator); + detail::TreeNode<BoundingBox<NumberT>> tl(allocator); + detail::TreeNode<BoundingBox<NumberT>> tr(allocator); + detail::TreeNode<BoundingBox<NumberT>> br(allocator); + detail::TreeNode<BoundingBox<NumberT>> bl(allocator); + root.top_left = &tl; + tl.top_right = &tr; + tr.bottom_right = &br; + root.bottom_left = &bl; + fortt.StartAt(&root, BoundingBox<NumberT>(0, 0, 64, 64)); + ASSERT(fortt.GetDepth() == 0); + ASSERT(fortt.GetNode() == &root); + ASSERT(fortt.GetNodeBoundingBox().left == 0); + ASSERT(fortt.GetNodeBoundingBox().top == 0); + ASSERT(fortt.GetNodeBoundingBox().width == 64); + ASSERT(fortt.GetNodeBoundingBox().height == 64); + fortt.GoTopLeft(); + ASSERT(fortt.GetDepth() == 1); + ASSERT(fortt.GetNode() == &tl); + ASSERT(fortt.GetNodeBoundingBox().left == 0); + ASSERT(fortt.GetNodeBoundingBox().top == 0); + ASSERT(fortt.GetNodeBoundingBox().width == 32); + ASSERT(fortt.GetNodeBoundingBox().height == 32); + fortt.GoTopRight(); + ASSERT(fortt.GetDepth() == 2); + ASSERT(fortt.GetNode() == &tr); + ASSERT(fortt.GetNodeBoundingBox().left == 16); + ASSERT(fortt.GetNodeBoundingBox().top == 0); + ASSERT(fortt.GetNodeBoundingBox().width == 16); + ASSERT(fortt.GetNodeBoundingBox().height == 16); + fortt.GoBottomRight(); + ASSERT(fortt.GetDepth() == 3); + ASSERT(fortt.GetNode() == &br); + ASSERT(fortt.GetNodeBoundingBox().left == 24); + ASSERT(fortt.GetNodeBoundingBox().top == 8); + ASSERT(fortt.GetNodeBoundingBox().width == 8); + ASSERT(fortt.GetNodeBoundingBox().height == 8); + fortt.StartAt(&root, BoundingBox<NumberT>(0, 0, 64, 64)); + ASSERT(fortt.GetDepth() == 0); + ASSERT(fortt.GetNode() == &root); + ASSERT(fortt.GetNodeBoundingBox().left == 0); + ASSERT(fortt.GetNodeBoundingBox().top == 0); + ASSERT(fortt.GetNodeBoundingBox().width == 64); + ASSERT(fortt.GetNodeBoundingBox().height == 64); + fortt.GoBottomLeft(); + ASSERT(fortt.GetDepth() == 1); + ASSERT(fortt.GetNode() == &bl); + ASSERT(fortt.GetNodeBoundingBox().left == 0); + ASSERT(fortt.GetNodeBoundingBox().top == 32); + ASSERT(fortt.GetNodeBoundingBox().width == 32); + ASSERT(fortt.GetNodeBoundingBox().height == 32); } template <typename NumberT> void TestFullTreeTraversal() { - detail::BlocksAllocator allocator; - detail::FullTreeTraversal<NumberT, BoundingBox<NumberT>> fultt; - detail::TreeNode<BoundingBox<NumberT>> root(allocator); - detail::TreeNode<BoundingBox<NumberT>> tl(allocator); - detail::TreeNode<BoundingBox<NumberT>> tr(allocator); - detail::TreeNode<BoundingBox<NumberT>> br(allocator); - detail::TreeNode<BoundingBox<NumberT>> bl(allocator); - root.top_left = &tl; - tl.top_right = &tr; - tr.bottom_right = &br; - br.bottom_left = &bl; - fultt.StartAt(&root, BoundingBox<NumberT>(0, 0, 64, 64)); - ASSERT(fultt.GetDepth() == 0); - ASSERT(fultt.GetNode() == &root); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); - fultt.GoTopLeft(); - ASSERT(fultt.GetDepth() == 1); - ASSERT(fultt.GetNode() == &tl); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); - fultt.GoTopRight(); - ASSERT(fultt.GetDepth() == 2); - ASSERT(fultt.GetNode() == &tr); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); - fultt.GoBottomRight(); - ASSERT(fultt.GetDepth() == 3); - ASSERT(fultt.GetNode() == &br); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); - fultt.GoBottomLeft(); - ASSERT(fultt.GetDepth() == 4); - ASSERT(fultt.GetNode() == &bl); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); - fultt.GoUp(); - ASSERT(fultt.GetDepth() == 3); - ASSERT(fultt.GetNode() == &br); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kBottomLeft); - fultt.GoUp(); - ASSERT(fultt.GetDepth() == 2); - ASSERT(fultt.GetNode() == &tr); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kBottomRight); - fultt.GoUp(); - ASSERT(fultt.GetDepth() == 1); - ASSERT(fultt.GetNode() == &tl); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kTopRight); - fultt.GoUp(); - ASSERT(fultt.GetDepth() == 0); - ASSERT(fultt.GetNode() == &root); - ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kTopLeft); + detail::BlocksAllocator allocator; + detail::FullTreeTraversal<NumberT, BoundingBox<NumberT>> fultt; + detail::TreeNode<BoundingBox<NumberT>> root(allocator); + detail::TreeNode<BoundingBox<NumberT>> tl(allocator); + detail::TreeNode<BoundingBox<NumberT>> tr(allocator); + detail::TreeNode<BoundingBox<NumberT>> br(allocator); + detail::TreeNode<BoundingBox<NumberT>> bl(allocator); + root.top_left = &tl; + tl.top_right = &tr; + tr.bottom_right = &br; + br.bottom_left = &bl; + fultt.StartAt(&root, BoundingBox<NumberT>(0, 0, 64, 64)); + ASSERT(fultt.GetDepth() == 0); + ASSERT(fultt.GetNode() == &root); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); + fultt.GoTopLeft(); + ASSERT(fultt.GetDepth() == 1); + ASSERT(fultt.GetNode() == &tl); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); + fultt.GoTopRight(); + ASSERT(fultt.GetDepth() == 2); + ASSERT(fultt.GetNode() == &tr); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); + fultt.GoBottomRight(); + ASSERT(fultt.GetDepth() == 3); + ASSERT(fultt.GetNode() == &br); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); + fultt.GoBottomLeft(); + ASSERT(fultt.GetDepth() == 4); + ASSERT(fultt.GetNode() == &bl); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kNone); + fultt.GoUp(); + ASSERT(fultt.GetDepth() == 3); + ASSERT(fultt.GetNode() == &br); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kBottomLeft); + fultt.GoUp(); + ASSERT(fultt.GetDepth() == 2); + ASSERT(fultt.GetNode() == &tr); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kBottomRight); + fultt.GoUp(); + ASSERT(fultt.GetDepth() == 1); + ASSERT(fultt.GetNode() == &tl); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kTopRight); + fultt.GoUp(); + ASSERT(fultt.GetDepth() == 0); + ASSERT(fultt.GetNode() == &root); + ASSERT(fultt.GetNodeCurrentChild() == detail::ChildPosition::kTopLeft); } template <typename NumberT> void TestBoundingBoxDiscrepancy() { - detail::BlocksAllocator allocator; - detail::FullTreeTraversal<NumberT, BoundingBox<NumberT>> ftt; - detail::TreeNode<BoundingBox<NumberT>> root(allocator); - detail::TreeNode<BoundingBox<NumberT>> tl(allocator); - detail::TreeNode<BoundingBox<NumberT>> tr(allocator); - detail::TreeNode<BoundingBox<NumberT>> br(allocator); - root.top_left = &tl; - root.top_right = &tr; - root.bottom_right = &br; - ftt.StartAt(&root, BoundingBox<NumberT>(10, 10, 17, 19)); - NumberT orig_width = ftt.GetNodeBoundingBox().width; - NumberT orig_height = ftt.GetNodeBoundingBox().height; - ftt.GoTopLeft(); - NumberT tl_width = ftt.GetNodeBoundingBox().width; - NumberT tl_height = ftt.GetNodeBoundingBox().height; - ftt.GoUp(); - ftt.GoTopRight(); - NumberT tr_width = ftt.GetNodeBoundingBox().width; - NumberT tr_height = ftt.GetNodeBoundingBox().height; - ftt.GoUp(); - ftt.GoBottomRight(); - NumberT br_width = ftt.GetNodeBoundingBox().width; - NumberT br_height = ftt.GetNodeBoundingBox().height; - ftt.GoUp(); - ASSERT(orig_width == tl_width + tr_width); - ASSERT(orig_height == tl_height + br_height); - ASSERT(tr_width == br_width); - ASSERT(tl_height == tr_height); + detail::BlocksAllocator allocator; + detail::FullTreeTraversal<NumberT, BoundingBox<NumberT>> ftt; + detail::TreeNode<BoundingBox<NumberT>> root(allocator); + detail::TreeNode<BoundingBox<NumberT>> tl(allocator); + detail::TreeNode<BoundingBox<NumberT>> tr(allocator); + detail::TreeNode<BoundingBox<NumberT>> br(allocator); + root.top_left = &tl; + root.top_right = &tr; + root.bottom_right = &br; + ftt.StartAt(&root, BoundingBox<NumberT>(10, 10, 17, 19)); + NumberT orig_width = ftt.GetNodeBoundingBox().width; + NumberT orig_height = ftt.GetNodeBoundingBox().height; + ftt.GoTopLeft(); + NumberT tl_width = ftt.GetNodeBoundingBox().width; + NumberT tl_height = ftt.GetNodeBoundingBox().height; + ftt.GoUp(); + ftt.GoTopRight(); + NumberT tr_width = ftt.GetNodeBoundingBox().width; + NumberT tr_height = ftt.GetNodeBoundingBox().height; + ftt.GoUp(); + ftt.GoBottomRight(); + NumberT br_width = ftt.GetNodeBoundingBox().width; + NumberT br_height = ftt.GetNodeBoundingBox().height; + ftt.GoUp(); + ASSERT(orig_width == tl_width + tr_width); + ASSERT(orig_height == tl_height + br_height); + ASSERT(tr_width == br_width); + ASSERT(tl_height == tr_height); } template <typename NumberT> void TestTraversals() { - TestForwardTreeTraversal<NumberT>(); - TestFullTreeTraversal<NumberT>(); - TestBoundingBoxDiscrepancy<NumberT>(); + TestForwardTreeTraversal<NumberT>(); + TestFullTreeTraversal<NumberT>(); + TestBoundingBoxDiscrepancy<NumberT>(); } template <typename NumberT> void TestInsertRemove(bool reclaim_losses) { - std::vector<BoundingBox<NumberT>> objects; - objects.emplace_back(1000, 1300, 50, 30); - objects.emplace_back(1060, 1300, 50, 30); - objects.emplace_back(1060, 1300, 5, 3); - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; - if (reclaim_losses) lqt.ForceCleanup(); - ASSERT(lqt.GetSize() == 0); - ASSERT(lqt.IsEmpty()); - ASSERT(!lqt.Contains(&objects[0])); - ASSERT(lqt.GetSize() == 0); - lqt.Insert(&objects[0]); - ASSERT(lqt.GetSize() == 1); - ASSERT(!lqt.IsEmpty()); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(!lqt.Contains(&objects[1])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); - ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); - lqt.Remove(&objects[0]); - ASSERT(!lqt.Contains(&objects[0])); - ASSERT(lqt.GetSize() == 0); - ASSERT(lqt.IsEmpty()); - if (reclaim_losses) lqt.ForceCleanup(); - - lqt.Insert(&objects[1]); - ASSERT(lqt.GetSize() == 1); - ASSERT(!lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - lqt.Insert(&objects[0]); - lqt.Insert(&objects[0]); - lqt.Insert(&objects[0]); - ASSERT(lqt.GetSize() == 2); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - ASSERT(!lqt.Contains(&objects[2])); - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Insert(&objects[2]); - ASSERT(lqt.GetSize() == 3); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - ASSERT(lqt.Contains(&objects[2])); - if (reclaim_losses) lqt.ForceCleanup(); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); - ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); - ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); - ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); - lqt.Remove(&objects[1]); - lqt.Remove(&objects[1]); - lqt.Remove(&objects[1]); - ASSERT(lqt.GetSize() == 2); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(!lqt.Contains(&objects[1])); - ASSERT(lqt.Contains(&objects[2])); - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Remove(&objects[0]); - ASSERT(lqt.GetSize() == 1); - ASSERT(!lqt.Contains(&objects[0])); - ASSERT(!lqt.Contains(&objects[1])); - ASSERT(lqt.Contains(&objects[2])); - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Remove(&objects[0]); - ASSERT(lqt.GetSize() == 1); - ASSERT(!lqt.Contains(&objects[0])); - ASSERT(!lqt.Contains(&objects[1])); - ASSERT(lqt.Contains(&objects[2])); - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Remove(&objects[2]); - ASSERT(lqt.GetSize() == 0); - ASSERT(!lqt.Contains(&objects[0])); - ASSERT(!lqt.Contains(&objects[1])); - ASSERT(!lqt.Contains(&objects[2])); - if (reclaim_losses) lqt.ForceCleanup(); + std::vector<BoundingBox<NumberT>> objects; + objects.emplace_back(1000, 1300, 50, 30); + objects.emplace_back(1060, 1300, 50, 30); + objects.emplace_back(1060, 1300, 5, 3); + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; + if (reclaim_losses) lqt.ForceCleanup(); + ASSERT(lqt.GetSize() == 0); + ASSERT(lqt.IsEmpty()); + ASSERT(!lqt.Contains(&objects[0])); + ASSERT(lqt.GetSize() == 0); + lqt.Insert(&objects[0]); + ASSERT(lqt.GetSize() == 1); + ASSERT(!lqt.IsEmpty()); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(!lqt.Contains(&objects[1])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); + ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); + lqt.Remove(&objects[0]); + ASSERT(!lqt.Contains(&objects[0])); + ASSERT(lqt.GetSize() == 0); + ASSERT(lqt.IsEmpty()); + if (reclaim_losses) lqt.ForceCleanup(); + + lqt.Insert(&objects[1]); + ASSERT(lqt.GetSize() == 1); + ASSERT(!lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + lqt.Insert(&objects[0]); + lqt.Insert(&objects[0]); + lqt.Insert(&objects[0]); + ASSERT(lqt.GetSize() == 2); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + ASSERT(!lqt.Contains(&objects[2])); + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Insert(&objects[2]); + ASSERT(lqt.GetSize() == 3); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + ASSERT(lqt.Contains(&objects[2])); + if (reclaim_losses) lqt.ForceCleanup(); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); + ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); + ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); + ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); + lqt.Remove(&objects[1]); + lqt.Remove(&objects[1]); + lqt.Remove(&objects[1]); + ASSERT(lqt.GetSize() == 2); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(!lqt.Contains(&objects[1])); + ASSERT(lqt.Contains(&objects[2])); + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Remove(&objects[0]); + ASSERT(lqt.GetSize() == 1); + ASSERT(!lqt.Contains(&objects[0])); + ASSERT(!lqt.Contains(&objects[1])); + ASSERT(lqt.Contains(&objects[2])); + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Remove(&objects[0]); + ASSERT(lqt.GetSize() == 1); + ASSERT(!lqt.Contains(&objects[0])); + ASSERT(!lqt.Contains(&objects[1])); + ASSERT(lqt.Contains(&objects[2])); + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Remove(&objects[2]); + ASSERT(lqt.GetSize() == 0); + ASSERT(!lqt.Contains(&objects[0])); + ASSERT(!lqt.Contains(&objects[1])); + ASSERT(!lqt.Contains(&objects[2])); + if (reclaim_losses) lqt.ForceCleanup(); } template <typename NumberT> void TestUpdate(bool reclaim_losses) { - std::vector<BoundingBox<NumberT>> objects; - objects.emplace_back(1000, 1000, 50, 30); - objects.emplace_back(1060, 1000, 50, 30); - objects.emplace_back(1060, 1000, 5, 3); - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Insert(&objects[0]); - lqt.Insert(&objects[1]); - lqt.Insert(&objects[2]); - if (reclaim_losses) lqt.ForceCleanup(); - ASSERT(lqt.GetSize() == 3); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - ASSERT(lqt.Contains(&objects[2])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); - ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); - objects[2].width = 50; - objects[2].height = 30; - lqt.Update(&objects[2]); - objects[0].left = 1060; - lqt.Update(&objects[0]); - ASSERT(lqt.GetSize() == 3); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - ASSERT(lqt.Contains(&objects[2])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); - ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); - if (reclaim_losses) lqt.ForceCleanup(); - ASSERT(lqt.GetSize() == 3); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - ASSERT(lqt.Contains(&objects[2])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); - ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); - lqt.Remove(&objects[0]); - ASSERT(lqt.GetSize() == 2); - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Remove(&objects[1]); - ASSERT(lqt.GetSize() == 1); - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Remove(&objects[2]); - ASSERT(lqt.GetSize() == 0); - if (reclaim_losses) lqt.ForceCleanup(); + std::vector<BoundingBox<NumberT>> objects; + objects.emplace_back(1000, 1000, 50, 30); + objects.emplace_back(1060, 1000, 50, 30); + objects.emplace_back(1060, 1000, 5, 3); + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Insert(&objects[0]); + lqt.Insert(&objects[1]); + lqt.Insert(&objects[2]); + if (reclaim_losses) lqt.ForceCleanup(); + ASSERT(lqt.GetSize() == 3); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + ASSERT(lqt.Contains(&objects[2])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); + ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); + objects[2].width = 50; + objects[2].height = 30; + lqt.Update(&objects[2]); + objects[0].left = 1060; + lqt.Update(&objects[0]); + ASSERT(lqt.GetSize() == 3); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + ASSERT(lqt.Contains(&objects[2])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); + ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); + if (reclaim_losses) lqt.ForceCleanup(); + ASSERT(lqt.GetSize() == 3); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + ASSERT(lqt.Contains(&objects[2])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); + ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); + lqt.Remove(&objects[0]); + ASSERT(lqt.GetSize() == 2); + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Remove(&objects[1]); + ASSERT(lqt.GetSize() == 1); + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Remove(&objects[2]); + ASSERT(lqt.GetSize() == 0); + if (reclaim_losses) lqt.ForceCleanup(); } template <typename NumberT> void TestMoreTrees(bool reclaim_losses) { - std::vector<BoundingBox<NumberT>> objects; - objects.emplace_back(1000, 1000, 50, 30); - objects.emplace_back(1060, 1000, 50, 30); - objects.emplace_back(1060, 1000, 5, 3); - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Insert(&objects[0]); - lqt.Insert(&objects[1]); - ASSERT(lqt.GetSize() == 2); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); - ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); - if (reclaim_losses) lqt.ForceCleanup(); - { - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt2; - if (reclaim_losses) lqt2.ForceCleanup(); - ASSERT(lqt2.GetSize() == 0); - lqt2.Insert(&objects[1]); - lqt2.Insert(&objects[2]); - lqt.Insert(&objects[2]); - if (reclaim_losses) lqt.ForceCleanup(); - ASSERT(lqt2.GetSize() == 2); - ASSERT(!lqt2.Contains(&objects[0])); - ASSERT(lqt2.Contains(&objects[1])); - ASSERT(lqt2.Contains(&objects[2])); - if (reclaim_losses) lqt2.ForceCleanup(); - lqt2.Remove(&objects[1]); - lqt2.Remove(&objects[2]); - ASSERT(lqt2.GetSize() == 0); - if (reclaim_losses) lqt2.ForceCleanup(); - } - { - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt2; - lqt2.Insert(&objects[1]); - if (reclaim_losses) lqt2.ForceCleanup(); - } - { - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt2; - lqt2.Insert(&objects[1]); - lqt2.Insert(&objects[2]); - lqt2.Insert(&objects[0]); - ASSERT(lqt2.Contains(&objects[1])); - lqt2.Clear(); - ASSERT(lqt2.GetSize() == 0); - ASSERT(!lqt2.Contains(&objects[1])); - if (reclaim_losses) lqt2.ForceCleanup(); - ASSERT(lqt2.GetSize() == 0); - ASSERT(!lqt2.Contains(&objects[1])); - lqt2.Insert(&objects[1]); - ASSERT(lqt2.GetSize() == 1); - ASSERT(lqt2.Contains(&objects[1])); - } - ASSERT(lqt.GetSize() == 3); - ASSERT(lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - ASSERT(lqt.Contains(&objects[2])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); - ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); - ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); - ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); - lqt.Remove(&objects[0]); - lqt.Remove(&objects[2]); - ASSERT(!lqt.Contains(&objects[0])); - ASSERT(lqt.Contains(&objects[1])); - ASSERT(lqt.GetSize() == 1); - if (reclaim_losses) lqt.ForceCleanup(); - lqt.Remove(&objects[1]); - ASSERT(lqt.GetSize() == 0); - if (reclaim_losses) lqt.ForceCleanup(); + std::vector<BoundingBox<NumberT>> objects; + objects.emplace_back(1000, 1000, 50, 30); + objects.emplace_back(1060, 1000, 50, 30); + objects.emplace_back(1060, 1000, 5, 3); + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Insert(&objects[0]); + lqt.Insert(&objects[1]); + ASSERT(lqt.GetSize() == 2); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); + ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); + if (reclaim_losses) lqt.ForceCleanup(); + { + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt2; + if (reclaim_losses) lqt2.ForceCleanup(); + ASSERT(lqt2.GetSize() == 0); + lqt2.Insert(&objects[1]); + lqt2.Insert(&objects[2]); + lqt.Insert(&objects[2]); + if (reclaim_losses) lqt.ForceCleanup(); + ASSERT(lqt2.GetSize() == 2); + ASSERT(!lqt2.Contains(&objects[0])); + ASSERT(lqt2.Contains(&objects[1])); + ASSERT(lqt2.Contains(&objects[2])); + if (reclaim_losses) lqt2.ForceCleanup(); + lqt2.Remove(&objects[1]); + lqt2.Remove(&objects[2]); + ASSERT(lqt2.GetSize() == 0); + if (reclaim_losses) lqt2.ForceCleanup(); + } + { + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt2; + lqt2.Insert(&objects[1]); + if (reclaim_losses) lqt2.ForceCleanup(); + } + { + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt2; + lqt2.Insert(&objects[1]); + lqt2.Insert(&objects[2]); + lqt2.Insert(&objects[0]); + ASSERT(lqt2.Contains(&objects[1])); + lqt2.Clear(); + ASSERT(lqt2.GetSize() == 0); + ASSERT(!lqt2.Contains(&objects[1])); + if (reclaim_losses) lqt2.ForceCleanup(); + ASSERT(lqt2.GetSize() == 0); + ASSERT(!lqt2.Contains(&objects[1])); + lqt2.Insert(&objects[1]); + ASSERT(lqt2.GetSize() == 1); + ASSERT(lqt2.Contains(&objects[1])); + } + ASSERT(lqt.GetSize() == 3); + ASSERT(lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + ASSERT(lqt.Contains(&objects[2])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[0])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[1])); + ASSERT(lqt.GetLooseBoundingBox().Intersects(objects[2])); + ASSERT(!objects[0].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[1].Contains(lqt.GetLooseBoundingBox())); + ASSERT(!objects[2].Contains(lqt.GetLooseBoundingBox())); + lqt.Remove(&objects[0]); + lqt.Remove(&objects[2]); + ASSERT(!lqt.Contains(&objects[0])); + ASSERT(lqt.Contains(&objects[1])); + ASSERT(lqt.GetSize() == 1); + if (reclaim_losses) lqt.ForceCleanup(); + lqt.Remove(&objects[1]); + ASSERT(lqt.GetSize() == 0); + if (reclaim_losses) lqt.ForceCleanup(); } template <typename NumberT> void TestContainer() { - TestInsertRemove<NumberT>(false); - TestInsertRemove<NumberT>(true); - TestUpdate<NumberT>(false); - TestUpdate<NumberT>(true); - TestMoreTrees<NumberT>(false); - TestMoreTrees<NumberT>(true); + TestInsertRemove<NumberT>(false); + TestInsertRemove<NumberT>(true); + TestUpdate<NumberT>(false); + TestUpdate<NumberT>(true); + TestMoreTrees<NumberT>(false); + TestMoreTrees<NumberT>(true); } template <typename NumberT> void TestQueryIntersects(const std::vector<BoundingBox<NumberT>>& objects, - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>>& lqt) { - auto query = lqt.QueryIntersectsRegion(BoundingBox<NumberT>(33,33,1,1)); - ASSERT(query.EndOfQuery()); - - query = lqt.QueryIntersectsRegion(BoundingBox<NumberT>(9000,9000,9000,9000)); - int count = 0; - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - (void)obj; - count++; - query.Next(); - } - ASSERT(count == 7); - - query = lqt.QueryIntersectsRegion(BoundingBox<NumberT>(10003,10003,3,7)); - count = 0; - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - if (obj != &objects[0] && obj != &objects[1] && obj != &objects[2]) { - ASSERT(false); - } - count++; - query.Next(); - } - ASSERT(count == 3); - - query = lqt.QueryIntersectsRegion(BoundingBox<NumberT>(14900,14900,200,200)); - count = 0; - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - if (obj != &objects[0] && obj != &objects[1] && obj != &objects[3] && obj != &objects[5]) { - ASSERT(false); - } - count++; - query.Next(); - } - ASSERT(count == 4); + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>>& lqt) { + auto query = lqt.QueryIntersectsRegion(BoundingBox<NumberT>(33,33,1,1)); + ASSERT(query.EndOfQuery()); + + query = lqt.QueryIntersectsRegion(BoundingBox<NumberT>(9000,9000,9000,9000)); + int count = 0; + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + (void)obj; + count++; + query.Next(); + } + ASSERT(count == 7); + + query = lqt.QueryIntersectsRegion(BoundingBox<NumberT>(10003,10003,3,7)); + count = 0; + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + if (obj != &objects[0] && obj != &objects[1] && obj != &objects[2]) { + ASSERT(false); + } + count++; + query.Next(); + } + ASSERT(count == 3); + + query = lqt.QueryIntersectsRegion(BoundingBox<NumberT>(14900,14900,200,200)); + count = 0; + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + if (obj != &objects[0] && obj != &objects[1] && obj != &objects[3] && obj != &objects[5]) { + ASSERT(false); + } + count++; + query.Next(); + } + ASSERT(count == 4); } template <typename NumberT> void TestQueryInside(const std::vector<BoundingBox<NumberT>>& objects, - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>>& lqt) { - auto query = lqt.QueryInsideRegion(BoundingBox<NumberT>(33,33,1,1)); - ASSERT(query.EndOfQuery()); - - query = lqt.QueryInsideRegion(BoundingBox<NumberT>(9000,9000,9000,9000)); - int count = 0; - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - (void)obj; - count++; - query.Next(); - } - ASSERT(count == 7); - - query = lqt.QueryInsideRegion(BoundingBox<NumberT>(10003,10003,3,7)); - ASSERT(query.EndOfQuery()); - - query = lqt.QueryInsideRegion(BoundingBox<NumberT>(14900,14900,300,300)); - count = 0; - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - if (obj != &objects[5] && obj != &objects[6]) { - ASSERT(false); - } - count++; - query.Next(); - } - ASSERT(count == 2); + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>>& lqt) { + auto query = lqt.QueryInsideRegion(BoundingBox<NumberT>(33,33,1,1)); + ASSERT(query.EndOfQuery()); + + query = lqt.QueryInsideRegion(BoundingBox<NumberT>(9000,9000,9000,9000)); + int count = 0; + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + (void)obj; + count++; + query.Next(); + } + ASSERT(count == 7); + + query = lqt.QueryInsideRegion(BoundingBox<NumberT>(10003,10003,3,7)); + ASSERT(query.EndOfQuery()); + + query = lqt.QueryInsideRegion(BoundingBox<NumberT>(14900,14900,300,300)); + count = 0; + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + if (obj != &objects[5] && obj != &objects[6]) { + ASSERT(false); + } + count++; + query.Next(); + } + ASSERT(count == 2); } template <typename NumberT> void TestQueryContains(const std::vector<BoundingBox<NumberT>>& objects, - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>>& lqt) { - auto query = lqt.QueryContainsRegion(BoundingBox<NumberT>(33,33,1,1)); - ASSERT(query.EndOfQuery()); - - query = lqt.QueryContainsRegion(BoundingBox<NumberT>(9000,9000,9000,9000)); - ASSERT(query.EndOfQuery()); - - query = lqt.QueryContainsRegion(BoundingBox<NumberT>(10003,10003,3,7)); - int count = 0; - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - if (obj != &objects[0] && obj != &objects[1]) { - ASSERT(false); - } - count++; - query.Next(); - } - ASSERT(count == 2); - - query = lqt.QueryContainsRegion(BoundingBox<NumberT>(14900,14900,200,200)); - count = 0; - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - if (obj != &objects[0] && obj != &objects[1]) { - ASSERT(false); - } - count++; - query.Next(); - } - ASSERT(count == 2); - - query = lqt.QueryContainsRegion(BoundingBox<NumberT>(15000,15000,2,2)); - count = 0; - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - if (obj != &objects[0] && obj != &objects[1] && obj != &objects[3] && obj != &objects[5]) { - ASSERT(false); - } - count++; - query.Next(); - } - ASSERT(count == 4); + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>>& lqt) { + auto query = lqt.QueryContainsRegion(BoundingBox<NumberT>(33,33,1,1)); + ASSERT(query.EndOfQuery()); + + query = lqt.QueryContainsRegion(BoundingBox<NumberT>(9000,9000,9000,9000)); + ASSERT(query.EndOfQuery()); + + query = lqt.QueryContainsRegion(BoundingBox<NumberT>(10003,10003,3,7)); + int count = 0; + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + if (obj != &objects[0] && obj != &objects[1]) { + ASSERT(false); + } + count++; + query.Next(); + } + ASSERT(count == 2); + + query = lqt.QueryContainsRegion(BoundingBox<NumberT>(14900,14900,200,200)); + count = 0; + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + if (obj != &objects[0] && obj != &objects[1]) { + ASSERT(false); + } + count++; + query.Next(); + } + ASSERT(count == 2); + + query = lqt.QueryContainsRegion(BoundingBox<NumberT>(15000,15000,2,2)); + count = 0; + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + if (obj != &objects[0] && obj != &objects[1] && obj != &objects[3] && obj != &objects[5]) { + ASSERT(false); + } + count++; + query.Next(); + } + ASSERT(count == 4); } template <typename NumberT> void TestQueries() { - std::vector<BoundingBox<NumberT>> objects; - objects.emplace_back(10000, 10000, 8000, 8000);//0 - objects.emplace_back(10000, 10000, 7000, 6000);//1 - objects.emplace_back(10000, 10000, 7, 6);//2 - objects.emplace_back(15000, 15000, 500, 600);//3 - objects.emplace_back(15100, 15100, 200, 200);//4 - objects.emplace_back(15000, 15000, 200, 200);//5 - objects.emplace_back(15100, 15100, 2, 2);//6 - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; - for (auto& obj : objects) { - lqt.Insert(&obj); - } - TestQueryIntersects<NumberT>(objects, lqt); - TestQueryInside<NumberT>(objects, lqt); - TestQueryContains<NumberT>(objects, lqt); + std::vector<BoundingBox<NumberT>> objects; + objects.emplace_back(10000, 10000, 8000, 8000);//0 + objects.emplace_back(10000, 10000, 7000, 6000);//1 + objects.emplace_back(10000, 10000, 7, 6);//2 + objects.emplace_back(15000, 15000, 500, 600);//3 + objects.emplace_back(15100, 15100, 200, 200);//4 + objects.emplace_back(15000, 15000, 200, 200);//5 + objects.emplace_back(15100, 15100, 2, 2);//6 + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; + for (auto& obj : objects) { + lqt.Insert(&obj); + } + TestQueryIntersects<NumberT>(objects, lqt); + TestQueryInside<NumberT>(objects, lqt); + TestQueryContains<NumberT>(objects, lqt); } @@ -597,122 +597,122 @@ void TestQueries() { template <typename NumberT> void StressTest() { #ifndef NDEBUG - const int objects_generated = 10000; - const int object_fluctuation = 1000; + const int objects_generated = 10000; + const int object_fluctuation = 1000; #else - const int objects_generated = 200000; - const int object_fluctuation = 20000; + const int objects_generated = 200000; + const int object_fluctuation = 20000; #endif - const int full_rounds = 24; - const int query_rounds = 4; - std::minstd_rand rand; - std::uniform_int_distribution<std::size_t> index(0, objects_generated - 1); - std::uniform_real_distribution<float> - coordinate(std::is_integral<NumberT>::value ? - (float)(std::is_signed<NumberT>::value ? - -std::numeric_limits<NumberT>::max() / 8 : - std::numeric_limits<NumberT>::max() / 16 * 7) : - -1.0f, - std::is_integral<NumberT>::value ? - (float)(std::is_signed<NumberT>::value ? - std::numeric_limits<NumberT>::max() / 8 : - std::numeric_limits<NumberT>::max() / 16 * 9) : - 1.0f); - std::uniform_real_distribution<float> - distance(0.0f, std::is_integral<NumberT>::value ? - (float)(std::is_signed<NumberT>::value ? - std::numeric_limits<NumberT>::max() / 8 : - std::numeric_limits<NumberT>::max() / 16) : - 0.5f); - - std::vector<BoundingBox<NumberT>> objects; - objects.reserve(objects_generated); - std::vector<bool> flags(objects_generated, false); - LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; - for (std::size_t i = 0; i < objects_generated; i++) { - objects.emplace_back((NumberT)coordinate(rand), (NumberT)coordinate(rand), - (NumberT)distance(rand), (NumberT)distance(rand)); - lqt.Insert(&objects[i]); - } - ASSERT(objects.size() == objects_generated); - ASSERT(flags.size() == objects_generated); - - for (int round = 0; round < full_rounds; round++) { - for (int fluctobj = 0; fluctobj < object_fluctuation; fluctobj++) { - std::size_t id = index(rand); - objects[id] = BoundingBox<NumberT>((NumberT)coordinate(rand), (NumberT)coordinate(rand), - (NumberT)distance(rand), (NumberT)distance(rand)); - lqt.Update(&objects[id]); - } - for (int query_round = 0; query_round < query_rounds; query_round++) { - BoundingBox<NumberT> query_region((NumberT)coordinate(rand), (NumberT)coordinate(rand), - (NumberT)distance(rand), (NumberT)distance(rand)); - for (std::size_t i = 0; i < objects_generated; i++) { - flags[i] = false; - } - - auto query = lqt.QueryIntersectsRegion(query_region); - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - ASSERT(query_region.Intersects(*obj)); - std::size_t id = (std::size_t)(obj - &objects[0]); - ASSERT(id >= 0 && id < objects_generated); - flags[id] = true; - query.Next(); - } - for (std::size_t i = 0; i < objects_generated; i++) { - ASSERT(flags[i] == query_region.Intersects(objects[i])); - flags[i] = false; - } - - query = lqt.QueryInsideRegion(query_region); - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - ASSERT(query_region.Contains(*obj)); - std::size_t id = (std::size_t)(obj - &objects[0]); - ASSERT(id >= 0 && id < objects_generated); - flags[id] = true; - query.Next(); - } - for (std::size_t i = 0; i < objects_generated; i++) { - ASSERT(flags[i] == query_region.Contains(objects[i])); - flags[i] = false; - } - - query = lqt.QueryContainsRegion(query_region); - while (!query.EndOfQuery()) { - BoundingBox<NumberT>* obj = query.GetCurrent(); - ASSERT(obj->Contains(query_region)); - std::size_t id = (std::size_t)(obj - &objects[0]); - ASSERT(id >= 0 && id < objects_generated); - flags[id] = true; - query.Next(); - } - for (std::size_t i = 0; i < objects_generated; i++) { - ASSERT(flags[i] == objects[i].Contains(query_region)); - //flags[i] = false; - } - } - } - lqt.ForceCleanup(); + const int full_rounds = 24; + const int query_rounds = 4; + std::minstd_rand rand; + std::uniform_int_distribution<std::size_t> index(0, objects_generated - 1); + std::uniform_real_distribution<float> + coordinate(std::is_integral<NumberT>::value ? + (float)(std::is_signed<NumberT>::value ? + -std::numeric_limits<NumberT>::max() / 8 : + std::numeric_limits<NumberT>::max() / 16 * 7) : + -1.0f, + std::is_integral<NumberT>::value ? + (float)(std::is_signed<NumberT>::value ? + std::numeric_limits<NumberT>::max() / 8 : + std::numeric_limits<NumberT>::max() / 16 * 9) : + 1.0f); + std::uniform_real_distribution<float> + distance(0.0f, std::is_integral<NumberT>::value ? + (float)(std::is_signed<NumberT>::value ? + std::numeric_limits<NumberT>::max() / 8 : + std::numeric_limits<NumberT>::max() / 16) : + 0.5f); + + std::vector<BoundingBox<NumberT>> objects; + objects.reserve(objects_generated); + std::vector<bool> flags(objects_generated, false); + LooseQuadtree<NumberT, BoundingBox<NumberT>, TrivialBBExtractor<NumberT>> lqt; + for (std::size_t i = 0; i < objects_generated; i++) { + objects.emplace_back((NumberT)coordinate(rand), (NumberT)coordinate(rand), + (NumberT)distance(rand), (NumberT)distance(rand)); + lqt.Insert(&objects[i]); + } + ASSERT(objects.size() == objects_generated); + ASSERT(flags.size() == objects_generated); + + for (int round = 0; round < full_rounds; round++) { + for (int fluctobj = 0; fluctobj < object_fluctuation; fluctobj++) { + std::size_t id = index(rand); + objects[id] = BoundingBox<NumberT>((NumberT)coordinate(rand), (NumberT)coordinate(rand), + (NumberT)distance(rand), (NumberT)distance(rand)); + lqt.Update(&objects[id]); + } + for (int query_round = 0; query_round < query_rounds; query_round++) { + BoundingBox<NumberT> query_region((NumberT)coordinate(rand), (NumberT)coordinate(rand), + (NumberT)distance(rand), (NumberT)distance(rand)); + for (std::size_t i = 0; i < objects_generated; i++) { + flags[i] = false; + } + + auto query = lqt.QueryIntersectsRegion(query_region); + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + ASSERT(query_region.Intersects(*obj)); + std::size_t id = (std::size_t)(obj - &objects[0]); + ASSERT(id >= 0 && id < objects_generated); + flags[id] = true; + query.Next(); + } + for (std::size_t i = 0; i < objects_generated; i++) { + ASSERT(flags[i] == query_region.Intersects(objects[i])); + flags[i] = false; + } + + query = lqt.QueryInsideRegion(query_region); + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + ASSERT(query_region.Contains(*obj)); + std::size_t id = (std::size_t)(obj - &objects[0]); + ASSERT(id >= 0 && id < objects_generated); + flags[id] = true; + query.Next(); + } + for (std::size_t i = 0; i < objects_generated; i++) { + ASSERT(flags[i] == query_region.Contains(objects[i])); + flags[i] = false; + } + + query = lqt.QueryContainsRegion(query_region); + while (!query.EndOfQuery()) { + BoundingBox<NumberT>* obj = query.GetCurrent(); + ASSERT(obj->Contains(query_region)); + std::size_t id = (std::size_t)(obj - &objects[0]); + ASSERT(id >= 0 && id < objects_generated); + flags[id] = true; + query.Next(); + } + for (std::size_t i = 0; i < objects_generated; i++) { + ASSERT(flags[i] == objects[i].Contains(query_region)); + //flags[i] = false; + } + } + } + lqt.ForceCleanup(); } template <typename NumberT> void RunTests(const char* type_str) { - printf("quadtree test %13s", type_str); - fflush(stdout); - auto start = std::chrono::high_resolution_clock::now(); - TestBoundingBox<NumberT>(); - TestTraversals<NumberT>(); - TestContainer<NumberT>(); - TestQueries<NumberT>(); - StressTest<NumberT>(); - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration<double, std::milli> time = end - start; - printf(": %.1f ms\n", time.count()); - fflush(stdout); + printf("quadtree test %13s", type_str); + fflush(stdout); + auto start = std::chrono::high_resolution_clock::now(); + TestBoundingBox<NumberT>(); + TestTraversals<NumberT>(); + TestContainer<NumberT>(); + TestQueries<NumberT>(); + StressTest<NumberT>(); + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double, std::milli> time = end - start; + printf(": %.1f ms\n", time.count()); + fflush(stdout); } } // namespace @@ -723,15 +723,15 @@ namespace floormat { void test_app::test_quadtree() { - RUN_TEST(float); - RUN_TEST(double); - RUN_TEST(long double); - RUN_TEST(std::int16_t); - RUN_TEST(std::int32_t); - RUN_TEST(std::int64_t); - RUN_TEST(std::uint16_t); - RUN_TEST(std::uint32_t); - RUN_TEST(std::uint64_t); + RUN_TEST(float); + RUN_TEST(double); + RUN_TEST(long double); + RUN_TEST(std::int16_t); + RUN_TEST(std::int32_t); + RUN_TEST(std::int64_t); + RUN_TEST(std::uint16_t); + RUN_TEST(std::uint32_t); + RUN_TEST(std::uint64_t); } } // namespace floormat |