20#ifndef EBGEOMETRY_RAYSPANS_HPP
21#define EBGEOMETRY_RAYSPANS_HPP
36#if defined(__GNUC__) && !defined(__clang__)
37#pragma GCC diagnostic push
38#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
85 a_to.m_count = a_from.m_count;
86 a_to.m_horizon = a_from.m_horizon;
88 for (uint32_t i = 0; i < a_from.m_count; i++) {
89 a_to.m_spans[i] = a_from.m_spans[i];
108 if (span.
m_out.m_t > a_horizon) {
129 const T horizon =
Math::min(a_a.m_horizon, a_b.m_horizon);
131 a_out.reset(horizon);
140 const bool fromA = i < a_a.m_count && a_a.m_spans[i].
m_in.m_t <= horizon;
141 const bool fromB = j < a_b.m_count && a_b.m_spans[j].m_in.m_t <= horizon;
143 if (!fromA && !fromB) {
150 if (fromA && fromB) {
163 else if (span.
m_in.m_t <= current.m_out.m_t) {
164 if (span.
m_out.m_t > current.m_out.m_t || (span.
m_out.m_t == current.m_out.m_t && !span.
m_out.crossing())) {
169 a_out.add(current.m_in, current.m_out);
176 a_out.add(current.m_in, current.m_out);
194 const T horizon =
Math::min(a_a.m_horizon, a_b.m_horizon);
196 a_out.reset(horizon);
201 while (i < a_a.m_count && j < a_b.m_count) {
202 if (a_a.m_spans[i].m_in.m_t > horizon || a_b.m_spans[j].m_in.m_t > horizon) {
243 while (count < a_spans.m_count && a_spans.m_spans[count].m_in.m_t <= a_horizon) {
244 if (a_spans.m_spans[count].m_out.m_t > a_horizon) {
245 a_spans.m_spans[count].m_out =
openAt(a_horizon);
251 a_spans.m_count = count;
252 a_spans.m_horizon = a_horizon;
268 if (a_spans.m_count == 0U) {
274 if (first.
m_in.crossing()) {
275 RayDetail::cutTo(first.
m_in.m_t, a_spans);
277 else if (first.
m_out.crossing()) {
278 RayDetail::cutTo(first.
m_out.m_t, a_spans);
296 const T horizon =
Math::min(a_spans.m_horizon, a_operand.m_horizon);
298 if (horizon < a_spans.m_horizon) {
299 RayDetail::cutTo(horizon, a_spans);
303 for (uint32_t k = 0; k < a_operand.m_count && a_operand.m_spans[k].m_in.m_t <= horizon; k++) {
308 while (first < a_spans.m_count && a_spans.m_spans[first].m_out.m_t < span.
m_in.m_t) {
313 uint32_t last = first;
315 while (last < a_spans.m_count && a_spans.m_spans[last].m_in.m_t <= span.
m_out.m_t) {
318 if (other.
m_in.m_t < span.
m_in.m_t || (other.
m_in.m_t == span.
m_in.m_t && !other.
m_in.crossing())) {
328 const uint32_t merged = last - first;
333 if (first == a_spans.m_count) {
334 a_spans.m_horizon =
Math::min(a_spans.m_horizon, span.
m_in.m_t);
339 a_spans.m_horizon =
Math::min(a_spans.m_horizon, a_spans.m_spans[a_spans.m_count - 1U].m_in.m_t);
343 for (uint32_t m = a_spans.m_count; m > first; m--) {
344 a_spans.m_spans[m] = a_spans.m_spans[m - 1U];
349 else if (merged > 1U) {
350 for (uint32_t m = last; m < a_spans.m_count; m++) {
351 a_spans.m_spans[m - merged + 1U] = a_spans.m_spans[m];
354 a_spans.m_count -= merged - 1U;
357 a_spans.m_spans[first] = span;
374 if (a_operand.m_count == 0U || a_spans.m_count == 0U) {
375 a_spans.reset(
Math::min(a_spans.m_horizon, a_operand.m_horizon));
380 RayDetail::intersect(a_spans, a_operand, a_scratch);
381 RayDetail::copySpans(a_scratch, a_spans);
398 const T horizon = a_a.m_horizon;
400 a_out.reset(horizon);
406 for (uint32_t i = 0; i < a_a.m_count && a_a.m_spans[i].m_in.m_t <= horizon; i++) {
410 if (span.
m_in.crossing() && gap) {
411 a_out.add(start, span.
m_in);
415 gap = span.
m_out.crossing();
425 a_out.add(start,
openAt(horizon));
473mapRay(
const T* a_map,
const RayT<T>& a_ray,
const T a_t0,
const T a_t1)
noexcept
477 const Vec3T<T>& d = a_ray.m_direction;
479 const Vec3T<T> origin(m[0] * o[0] + m[1] * o[1] + m[2] * o[2] + m[9],
480 m[3] * o[0] + m[4] * o[1] + m[5] * o[2] + m[10],
481 m[6] * o[0] + m[7] * o[1] + m[8] * o[2] + m[11]);
482 const Vec3T<T> direction(m[0] * d[0] + m[1] * d[1] + m[2] * d[2],
483 m[3] * d[0] + m[4] * d[1] + m[5] * d[2],
484 m[6] * d[0] + m[7] * d[1] + m[8] * d[2]);
486 const T scale = direction.
length();
488 return MappedRay<T>{
RayT<T>{origin, direction / scale}, scale, a_t0 * scale, a_t1 * scale};
508 const auto distance = [&a_mapped, a_t0, a_t1](
const T a_t)
noexcept -> T {
509 if (a_t <= a_mapped.m_t0) {
512 if (a_t >= a_mapped.m_t1) {
517 return Math::clamp(a_t / a_mapped.m_scale, a_t0, a_t1);
520 a_spans.m_horizon = distance(a_spans.m_horizon);
522 for (uint32_t i = 0; i < a_spans.m_count; i++) {
523 a_spans.m_spans[i].m_in.m_t = distance(a_spans.m_spans[i].m_in.m_t);
524 a_spans.m_spans[i].m_out.m_t = distance(a_spans.m_spans[i].m_out.m_t);
544 const Vec3T<T> g(m[0] * n[0] + m[3] * n[1] + m[6] * n[2],
545 m[1] * n[0] + m[4] * n[1] + m[7] * n[2],
546 m[2] * n[0] + m[5] * n[1] + m[8] * n[2]);
564 for (uint32_t i = 0; i < a_spans.m_count; i++) {
565 a_spans.m_spans[i].m_in.m_leaf = a_leaf;
566 a_spans.m_spans[i].m_out.m_leaf = a_leaf;
583 for (uint32_t i = 0; i < a_spans.m_count; i++) {
584 a_spans.m_spans[i].m_in.m_leaf += a_offset;
585 a_spans.m_spans[i].m_out.m_leaf += a_offset;
599template <
class T,
class S>
604 const auto box = a_shape.computeBoundingVolume();
605 const Vec3T<T>& lo = box.getLowCorner();
606 const Vec3T<T>& hi = box.getHighCorner();
608 for (
size_t dir = 0; dir < 3; dir++) {
609 if (!(a_point[dir] >= lo[dir] && a_point[dir] <= hi[dir])) {
614 return RayDetail::valueAt(a_shape, a_point) < T(0);
631template <
class T,
class S>
655template <
class T,
class S>
667 const HitT<T> hit = RayDetail::shapeHit(a_shape, a_ray, a_t0, a_t1, a_options);
678 a_spans.m_horizon = hit.
m_t;
688 if (RayDetail::insideAt(a_shape, a_ray.at(a_t0))) {
746 a_spans.add(
openAt(a_t0), a_end);
783template <
class T,
class S>
795 const auto box = a_shape.computeBoundingVolume();
796 const T scale = RayDetail::scaleOf(box.getLowCorner(), box.getHighCorner(), a_options);
797 const T step = a_options.m_tolerance * scale;
804 for (uint32_t k = 0; k < 2U * RaySpansT<T>::Capacity + 1U; k++) {
805 const HitT<T> hit = RayDetail::shapeHit(a_shape, a_ray, t, a_t1, a_options);
814 pairer.
finish(horizon, a_spans);
816 a_spans.m_horizon =
Math::min(a_spans.m_horizon, horizon);
823 if (a_spans.m_horizon < a_t1) {
835 pairer.
finish(t, a_spans);
837 a_spans.m_horizon =
Math::min(a_spans.m_horizon, t);
844 if (RayDetail::insideAt(a_shape, a_ray.at(a_t0))) {
849 pairer.
finish(a_t1, a_spans);
867template <
class T,
class S>
875 const bool a_firstOnly,
878 if constexpr (HasRaySpans<S, T>::value) {
883 RayDetail::firstSpan(a_shape, a_ray, a_t0, a_t1, a_options, a_spans);
886 RayDetail::crossingSpans(a_shape, a_ray, a_t0, a_t1, a_options, a_spans);
910template <
class T,
class S>
917 const bool a_firstOnly,
921 a_spans.reset(a_within.m_horizon);
923 for (uint32_t i = 0; i < a_within.m_count && a_within.m_spans[i].m_in.m_t <= a_within.m_horizon; i++) {
924 const T t0 = a_within.m_spans[i].m_in.m_t;
925 const T t1 =
Math::min(a_within.m_spans[i].m_out.m_t, a_within.m_horizon);
927 RayDetail::shapeSpans(a_shape, a_ray, t0, t1, a_options, a_firstOnly, a_piece);
929 for (uint32_t k = 0; k < a_piece.m_count && a_piece.m_spans[k].m_in.m_t <= a_piece.m_horizon; k++) {
930 const typename RaySpansT<T>::Span span = RayDetail::cut(a_piece.m_spans[k], a_piece.m_horizon);
935 if (a_piece.m_horizon < t1 || (a_firstOnly && a_piece.m_count > 0U)) {
936 a_spans.m_horizon =
Math::min(a_spans.m_horizon, a_piece.m_horizon);
940 if (a_spans.m_horizon <= t1) {
960template <
class T,
class S>
965 const auto box = a_shape.computeBoundingVolume();
966 const T delta = a_options.m_tolerance * RayDetail::scaleOf(box.getLowCorner(), box.getHighCorner(), a_options);
970 T from = a_t - delta;
973 for (
int k = 0; k < 3; k++) {
974 const HitT<T> hit = RayDetail::shapeHit(a_shape, a_ray, from, a_t + delta, a_options);
980 if (!nearest.
hit() || std::abs(hit.
m_t - a_t) < std::abs(nearest.
m_t - a_t)) {
984 if (hit.
m_t >= a_t) {
988 from = hit.
m_t + T(1e-3) * delta;
991 if (!nearest.
hit()) {
992 const Vec3T<T> point = a_ray.at(a_t);
994 nearest.
m_normal = RayDetail::gradientNormal(a_shape, point, delta);
995 nearest.
m_primitive = RayDetail::primitiveOf(a_shape, point);
1019template <
class T,
class Trace,
class Resolve>
1023 const Trace& a_trace,
const Resolve& a_resolve,
const RayT<T>& a_ray,
const T a_tMin,
const T a_tMax)
noexcept
1025 constexpr uint32_t MaxPasses = 64;
1029 if (!(a_tMin <= a_tMax)) {
1038 for (uint32_t pass = 0; pass < MaxPasses; pass++) {
1039 a_trace(t0, a_tMax, all, spans);
1043 for (uint32_t i = 0; i < spans.
m_count; i++) {
1044 for (
int side = 0; side < 2; side++) {
1070 if (!(horizon < a_tMax)) {
1095#if defined(__GNUC__) && !defined(__clang__)
1096#pragma GCC diagnostic pop
#define EBGEOMETRY_DEVICE_NOINLINE
Keep a function out of line in the device pass (CUDA/HIP); nothing on the host.
Definition EBGeometry_GPU.hpp:110
#define EBGEOMETRY_HOST_DEVICE
Mark a function as callable from both host and device code (no-op on host compilers).
Definition EBGeometry_GPU.hpp:80
Utility macros for EBGeometry.
Scalar helpers and numeric limits that compile for both host and device.
void intersectInto(RaySpansT< T > &a_spans, const RaySpansT< T > &a_operand, RaySpansT< T > &a_scratch) noexcept
Intersect a list with another, in place.
Definition EBGeometry_RaySpans.hpp:372
void nameLeaf(const uint32_t a_leaf, RaySpansT< T > &a_spans) noexcept
Name the leaf every crossing of a list lies on.
Definition EBGeometry_RaySpans.hpp:562
void uniteInto(RaySpansT< T > &a_spans, const RaySpansT< T > &a_operand) noexcept
Unite a list into another, in place: each of the operand's spans merged with the spans it meets,...
Definition EBGeometry_RaySpans.hpp:294
void shapeSpans(const S &a_shape, const RayT< T > &a_ray, const T a_t0, const T a_t1, const RayOptions< T > &a_options, const bool a_firstOnly, RaySpansT< T > &a_spans) noexcept
A shape's list over an interval: from its ray form's spans() if it has one, and otherwise from firstH...
Definition EBGeometry_RaySpans.hpp:870
void offsetLeaves(const uint32_t a_offset, RaySpansT< T > &a_spans) noexcept
Shift the leaves every crossing of a list names by an offset: an operand's own leaves,...
Definition EBGeometry_RaySpans.hpp:581
SpanEndT< T > openAt(const T a_t) noexcept
An end that is no crossing.
Definition EBGeometry_RaySpans.hpp:53
HitT< T > leafHit(const S &a_shape, const RayT< T > &a_ray, const T a_t, const RayOptions< T > &a_options) noexcept
A shape's crossing at a distance along a ray, with its normal and primitive: what a composition asks ...
Definition EBGeometry_RaySpans.hpp:963
void complement(const RaySpansT< T > &a_a, const T a_t0, RaySpansT< T > &a_out) noexcept
The complement of a list over [a_t0, a_t1]: where the ray is outside. A crossing is the same crossing...
Definition EBGeometry_RaySpans.hpp:396
SpanEndT< T > endOf(const HitT< T > &a_hit) noexcept
The end a hit is.
Definition EBGeometry_RaySpans.hpp:68
RaySpansT< T >::Span cut(const typename RaySpansT< T >::Span &a_span, const T a_horizon) noexcept
A span cut to a horizon: an end beyond it becomes an Open end there.
Definition EBGeometry_RaySpans.hpp:104
HitT< T > shapeHit(const S &a_shape, const RayT< T > &a_ray, const T a_t0, const T a_t1, const RayOptions< T > &a_options) noexcept
A shape's first crossing along a ray (firstHit()).
Definition EBGeometry_RaySpans.hpp:635
bool insideAt(const S &a_shape, const Vec3T< T > &a_point) noexcept
Whether a point is inside a shape: within its box, and its value negative.
Definition EBGeometry_RaySpans.hpp:602
void cutTo(const T a_horizon, RaySpansT< T > &a_spans) noexcept
Cut a list to a horizon: spans that begin beyond it dropped, and ends beyond it Open ends there.
Definition EBGeometry_RaySpans.hpp:239
void unite(const RaySpansT< T > &a_a, const RaySpansT< T > &a_b, RaySpansT< T > &a_out) noexcept
The union of two lists: where the ray is inside either.
Definition EBGeometry_RaySpans.hpp:127
void spansWithin(const S &a_shape, const RayT< T > &a_ray, const RaySpansT< T > &a_within, const RayOptions< T > &a_options, const bool a_firstOnly, RaySpansT< T > &a_piece, RaySpansT< T > &a_spans) noexcept
A marched operand's list within another list's spans: what an intersection asks a marched operand for...
Definition EBGeometry_RaySpans.hpp:913
void crossingSpans(const S &a_shape, const RayT< T > &a_ray, const T a_t0, const T a_t1, const RayOptions< T > &a_options, RaySpansT< T > &a_spans) noexcept
Every span of a shape over an interval, from firstHit() called from one crossing to the next.
Definition EBGeometry_RaySpans.hpp:786
void copySpans(const RaySpansT< T > &a_from, RaySpansT< T > &a_to) noexcept
Copy a list, only as many spans as it holds.
Definition EBGeometry_RaySpans.hpp:83
void mapBack(const MappedRay< T > &a_mapped, const T a_t0, const T a_t1, RaySpansT< T > &a_spans) noexcept
Map an operand's list, traced along a mapped ray, back to the original ray: distances divided by the ...
Definition EBGeometry_RaySpans.hpp:506
Vec3T< T > mapNormalBack(const T *a_map, const Vec3T< T > &a_normal) noexcept
A normal of the operand of an affine map, mapped back to the original frame: by the transposed matrix...
Definition EBGeometry_RaySpans.hpp:540
void intersect(const RaySpansT< T > &a_a, const RaySpansT< T > &a_b, RaySpansT< T > &a_out) noexcept
The intersection of two lists: where the ray is inside both.
Definition EBGeometry_RaySpans.hpp:192
MappedRay< T > mapRay(const T *a_map, const RayT< T > &a_ray, const T a_t0, const T a_t1) noexcept
A ray mapped by an affine map (CSGOps::affinePoint()'s coefficients: the matrix's rows,...
Definition EBGeometry_RaySpans.hpp:473
HitT< T > traceSpans(const Trace &a_trace, const Resolve &a_resolve, const RayT< T > &a_ray, const T a_tMin, const T a_tMax) noexcept
The first crossing of a composition along a ray, from its lists: the first crossing in the list,...
Definition EBGeometry_RaySpans.hpp:1022
void firstSpan(const S &a_shape, const RayT< T > &a_ray, const T a_t0, const T a_t1, const RayOptions< T > &a_options, RaySpansT< T > &a_spans) noexcept
The list up to a shape's first crossing, from firstHit(): a span from it if the ray enters there,...
Definition EBGeometry_RaySpans.hpp:658
void keepFirst(RaySpansT< T > &a_spans) noexcept
Keep a list only up to its first crossing, which is all a union asked for its first crossing needs: t...
Definition EBGeometry_RaySpans.hpp:266
Ray queries on any shape: where a ray, or the segment between two points, first crosses its surface (...
Three-dimensional vector class with arithmetic operators.
Definition EBGeometry_Vec.hpp:258
T length() const noexcept
Compute vector length.
constexpr T clamp(const T &a_value, const T &a_lo, const T &a_hi) noexcept
A value limited to [lo, hi].
Definition EBGeometry_Math.hpp:78
constexpr T max(const T &a_a, const T &a_b) noexcept
The larger of two values.
Definition EBGeometry_Math.hpp:61
constexpr T min(const T &a_a, const T &a_b) noexcept
The smaller of two values.
Definition EBGeometry_Math.hpp:44
Namespace containing all of EBGeometry's functionality.
Definition EBGeometry_Affine.hpp:26
T length(const Vec2T< T > &v) noexcept
Euclidean length of a 2D vector.
T dot(const Vec2T< T > &u, const Vec2T< T > &v) noexcept
Dot product of two 2D vectors.
@ Unresolved
The query ran out of steps or passes before it could decide (a ray grazing the surface,...
@ Miss
The ray does not cross the surface in the interval.
@ Hit
The ray crosses the surface; HitT says where.
HitT< T > firstHit(const S &a_shape, const RayT< T > &a_ray, typename RayT< T >::Scalar a_tMin, typename RayT< T >::Scalar a_tMax, const RayOptions< T > &a_options=RayOptions< T >()) noexcept
The first crossing of a shape's surface along a ray, entering or leaving.
Where a ray first crosses a surface.
Definition EBGeometry_Ray.hpp:96
bool m_entering
Whether the ray enters the object there (it was outside just before), rather than leaving it.
Definition EBGeometry_Ray.hpp:129
bool m_exact
Whether the crossing is exact (found by a ray form), rather than found to within RayOptions::m_tolera...
Definition EBGeometry_Ray.hpp:135
bool hit() const noexcept
Whether the ray crosses the surface.
T m_t
Distance along the ray: of the crossing for a hit, of the last point reached for an unresolved query,...
Definition EBGeometry_Ray.hpp:106
Vec3T< T > m_normal
The outward unit normal at the crossing: from the shape's ray form, or the normalized gradient of its...
Definition EBGeometry_Ray.hpp:124
uint32_t m_primitive
The finest element the shape can name at the crossing: the face of a mesh SDF, the deciding leaf of a...
Definition EBGeometry_Ray.hpp:118
HitStatus m_status
Whether the ray crosses the surface.
Definition EBGeometry_Ray.hpp:100
Vec3T< T > m_point
The point at m_t (for a hit or an unresolved query).
Definition EBGeometry_Ray.hpp:111
Pairs crossings, in order, into spans: a span from each crossing the ray enters at to the next it lea...
Definition EBGeometry_RaySpans.hpp:707
void take(const SpanEndT< T > &a_end, const bool a_entering, const T a_t0, RaySpansT< T > &a_spans) noexcept
Take the next crossing.
Definition EBGeometry_RaySpans.hpp:732
SpanEndT< T > m_start
Where the open span begins.
Definition EBGeometry_RaySpans.hpp:711
bool m_first
Whether no crossing has been seen yet.
Definition EBGeometry_RaySpans.hpp:721
void finish(const T a_t, RaySpansT< T > &a_spans) noexcept
Close the open span, if any, at an Open end.
Definition EBGeometry_RaySpans.hpp:759
bool m_inside
Whether a span is open.
Definition EBGeometry_RaySpans.hpp:716
A ray seen through an affine map, with the interval it is traced over: what the operand of the map is...
Definition EBGeometry_RaySpans.hpp:437
RayT< T > m_ray
The mapped ray, with a unit direction.
Definition EBGeometry_RaySpans.hpp:441
T m_t1
End of the interval, along the mapped ray.
Definition EBGeometry_RaySpans.hpp:456
T m_t0
Start of the interval, along the mapped ray.
Definition EBGeometry_RaySpans.hpp:451
T m_scale
Distance along the mapped ray per distance along the original.
Definition EBGeometry_RaySpans.hpp:446
How a query marches, where a shape has no ray form.
Definition EBGeometry_Ray.hpp:155
A span: where the ray enters, and where it leaves.
Definition EBGeometry_Ray.hpp:258
SpanEndT< T > m_out
Where it leaves.
Definition EBGeometry_Ray.hpp:267
SpanEndT< T > m_in
Where the ray enters.
Definition EBGeometry_Ray.hpp:262
Where a ray is inside an object over an interval [t0, t1]: its spans, in order, each from where it en...
Definition EBGeometry_Ray.hpp:248
uint32_t m_count
How many are held.
Definition EBGeometry_Ray.hpp:278
T m_horizon
The list is complete on [t0, m_horizon]: nothing about the object beyond it is known.
Definition EBGeometry_Ray.hpp:283
Span m_spans[Capacity]
The spans, in order and disjoint.
Definition EBGeometry_Ray.hpp:273
A ray: the points origin + t * direction.
Definition EBGeometry_Ray.hpp:54
One end of a span: where a ray enters or leaves an object.
Definition EBGeometry_Ray.hpp:200
Kind m_kind
What the end is.
Definition EBGeometry_Ray.hpp:225
T m_t
Distance along the ray.
Definition EBGeometry_Ray.hpp:214
uint32_t m_leaf
Which of a composition's leaves the crossing lies on, numbered by the composition; a shape that is no...
Definition EBGeometry_Ray.hpp:220
bool crossing() const noexcept
Whether the end is a crossing of the surface.