38 typedef typename allocator_type::pointer
pointer;
40 typedef typename allocator_type::reference
reference;
50 typedef std::array<std::array<aabb_2d, 2>, 2> quadrants;
51 typedef std::array<std::array<node*, 2>, 2> children;
53 struct no_parent : std::logic_error { no_parent() : std::logic_error{
"neogfx::aabb_quadtree::node::no_parent" } {} };
54 struct no_children : std::logic_error { no_children() : std::logic_error{
"neogfx::aabb_quadtree::node::no_children" } {} };
56 node(
aabb_quadtree& aTree,
const aabb_2d& aAabb) : iTree{ aTree }, iParent{
nullptr }, iDepth{ 1 }, iAabb { aAabb }, iChildren{}
58 iTree.iDepth = std::max(iTree.iDepth, iDepth);
61 node(
const node& aParent,
const aabb_2d& aAabb) : iTree{ aParent.iTree }, iParent{ &aParent }, iDepth{ aParent.iDepth + 1 }, iAabb { aAabb }, iChildren{}
63 iTree.iDepth = std::max(iTree.iDepth, iDepth);
69 if (has_child<0, 0>())
71 if (has_child<0, 1>())
73 if (has_child<1, 0>())
75 if (has_child<1, 1>())
78 parent().unsplit(
this);
81 bool has_parent()
const
83 return iParent !=
nullptr;
85 const node& parent()
const
93 return const_cast<node&
>(to_const(*this).parent());
95 uint32_t depth()
const
105 iTree.iDepth = std::max(iTree.iDepth, iDepth);
109 child<0, 0>().add_entity(aEntity, aCollider);
111 child<0, 1>().add_entity(aEntity, aCollider);
113 child<1, 0>().add_entity(aEntity, aCollider);
115 child<1, 1>().add_entity(aEntity, aCollider);
119 iEntities.push_back(aEntity);
120 if (iEntities.size() > BucketSize && (iAabb.max - iAabb.min).min() > iTree.minimum_quadrant_size())
126 if (aCollider.previousAabb && aCollider.currentAabb)
127 remove_entity(aEntity, aCollider,
aabb_union(*aCollider.previousAabb, *aCollider.currentAabb));
133 auto existing = std::find(iEntities.begin(), iEntities.end(), aEntity);
134 if (existing != iEntities.end())
135 iEntities.erase(existing);
138 child<0, 0>().remove_entity(aEntity, aCollider, aAabb);
140 child<0, 1>().remove_entity(aEntity, aCollider, aAabb);
142 child<1, 0>().remove_entity(aEntity, aCollider, aAabb);
144 child<1, 1>().remove_entity(aEntity, aCollider, aAabb);
146 iTree.destroy_node(*
this);
150 iTree.iDepth = std::max(iTree.iDepth, iDepth);
151 auto const& currentAabb = aCollider.currentAabb;
152 auto const& previousAabb = aCollider.previousAabb;
153 if (currentAabb == previousAabb)
156 add_entity(aEntity, aCollider);
158 remove_entity(aEntity, aCollider, previousAabb);
162 bool result = iEntities.empty();
163 if (has_child<0, 0>())
164 result = child<0, 0>().empty() && result;
165 if (has_child<0, 1>())
166 result = child<0, 1>().empty() && result;
167 if (has_child<1, 0>())
168 result = child<1, 0>().empty() && result;
169 if (has_child<1, 1>())
170 result = child<1, 1>().empty() && result;
173 const entity_list& entities()
const
177 template <
typename Visitor>
178 void visit(
const collider_type& aCandidate,
const Visitor& aVisitor)
const
180 if (aCandidate.currentAabb)
181 visit(*aCandidate.currentAabb, aVisitor);
183 template <
typename Visitor>
184 void visit(
const vec2& aPoint,
const Visitor& aVisitor)
const
186 visit(
aabb_2d{ aPoint, aPoint }, aVisitor);
188 template <
typename Visitor>
189 void visit(
const aabb_2d& aAabb,
const Visitor& aVisitor)
const
191 for (
auto e : entities())
195 child<0, 0>().visit(aAabb, aVisitor);
197 child<0, 1>().visit(aAabb, aVisitor);
199 child<1, 0>().visit(aAabb, aVisitor);
201 child<1, 1>().visit(aAabb, aVisitor);
203 template <
typename Visitor>
204 void visit_entities(
const Visitor& aVisitor)
const
206 for (
auto e : entities())
208 if (has_child<0, 0>())
209 child<0, 0>().visit_entities(aVisitor);
210 if (has_child<0, 1>())
211 child<0, 1>().visit_entities(aVisitor);
212 if (has_child<1, 0>())
213 child<1, 0>().visit_entities(aVisitor);
214 if (has_child<1, 1>())
215 child<1, 1>().visit_entities(aVisitor);
217 template <
typename Visitor>
218 void visit_aabbs(
const Visitor& aVisitor)
const
221 if (has_child<0, 0>())
222 child<0, 0>().visit_aabbs(aVisitor);
223 if (has_child<0, 1>())
224 child<0, 1>().visit_aabbs(aVisitor);
225 if (has_child<1, 0>())
226 child<1, 0>().visit_aabbs(aVisitor);
227 if (has_child<1, 1>())
228 child<1, 1>().visit_aabbs(aVisitor);
231 void populate_quadrants()
233 auto const& min = iAabb.min;
234 auto const& max = iAabb.max;
235 auto const& center = (min + max) / 2.0;
236 iQuadrants[0][0] =
aabb_2d{ min, center };
239 iQuadrants[1][1] =
aabb_2d{ center, max };
241 template <std::
size_t X, std::
size_t Y>
244 if (iChildren == std::nullopt)
246 if ((*iChildren)[
X][
Y] ==
nullptr)
247 (*iChildren)[
X][
Y] = iTree.create_node(*
this, iQuadrants[
X][
Y]);
248 return *(*iChildren)[
X][
Y];
250 template <std::
size_t X, std::
size_t Y>
251 bool has_child()
const
253 if (iChildren == std::nullopt)
255 return (*iChildren)[
X][
Y] !=
nullptr;
257 template <std::
size_t X, std::
size_t Y>
258 bool remove_child(node* aDestroyedNode =
nullptr)
const
260 if (iChildren == std::nullopt)
262 if ((*iChildren)[
X][
Y] ==
nullptr)
264 if ((*iChildren)[
X][
Y] == aDestroyedNode || aDestroyedNode ==
nullptr)
266 auto n = (*iChildren)[
X][
Y];
267 (*iChildren)[
X][
Y] =
nullptr;
268 iTree.destroy_node(*n);
273 bool is_split()
const
275 return iChildren != std::nullopt;
279 for (
auto e : entities())
281 auto const& collider = iTree.iEcs.component<
collider_type>().entity_record(e);
283 child<0, 0>().add_entity(e, collider);
285 child<0, 1>().add_entity(e, collider);
287 child<1, 0>().add_entity(e, collider);
289 child<1, 1>().add_entity(e, collider);
293 void unsplit(node* aDestroyedNode)
295 bool haveChildren =
false;
296 if (!remove_child<0, 0>(aDestroyedNode))
298 if (!remove_child<0, 1>(aDestroyedNode))
300 if (!remove_child<1, 0>(aDestroyedNode))
302 if (!remove_child<1, 1>(aDestroyedNode))
305 iChildren = std::nullopt;
307 iTree.destroy_node(*
this);
314 quadrants iQuadrants;
315 entity_list iEntities;
316 mutable std::optional<children> iChildren;
318 typedef typename allocator_type::template rebind<node>::other node_allocator;
321 iAllocator{ aAllocator },
323 iRootAabb{ aRootAabb },
326 iRootNode{ *this, aRootAabb },
327 iMinimumQuadrantSize{ aMinimumQuadrantSize },
328 iCollisionUpdateId{ 0 }
334 return iMinimumQuadrantSize;
340 new(&iRootNode) node{ *
this, iRootAabb };
344 iRootNode.add_entity(
entity, collider);
353 iRootNode.update_entity(
entity, collider);
356 template <
typename CollisionAction>
362 if (candidateInfo.destroyed)
365 if (++iCollisionUpdateId == 0)
366 iCollisionUpdateId = 1;
367 iRootNode.visit(candidateCollider, [&](
entity_id aHit)
369 if (candidateInfo.destroyed)
371 if (candidate < aHit)
374 if (hitInfo.destroyed)
377 if ((candidateCollider.mask & hitCollider.mask) == 0 && hitCollider.collisionEventId != iCollisionUpdateId)
379 hitCollider.collisionEventId = iCollisionUpdateId;
380 aCollisionAction(candidate, aHit);
386 template <
typename ResultContainer>
387 void pick(
const vec2& aPoint, ResultContainer& aResult, std::function<
bool(
entity_id aMatch,
const vec2& aPoint)> aColliderPredicate = [](
entity_id,
const vec2&) {
return true; })
const
389 iRootNode.visit(aPoint, [&](
entity_id aMatch)
392 if (!matchInfo.destroyed && aColliderPredicate(aMatch, aPoint))
393 aResult.insert(aResult.end(), aMatch);
396 template <
typename Visitor>
399 iRootNode.visit_aabbs(aVisitor);
404 iRootNode.add_entity(aItem);
408 iRootNode.remove_entity(aItem);
425 node* create_node(
const node& aParent,
const aabb_2d& aAabb)
428 node* newNode = iAllocator.allocate(1);
429 iAllocator.construct(newNode, aParent, aAabb);
432 void destroy_node(node& aNode)
434 if (&aNode != &iRootNode && aNode.is_alive())
437 iAllocator.destroy(&aNode);
438 iAllocator.deallocate(&aNode, 1);
442 node_allocator iAllocator;
445 scalar iMinimumQuadrantSize;
447 mutable uint32_t iDepth;
449 mutable uint32_t iCollisionUpdateId;