Game of Ur 0.3.3
This is a computer adaptation of Game of Ur, written in C++ mainly using SDL and OpenGL.
Loading...
Searching...
No Matches
spatial_query_octree.hpp
Go to the documentation of this file.
1
10
11#ifndef FOOLSENGINE_SPATIALQUERYOCTREE_H
12#define FOOLSENGINE_SPATIALQUERYOCTREE_H
13
14#include <memory>
15#include <array>
16#include <algorithm>
17#include <cmath>
18
21#include "core/ecs_world.hpp"
22
23namespace ToyMaker {
24 class Octree;
25
31 class OctreeNode: public std::enable_shared_from_this<OctreeNode> {
32 public:
39 using Octant = uint8_t;
40
45 using Depth = uint8_t;
46
51 using Address = uint64_t;
52
58 RIGHT=0x1,
59 TOP=0x2,
60 FRONT=0x4,
61 };
62
67 static constexpr uint8_t knDepthBits { 5 };
68
74 static constexpr uint8_t kDepthBitOffset { sizeof(Address)*8 - knDepthBits };
75
80 static constexpr uint8_t knRouteBits { (kDepthBitOffset/3) * 3};
81
86 static constexpr Depth kMaxDepthInclusive {std::min(
87 1 + knRouteBits/3,
88 1 + (1<<knDepthBits)
89 )}; // +1 as depth 0 needs no bits
90
95 static constexpr Address kNoAddress { 0x0 };
96
104 static Address MakeAddress(Octant childOctant, Address parentAddress);
105
112 static Depth GetDepth(Address address);
113
125 static Octant ToGrowthDirection(Octant octant);
126
139 static Octant ToOctant(Octant growthDirection);
140
147 static Octant GetOctant(Address address);
148
155 static Address GetBaseRouteMask(Depth baseDepth);
156
164 static Address GetBaseRoute(Address address, Depth baseDepth);
165
173 static Octant GetOctantAt(Address address, Depth depth);
174
186 static Address GrowAddress(Address address, Address rootAddress);
187
197 static Address ShrinkAddress(Address address, Depth depthRemoved);
198
207 static bool SharesBranch(Address one, Address two);
208
214 DEPTH_MASK = -(1ull << kDepthBitOffset), //< Mask for the most significant knDepthBits of the address; mask corresponding to the depth section of the address.
215 ROUTE_MASK = ~(-(1ull << knRouteBits)), //< Mask for the least significant knRouteBits of the address; mask corresponding to the route section of the address.
216 };
217 static_assert(DEPTH_MASK != 0 && "Depth mask cannot be zero");
218 static_assert(ROUTE_MASK != 0 && "Route mask cannot be zero");
219 static_assert(knDepthBits + kDepthBitOffset == sizeof(Address)*8 && "sum of depth bits and depth offset must add up to the size of the address in bits");
220 static_assert(kDepthBitOffset >= knRouteBits && "There must be at least as many bits in the depth bit offset as those used to make the route");
221 static_assert(kNoAddress == 0 && "NoAddress must correspond with 0");
222
230 static std::shared_ptr<OctreeNode> CreateRootNode(
231 uint8_t subdivisionThreshold, AxisAlignedBounds boundRegion
232 );
233
241 static std::shared_ptr<OctreeNode> GrowTreeAndCreateRoot(
242 std::shared_ptr<OctreeNode> oldRoot,
243 const AxisAlignedBounds& regionToCover
244 );
245
249
255 std::vector<std::pair<EntityID, AxisAlignedBounds>> findAllMemberEntities() const;
256
264 std::vector<std::pair<EntityID, AxisAlignedBounds>> findEntitiesOverlapping(const AxisAlignedBounds& searchBounds) const;
272 std::vector<std::pair<EntityID, AxisAlignedBounds>> findEntitiesOverlapping(const Ray& searchRay) const;
273
279 uint8_t getChildCount() const;
280
286 Address getAddress() const { return mAddress; }
287
294
302 Address insertEntity(EntityID entityID, const AxisAlignedBounds& entityWorldBounds);
303
311 std::shared_ptr<OctreeNode> removeEntity(EntityID entityID, Address entityAddressHint=kNoAddress);
312
320 std::shared_ptr<OctreeNode> getNode(Address octantAddress);
321
329 std::shared_ptr<OctreeNode> nextNodeInAddress(Address octantAddress);
330
339 std::shared_ptr<OctreeNode> getSmallestNodeContaining(const AxisAlignedBounds& entityWorldBounds);
340
348 std::shared_ptr<OctreeNode> findCandidateRoot();
349
356 Address getBaseRoute(Address address) const;
357
363 Depth getDepth() const;
364
370 Octant getOctant() const;
371
378 Octant nextOctant(Address address) const;
379
385
386 private:
396 Address octantAddress,
397 uint8_t subdivisionThreshold,
398 AxisAlignedBounds worldBounds,
399 std::shared_ptr<OctreeNode> parent
400 ):
401 mAddress { octantAddress },
402 mSubdivisionThreshold { subdivisionThreshold },
403 mWorldBounds { worldBounds },
404 mParent { parent }
405 {}
406
412
417 uint8_t mSubdivisionThreshold { 40 };
418
424
429 std::weak_ptr<OctreeNode> mParent {};
430
437 std::array<std::shared_ptr<OctreeNode>, 8> mChildren {};
438
443 std::map<EntityID, AxisAlignedBounds> mEntities{};
444 };
445
460 class Octree {
461 public:
468 static constexpr float kMaxDimensionRatio { 20.f };
469
474 using EntityAddressPair = std::pair<EntityID, OctreeNode::Address>;
475
482 Octree(uint8_t subdivisionThreshold, const AxisAlignedBounds& totalWorldBounds):
483 mRootNode { OctreeNode::CreateRootNode(subdivisionThreshold, totalWorldBounds) }
484 {}
485
489
496 inline std::vector<std::pair<EntityID, AxisAlignedBounds>> findAllMemberEntities() const {
497 return mRootNode->findAllMemberEntities();
498 }
499
506 inline std::vector<std::pair<EntityID, AxisAlignedBounds>> findEntitiesOverlapping(const AxisAlignedBounds& searchBounds) const {
507 return mRootNode->findEntitiesOverlapping(searchBounds);
508 }
509
516 std::vector<std::pair<EntityID, AxisAlignedBounds>> findEntitiesOverlapping(const Ray& searchRay) const;
517
524 void insertEntity(EntityID entityID, const AxisAlignedBounds& entityWorldBounds);
525
531 void removeEntity(EntityID entityID);
532
533 private:
538 std::shared_ptr<OctreeNode> mRootNode;
539
544 std::map<EntityID, OctreeNode::Address> mEntityAddresses {};
545 };
546}
547
548#endif
An object containing a coarse simplified representation, AABB, of spatially queryable objects.
Definition spatial_query_math.hpp:317
A single node of an octree, representing a single octant of the 8 that make up its parent region.
Definition spatial_query_octree.hpp:31
std::vector< std::pair< EntityID, AxisAlignedBounds > > findEntitiesOverlapping(const AxisAlignedBounds &searchBounds) const
Retrieves all entities that intersect with the region described by searchBounds.
Definition spatial_query_octree.cpp:327
static Address MakeAddress(Octant childOctant, Address parentAddress)
Prepends the address of a child octant to the address of its parent in order to make the child's addr...
Definition spatial_query_octree.cpp:64
static std::shared_ptr< OctreeNode > CreateRootNode(uint8_t subdivisionThreshold, AxisAlignedBounds boundRegion)
Produces a node for the root of an octree that encloses the region to be divided.
Definition spatial_query_octree.cpp:31
void shrinkTreeAndBecomeRoot()
Trims the addresses of this node and its children (and consequently their entities) such that this no...
Definition spatial_query_octree.cpp:386
AxisAlignedBounds getWorldBounds() const
Retrieves the AABB representing the region this node covers.
Definition spatial_query_octree.hpp:293
static Address GetBaseRouteMask(Depth baseDepth)
Gets a bit mask covering the first 3*depth bits based on a given depth value.
Definition spatial_query_octree.cpp:83
std::weak_ptr< OctreeNode > mParent
The parent of this node, which this node is an octant of.
Definition spatial_query_octree.hpp:429
static bool SharesBranch(Address one, Address two)
Tests whether two nodes are present on the same branch of an octree (or in other words,...
Definition spatial_query_octree.cpp:119
static std::shared_ptr< OctreeNode > GrowTreeAndCreateRoot(std::shared_ptr< OctreeNode > oldRoot, const AxisAlignedBounds &regionToCover)
Expands an octree such that it encloses a previously unmapped region, and creates a node to be used a...
Definition spatial_query_octree.cpp:404
OctantSpecifier
Mask values which, when applied to the octant value, tell you which sub-region of the parent region t...
Definition spatial_query_octree.hpp:57
Depth getDepth() const
The depth of this node relative to the root of the Octree it is a part of.
Definition spatial_query_octree.cpp:296
static Octant ToOctant(Octant growthDirection)
Converts a growth direction to its corresponding octant.
Definition spatial_query_octree.cpp:79
static constexpr Address kNoAddress
A special value reserved for the absence of an address, as in the root node of the Octree.
Definition spatial_query_octree.hpp:95
std::shared_ptr< OctreeNode > removeEntity(EntityID entityID, Address entityAddressHint=kNoAddress)
Removes an entity situated at a node at some address (or on a descendant node).
Definition spatial_query_octree.cpp:201
uint8_t getChildCount() const
Gets the number of active child octants this octant has.
Definition spatial_query_octree.cpp:549
static Octant GetOctant(Address address)
Returns the 3 bits representing just this node's octant value, relative to its own parent.
Definition spatial_query_octree.cpp:60
static constexpr Depth kMaxDepthInclusive
The total depth representable given the value range of the depth-section of the address,...
Definition spatial_query_octree.hpp:86
std::vector< std::pair< EntityID, AxisAlignedBounds > > findAllMemberEntities() const
Retrieves all entities in this octant and its descendants.
Definition spatial_query_octree.cpp:308
static constexpr uint8_t kDepthBitOffset
(Computed) The number of bits by which to shift the address right in order to retrieve the depth valu...
Definition spatial_query_octree.hpp:74
Address getAddress() const
Gets the address value for this node.
Definition spatial_query_octree.hpp:286
std::shared_ptr< OctreeNode > getSmallestNodeContaining(const AxisAlignedBounds &entityWorldBounds)
Gets the node whose region just encompasses the bounds provided as input.
Definition spatial_query_octree.cpp:264
static Octant GetOctantAt(Address address, Depth depth)
Gets the octant corresponding to a specific depth within an address.
Definition spatial_query_octree.cpp:56
uint8_t mSubdivisionThreshold
The number of member entities a node (or its descendant) may have, beyond which the node's subdivisio...
Definition spatial_query_octree.hpp:417
uint64_t Address
The full address of this node, where every three bits right-to-left represent the octant in the hiera...
Definition spatial_query_octree.hpp:51
uint8_t Octant
A number representing the portion of the parent region represented by this node.
Definition spatial_query_octree.hpp:39
std::shared_ptr< OctreeNode > nextNodeInAddress(Address octantAddress)
Gets the child node corresponding to the next node in the argument's route section relative to the th...
Definition spatial_query_octree.cpp:239
std::array< std::shared_ptr< OctreeNode >, 8 > mChildren
An array of up to 8 child nodes maintained by this node, where each index corresponds to one possible...
Definition spatial_query_octree.hpp:437
static constexpr uint8_t knRouteBits
The number of bits of the address, starting from the right, representing the route to follow in the O...
Definition spatial_query_octree.hpp:80
std::map< EntityID, AxisAlignedBounds > mEntities
The member entities of this node.
Definition spatial_query_octree.hpp:443
std::shared_ptr< OctreeNode > findCandidateRoot()
Gets the smallest node, this node or a descendant, whose region encompasses all entities remaining in...
Definition spatial_query_octree.cpp:276
OctreeNode(Address octantAddress, uint8_t subdivisionThreshold, AxisAlignedBounds worldBounds, std::shared_ptr< OctreeNode > parent)
Constructs a new OctreeNode.
Definition spatial_query_octree.hpp:395
AxisAlignedBounds mWorldBounds
The region, as an AABB, encompassed by this node.
Definition spatial_query_octree.hpp:423
Address mAddress
The address of this node, where kNoAddress is the address of the root node of an octree.
Definition spatial_query_octree.hpp:411
static Address GrowAddress(Address address, Address rootAddress)
Adds root-address' route to address' route.
Definition spatial_query_octree.cpp:91
static constexpr uint8_t knDepthBits
The number of bits on the left hand side of a node address giving the depth of this node.
Definition spatial_query_octree.hpp:67
Address getBaseRoute(Address address) const
Gets the route section of the address up to the current node's depth.
Definition spatial_query_octree.cpp:292
static Address GetBaseRoute(Address address, Depth baseDepth)
Gets the value of the route section of an address up to some specified depth.
Definition spatial_query_octree.cpp:87
Octant getOctant() const
Gets the octant value of this node relative to its parent.
Definition spatial_query_octree.cpp:300
static Octant ToGrowthDirection(Octant octant)
Maps an octant to its corresponding growth direction.
Definition spatial_query_octree.cpp:75
Octant nextOctant(Address address) const
Fetches the octant of the next node in the route section of the argument address.
Definition spatial_query_octree.cpp:304
AddressMasks
Mask values for retrieving the different sections of an Address.
Definition spatial_query_octree.hpp:213
uint8_t Depth
The depth of this node relative to the overall octree; the number of hops to go from this node up to ...
Definition spatial_query_octree.hpp:45
std::shared_ptr< OctreeNode > getNode(Address octantAddress)
Gets a descendant of this node (or this node itself) by its address.
Definition spatial_query_octree.cpp:248
static Address ShrinkAddress(Address address, Depth depthRemoved)
Shrinks an address according to the depth removed.
Definition spatial_query_octree.cpp:108
static Depth GetDepth(Address address)
Gets the depth value of a node based on its address.
Definition spatial_query_octree.cpp:52
Address insertEntity(EntityID entityID, const AxisAlignedBounds &entityWorldBounds)
Adds an entity to this node or its subtree, per its configuration and the bounds of the object.
Definition spatial_query_octree.cpp:124
A data structure used for speeding up spatial queries about 3-dimensional objects in the scene.
Definition spatial_query_octree.hpp:460
std::map< EntityID, OctreeNode::Address > mEntityAddresses
A mapping of entity IDs to their addresses computed at entity insertion (and recomputed when the octr...
Definition spatial_query_octree.hpp:544
std::pair< EntityID, OctreeNode::Address > EntityAddressPair
An entity-id node-address pair indicating the address at which some entity known by the entity is pre...
Definition spatial_query_octree.hpp:474
void insertEntity(EntityID entityID, const AxisAlignedBounds &entityWorldBounds)
Inserts an entity into the octree.
Definition spatial_query_octree.cpp:557
static constexpr float kMaxDimensionRatio
The maximum possible ratio between two dimensions of the region enclosed by the octree.
Definition spatial_query_octree.hpp:468
std::vector< std::pair< EntityID, AxisAlignedBounds > > findAllMemberEntities() const
Retrieves all entities in this octant and its descendants.
Definition spatial_query_octree.hpp:496
Octree(uint8_t subdivisionThreshold, const AxisAlignedBounds &totalWorldBounds)
Constructs a new octree which encapsulates the bounds specified in the argument.
Definition spatial_query_octree.hpp:482
void removeEntity(EntityID entityID)
Removes an entity from the octree, based on its cached node address.
Definition spatial_query_octree.cpp:611
std::vector< std::pair< EntityID, AxisAlignedBounds > > findEntitiesOverlapping(const AxisAlignedBounds &searchBounds) const
Retrieve all entities that intersect with the region described by searchBounds.
Definition spatial_query_octree.hpp:506
std::shared_ptr< OctreeNode > mRootNode
The root node of the octree.
Definition spatial_query_octree.hpp:538
ToyMaker Engine's implementation of an ECS system.
std::uint64_t EntityID
A single unsigned integer used as a name for an entity managed by an ECS system.
Definition ecs_world.hpp:68
Namespace containing all class definitions and functions related to the ToyMaker engine.
Definition camera_system.hpp:20
Classes and structs representing data related to the engine's spatial query system (the precursor to ...
Geometrical, mathematical functions and related structs used to answer some simple questions about sh...
A set of numbers describing a ray with its source at some finite point in the world,...
Definition spatial_query_basic_types.hpp:374