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,

\[\texttt{value}(\mathbf{x}) : \mathbb{R}^3 \rightarrow \mathbb{R},\]

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

TranslateIF

Translate

class / function

Rotation

RotateIF

Rotate

class / function

Scaling

ScaleIF

Scale

class / function

Complement

ComplementIF

Complement

class / function

Reflection

ReflectIF

Reflect

class / function

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 factor alpha (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

OffsetIF

Offset

class / function

Annular (shell)

AnnularIF

Annular

class / function

Blur

BlurIF

Blur

class / function

Mollification

MollifyIF

Mollify

class / function

Elongation

ElongateIF

Elongate

class / function

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

UnionIF

Union

class / function

Smooth union

SmoothUnionIF

SmoothUnion

class / function

Intersection

IntersectionIF

Intersection

class / function

Smooth intersection

SmoothIntersectionIF

SmoothIntersection

class / function

Difference

DifferenceIF

Difference

class / function

Smooth difference

SmoothDifferenceIF

SmoothDifference

class / function

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

BVHUnionIF

BVHUnion

class / function

BVH-accelerated smooth union

BVHSmoothUnionIF

BVHSmoothUnion

class / function

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.