#pragma once #include "LooseQuadtree.h" #include "compat/assert.hpp" #undef assert #define assert(...) fm_debug_assert(__VA_ARGS__) #include #include #include #include #include #include #include #include #include #include #ifdef __GNUG__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" #endif namespace loose_quadtree::detail { #define LQT_USE_OWN_ALLOCATOR 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 T* New(Args&&... args); template void Delete(T* p); private: struct Block { alignas(kBlockAlign) unsigned char data[kBlockSize]; }; //template //union Slot { // Slot* next_empty_slot; // std::array data; //}; using BlocksAndEmptySlots = std::map; 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 size_to_blocks_; }; template 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 struct rebind {using other = BlocksAllocatorAdaptor;}; BlocksAllocatorAdaptor(BlocksAllocator& allocator); template BlocksAllocatorAdaptor(const BlocksAllocatorAdaptor& other); template BlocksAllocatorAdaptor& operator=(const BlocksAllocatorAdaptor& 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::max();} template void construct(U* p, Args&&... args) { new((void*)p) U(std::forward(args)...); } template void destroy(U* p) { p->~U(); } T* allocate(std::size_t n); void deallocate(T* p, std::size_t n); BlocksAllocator* allocator_; }; template T* BlocksAllocator::New(Args&&... args) { return new(Allocate(sizeof(T))) T(std::forward(args)...); } template void BlocksAllocator::Delete(T* p) { p->~T(); Deallocate(p, sizeof(T)); } template BlocksAllocatorAdaptor::BlocksAllocatorAdaptor(BlocksAllocator& allocator) : allocator_(&allocator) { } template template BlocksAllocatorAdaptor::BlocksAllocatorAdaptor(const BlocksAllocatorAdaptor& other) : allocator_(other.allocator_) { } template template BlocksAllocatorAdaptor& BlocksAllocatorAdaptor::operator=(const BlocksAllocatorAdaptor& other) { allocator_ = other.allocator_; } template T* BlocksAllocatorAdaptor::allocate(std::size_t n) { if (sizeof(T) <= BlocksAllocator::kMaxAllowedAlloc && n == 1) { return reinterpret_cast(allocator_->Allocate(sizeof(T))); } else { return reinterpret_cast(new char[sizeof(T) * n]); } } template void BlocksAllocatorAdaptor::deallocate(T* p, std::size_t n) { if (sizeof(T) <= BlocksAllocator::kMaxAllowedAlloc && n == 1) { allocator_->Deallocate(p, sizeof(T)); } else { delete[] reinterpret_cast(p); } } template struct MakeDistance { using Type = typename std::make_unsigned::type;}; template <> struct MakeDistance { using Type = float;}; template <> struct MakeDistance { using Type = double;}; template <> struct MakeDistance { using Type = long double;}; enum class ChildPosition { kNone, kTopLeft, kTopRight, kBottomRight, kBottomLeft, }; template struct TreeNode { using Object = ObjectT; using ObjectContainer = std::forward_list>; TreeNode(BlocksAllocator& allocator) : top_left(nullptr), top_right(nullptr), bottom_right(nullptr), bottom_left(nullptr), objects(BlocksAllocatorAdaptor(allocator)) {} TreeNode* top_left; TreeNode* top_right; TreeNode* bottom_right; TreeNode* bottom_left; ObjectContainer objects; }; template class ForwardTreeTraversal { public: using Number = NumberT; using Object = ObjectT; struct TreePosition { TreePosition(const BoundingBox& _bbox, TreeNode* _node) : bounding_box(_bbox), node(_node), current_child(ChildPosition::kNone) { } BoundingBox bounding_box; TreeNode* node; ChildPosition current_child; }; ForwardTreeTraversal(); void StartAt(TreeNode* root, const BoundingBox& root_bounds); int GetDepth() const; ///< starting from 0 TreeNode* GetNode() const; const BoundingBox& GetNodeBoundingBox() const; void GoTopLeft(); void GoTopRight(); void GoBottomRight(); void GoBottomLeft(); protected: TreePosition position_; int depth_; }; template class FullTreeTraversal : public ForwardTreeTraversal { public: using Number = NumberT; using Object = ObjectT; using typename ForwardTreeTraversal::TreePosition; void StartAt(TreeNode* root, const BoundingBox& root_bounds); ChildPosition GetNodeCurrentChild() const; void SetNodeCurrentChild(ChildPosition child_position); void GoUp(); void GoTopLeft(); void GoTopRight(); void GoBottomRight(); void GoBottomLeft(); private: using ForwardTreeTraversal::position_; using ForwardTreeTraversal::depth_; std::vector position_stack_; }; } // namespace loose_quadtree::detail namespace loose_quadtree { template class LooseQuadtree::Query::Impl { public: enum class QueryType {kIntersects, kInside, kContains, kEndOfQuery}; Impl(); void Acquire(typename LooseQuadtree::Impl* quadtree, const BoundingBox* 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::Impl* quadtree_; detail::FullTreeTraversal traversal_; typename detail::TreeNode::ObjectContainer::iterator object_iterator_; typename detail::TreeNode::ObjectContainer::iterator object_iterator_before_; BoundingBox query_region_; QueryType query_type_; int free_ride_from_level_; }; template class LooseQuadtree::Impl { public: constexpr static int kInternalMinDepth = 4; constexpr static int kInternalMaxDepth = (sizeof(long long) * 8 - 1) / 2; constexpr static Number kMinimalObjectExtent = std::is_integral::value ? 1 : std::numeric_limits::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& region); Query QueryInsideRegion(const BoundingBox& region); Query QueryContainsRegion(const BoundingBox& region); const BoundingBox& GetBoundingBox() const; ///< loose sense bounds int GetSize() const; void Clear(); void ForceCleanup(); private: friend class Query::Impl; using ObjectPointerContainer = std::unordered_map, std::equal_to, detail::BlocksAllocatorAdaptor>>; using QueryPoolContainer = std::deque::Query::Impl>; void RecalculateMaximalDepth(); void DeleteTree(); Object** InsertIntoTree(Object* object); typename Query::Impl* GetAvailableQueryFromPool(); detail::BlocksAllocator allocator_; detail::TreeNode* root_; BoundingBox bounding_box_; ObjectPointerContainer object_pointers_; int number_of_objects_; int maximal_depth_; detail::FullTreeTraversal internal_traversal_; QueryPoolContainer query_pool_; int running_queries_; ///< queries which are opened and not at their end }; template bool BoundingBox::Intersects(const BoundingBox& other) const { return !( left + width <= other.left || other.left + other.width <= left || top + height <= other.top || other.top + other.height <= top ); } template bool BoundingBox::Contains(const BoundingBox& other) const { return left <= other.left && left + width >= other.left + other.width && top <= other.top && top + height >= other.top + other.height; } template bool BoundingBox::Contains(Number x, Number y) const { return left <= x && x < left + width && top <= y && y < top + height; } template detail::ForwardTreeTraversal::ForwardTreeTraversal() : position_(BoundingBox(0, 0, 0, 0), nullptr), depth_(0) { } template void detail::ForwardTreeTraversal::StartAt(TreeNode* root, const BoundingBox& root_bounds) { position_.bounding_box = root_bounds; position_.node = root; depth_ = 0; } template int detail::ForwardTreeTraversal::GetDepth() const { return depth_; } template detail::TreeNode* detail::ForwardTreeTraversal::GetNode() const { return position_.node; } template const BoundingBox& detail::ForwardTreeTraversal::GetNodeBoundingBox() const { return position_.bounding_box; } template void detail::ForwardTreeTraversal::GoTopLeft() { BoundingBox& bbox = position_.bounding_box; bbox.width = (Number)((typename MakeDistance::Type)bbox.width / 2); bbox.height = (Number)((typename MakeDistance::Type)bbox.height / 2); position_.node = position_.node->top_left; assert(position_.node != nullptr); depth_++; } template void detail::ForwardTreeTraversal::GoTopRight() { BoundingBox& bbox = position_.bounding_box; Number right = (Number)(bbox.left + bbox.width); bbox.left = (Number)(bbox.left + (Number)((typename MakeDistance::Type)bbox.width / 2)); bbox.width = (Number)(right - bbox.left); bbox.height = (Number)((typename MakeDistance::Type)bbox.height / 2); position_.node = position_.node->top_right; assert(position_.node != nullptr); depth_++; } template void detail::ForwardTreeTraversal::GoBottomRight() { BoundingBox& bbox = position_.bounding_box; Number right = (Number)(bbox.left + bbox.width); bbox.left = (Number)(bbox.left + (Number)((typename MakeDistance::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::Type)bbox.height / 2)); bbox.height = (Number)(bottom - bbox.top); position_.node = position_.node->bottom_right; assert(position_.node != nullptr); depth_++; } template void detail::ForwardTreeTraversal::GoBottomLeft() { BoundingBox& bbox = position_.bounding_box; bbox.width = (Number)((typename MakeDistance::Type)bbox.width / 2); Number bottom = (Number)(bbox.top + bbox.height); bbox.top = (Number)(bbox.top + (Number)((typename MakeDistance::Type)bbox.height / 2)); bbox.height = (Number)(bottom - bbox.top); position_.node = position_.node->bottom_left; assert(position_.node != nullptr); depth_++; } template void detail::FullTreeTraversal::StartAt(TreeNode* root, const BoundingBox& root_bounds) { ForwardTreeTraversal::StartAt(root, root_bounds); position_.current_child = ChildPosition::kNone; position_stack_.clear(); } template detail::ChildPosition detail::FullTreeTraversal::GetNodeCurrentChild() const { return position_.current_child; } template void detail::FullTreeTraversal::SetNodeCurrentChild(ChildPosition child_position) { position_.current_child = child_position; } template void detail::FullTreeTraversal::GoTopLeft() { assert((size_t)depth_ == position_stack_.size()); position_.current_child = ChildPosition::kTopLeft; position_stack_.emplace_back(position_); ForwardTreeTraversal::GoTopLeft(); position_.current_child = ChildPosition::kNone; } template void detail::FullTreeTraversal::GoTopRight() { assert((size_t)depth_ == position_stack_.size()); position_.current_child = ChildPosition::kTopRight; position_stack_.emplace_back(position_); ForwardTreeTraversal::GoTopRight(); position_.current_child = ChildPosition::kNone; } template void detail::FullTreeTraversal::GoBottomRight() { assert((size_t)depth_ == position_stack_.size()); position_.current_child = ChildPosition::kBottomRight; position_stack_.emplace_back(position_); ForwardTreeTraversal::GoBottomRight(); position_.current_child = ChildPosition::kNone; } template void detail::FullTreeTraversal::GoBottomLeft() { assert((size_t)depth_ == position_stack_.size()); position_.current_child = ChildPosition::kBottomLeft; position_stack_.emplace_back(position_); ForwardTreeTraversal::GoBottomLeft(); position_.current_child = ChildPosition::kNone; } template void detail::FullTreeTraversal::GoUp() { assert((size_t)depth_ == position_stack_.size() && depth_ > 0); position_ = position_stack_.back(); depth_--; position_stack_.pop_back(); } template LooseQuadtree::Query::Impl::Impl() : quadtree_(nullptr), query_region_(0,0,0,0), query_type_(QueryType::kEndOfQuery), free_ride_from_level_(LooseQuadtree::Impl::kInternalMaxDepth) { } template void LooseQuadtree::Query::Impl::Acquire(typename LooseQuadtree::Impl* quadtree, const BoundingBox* 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::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 void LooseQuadtree::Query::Impl::Release() { assert(!IsAvailable()); quadtree_ = nullptr; } template bool LooseQuadtree::Query::Impl::IsAvailable() const { return quadtree_ == nullptr; } template bool LooseQuadtree::Query::Impl::EndOfQuery() const { assert(!IsAvailable()); return query_type_ == QueryType::kEndOfQuery; } template ObjectT* LooseQuadtree::Query::Impl::GetCurrent() const { assert(!IsAvailable()); assert(!EndOfQuery()); return *object_iterator_; } template void LooseQuadtree::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: #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_); #endif //only run this if no parallel queries are running if (traversal_.GetDepth() > quadtree_->maximal_depth_ && quadtree_->running_queries_ == 1) { typename detail::TreeNode::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* 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::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(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 bool LooseQuadtree::Query::Impl::CurrentObjectFits() const { BoundingBox 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 auto LooseQuadtree::Query::Impl::CurrentNodeFits() const -> FitType { const BoundingBox& node_bounds = traversal_.GetNodeBoundingBox(); BoundingBox extended_bounds = node_bounds; Number half_width = (Number)((typename detail::MakeDistance::Type)node_bounds.width / 2); Number half_height = (Number)((typename detail::MakeDistance::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 LooseQuadtree::Impl::Impl() : root_(nullptr), bounding_box_(0, 0, 0, 0), object_pointers_(64, std::hash(), std::equal_to(), detail::BlocksAllocatorAdaptor>(allocator_)), number_of_objects_(0), maximal_depth_(kInternalMinDepth), running_queries_(0) { assert(maximal_depth_ < kInternalMaxDepth); //object_pointers_.reserve(64); } template LooseQuadtree::Impl::~Impl() { DeleteTree(); } template bool LooseQuadtree::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; } template bool LooseQuadtree::Impl::Update(Object* object) { return !Insert(object); } template bool LooseQuadtree::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; } template bool LooseQuadtree::Impl::Contains(Object* object) const { return object_pointers_.find(object) != object_pointers_.end(); } template auto LooseQuadtree::Impl::QueryIntersectsRegion(const BoundingBox& region) -> Query { typename Query::Impl* query_impl = GetAvailableQueryFromPool(); query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kIntersects); return Query(query_impl); } template auto LooseQuadtree::Impl::QueryInsideRegion(const BoundingBox& region) -> Query { typename Query::Impl* query_impl = GetAvailableQueryFromPool(); query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kInside); return Query(query_impl); } template auto LooseQuadtree::Impl::QueryContainsRegion(const BoundingBox& region) -> Query { typename Query::Impl* query_impl = GetAvailableQueryFromPool(); query_impl->Acquire(this, ®ion, Query::Impl::QueryType::kContains); return Query(query_impl); } template const BoundingBox& LooseQuadtree::Impl::GetBoundingBox() const { return bounding_box_; } template void LooseQuadtree::Impl::ForceCleanup() { Query query = QueryIntersectsRegion(bounding_box_); while (!query.EndOfQuery()) { query.Next(); } allocator_.ReleaseFreeBlocks(); } template int LooseQuadtree::Impl::GetSize() const { return number_of_objects_; } template void LooseQuadtree::Impl::Clear() { DeleteTree(); } template void LooseQuadtree::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); } template void LooseQuadtree::Impl::DeleteTree() { object_pointers_.clear(); detail::FullTreeTraversal& trav = internal_traversal_; trav.StartAt(root_, bounding_box_); while (root_ != nullptr) { assert(trav.GetDepth() >= 0 && trav.GetDepth() <= kInternalMaxDepth); detail::TreeNode* 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(0, 0, 0, 0); number_of_objects_ = 0; maximal_depth_ = kInternalMinDepth; } template ObjectT** LooseQuadtree::Impl::InsertIntoTree(Object* object) { BoundingBox 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::Type)object_bounds.width / 2)); Number object_center_y = (Number)(object_bounds.top + (Number)((typename detail::MakeDistance::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::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* old_root = root_; root_ = allocator_.New>(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::value || bounding_box_.width < std::numeric_limits::max() / 8 * 7); assert(!std::is_integral::value || bounding_box_.height < std::numeric_limits::max() / 8 * 7); } detail::ForwardTreeTraversal trav; trav.StartAt(root_, bounding_box_); do { const BoundingBox& 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::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::Type)node_bounds.width / 2)); Number node_center_y = (Number)(node_bounds.top + (Number)((typename detail::MakeDistance::Type)node_bounds.height / 2)); detail::TreeNode** 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>(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 effective_bounds = trav.GetNodeBoundingBox(); Number half_width = (Number)((typename detail::MakeDistance::Type)effective_bounds.width / 2); Number half_height = (Number)((typename detail::MakeDistance::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::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::Type)maximal_object_extent * 2 * 7 / 8); bounding_box_.height = bounding_box_.width; Number extent_half = (Number)((typename detail::MakeDistance::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>(allocator_); root_->objects.emplace_front(object); return &root_->objects.front(); } } template auto LooseQuadtree::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(); } template bool LooseQuadtree::Insert(Object* object) { return impl_.Insert(object); } template bool LooseQuadtree::Update(Object* object) { return impl_.Update(object); } template bool LooseQuadtree::Remove(Object* object) { return impl_.Remove(object); } template bool LooseQuadtree::Contains(Object* object) const { return impl_.Contains(object); } template auto LooseQuadtree::QueryIntersectsRegion(const BoundingBox& region) -> Query { return impl_.QueryIntersectsRegion(region); } template auto LooseQuadtree::QueryInsideRegion(const BoundingBox& region) -> Query { return impl_.QueryInsideRegion(region); } template auto LooseQuadtree::QueryContainsRegion(const BoundingBox& region) -> Query { return impl_.QueryContainsRegion(region); } template const BoundingBox& LooseQuadtree::GetLooseBoundingBox() const { return impl_.GetBoundingBox(); } template void LooseQuadtree::ForceCleanup() { impl_.ForceCleanup(); } template int LooseQuadtree::GetSize() const { return impl_.GetSize(); } template bool LooseQuadtree::IsEmpty() const { return impl_.GetSize() == 0; } template void LooseQuadtree::Clear() { impl_.Clear(); } template LooseQuadtree::Query::Query(Impl* pimpl) : pimpl_(pimpl) { assert(pimpl_ != nullptr); assert(!pimpl_->IsAvailable()); } template LooseQuadtree::Query::~Query() { if (pimpl_ != nullptr) { pimpl_->Release(); assert(pimpl_->IsAvailable()); pimpl_ = nullptr; } } template LooseQuadtree::Query::Query(Query&& other) noexcept : pimpl_(other.pimpl_) { other.pimpl_ = nullptr; } template auto LooseQuadtree::Query::operator=(Query&& other) noexcept -> Query& { this->~Query(); pimpl_ = other.pimpl_; other.pimpl_ = nullptr; return *this; } template bool LooseQuadtree::Query::EndOfQuery() const { return pimpl_->EndOfQuery(); } template ObjectT* LooseQuadtree::Query::GetCurrent() const { return pimpl_->GetCurrent(); } template void LooseQuadtree::Query::Next() { pimpl_->Next(); } template struct TrivialBBExtractor { static void ExtractBoundingBox(const BoundingBox *object, BoundingBox *bbox) { bbox->left = object->left; bbox->top = object->top; bbox->width = object->width; bbox->height = object->height; } }; } // namespace loose_quadtree #ifdef __GNUG__ #pragma GCC diagnostic pop #endif #undef assert