19#include <unordered_map>
40template<
typename DataT>
47 DataT * data_ =
nullptr;
49 bool external_memory_ =
false;
56 if constexpr (!std::is_same_v<DataT, EmptyVoxel>) {
57 size_ = dim_ * dim_ * dim_;
58 data_ =
new DataT[size_];
62 Grid(
size_t log2dim, DataT * preAllocatedMemory)
64 data_(preAllocatedMemory),
66 external_memory_(true) {}
76 if (data_ !=
nullptr && !external_memory_) {
83 [[nodiscard]]
size_t size()
const
98 [[nodiscard]] DataT &
cell(
size_t index)
101 !std::is_same_v<DataT, EmptyVoxel>,
"Cells have no value, when DataT == EmptyVoxel");
105 [[nodiscard]]
const DataT &
cell(
size_t index)
const
108 !std::is_same_v<DataT, EmptyVoxel>,
"Cells have no value, when DataT == EmptyVoxel");
123template<
typename DataT>
130 double inv_resolution;
139 using RootMap = std::unordered_map<CoordT, InnerGrid>;
147 explicit VoxelGrid(
double voxel_size, uint8_t inner_bits = 2, uint8_t leaf_bits = 3);
209 template<
class VisitorFunction>
219 template<
class VisitorFunction>
280 mutable_grid_(grid) {}
296 [[nodiscard]] DataT *
value(
const CoordT & coord,
bool create_if_missing =
false);
327 CoordT prev_root_coord_ = {std::numeric_limits<int32_t>::max(), 0, 0};
335 return Accessor(*
this);
340 return ConstAccessor(*
this);
361template<
typename DataT>
365 mask_(
std::move(other.mask_))
367 std::swap(data_, other.data_);
370template<
typename DataT>
375 mask_ = std::move(other.mask_);
376 std::swap(data_, other.data_);
380template<
typename DataT>
383 auto mem = mask_.memUsage() +
sizeof(uint8_t) +
sizeof(uint32_t) +
sizeof(DataT *);
384 if (!std::is_same_v<DataT, EmptyVoxel>&& !external_memory_) {
385 mem +=
sizeof(DataT) * size_;
390template<
typename DataT>
393 std::vector<CoordT> keys_to_delete;
394 for (
auto & [key, inner_grid] : root_map) {
395 for (
auto inner_it = inner_grid.mask().beginOn(); inner_it; ++inner_it) {
396 const int32_t inner_index = *inner_it;
397 auto & leaf_grid = inner_grid.cell(inner_index);
398 if (leaf_grid->mask().isOff()) {
399 inner_grid.mask().setOff(inner_index);
403 if (inner_grid.mask().isOff()) {
404 keys_to_delete.push_back(key);
407 for (
const auto & key : keys_to_delete) {
410 leaf_block_allocator_.releaseUnusedMemory();
413template<
typename DataT>
415: INNER_BITS(inner_bits),
416 LEAF_BITS(leaf_bits),
417 Log2N(INNER_BITS + LEAF_BITS),
418 resolution(voxel_size),
419 inv_resolution(1.0 / resolution),
420 INNER_MASK((1 << INNER_BITS) - 1),
421 LEAF_MASK((1 << LEAF_BITS) - 1),
422 leaf_block_allocator_(leaf_bits)
424 if (LEAF_BITS < 1 || INNER_BITS < 1) {
425 throw std::runtime_error(
"The minimum value of the inner_bits and leaf_bits should be 1");
429template<
typename DataT>
433 static_cast<int32_t
>(std::floor(x * inv_resolution)),
434 static_cast<int32_t
>(std::floor(y * inv_resolution)),
435 static_cast<int32_t
>(std::floor(z * inv_resolution))};
438template<
typename DataT>
442 (
static_cast<double>(coord.
x)) * resolution, (
static_cast<double>(coord.
y)) * resolution,
443 (
static_cast<double>(coord.
z)) * resolution};
446template<
typename DataT>
449 const int32_t MASK = ~((1 << Log2N) - 1);
450 return {coord.
x & MASK, coord.
y & MASK, coord.
z & MASK};
453template<
typename DataT>
456 const int32_t MASK = ~((1 << LEAF_BITS) - 1);
457 return {coord.
x & MASK, coord.
y & MASK, coord.
z & MASK};
460template<
typename DataT>
464 return ((coord.
x >> LEAF_BITS) & INNER_MASK) |
465 (((coord.
y >> LEAF_BITS) & INNER_MASK) << INNER_BITS) |
466 (((coord.
z >> LEAF_BITS) & INNER_MASK) << (INNER_BITS * 2));
470template<
typename DataT>
474 return (coord.
x & LEAF_MASK) |
475 ((coord.
y & LEAF_MASK) << LEAF_BITS) |
476 ((coord.
z & LEAF_MASK) << (LEAF_BITS * 2));
480template<
typename DataT>
484 !std::is_same_v<DataT, EmptyVoxel>,
485 "You can not access a value when using type EmptyVoxel. Use "
486 "setCellOn / setCellOff");
488 const CoordT inner_key = mutable_grid_.getInnerKey(coord);
489 if (inner_key != prev_inner_coord_ || prev_leaf_ptr_ ==
nullptr) {
491 prev_inner_coord_ = inner_key;
494 const uint32_t index = mutable_grid_.getLeafIndex(coord);
495 const bool was_on = prev_leaf_ptr_->mask().setOn(index);
496 prev_leaf_ptr_->cell(index) =
value;
501template<
typename DataT>
505 !std::is_same_v<DataT, EmptyVoxel>,
506 "You can not access a value when using type EmptyVoxel. Use "
507 "isCellOn / setCellOn / setCellOff");
509 const CoordT inner_key = mutable_grid_.getInnerKey(coord);
511 if (inner_key != prev_inner_coord_) {
512 prev_leaf_ptr_ =
getLeafGrid(coord, create_if_missing);
513 prev_inner_coord_ = inner_key;
516 if (prev_leaf_ptr_) {
517 const uint32_t index = mutable_grid_.getLeafIndex(coord);
518 if (prev_leaf_ptr_->mask().isOn(index)) {
519 return &(prev_leaf_ptr_->cell(index));
520 }
else if (create_if_missing) {
521 prev_leaf_ptr_->mask().setOn(index);
522 prev_leaf_ptr_->cell(index) = {};
523 return &(prev_leaf_ptr_->cell(index));
529template<
typename DataT>
533 !std::is_same_v<DataT, EmptyVoxel>,
534 "You can not access a value when using type EmptyVoxel. Use isCellOn");
544 const uint32_t index =
grid_.getLeafIndex(coord);
552template<
typename DataT>
563 const uint32_t index =
grid_.getLeafIndex(coord);
572template<
typename DataT>
575 const CoordT inner_key = mutable_grid_.getInnerKey(coord);
577 if (inner_key != prev_inner_coord_) {
579 prev_inner_coord_ = inner_key;
581 uint32_t index = mutable_grid_.getLeafIndex(coord);
582 bool was_on = prev_leaf_ptr_->mask().setOn(index);
583 if constexpr (!std::is_same_v<DataT, EmptyVoxel>) {
585 prev_leaf_ptr_->cell(index) = default_value;
592template<
typename DataT>
595 const CoordT inner_key = mutable_grid_.getInnerKey(coord);
597 if (inner_key != prev_inner_coord_) {
599 prev_inner_coord_ = inner_key;
601 if (prev_leaf_ptr_) {
602 uint32_t index = mutable_grid_.getLeafIndex(coord);
603 return prev_leaf_ptr_->mask().setOff(index);
609template<
typename DataT>
612 if constexpr (std::is_trivial_v<DataT>&& !std::is_same_v<DataT, EmptyVoxel>) {
613 auto allocated = leaf_block_allocator_.allocateBlock();
614 DataT * memory_block = allocated.first;
615 auto deleter = [deleter_impl = std::move(allocated.second)](
LeafGrid * ptr) {
620 return std::shared_ptr<LeafGrid>(
new LeafGrid(LEAF_BITS, memory_block), deleter);
622 return std::make_shared<LeafGrid>(LEAF_BITS);
626template<
typename DataT>
628 const CoordT & coord,
bool create_if_missing)
631 const CoordT root_key = mutable_grid_.getRootKey(coord);
633 if (root_key != prev_root_coord_ || !inner_ptr) {
634 auto it = mutable_grid_.root_map.find(root_key);
635 if (it == mutable_grid_.root_map.end()) {
636 if (!create_if_missing) {
639 it = mutable_grid_.root_map.insert({root_key,
InnerGrid(mutable_grid_.INNER_BITS)}).first;
641 inner_ptr = &(it->second);
643 prev_root_coord_ = root_key;
644 prev_inner_ptr_ = inner_ptr;
647 const uint32_t inner_index = mutable_grid_.getInnerIndex(coord);
648 auto & inner_data = inner_ptr->
cell(inner_index);
650 if (create_if_missing) {
651 if (!inner_ptr->
mask().
setOn(inner_index)) {
652 inner_data = mutable_grid_.allocateLeafGrid();
655 if (!inner_ptr->
mask().
isOn(inner_index)) {
659 return inner_data.get();
662template<
typename DataT>
664 const CoordT & coord)
const
670 auto it =
grid_.root_map.find(root_key);
671 if (it ==
grid_.root_map.end()) {
674 inner_ptr = &(it->second);
680 const uint32_t inner_index =
grid_.getInnerIndex(coord);
681 const auto & inner_data = inner_ptr->
cell(inner_index);
683 if (!inner_ptr->
mask().
isOn(inner_index)) {
686 return inner_data.get();
689template<
typename DataT>
692 size_t total_size = 0;
694 for (
unsigned i = 0; i < root_map.bucket_count(); ++i) {
695 size_t bucket_size = root_map.bucket_size(i);
696 if (bucket_size == 0) {
699 total_size += bucket_size;
703 total_size += root_map.size() * (
sizeof(
CoordT) +
sizeof(
void *));
705 for (
const auto & [key, inner_grid] : root_map) {
706 total_size += inner_grid.memUsage();
707 for (
auto inner_it = inner_grid.mask().beginOn(); inner_it; ++inner_it) {
708 const int32_t inner_index = *inner_it;
709 auto & leaf_grid = inner_grid.cell(inner_index);
710 total_size += leaf_grid->memUsage();
715 total_size += leaf_block_allocator_.memUsage();
719template<
typename DataT>
724 leaf_block_allocator_.clear();
728 forEachCell([&accessor,
this](DataT &,
const CoordT & coord) {accessor.setCellOff(coord);});
731template<
typename DataT>
734 size_t total_size = 0;
736 for (
const auto & [key, inner_grid] : root_map) {
737 for (
auto inner_it = inner_grid.mask().beginOn(); inner_it; ++inner_it) {
738 const int32_t inner_index = *inner_it;
739 auto & leaf_grid = inner_grid.cell(inner_index);
740 total_size += leaf_grid->mask().countOn();
747template<
typename DataT>
748template<
class VisitorFunction>
751 const int32_t MASK_LEAF = ((1 << LEAF_BITS) - 1);
752 const int32_t MASK_INNER = ((1 << INNER_BITS) - 1);
754 for (
auto & map_it : root_map) {
755 const auto & [xA, yA, zA] = (map_it.first);
756 const InnerGrid & inner_grid = map_it.second;
757 const auto & mask2 = inner_grid.
mask();
759 for (
auto inner_it = mask2.beginOn(); inner_it; ++inner_it) {
760 const int32_t inner_index = *inner_it;
761 const int32_t INNER_BITS_2 = INNER_BITS * 2;
763 int32_t xB = xA | ((inner_index & MASK_INNER) << LEAF_BITS);
764 int32_t yB = yA | (((inner_index >> INNER_BITS) & MASK_INNER) << LEAF_BITS);
765 int32_t zB = zA | (((inner_index >> (INNER_BITS_2)) & MASK_INNER) << LEAF_BITS);
768 const auto & leaf_grid = inner_grid.
cell(inner_index);
769 const auto & mask1 = leaf_grid->mask();
771 for (
auto leaf_it = mask1.beginOn(); leaf_it; ++leaf_it) {
772 const int32_t leaf_index = *leaf_it;
773 const int32_t LEAF_BITS_2 = LEAF_BITS * 2;
775 xB | (leaf_index & MASK_LEAF), yB | ((leaf_index >> LEAF_BITS) & MASK_LEAF),
776 zB | ((leaf_index >> (LEAF_BITS_2)) & MASK_LEAF)};
778 if constexpr (std::is_same_v<DataT, EmptyVoxel>) {
782 func(leaf_grid->cell(leaf_index), pos);
The GridBlockAllocator is used to pre-allocate the meory of multiple Grids in "chunks".
Definition grid_allocator.hpp:30
The Grid class is used to store data in a cube.
Definition bonxai.hpp:41
size_t memUsage() const
Definition bonxai.hpp:381
Grid(const Grid &other)=delete
~Grid()
Definition bonxai.hpp:74
Grid & operator=(const Grid &other)=delete
Grid(size_t log2dim, DataT *preAllocatedMemory)
Definition bonxai.hpp:62
size_t size() const
Definition bonxai.hpp:83
Bonxai::Mask & mask()
Definition bonxai.hpp:88
const DataT & cell(size_t index) const
Definition bonxai.hpp:105
Grid(Grid &&other)
Definition bonxai.hpp:362
const Bonxai::Mask & mask() const
Definition bonxai.hpp:93
Grid & operator=(Grid &&other)
Definition bonxai.hpp:371
Grid(size_t log2dim)
Definition bonxai.hpp:52
DataT & cell(size_t index)
Definition bonxai.hpp:98
bool isOn(uint32_t n) const
Return true if the given bit is set.
Definition mask.hpp:356
bool setOn(uint32_t n)
Definition mask.hpp:381
bool setCellOff(const CoordT &coord)
setCellOff will disable a cell without deleting its content.
Definition bonxai.hpp:593
bool setCellOn(const CoordT &coord, const DataT &default_value=DataT())
setCellOn is similar to setValue, but the value is changed only if the cell has been created,...
Definition bonxai.hpp:573
Accessor(VoxelGrid &grid)
Definition bonxai.hpp:278
LeafGrid * getLeafGrid(const CoordT &coord, bool create_if_missing=false)
getLeafGrid gets the pointer to the LeafGrid containing the cell.
Definition bonxai.hpp:627
bool setValue(const CoordT &coord, const DataT &value)
setValue of a cell.
Definition bonxai.hpp:481
EmptyVoxel * value(const CoordT &coord, bool create_if_missing=false)
Definition bonxai.hpp:502
const InnerGrid * prev_inner_ptr_
Definition bonxai.hpp:267
CoordT prev_root_coord_
Definition bonxai.hpp:265
const VoxelGrid & grid_
Definition bonxai.hpp:264
ConstAccessor(const VoxelGrid &grid)
Definition bonxai.hpp:233
bool isCellOn(const CoordT &coord) const
isCellOn only check if a cell is in "On" state
Definition bonxai.hpp:553
const LeafGrid * lastLeafGrid() const
lastLeafGrid returns the pointer to the LeafGrid in the cache.
Definition bonxai.hpp:256
const LeafGrid * prev_leaf_ptr_
Definition bonxai.hpp:268
const InnerGrid * lastInnerGrid() const
lastInnerGrid returns the pointer to the InnerGrid in the cache.
Definition bonxai.hpp:250
CoordT prev_inner_coord_
Definition bonxai.hpp:266
const LeafGrid * getLeafGrid(const CoordT &coord) const
Definition bonxai.hpp:663
const DataT * value(const CoordT &coord) const
value getter.
Definition bonxai.hpp:530
Definition bonxai.hpp:124
uint32_t innetBits() const
Definition bonxai.hpp:155
Grid< std::shared_ptr< LeafGrid > > InnerGrid
Definition bonxai.hpp:138
size_t memUsage() const
getMemoryUsage returns the amount of bytes used by this data structure
Definition bonxai.hpp:690
ConstAccessor createConstAccessor() const
Definition bonxai.hpp:338
CoordT posToCoord(const Point3D &pos) const
posToCoord is used to convert real coordinates to CoordT indices.
Definition bonxai.hpp:194
Accessor createAccessor()
Definition bonxai.hpp:333
void forEachCell(VisitorFunction func)
forEachCell apply a function of type:
Definition bonxai.hpp:220
VoxelGrid(double voxel_size, uint8_t inner_bits=2, uint8_t leaf_bits=3)
VoxelGrid constructor.
Definition bonxai.hpp:414
uint32_t leafBits() const
Definition bonxai.hpp:159
void clear(ClearOption opt)
Definition bonxai.hpp:720
const RootMap & rootMap() const
Definition bonxai.hpp:168
VoxelGrid & operator=(VoxelGrid &&other)=default
uint32_t getInnerIndex(const CoordT &coord) const
Definition bonxai.hpp:461
CoordT getInnerKey(const CoordT &coord) const
Definition bonxai.hpp:454
Grid< DataT > LeafGrid
Definition bonxai.hpp:137
VoxelGrid(VoxelGrid &&other)=default
double voxelSize() const
Definition bonxai.hpp:163
CoordT getRootKey(const CoordT &coord) const
Definition bonxai.hpp:447
RootMap & rootMap()
Definition bonxai.hpp:172
VoxelGrid(const VoxelGrid &)=delete
uint32_t getLeafIndex(const CoordT &coord) const
Definition bonxai.hpp:471
std::shared_ptr< LeafGrid > allocateLeafGrid()
Definition bonxai.hpp:610
void forEachCell(VisitorFunction func) const
forEachCell apply a function of type:
Definition bonxai.hpp:749
CoordT posToCoord(double x, double y, double z) const
posToCoord is used to convert real coordinates to CoordT indices.
Definition bonxai.hpp:430
size_t activeCellsCount() const
Return the total number of active cells.
Definition bonxai.hpp:732
VoxelGrid & operator=(const VoxelGrid &)=delete
void releaseUnusedMemory()
Try freeing memory; this will discard grids where all the cells are OFF.
Definition bonxai.hpp:391
Point3D coordToPos(const CoordT &coord) const
coordToPos converts CoordT indices to Point3D.
Definition bonxai.hpp:439
std::unordered_map< CoordT, InnerGrid > RootMap
Definition bonxai.hpp:139
VoxelGrid< EmptyVoxel > BinaryVoxelGrid
Definition bonxai.hpp:355
ClearOption
Definition bonxai.hpp:116
@ CLEAR_MEMORY
Definition bonxai.hpp:118
@ SET_ALL_CELLS_OFF
Definition bonxai.hpp:120
Definition grid_coord.hpp:226
Definition grid_coord.hpp:67
int32_t z
Definition grid_coord.hpp:70
int32_t y
Definition grid_coord.hpp:69
int32_t x
Definition grid_coord.hpp:68
Definition grid_coord.hpp:34
double z
Definition grid_coord.hpp:37
double y
Definition grid_coord.hpp:36
double x
Definition grid_coord.hpp:35