1#ifndef PBAT_GEOMETRY_HIERARCHICALHASHGRID_H
2#define PBAT_GEOMETRY_HIERARCHICALHASHGRID_H
10#include "pbat/math/linalg/mini/Eigen.h"
28template <
int Dims, common::CFloatingPo
int TScalar = Scalar, common::CIndex TIndex = Index>
34 static constexpr int kDims = Dims;
35 static_assert(Dims >= 2 and Dims <= 3,
"HierarchicalHashGrid only supports 2D and 3D");
68 template <
class TDerivedL,
class TDerivedU>
69 void Construct(Eigen::DenseBase<TDerivedL>
const& L, Eigen::DenseBase<TDerivedU>
const& U);
80 template <
class FOnPair,
class TDerivedX>
81 void BroadPhase(Eigen::DenseBase<TDerivedX>
const& X, FOnPair fOnPair)
const;
94 template <
class FOnPair,
class TDerivedL,
class TDerivedU>
96 Eigen::DenseBase<TDerivedL>
const& L,
97 Eigen::DenseBase<TDerivedU>
const& U,
98 FOnPair fOnPair)
const;
112 template <
class FOnPair,
class TDerivedLP,
class TDerivedUP,
class TDerivedX>
114 Eigen::DenseBase<TDerivedLP>
const& LP,
115 Eigen::DenseBase<TDerivedUP>
const& UP,
116 Eigen::DenseBase<TDerivedX>
const& XQ,
117 FOnPair fOnPair)
const;
133 template <
class FOnPair,
class TDerivedLP,
class TDerivedUP,
class TDerivedLQ,
class TDerivedUQ>
135 Eigen::DenseBase<TDerivedLP>
const& LP,
136 Eigen::DenseBase<TDerivedUP>
const& UP,
137 Eigen::DenseBase<TDerivedLQ>
const& LQ,
138 Eigen::DenseBase<TDerivedUQ>
const& UQ,
139 FOnPair fOnPair)
const;
154 auto Levels() const -> std::span<std::int16_t const>
156 return std::span<std::int16_t const>(mSetOfLevels.begin(), mSetOfLevels.Size());
166 template <
class TDerivedX>
168 Eigen::DenseBase<TDerivedX>
const& X,
170 -> Eigen::Vector<IndexType, kDims>;
178 template <
class TDerivedX>
179 auto Hash(Eigen::DenseBase<TDerivedX>
const& X, std::int16_t l)
const;
188 Eigen::Vector<std::uint8_t, Eigen::Dynamic>
190 Eigen::Vector<IndexType, Eigen::Dynamic>
194 Eigen::Vector<IndexType, Eigen::Dynamic>
198 Eigen::Vector<IndexType, Eigen::Dynamic>
205template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
218template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
223 mCellCounts.resize(nPrimitives);
224 mBucketIds.resize(nBuckets);
225 mPrefix.resize(nBuckets + 1);
226 mPrimitiveIds.resize(nBuckets);
229template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
230template <
class TDerivedL,
class TDerivedU>
232 Eigen::DenseBase<TDerivedL>
const& L,
233 Eigen::DenseBase<TDerivedU>
const& U)
235 PBAT_PROFILE_NAMED_SCOPE(
"pbat.geometry.HierarchicalHashGrid.Construct");
236 assert(L.rows() ==
kDims and U.rows() ==
kDims);
237 assert(L.cols() == U.cols());
238 auto const nPrimitives =
static_cast<IndexType>(L.cols());
240 assert(nPrimitives <= nBuckets);
241 assert(mPrefix.size() == nBuckets + 1);
246 for (
IndexType i = 0; i < nPrimitives; ++i)
248 ScalarType const maxExtent = (U.col(i) - L.col(i)).maxCoeff();
249 ScalarType const l = std::ceil(std::log2(maxExtent));
251 Eigen::Vector<IndexType, kDims>
const ib =
253 Eigen::Vector<IndexType, kDims>
const ie =
255 auto const level =
static_cast<std::int16_t
>(l);
256 Eigen::Vector<IndexType, kDims> ix;
258 for (ix(0) = ib(0); ix(0) <= ie(0); ++ix(0))
260 for (ix(1) = ib(1); ix(1) <= ie(1); ++ix(1))
262 if constexpr (
kDims == 2)
265 mBucketIds(k++) = common::Modulo(hash, nBuckets);
270 for (ix(2) = ib(2); ix(2) <= ie(2); ++ix(2))
273 mBucketIds(k++) = common::Modulo(hash, nBuckets);
279 mSetOfLevels.Insert(level);
282 mPrefix(mBucketIds.segment(0, k)).array() += 1;
284 std::inclusive_scan(mPrefix.begin(), mPrefix.end(), mPrefix.begin());
287 for (
IndexType i = 0; i < nPrimitives; ++i)
289 for (std::uint8_t j = 0; j < mCellCounts(i); ++j, ++k)
291 auto bucketId = mBucketIds(k);
292 mPrimitiveIds(--mPrefix(bucketId)) = i;
297template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
298template <
class FOnPair,
class TDerivedX>
300 Eigen::DenseBase<TDerivedX>
const& X,
301 FOnPair fOnPair)
const
303 PBAT_PROFILE_NAMED_SCOPE(
"pbat.geometry.HierarchicalHashGrid.BroadPhase");
304 assert(X.rows() ==
kDims);
305 auto const nQueries =
static_cast<IndexType>(X.cols());
309 for (std::int16_t l : mSetOfLevels)
313 auto bucketId = (
kDims == 2) ?
314 common::Modulo(
Hash(iq, l), nBuckets) :
315 common::Modulo(
Hash(iq, l), nBuckets);
316 auto beginBucket = mPrefix(bucketId);
317 auto endBucket = mPrefix(bucketId + 1);
318 for (
auto k = beginBucket; k < endBucket; ++k)
320 auto const i = mPrimitiveIds(k);
327template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
328template <
class FOnPair,
class TDerivedL,
class TDerivedU>
330 Eigen::DenseBase<TDerivedL>
const& L,
331 Eigen::DenseBase<TDerivedU>
const& U,
332 FOnPair fOnPair)
const
334 PBAT_PROFILE_NAMED_SCOPE(
"pbat.geometry.HierarchicalHashGrid.BroadPhase");
335 assert(L.rows() ==
kDims);
336 assert(U.rows() ==
kDims);
337 assert(L.cols() == U.cols());
338 auto const nQueries =
static_cast<IndexType>(L.cols());
342 for (std::int16_t l : mSetOfLevels)
347 Eigen::Vector<IndexType, kDims> iq;
348 for (iq(0) = iqb(0); iq(0) <= iqe(0); ++iq(0))
350 for (iq(1) = iqb(1); iq(1) <= iqe(1); ++iq(1))
352 if constexpr (
kDims == 2)
354 auto bucketId = common::Modulo(
Hash(iq, l), nBuckets);
355 auto beginBucket = mPrefix(bucketId);
356 auto endBucket = mPrefix(bucketId + 1);
357 for (
auto k = beginBucket; k < endBucket; ++k)
359 auto const i = mPrimitiveIds(k);
365 for (iq(2) = iqb(2); iq(2) <= iqe(2); ++iq(2))
367 auto bucketId = common::Modulo(
Hash(iq, l), nBuckets);
368 auto beginBucket = mPrefix(bucketId);
369 auto endBucket = mPrefix(bucketId + 1);
370 for (
auto k = beginBucket; k < endBucket; ++k)
372 auto const i = mPrimitiveIds(k);
383template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
384template <
class FOnPair,
class TDerivedLP,
class TDerivedUP,
class TDerivedX>
386 Eigen::DenseBase<TDerivedLP>
const& LP,
387 Eigen::DenseBase<TDerivedUP>
const& UP,
388 Eigen::DenseBase<TDerivedX>
const& XQ,
389 FOnPair fOnPair)
const
394 using pbat::math::linalg::mini::FromEigen;
396 FromEigen(XQ.col(q).template head<kDims>()),
397 FromEigen(LP.col(p).template head<kDims>()),
398 FromEigen(UP.col(p).template head<kDims>())))
405template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
406template <
class FOnPair,
class TDerivedLP,
class TDerivedUP,
class TDerivedLQ,
class TDerivedUQ>
408 Eigen::DenseBase<TDerivedLP>
const& LP,
409 Eigen::DenseBase<TDerivedUP>
const& UP,
410 Eigen::DenseBase<TDerivedLQ>
const& LQ,
411 Eigen::DenseBase<TDerivedUQ>
const& UQ,
412 FOnPair fOnPair)
const
414 using pbat::math::linalg::mini::FromEigen;
420 FromEigen(LP.col(p).template head<kDims>()),
421 FromEigen(UP.col(p).template head<kDims>()),
422 FromEigen(LQ.col(q).template head<kDims>()),
423 FromEigen(UQ.col(q).template head<kDims>())))
430template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
431template <
class TDerivedX>
433 Eigen::DenseBase<TDerivedX>
const& X,
434 ScalarType const cellSize)
const -> Eigen::Vector<IndexType, kDims>
436 return Eigen::Vector<ScalarType, kDims>(X.derived().array() /
static_cast<ScalarType>(cellSize))
439 .template cast<IndexType>();
442template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
443template <
class TDerivedX>
445 Eigen::DenseBase<TDerivedX>
const& X,
446 std::int16_t l)
const
448 if constexpr (
kDims == 2)
449 return (X(0) * 73856093) ^ (X(1) * 19349663) ^ (l * 67867979);
451 return (X(0) * 73856093) ^ (X(1) * 19349663) ^ (X(2) * 834927911) ^ (l * 67867979);
454template <
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
457 mCellCounts.setZero();
458 mPrimitiveIds.setConstant(
IndexType(-1));
460 mSetOfLevels.Clear();
Fixed-size brute-force set implementation usable in both host and device code, suitable for small set...
This file contains functions to answer overlap queries.
Fixed-size brute-force set implementation.
Definition BruteSet.h:29
auto Levels() const -> std::span< std::int16_t const >
Get the set of levels in the hierarchical grid.
Definition HierarchicalHashGrid.h:154
void Construct(Eigen::DenseBase< TDerivedL > const &L, Eigen::DenseBase< TDerivedU > const &U)
Construct a HashGrid from lower and upper bounds of input axis-aligned bounding boxes (aabbs).
Definition HierarchicalHashGrid.h:231
IndexType NumberOfBuckets() const
Get the number of buckets in the hash table.
Definition HierarchicalHashGrid.h:144
static constexpr int kMaxCellsPerPrimitive
Maximum number of cells per primitive in the grid.
Definition HierarchicalHashGrid.h:36
HierarchicalHashGrid()=default
Default constructor for HierarchicalHashGrid.
void Configure(IndexType nPrimitives, IndexType nBuckets=0)
Configure the hash grid with a specific number of buckets.
Definition HierarchicalHashGrid.h:220
auto ToIntegerCoordinates(Eigen::DenseBase< TDerivedX > const &X, ScalarType const cellSize) const -> Eigen::Vector< IndexType, kDims >
Convert a point X to integer coordinates in the grid.
Definition HierarchicalHashGrid.h:432
TIndex IndexType
Type alias for index values (e.g., int or long).
Definition HierarchicalHashGrid.h:33
IndexType NumberOfLevels() const
Get the number of levels in the hierarchical grid.
Definition HierarchicalHashGrid.h:149
void ClearHashTable()
Clear the hash table, resetting all internal data structures.
Definition HierarchicalHashGrid.h:455
TScalar ScalarType
Type alias for scalar values (e.g., float or double).
Definition HierarchicalHashGrid.h:32
auto Hash(Eigen::DenseBase< TDerivedX > const &X, std::int16_t l) const
Hash a point X at level l in the grid. See eitz2007hierarchical for details on the hashing scheme.
Definition HierarchicalHashGrid.h:444
void BroadPhase(Eigen::DenseBase< TDerivedX > const &X, FOnPair fOnPair) const
Find all primitives whose cell overlaps with points X.
Definition HierarchicalHashGrid.h:299
static constexpr int kDims
Number of spatial dimensions.
Definition HierarchicalHashGrid.h:34
Concepts for common types.
Eigen adaptors for ranges.
PBAT_HOST_DEVICE bool AxisAlignedBoundingBoxes(TMatrixL1 const &L1, TMatrixU1 const &U1, TMatrixL2 const &L2, TMatrixU2 const &U2)
Tests for overlap between axis-aligned bounding box (L1,U1) and axis-aligned bounding box (L2,...
Definition OverlapQueries.h:608
PBAT_HOST_DEVICE bool PointAxisAlignedBoundingBox(TMatrixP const &P, TMatrixL const &L, TMatrixU const &U)
Tests for overlap between point P and axis-aligned bounding box (L,U)
Definition OverlapQueries.h:536
Geometric queries, quantities and data structures.
Definition AabbKdTreeHierarchy.h:23
std::ptrdiff_t Index
Index type.
Definition Aliases.h:17
Profiling utilities for the Physics-Based Animation Toolkit (PBAT)