Geometries
This page covers the concrete classes behind two Concepts pages: Geometry representations (signed distance fields and implicit functions in general) and Constructive solid geometry (transformations and CSG combinators) – read those first for the conceptual picture, and use this page for the class/function-level detail and Doxygen links.
ImplicitFunction
ImplicitFunction<T> (Source/EBGeometry_ImplicitFunction.hpp) is the root of
EBGeometry’s polymorphic geometry hierarchy. Every concrete piece of geometry the library can
represent – analytic shapes, DCEL/triangle-mesh distance fields, and CSG combinations of either
– ultimately derives from it. It declares a single pure virtual member function,
returning a value that is negative for points inside the object and positive for points outside
it, plus a call operator (operator()) that simply forwards to value(). Because every
concrete geometry type honors exactly this same contract, code elsewhere in the library (and in
user code) can hold a shared_ptr<ImplicitFunction<T>> and call value() on it through
ordinary virtual dispatch without ever needing to know which concrete class it actually points
to – this is what lets the transform and CSG machinery below wrap or combine any implicit
function interchangeably.
ImplicitFunction<T> also provides one concrete (non-virtual) member function,
approximateBoundingVolumeOctree, for shapes that have no closed-form bounding volume. It
refines an octree over a caller-supplied initial box, marking a cell as intersecting the surface
once the implicit function’s value at the cell center falls within a safety-scaled margin of the
cell’s half-width, then builds a bounding volume of the caller-chosen type BV from the
corners of the intersected leaf cells. This is the same octree-refinement idea described
conceptually in Octree; see that page for how the subdivision itself works. The
result is only meaningful when value() is reasonably close to a true signed distance, since
the safety margin is interpreted in units of distance.
For the full API (including the exact parameters and defaults of
approximateBoundingVolumeOctree), see the Doxygen page for
ImplicitFunction.
SignedDistanceFunction
SignedDistanceFunction<T> (Source/EBGeometry_SignedDistanceFunction.hpp) inherits
from ImplicitFunction<T> and refines its contract, without adding to the public value()
interface itself: it implements value() (marked final) to delegate to a new pure virtual
member function, signedDistance(point), which subclasses must implement instead. The
distinction is one of guarantee rather than signature – an arbitrary ImplicitFunction<T>
only promises that the sign of its output indicates inside/outside, whereas a
SignedDistanceFunction<T> additionally promises that the magnitude of its output is the
true Euclidean distance to the surface (the Eikonal property, \(|\nabla S| = 1\); see
Geometry representations for why this property matters). Every analytic shape and
mesh distance field shipped with EBGeometry is a SignedDistanceFunction<T>.
Because the true distance is available, SignedDistanceFunction<T> also provides a concrete
normal(point, delta) member function that estimates the outward unit normal from central
finite differences of signedDistance with step size delta – something that cannot be
done reliably from an arbitrary implicit function’s value alone.
For the full API, see the Doxygen page for SignedDistanceFunction.
Tip
Various ready-to-use implementations of both interfaces are declared in
Source/EBGeometry_AnalyticDistanceFunctions.hpp (spheres, boxes, planes, cylinders,
tori, and other closed-form primitives) and in
Source/EBGeometry_MeshDistanceFunctions.hpp (the DCEL/triangle-mesh-backed classes
FlatMeshSDF, MeshSDF, and TriMeshSDF – see Mesh SDF classes).
Transformations
EBGeometry implements every transformation as a small wrapper class that stores a
shared_ptr<ImplicitFunction<T>> to the wrapped function together with the transformation’s
own parameters, and implements value() by applying the (typically inverse) transformation to
the query point before evaluating the wrapped function. Since every such wrapper is itself an
ImplicitFunction<T>, transformations compose freely – wrapping a wrapper is just as valid as
wrapping a leaf shape. Each wrapper class has a same-named free function that constructs it and
returns it already cast to shared_ptr<ImplicitFunction<T>>, ready to be passed into further
transformations or CSG combinators without the caller ever naming the concrete wrapper type.
Both are declared in Source/EBGeometry_Transform.hpp.
The five simplest transformations – translation, rotation, scaling, the complement, and reflection – are described mathematically in Constructive solid geometry; the table below just maps each to its wrapper class, free function, and Doxygen entry:
Transformation |
Wrapper class |
Free function |
Doxygen |
|---|---|---|---|
Translation |
|
|
|
Rotation |
|
|
|
Scaling |
|
|
|
Complement |
|
|
|
Reflection |
|
|
EBGeometry implements several further transformations that have no closed-form counterpart in Constructive solid geometry and are only described here:
Offset (
OffsetIF/Offset) subtracts a constant from the wrapped function’s value, growing the object if the offset is positive and shrinking it if negative. For a true signed distance function this simply moves the isosurface outward or inward by the offset distance.Annular (
AnnularIF/Annular) turns a solid into a hollow shell of total thickness \(2\delta\) by evaluating \(|I(\mathbf{x})| - \delta\): the two new zero-isosurfaces sit where \(I(\mathbf{x}) = \pm\delta\), i.e. the original surface offset inward and outward by \(\delta\) each, hollowing out everything in between.Blur (
BlurIF/Blur) smooths sharp features by passing the wrapped function through a 3D box filter sampled at the face centers, edge centers, and corners of a cube of half-width equal to the blur distance, with per-sample weights controlled by a blend factoralpha(1= no blur,0= maximal blur).Mollify (
MollifyIF/Mollify) is a more general smoothing operation: it convolves the wrapped function with a caller-supplied mollifier implicit function (typically a small sphere SDF) sampled on a uniform grid of offsets, normalizing the sample weights to sum to one.Elongate (
ElongateIF/Elongate) stretches a shape along one or more axes without changing its cross-section: the query point is clamped component-wise to \([-\mathbf{e}, \mathbf{e}]\) for a per-axis elongation vector \(\mathbf{e}\), and the clamped offset is subtracted from the point before evaluating the wrapped function.
Transformation |
Wrapper class |
Free function |
Doxygen |
|---|---|---|---|
Offset |
|
|
|
Annular (shell) |
|
|
|
Blur |
|
|
|
Mollification |
|
|
|
Elongation |
|
|
Warning
Not every transformation preserves the signed distance property. Rotation, translation, and
the complement always do; scaling does provided the value is rescaled alongside the query
point (which ScaleIF does); offset, annular, blur, mollification, and elongation generally
do not produce an exact signed distance even when the input is one.
Every wrapper class and free function above is declared in
Source/EBGeometry_Transform.hpp; see the Doxygen page for the file itself,
EBGeometry_Transform.hpp, for the complete,
single-page API listing.
CSG
The Boolean combinators for combining multiple implicit functions into one – union,
intersection, difference, and their smooth-blended variants – are described conceptually in
Constructive solid geometry. EBGeometry implements each with the same wrapper-class
pattern as the transformations above: a class stores the combined implicit functions and
implements value() as the appropriate combination over them, with a matching free function
returning it as a shared_ptr<ImplicitFunction<T>>. All of the following are declared in
Source/EBGeometry_CSG.hpp:
Combinator |
Wrapper class |
Free function |
Doxygen |
|---|---|---|---|
Union |
|
|
|
Smooth union |
|
|
|
Intersection |
|
|
|
Smooth intersection |
|
|
|
Difference |
|
|
|
Smooth difference |
|
|
Union, SmoothUnion, Intersection, and SmoothIntersection each have two overloads
in the Doxygen listing above – one taking a std::vector of any number of implicit functions,
and one taking exactly two – both constructing the same underlying wrapper class.
The “smooth” combinators blend the transition between objects instead of leaving a sharp crease,
using a caller-replaceable blending functor rather than a plain min/max. Two are provided
as std::function template variables in Source/EBGeometry_CSG.hpp: SmoothMin<T>
(a cheap polynomial smooth-minimum, the default for SmoothUnion) and SmoothMax<T> (its
symmetric counterpart, the default for both SmoothIntersection and SmoothDifference –
difference is implemented internally as the intersection of A with the complement of B,
which is why it defaults to the same operator as intersection rather than to SmoothMin<T>),
plus a more expensive exponential alternative, ExpMin<T>. Any of the three – or a
user-supplied functor of the same signature, T(const T&, const T&, const T&) – can be passed
as the smoothing operator to the smooth combinators’ constructors/free functions.
Because a plain CSG union is evaluated as \(\min(I_1, \ldots, I_N)\), querying it costs
\(\mathcal{O}(N)\) per point for \(N\) objects. BVHUnionIF/BVHUnion and
BVHSmoothUnionIF/BVHSmoothUnion accelerate this by placing the objects’ bounding volumes
in a PackedBVH and reducing a closest-object query to an \(\mathcal{O}(\log N)\) tree
traversal instead of a linear scan – see BVH for how the BVH itself is built
and traversed; this section only concerns how CSG uses it. Unlike the plain combinators, the BVH
variants take the objects’ bounding volumes explicitly (a std::vector<BV>, one per object)
since these are needed up front to build the tree.
Combinator |
Wrapper class |
Free function |
Doxygen |
|---|---|---|---|
BVH-accelerated union |
|
|
|
BVH-accelerated smooth union |
|
|
Finally, FiniteRepetitionIF/FiniteRepetition tiles a single base implicit function
periodically over a finite number of repetitions per axis, by mapping the query point into the
nearest tile before evaluating the wrapped function – effectively a cheap way to instance the
same shape many times without constructing a separate ImplicitFunction<T> (or a CSG union) per
copy. See its Doxygen entries for
FiniteRepetitionIF and
FiniteRepetition.
For the complete, single-page API listing of every class and free function on this page, see the Doxygen page for EBGeometry_CSG.hpp.