53#ifndef PECLET_CORE_GEOM_SCENE_QUERY_HPP
54#define PECLET_CORE_GEOM_SCENE_QUERY_HPP
87 d.x = cd::hdFma(-cd::hdNearbyint(
d.x / b.
Lx), b.
Lx,
d.x);
88 d.y = cd::hdFma(-cd::hdNearbyint(
d.y / b.
Ly), b.
Ly,
d.y);
89 d.z = cd::hdFma(-cd::hdNearbyint(
d.z / b.
Lz), b.
Lz,
d.z);
119 return cd::hdFma(
d.z,
d.z, cd::hdFma(
d.y,
d.y,
d.x *
d.x));
131 for (
int k = 0;
k < count; ++
k) {
139 for (
int k = 0;
k < count; ++
k) {
140 const int i = items[
k];
155 for (
int i = 0;
i < u.
n; ++
i) {
163 for (
int i = 0;
i < u.
n; ++
i) {
211 const long b = g.
binOf(p);
251 throw std::invalid_argument(
"buildSphereCandidateGrid: empty union");
253 for (
int i = 0;
i < u.
n; ++
i)
260 return nb < 2 ? 2 : (
nb > 96 ? 96 :
nb);
270 m.bx = extent.
x /
m.nx;
271 m.by = extent.
y /
m.ny;
272 m.bz = extent.
z /
m.nz;
281 const long i = b %
m.nx,
j = (b /
m.nx) %
m.ny,
k = b / ((
long)
m.nx *
m.ny);
283 m.oz + (
k +
Real(0.5)) *
m.bz};
287 return std::sqrt(
d.x *
d.x +
d.y *
d.y +
d.z *
d.z);
292 const int riX =
static_cast<int>(
reach /
m.bx) + 1;
293 const int riY =
static_cast<int>(
reach /
m.by) + 1;
294 const int riZ =
static_cast<int>(
reach /
m.bz) + 1;
303 ii = ((
ii %
m.nx) +
m.nx) %
m.nx;
304 jj = ((
jj %
m.ny) +
m.ny) %
m.ny;
305 kk = ((
kk %
m.nz) +
m.nz) %
m.nz;
319 : std::sqrt(extent.
x * extent.
x + extent.
y * extent.
y + extent.
z * extent.
z);
320 for (
int i = 0;
i < u.
n; ++
i)
325 if (
up <
U[(std::size_t)b])
326 U[(std::size_t)b] =
up;
335 std::vector<std::vector<int>>
lists((std::size_t)
nbins);
336 for (
int i = 0;
i < u.
n; ++
i)
340 const Real lower = dist(c, i) - halfDiag - u.r[i];
341 if (lower <= U[(std::size_t)b] + slack)
342 lists[(std::size_t)b].push_back(i);
346 for (
long b = 0; b <
nbins; ++b)
347 g.
offsets[(std::size_t)b + 1] =
348 g.
offsets[(std::size_t)b] +
static_cast<int>(
lists[(std::size_t)b].size());
350 for (
long b = 0; b <
nbins; ++b)
351 std::copy(
lists[(std::size_t)b].begin(),
lists[(std::size_t)b].end(),
381 return inst.transform.scale *
389 int nAlt[3] = {1, 1, 1};
391 for (
int a = 0; a < 3; ++a) {
407 sc.nodeCount,
inst.shapeRoot,
q,
423 for (
int i = 0;
i <
sc.instanceCount; ++
i) {
445namespace query_detail {
529 }
else if (
dist + a.
r <= b.
r) {
560 inst.transform.translation);
579 const long b = g.
binOf(p);
594 for (
int k =
lo;
k <
hi; ++
k) {
615 std::vector<InstanceBound<Real>>
ib((std::size_t)
sc.instanceCount);
619 for (
int i = 0;
i <
sc.instanceCount; ++
i) {
622 if (
ib[(std::size_t)
i].certified) {
632 int nb =
static_cast<int>(
L /
bin);
633 return nb < 2 ? 2 : (
nb > 96 ? 96 :
nb);
641 m.bx = extent.
x /
m.nx;
642 m.by = extent.
y /
m.ny;
643 m.bz = extent.
z /
m.nz;
650 const long i = b %
m.nx,
j = (b /
m.nx) %
m.ny,
k = b / ((
long)
m.nx *
m.ny);
652 m.oz + (
k +
Real(0.5)) *
m.bz};
655 const int riX =
static_cast<int>(
reach /
m.bx) + 1;
656 const int riY =
static_cast<int>(
reach /
m.by) + 1;
657 const int riZ =
static_cast<int>(
reach /
m.bz) + 1;
658 const int ci =
static_cast<int>(std::floor((c.
x -
m.ox) /
m.bx));
659 const int cj =
static_cast<int>(std::floor((c.
y -
m.oy) /
m.by));
660 const int ck =
static_cast<int>(std::floor((c.
z -
m.oz) /
m.bz));
666 ii = ((
ii %
m.nx) +
m.nx) %
m.nx;
667 jj = ((
jj %
m.ny) +
m.ny) %
m.ny;
668 kk = ((
kk %
m.nz) +
m.nz) %
m.nz;
688 for (
int i = 0;
i <
sc.instanceCount; ++
i)
689 if (
ib[(std::size_t)
i].certified)
692 std::vector<std::vector<int>>
lists((std::size_t)
nbins);
693 for (
long b = 0; b <
nbins; ++b) {
696 for (std::size_t
k = 0;
k <
certIdx.size(); ++
k) {
703 for (std::size_t
k = 0;
k <
certIdx.size(); ++
k)
709 for (
long b = 0; b <
nbins; ++b)
710 g.
offsets[(std::size_t)b + 1] =
711 g.
offsets[(std::size_t)b] +
static_cast<int>(
lists[(std::size_t)b].size());
713 for (
long b = 0; b <
nbins; ++b)
714 std::copy(
lists[(std::size_t)b].begin(),
lists[(std::size_t)b].end(),
742namespace owner_detail {
761 for (
int k = 0;
k < count; ++
k) {
762 const int i = items[
k];
767 for (
int k = 0;
k < count; ++
k) {
768 const int i = items[
k];
782 for (
int i = 0;
i < u.
n; ++
i)
787 for (
int i = 0;
i < u.
n; ++
i)
800 const long b = g.
binOf(p);
820 for (
int i = 0;
i <
sc.instanceCount; ++
i)
841 const long b = g.
binOf(p);
843 if (b < 0 ||
lo ==
hi) {
844 for (
int i = 0;
i <
sc.instanceCount; ++
i)
850 for (
int k =
lo;
k <
hi; ++
k) {
925 v.x =
m.
lin[3 *
i + 0];
926 v.y =
m.lin[3 *
i + 1];
927 v.z =
m.lin[3 *
i + 2];
929 if (!
m.ang || !
m.cen)
931 const Real wx =
m.ang[3 *
i + 0],
wy =
m.ang[3 *
i + 1],
wz =
m.ang[3 *
i + 2];
936 v.x +=
wy * r.
z -
wz * r.
y;
937 v.y +=
wz * r.
x -
wx * r.
z;
938 v.z +=
wx * r.
y -
wy * r.
x;
952 const Real g2 = cd::hdFma(grad.
z, grad.
z, cd::hdFma(grad.
y, grad.
y, grad.
x * grad.
x));
965 for (
int i = 0;
i < 3 *
m.n; ++
i) {
966 if (
m.lin &&
m.lin[
i] !=
Real(0))
968 if (
m.ang &&
m.ang[
i] !=
Real(0))
1017template <
class Real>
1019 std::vector<Real>& cy, std::vector<Real>& cz, std::vector<Real>& r) {
1025 const bool q =
t.rotation.x ==
Real(0) &&
t.rotation.y ==
Real(0) &&
t.rotation.z ==
Real(0) &&
1026 t.rotation.w ==
Real(1) &&
t.scale ==
Real(1);
1028 t.translation.z ==
Real(0));
1031 for (
int i = 0;
i <
sc.instanceCount; ++
i) {
1033 if (
inst.shapeRoot < 0 ||
inst.shapeRoot >=
sc.nodeCount)
1038 cx.push_back(
inst.transform.translation.x);
1039 cy.push_back(
inst.transform.translation.y);
1040 cz.push_back(
inst.transform.translation.z);
1041 r.push_back(n.
params[0]);
1055 SphereBedQuery(std::vector<double> cx, std::vector<double> cy, std::vector<double> cz,
1058 const int n =
static_cast<int>(cx_.size());
1059 if (n == 0 || cy_.size() != cx_.size() || cz_.size() != cx_.size() || r_.size() != cx_.size())
1060 throw std::invalid_argument(
"SphereBedQuery: centers/radii sizes disagree");
1062 box_.
Lx = extent[0];
1063 box_.
Ly = extent[1];
1064 box_.
Lz = extent[2];
1065 union_.
cx = cx_.data();
1066 union_.
cy = cy_.data();
1067 union_.
cz = cz_.data();
1068 union_.
r = r_.data();
1071 for (
int i = 1;
i < n; ++
i)
1077 gview_ = grid_.
view();
1089 return grid_.
offsets.empty() ? 0.0
1094 std::vector<double> cx_, cy_, cz_, r_;
Owning, host-side accelerated union-of-spheres query.
const SphereUnionView< double > & sphereUnion() const
double meanListLength() const
Mean candidate-list length (diagnostics for the acceptance report).
SphereBedQuery(std::vector< double > cx, std::vector< double > cy, std::vector< double > cz, std::vector< double > r, Vec< 3 > origin, Vec< 3 > extent, bool periodic, int nbHint=0)
double operator()(const Vec< 3 > &p) const
const PeriodicBox< double > & box() const
const CandidateGridView< double > & grid() const
PECLET_HD Real hdFloor(Real v)
PECLET_HD Real hdSqrt(Real v)
PECLET_HD void take(Real v, int i, Real &best, int &bestI)
The single tie-break rule (lowest index wins an exact tie), shared by every owner path.
NodeBound< Real > nodeBound(const SceneView< Real > &sc, int node)
PECLET_HD Real evalSphereUnionGrid(const SphereUnionView< Real > &u, Vec3< Real > p, const PeriodicBox< Real > &box, const CandidateGridView< Real > &g)
Union SDF through the candidate grid: bin lookup + short list, full-scan fallback when the bin is out...
PECLET_HD Real sphereUnionEvalOwner(const SphereUnionView< Real > &u, Vec3< Real > p, const PeriodicBox< Real > &box, int &own)
Brute-force value + owner (all spheres) — the reference the candidate path must match,...
PECLET_HD int sphereUnionOwner(const SphereUnionView< Real > &u, Vec3< Real > p, const PeriodicBox< Real > &box)
Owner-only wrappers (the value is discarded by the compiler on every backend).
PECLET_HD Real evalSceneGrid(const SceneView< Real > &sc, Vec3< Real > p, const PeriodicBox< Real > &box, const CandidateGridView< Real > &g, const Real *boundR=nullptr)
Union over a candidate list + the always-list, min-image periodic.
CandidateGrid< Real > buildSceneCandidateGrid(const SceneView< Real > &sc, Vec3< Real > origin, Vec3< Real > extent, const PeriodicBox< Real > &box, Real binSizeHint=0)
Candidate grid for a GENERAL scene: certified instances splat Lipschitz bounds evaluated at bin cente...
PECLET_HD Real sphereDist2(const SphereUnionView< Real > &u, int i, Vec3< Real > p, const PeriodicBox< Real > &box)
Squared min-image distance from p to sphere i — THE per-sphere expression, shared by every path (brut...
bool extractSphereUnion(const SceneView< Real > &sc, std::vector< Real > &cx, std::vector< Real > &cy, std::vector< Real > &cz, std::vector< Real > &r)
Try to view a scene as a PLAIN sphere union: every instance a single kSphere leaf with a bitwise-iden...
InstanceBound< Real > instanceBound(const SceneView< Real > &sc, int i)
World bounding sphere + certificate of one instance (host-side; used by candidate builds).
PECLET_HD void sphereUnionOwnerSubset(const SphereUnionView< Real > &u, Vec3< Real > p, const PeriodicBox< Real > &box, const int *items, int count, Real &best, int &bestI)
Accumulate the argmin over an explicit index subset (a candidate list) into (best,...
PECLET_HD Real sphereUnionEvalOwnerGrid(const SphereUnionView< Real > &u, Vec3< Real > p, const PeriodicBox< Real > &box, const CandidateGridView< Real > &g, int &own)
Value + owner through the candidate grid.
bool motionIsStatic(const InstanceMotionView< Real > &m)
True when no instance carries motion – the predicate a consumer uses to keep the static path bit-iden...
@ kSphere
params[0] = radius
@ kEllipsoid
params[0..2] = rx, ry, rz (BOUND, under-estimates)
@ kTorus
params[0..1] = majorRadius, minorRadius (exact, y axis)
@ kBox
params[0..2] = hx, hy, hz
@ kSuperquadric
params[0..3] = rx, ry, rz, exponent (BOUND, under-estimates)
@ kHollowCylinderShell
params[0..2] = rOuter, rInner, height (sign-exact, z axis)
@ kCapsule
params[0..1] = radius, halfLength (exact, y axis)
@ kCone
params[0..2] = rBottom, rTop, halfHeight (exact, y axis)
@ kHollowCylinder
params[0..2] = rOuter, height, thickness (distance-exact, y axis)
@ kUnion
min(L, R) — aux0/aux1 = child node indices
PECLET_HD Real evalScenePeriodic(const SceneView< Real > &sc, Vec3< Real > p, const PeriodicBox< Real > &box, const Real *boundR=nullptr)
Union over every instance, min-image periodic.
PECLET_HD Real evalInstancePeriodic(const SceneView< Real > &sc, int i, Vec3< Real > p, const PeriodicBox< Real > &box, Real boundR=Real(-1))
Instance evaluation with MIN-IMAGE periodicity.
PECLET_HD Vec3< Real > instanceVelocity(const Instance< Real > &inst, Vec3< Real > p)
PECLET_HD Real sceneEvalOwnerPeriodic(const SceneView< Real > &sc, Vec3< Real > p, const PeriodicBox< Real > &box, int &own, const Real *boundR=nullptr)
Value + owner over every instance of a general scene, min-image periodic.
PECLET_HD Vec3< Real > wallPoint(Vec3< Real > p, Real sdf, Vec3< Real > grad)
Project a probe onto the zero level set along the local gradient: w = p - sdf(p) * n_hat.
PECLET_HD int sceneOwnerPeriodic(const SceneView< Real > &sc, Vec3< Real > p, const PeriodicBox< Real > &box, const Real *boundR=nullptr)
PECLET_HD int sphereUnionOwnerGrid(const SphereUnionView< Real > &u, Vec3< Real > p, const PeriodicBox< Real > &box, const CandidateGridView< Real > &g)
PECLET_HD Vec3< Real > minImage(Vec3< Real > d, const PeriodicBox< Real > &b)
Min-image a displacement.
PECLET_HD Real evalSphereUnion(const SphereUnionView< Real > &u, Vec3< Real > p, const PeriodicBox< Real > &box)
Brute-force union SDF (all spheres) — the reference the candidate path must match bit-for-bit,...
PECLET_HD Real evalSphereUnionSubset(const SphereUnionView< Real > &u, Vec3< Real > p, const PeriodicBox< Real > &box, const int *items, int count)
Union SDF over an index subset (a candidate list).
PECLET_HD int sceneOwnerGrid(const SceneView< Real > &sc, Vec3< Real > p, const PeriodicBox< Real > &box, const CandidateGridView< Real > &g, const Real *boundR=nullptr)
PECLET_HD Real sceneEvalOwnerGrid(const SceneView< Real > &sc, Vec3< Real > p, const PeriodicBox< Real > &box, const CandidateGridView< Real > &g, int &own, const Real *boundR=nullptr)
Value + owner through a general-scene candidate grid: always-list ∪ candidate list,...
CandidateGrid< Real > buildSphereCandidateGrid(const SphereUnionView< Real > &u, Vec3< Real > origin, Vec3< Real > extent, const PeriodicBox< Real > &box, int nbHint=0)
Geometry-driven candidate build for a sphere union over [origin, origin+extent).
PECLET_HD Vec3< Real > rotate(Quat< Real > q, Vec3< Real > v)
Rotate v by q.
PECLET_HD Vec3< Real > add(Vec3< Real > a, Vec3< Real > b)
PECLET_HD Vec3< Real > invRotate(Quat< Real > q, Vec3< Real > v)
Rotate v by the conjugate of q — dem invRotateVector.
Kokkos::View< T *, MemSpace > View
1D device array.
PECLET_HD Vec3< Real > sub(Vec3< Real > a, Vec3< Real > b)
PECLET_HD Vec3< Real > scale(Vec3< Real > a, Real s)
double Real
Default host floating type. Device kernels may use float; conversions happen at the boundary.
Non-owning candidate grid: uniform bins over [origin, origin+extent), CSR lists of primitive (or inst...
PECLET_HD long binOf(Vec3< Real > p) const
Flat bin index of a point, or -1 when the point is outside a non-periodic grid's coverage (the caller...
Owning host-side candidate grid.
CandidateGridView< Real > meta
CandidateGridView< Real > view() const
std::vector< Real > instBoundR
std::vector< int > offsets
std::vector< int > always
World bounding sphere of an instance + the PRUNING CERTIFICATE.
Non-owning, POD, device-copyable rigid-body motion state for a scene's instances.
Min-image box. on = false disables wrapping (all extents ignored).
The one POD every consumer captures: sphere-union fast path when the scene is a plain sphere union,...
PECLET_HD int owner(Vec3< Real > p) const
Owner only.
SphereUnionView< Real > u
PECLET_HD Real evalOwner(Vec3< Real > p, int &own) const
eval(p) AND the index of the instance (sphere-union mode: the sphere) whose surface is nearest — the ...
PECLET_HD Real eval(Vec3< Real > p) const
CandidateGridView< Real > grid
int aux0
CSG: left child index. kGrid: GridDesc table index.
Transform< Real > transform
int aux1
CSG: right child index.
Non-owning union-of-spheres view.