36 static auto constexpr kDims = 3;
37 using OverlapType = cuda::std::pair<GpuIndex, GpuIndex>;
40 friend class BvhQuery;
43 std::is_same_v<GpuIndex, std::int32_t>,
44 "gpu::BvhImpl only supported for 32-bit signed integer indices");
58 void Build(
Aabb<kDims>& aabbs, Morton::Bound
const& min, Morton::Bound
const& max);
87 template <
class FOnOverlapDetected>
99 template <
class FOnOverlapDetected, auto kStackSize = 64>
103 FOnOverlapDetected fOnOverlapDetected);
132 class FGetQueryObject,
133 class FMinDistanceToBox,
134 class FDistanceToLeaf,
135 class FDistanceUpperBound,
136 class FOnNearestNeighbourFound,
138 auto kStackSize = 64>
142 FGetQueryObject fGetQueryObject,
143 FMinDistanceToBox fMinDistanceToBox,
144 FDistanceToLeaf fDistanceToleaf,
145 FDistanceUpperBound fDistanceUpperBound,
146 FOnNearestNeighbourFound fOnNearestNeighbourFound,
173 class FGetQueryObject,
174 class FMinDistanceToBox,
175 class FDistanceToLeaf,
176 class FDistanceUpperBound,
178 auto kStackSize = 64>
182 FGetQueryObject fGetQueryObject,
183 FMinDistanceToBox fMinDistanceToBox,
184 FDistanceToLeaf fDistanceToleaf,
185 FDistanceUpperBound fDistanceUpperBound,
208 PBAT_PROFILE_CUDA_NAMED_SCOPE(
"pbat.gpu.impl.geometry.Bvh.DetectOverlaps");
209 auto const nLeafBoxes = aabbs.Size();
212 thrust::make_counting_iterator(0),
213 thrust::make_counting_iterator(nLeafBoxes),
221 leafBegin = nLeafBoxes - 1,
223 std::forward<FOnOverlapDetected>(fOnOverlapDetected)] PBAT_DEVICE(
GpuIndex s)
mutable {
228 auto const leaf = leafBegin + s;
229 auto Ls = mini::FromBuffers<3, 1>(b, s);
230 auto Us = mini::FromBuffers<3, 1>(e, s);
231 Stack<GpuIndex, 64> stack{};
235 assert(not stack.IsFull());
240 bool const bIsLeftLeaf = lc >= leafBegin;
241 bool const bIsRightLeaf = rc >= leafBegin;
242 auto Llc = bIsLeftLeaf ? mini::FromBuffers<3, 1>(b, lc - leafBegin) :
243 mini::FromBuffers<3, 1>(ib, lc);
244 auto Ulc = bIsLeftLeaf ? mini::FromBuffers<3, 1>(e, lc - leafBegin) :
245 mini::FromBuffers<3, 1>(ie, lc);
246 auto Lrc = bIsRightLeaf ? mini::FromBuffers<3, 1>(b, rc - leafBegin) :
247 mini::FromBuffers<3, 1>(ib, rc);
248 auto Urc = bIsRightLeaf ? mini::FromBuffers<3, 1>(e, rc - leafBegin) :
249 mini::FromBuffers<3, 1>(ie, rc);
250 bool const bLeftBoxOverlaps =
253 bool const bRightBoxOverlaps =
258 if (bLeftBoxOverlaps and bIsLeftLeaf)
262 fOnOverlapDetected(si, sj);
264 if (bRightBoxOverlaps and bIsRightLeaf)
268 fOnOverlapDetected(si, sj);
272 bool const bTraverseLeft = bLeftBoxOverlaps and not bIsLeftLeaf;
273 bool const bTraverseRight = bRightBoxOverlaps and not bIsRightLeaf;
278 }
while (not stack.IsEmpty());
286 FOnOverlapDetected fOnOverlapDetected)
288 PBAT_PROFILE_CUDA_NAMED_SCOPE(
"pbat.gpu.impl.geometry.Bvh.DetectOverlaps");
291 std::is_invocable_v<FOnOverlapDetected, GpuIndex, GpuIndex>,
292 "FOnOverlapDetected must be callable with signature void f(GpuIndex,GpuIndex)");
295 auto fGetQueryObject = [b = queryAabbs.b.Raw(),
296 e = queryAabbs.e.Raw()] PBAT_DEVICE(
GpuIndex q) {
298 LU.Col(0) = mini::FromBuffers<3, 1>(b, q);
299 LU.Col(1) = mini::FromBuffers<3, 1>(e, q);
302 auto fMinDistanceToBox = [] PBAT_DEVICE(
304 mini::SVector<GpuScalar, 3>
const& L2,
305 mini::SVector<GpuScalar, 3>
const& U2) {
311 return static_cast<GpuScalar>(not bBoxesOverlap);
313 auto fDistanceToLeaf = [] PBAT_DEVICE(
320 auto fQueryUpperBound = [] PBAT_DEVICE(
GpuIndex q) {
323 auto fOnFound = [fOnOverlapDetected] PBAT_DEVICE(
328 fOnOverlapDetected(q, i);
332 decltype(fGetQueryObject),
333 decltype(fMinDistanceToBox),
334 decltype(fDistanceToLeaf),
335 decltype(fQueryUpperBound),
358 FGetQueryObject fGetQueryObject,
359 FMinDistanceToBox fMinDistanceToBox,
360 FDistanceToLeaf fDistanceToLeaf,
361 FDistanceUpperBound fDistanceUpperBound,
362 FOnNearestNeighbourFound fOnNearestNeighbourFound,
365 PBAT_PROFILE_CUDA_NAMED_SCOPE(
"pbat.gpu.impl.geometry.Bvh.NearestNeighbours");
367 using TQuery = std::invoke_result_t<FGetQueryObject, GpuIndex>;
368 using Point = pbat::math::linalg::mini::SVector<GpuScalar, kDims>;
371 std::is_invocable_v<FGetQueryObject, GpuIndex> and not std::is_same_v<TQuery, void>,
372 "FGetQueryObject must be callable with signature TQuery f(GpuIndex)");
374 std::is_invocable_v<FMinDistanceToBox, TQuery, Point, Point> and
375 std::is_convertible_v<
376 std::invoke_result_t<FMinDistanceToBox, TQuery, Point, Point>,
378 "FMinDistanceToBox must be callable with signature GpuScalar f(TQuery, Point, Point) where "
379 "Point=pbat::math::linalg::mini::SVector<GpuScalar, 3>");
381 std::is_invocable_v<FDistanceToLeaf, GpuIndex, TQuery, GpuIndex, GpuIndex> and
382 std::is_convertible_v<
383 std::invoke_result_t<FDistanceToLeaf, GpuIndex, TQuery, GpuIndex, GpuIndex>,
385 "FDistanceToLeaf must be callable with signature GpuScalar f(GpuIndex, TQuery query, "
389 std::is_invocable_v<FDistanceUpperBound, GpuIndex> and
390 std::is_convertible_v<std::invoke_result_t<FDistanceUpperBound, GpuIndex>,
GpuScalar>,
391 "FDistanceUpperBound must be callable with signature GpuScalar f(GpuIndex)");
393 std::is_invocable_v<FOnNearestNeighbourFound, GpuIndex, GpuIndex, GpuScalar, GpuIndex>,
394 "FOnNearestNeighbourFound must be callable with signature void f(GpuIndex query, GpuIndex "
395 "leaf, GpuScalar dmin, GpuIndex k)");
399 thrust::make_counting_iterator(0),
400 thrust::make_counting_iterator(nQueries),
406 fOnNearestNeighbourFound,
407 leafBegin = aabbs.Size() - 1,
414 using pbat::math::linalg::mini::FromBuffers;
422 TQuery
const query{fGetQueryObject(q)};
427 assert(not dfs.IsFull());
429 bool const bIsLeafNode = nodeIdx >= leafBegin;
430 auto lo = dmin - eps;
431 auto hi = dmin + eps;
434 auto L = FromBuffers<3, 1>(ib, nodeIdx);
435 auto U = FromBuffers<3, 1>(ie, nodeIdx);
436 auto db = fMinDistanceToBox(query, L, U);
439 dfs.Push(
child[0][nodeIdx]);
440 dfs.Push(
child[1][nodeIdx]);
445 nodeIdx -= leafBegin;
446 auto L = FromBuffers<3, 1>(b, nodeIdx);
447 auto U = FromBuffers<3, 1>(e, nodeIdx);
448 GpuScalar const db = fMinDistanceToBox(query, L, U);
452 GpuScalar const d = fDistanceToLeaf(q, query, nodeIdx, i);
459 else if (d <= hi and not nn.IsFull())
465 }
while (not dfs.IsEmpty());
467 while (not nn.IsEmpty())
471 fOnNearestNeighbourFound(q, i, dmin, k++);
486 FGetQueryObject fGetQueryObject,
487 FMinDistanceToBox fMinDistanceToBox,
488 FDistanceToLeaf fDistanceToleaf,
489 FDistanceUpperBound fDistanceUpperBound,
492 PBAT_PROFILE_CUDA_NAMED_SCOPE(
"pbat.gpu.impl.geometry.Bvh.RangeSearch");
494 using TQuery = std::invoke_result_t<FGetQueryObject, GpuIndex>;
495 using Point = pbat::math::linalg::mini::SVector<GpuScalar, kDims>;
497 std::is_invocable_v<FGetQueryObject, GpuIndex> and not std::is_same_v<TQuery, void>,
498 "FGetQueryObject must be callable with signature TQuery f(GpuIndex)");
500 std::is_invocable_v<FMinDistanceToBox, TQuery, Point, Point> and
501 std::is_convertible_v<
502 std::invoke_result_t<FMinDistanceToBox, TQuery, Point, Point>,
504 "FMinDistanceToBox must be callable with signature GpuScalar f(TQuery, Point, Point) where "
505 "Point=pbat::math::linalg::mini::SVector<GpuScalar, 3>");
507 std::is_invocable_v<FDistanceToLeaf, GpuIndex, TQuery, GpuIndex, GpuIndex> and
508 std::is_convertible_v<
509 std::invoke_result_t<FDistanceToLeaf, GpuIndex, TQuery, GpuIndex, GpuIndex>,
511 "FDistanceToLeaf must be callable with signature GpuScalar f(GpuIndex q, TQuery query, "
515 std::is_invocable_v<FDistanceUpperBound, GpuIndex> and
516 std::is_convertible_v<std::invoke_result_t<FDistanceUpperBound, GpuIndex>,
GpuScalar>,
517 "FDistanceUpperBound must be callable with signature GpuScalar f(GpuIndex)");
519 std::is_invocable_v<FOnFound, GpuIndex, GpuIndex, GpuIndex, GpuScalar>,
520 "FOnFound must be callable with signature void f(GpuIndex q, GpuIndex "
521 "leafIdx, GpuIndex i, GpuScalar d)");
525 thrust::make_counting_iterator(0),
526 thrust::make_counting_iterator(nQueries),
527 [leafBegin = aabbs.Size() - 1,
534 fGetQueryObject = std::forward<FGetQueryObject>(fGetQueryObject),
535 fMinDistanceToBox = std::forward<FMinDistanceToBox>(fMinDistanceToBox),
536 fDistanceToLeaf = std::forward<FDistanceToLeaf>(fDistanceToleaf),
537 fDistanceUpperBound = std::forward<FDistanceUpperBound>(fDistanceUpperBound),
538 fOnFound = std::forward<FOnFound>(fOnFound)] PBAT_DEVICE(
GpuIndex q)
mutable {
539 using pbat::math::linalg::mini::FromBuffers;
544 GpuScalar const upper{fDistanceUpperBound(q)};
545 TQuery
const query{fGetQueryObject(q)};
550 assert(not dfs.IsFull());
552 bool const bIsLeafNode = nodeIdx >= leafBegin;
555 auto L = FromBuffers<3, 1>(ib, nodeIdx);
556 auto U = FromBuffers<3, 1>(ie, nodeIdx);
557 if (fMinDistanceToBox(query, L, U) <= upper)
559 dfs.Push(
child[0][nodeIdx]);
560 dfs.Push(
child[1][nodeIdx]);
565 nodeIdx -= leafBegin;
566 auto L = FromBuffers<3, 1>(b, nodeIdx);
567 auto U = FromBuffers<3, 1>(e, nodeIdx);
568 GpuScalar const db = fMinDistanceToBox(query, L, U);
572 GpuScalar const d = fDistanceToLeaf(q, query, nodeIdx, i);
575 fOnFound(q, nodeIdx, i, d);
579 }
while (not dfs.IsEmpty());
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