31#ifndef PECLET_CORE_GEOM_SCENE_BUILDER_HPP
32#define PECLET_CORE_GEOM_SCENE_BUILDER_HPP
36#include <initializer_list>
62 for (
int i = 0;
i < 8; ++
i)
80 for (
int i = 0;
i < 8; ++
i)
131 std::isfinite(v.
center.x) && std::isfinite(v.
center.y) &&
132 std::isfinite(v.
center.z);
151 throw std::invalid_argument(
"SceneBuilder::addLeaf: kind is a CSG operator, not a leaf");
152 if (params.size() > 8)
153 throw std::invalid_argument(
"SceneBuilder::addLeaf: at most 8 parameters");
157 for (
Real v : params)
161 return static_cast<int>(nodes_.size()) - 1;
168 throw std::invalid_argument(
"SceneBuilder::addNode: CSG kinds go through addUnion/...");
170 throw std::invalid_argument(
"SceneBuilder::addNode: grid leaves go through addGrid");
172 return static_cast<int>(nodes_.size()) - 1;
179 if (nx < 2 || ny < 2 || nz < 2)
180 throw std::invalid_argument(
"SceneBuilder::addGrid: dims must be >= 2 on each axis");
181 if (
static_cast<std::size_t
>(nx) * ny * nz !=
samples.size())
182 throw std::invalid_argument(
"SceneBuilder::addGrid: samples.size() must equal nx*ny*nz");
187 d.offset =
static_cast<int>(pool_.size());
197 n.aux0 =
static_cast<int>(grids_.size()) - 1;
200 return static_cast<int>(nodes_.size()) - 1;
216 Vec3<Real> center = {std::numeric_limits<Real>::quiet_NaN(),
217 std::numeric_limits<Real>::quiet_NaN(),
218 std::numeric_limits<Real>::quiet_NaN()},
219 int materialId = -1) {
220 requireNode(shapeRoot,
"addInstance");
222 v.shapeRoot = shapeRoot;
223 v.materialId = materialId;
228 v.centerPinned = std::isfinite(center.x) && std::isfinite(center.y) && std::isfinite(center.z);
229 instances_.push_back(v);
230 return static_cast<int>(instances_.size()) - 1;
236 s.
nodes = nodes_.data();
237 s.
nodeCount =
static_cast<int>(nodes_.size());
238 s.
grids = grids_.data();
239 s.
gridCount =
static_cast<int>(grids_.size());
247 const std::vector<ShapeNode<Real>>&
nodes()
const {
return nodes_; }
248 const std::vector<GridDesc<Real>>&
grids()
const {
return grids_; }
249 const std::vector<float>&
samples()
const {
return pool_; }
250 const std::vector<Instance<Real>>&
instances()
const {
return instances_; }
261 B.translation.z * A.scale});
273 requireNode(
root,
"addReframed");
275 std::vector<int> order;
278 std::vector<char>
seen(nodes_.size(), 0);
279 while (!
stack.empty()) {
285 order.push_back(
nidx);
293 std::vector<int>
remap(nodes_.size(), -1);
296 for (
auto it = order.rbegin();
it != order.rend(); ++
it) {
302 nodes_.push_back(
nd);
303 remap[(std::size_t)*
it] =
static_cast<int>(nodes_.size()) - 1;
306 nodes_[(std::size_t)
newRoot].transform =
317 throw std::out_of_range(
"SceneBuilder::instanceRef: index out of range");
318 return instances_[
static_cast<std::size_t
>(
i)];
327 for (std::size_t
i = 0;
i < nodes_.size(); ++
i)
331 for (std::size_t
i = 0;
i < instances_.size(); ++
i)
340 const std::vector<float>&
pool) {
342 throw std::invalid_argument(
343 "SceneBuilder::decode: node arrays are not a whole number of "
347 throw std::invalid_argument(
"SceneBuilder::decode: node int/real counts disagree");
351 b.nodes_.reserve(
nn);
352 for (std::size_t
i = 0;
i <
nn; ++
i)
364 throw std::invalid_argument(
365 "SceneBuilder::decode: instance reals are neither 18 nor 17 per instance record");
367 b.instances_.reserve(
ni);
368 for (std::size_t
i = 0;
i <
ni; ++
i)
376 requireNode(a,
"addCsg");
377 requireNode(b,
"addCsg");
384 return static_cast<int>(nodes_.size()) - 1;
386 void requireNode(
int i,
const char*
who)
const {
388 throw std::invalid_argument(std::string(
"SceneBuilder::") +
who +
389 ": node index out of range");
392 std::vector<ShapeNode<Real>> nodes_;
393 std::vector<GridDesc<Real>> grids_;
394 std::vector<float> pool_;
395 std::vector<Instance<Real>> instances_;
417 std::vector<Vec3<Real>>
out;
427 const Real h = spacing *
Real(1e-3);
432 const Real l = std::sqrt(g.x * g.x + g.y * g.y + g.z * g.z);
439 std::set<std::tuple<long, long, long>>
seen;
440 const int nx =
static_cast<int>((
hi.x -
lo.x) / spacing) + 1;
441 const int ny =
static_cast<int>((
hi.y -
lo.y) / spacing) + 1;
442 const int nz =
static_cast<int>((
hi.z -
lo.z) / spacing) + 1;
443 for (
int k = 0;
k <= nz; ++
k)
444 for (
int j = 0;
j <= ny; ++
j)
445 for (
int i = 0;
i <= nx; ++
i) {
447 if (std::fabs(
f(p)) >
band)
454 if (std::fabs(
f(p)) > spacing *
Real(0.05))
456 const std::tuple<long, long, long>
key{
static_cast<long>(std::llround(p.x /
snap)),
457 static_cast<long>(std::llround(p.y /
snap)),
458 static_cast<long>(std::llround(p.z /
snap))};
Owns a scene under construction and hands out a non-owning SceneView over it.
const std::vector< ShapeNode< Real > > & nodes() const
int addUnion(int a, int b, Transform< Real > tr={})
const std::vector< Instance< Real > > & instances() const
Instance< Real > & instanceRef(int i)
Mutable access to one placed instance – how a MOVING scene advances: a driver updates the transform (...
int addNode(const ShapeNode< Real > &n)
Analytic leaf from a prebuilt node (the runtime-parameter sibling of addLeaf, for callers whose param...
SceneView< Real > view() const
Non-owning view over this builder's arrays. Invalidated by any further add*.
const std::vector< float > & samples() const
int addLeaf(int kind, std::initializer_list< Real > params, Transform< Real > tr={})
Analytic leaf. params follows the per-kind layout documented on ShapeKind.
int addIntersection(int a, int b, Transform< Real > tr={})
int addDifference(int a, int b, Transform< Real > tr={})
a MINUS b.
void encode(std::vector< int > &nodeInts, std::vector< Real > &nodeReals, std::vector< int > &instInts, std::vector< Real > &instReals) const
const std::vector< GridDesc< Real > > & grids() const
int addReframed(int root, const Transform< Real > &W)
Deep-copy the subtree rooted at root and pre-compose transform W onto the COPIED root,...
int addInstance(int shapeRoot, Transform< Real > tr={}, Vec3< Real > linVel={0, 0, 0}, Vec3< Real > angVel={0, 0, 0}, Vec3< Real > center={std::numeric_limits< Real >::quiet_NaN(), std::numeric_limits< Real >::quiet_NaN(), std::numeric_limits< Real >::quiet_NaN()}, int materialId=-1)
Place a tree in the world.
int addGrid(const std::vector< float > &samples, int nx, int ny, int nz, Vec3< Real > origin, Vec3< Real > spacing, GridExtension ext, Transform< Real > tr={})
Sampled field: copies samples into the shared pool, registers a descriptor, returns the node index.
static Transform< Real > composeTransform(const Transform< Real > &A, const Transform< Real > &B)
Compose two transforms so that toLocal(C, p) == toLocal(B, toLocal(A, p)) – i.e.
static SceneBuilder decode(const std::vector< int > &nodeInts, const std::vector< Real > &nodeReals, const std::vector< int > &instInts, const std::vector< Real > &instReals, const std::vector< GridDesc< Real > > &grids, const std::vector< float > &pool)
Rebuild from the flat encoding (grids and the sample pool are carried across verbatim).
constexpr int kInstanceRealStrideLegacy
constexpr int kInstanceRealStride
constexpr int kNodeIntStride
Instance< Real > decodeInstance(const int *ints, const Real *reals, int stride=kInstanceRealStride)
void encodeNode(const ShapeNode< Real > &n, int *ints, Real *reals)
@ kDifference
max(L, -R) — L minus R
@ kGrid
sampled field; aux0 = index into the GridDesc table
@ kUnion
min(L, R) — aux0/aux1 = child node indices
void encodeInstance(const Instance< Real > &v, int *ints, Real *reals)
std::vector< Vec3< Real > > surfacePoints(const SceneView< Real > &sc, int root, Real spacing, Vec3< Real > lo, Vec3< Real > hi, int projectIters=4)
Sample points on the zero level set of a shape tree — the GENERAL surface-point generator.
ShapeNode< Real > decodeNode(const int *ints, const Real *reals)
GridExtension
NOT YET A NODE KIND: prim::Rounded (offset/rounding) stays a compile-time wrapper for now.
constexpr int kInstanceIntStride
constexpr int kNodeRealStride
PECLET_HD Quat< Real > mulQuat(Quat< Real > a, Quat< Real > b)
Hamilton product a ⊗ b in the (x, y, z, w) storage convention rotate uses, so rotate(mulQuat(a,...
PECLET_HD Vec3< Real > rotate(Quat< Real > q, Vec3< Real > v)
Rotate v by q.
Kokkos::View< T *, MemSpace > View
1D device array.
double Real
Default host floating type. Device kernels may use float; conversions happen at the boundary.
int materialId
consumer-defined; -1 = unset
bool centerPinned
true: center is an explicit world point (the origin included); false: the centre follows the body (co...
Vec3< Real > center
reference point of the rotation, in world coordinates
Transform< Real > transform
int shapeRoot
index of the root ShapeNode of this instance's tree
const Instance< Real > * instances
const GridDesc< Real > * grids
const ShapeNode< Real > * nodes
int aux0
CSG: left child index. kGrid: GridDesc table index.
Transform< Real > transform
int aux1
CSG: right child index.