Geometry representation
Implicit functions
EBGeometry
implements implement functions and signed distance functions through virtual classes
template <class T>
class ImplicitFunction
{
public:
/*!
@brief Disallowed, use the full constructor
*/
ImplicitFunction() = default;
/*!
@brief Destructor (does nothing)
*/
virtual ~ImplicitFunction() = default;
/*!
@brief Value function. Points are outside the object if value > 0.0 and inside
if value < 0.0
@param[in] a_point 3D point.
*/
virtual T
value(const Vec3T<T>& a_point) const noexcept = 0;
/*!
@brief Alternative signature for the value function.
@param[in] a_point 3D point.
*/
T
operator()(const Vec3T<T>& a_point) const noexcept;
/*!
@brief Compute an approximation to the bounding volume for the implicit surface, using octrees.
@details This routine will try to compute a bonding using octree subdivision of the implicit function. This routine will
characterize a cubic region in space as being 'inside', 'outside', or intersected by computing the value function at the
center of the cube. If the value function is larger than the extents of the cube, we assume that there is no intersection
inside the cube. The success of this algorithm therefore relies on the implicit function also being a signed distance
function, or at the very least not being horrendously far from being an SDF. If octree subdivision fails, this will return
the maximally representable bounding volume.
@param[in] a_initialLowCorner Initial low corner.
@param[in] a_initialHighCorner Initial high corner.
@param[in] a_maxTreeDepth Maximum permitted octree depth.
@param[in] a_safety Safety factor when determining intersection. a_safety=1 sets safety factor to cube width, a_safety=2 sets twice the cube width, etc.
@note The bounding volume type BV MUST have a constructor BV(std::vector<Vec3T<T>>).
*/
template <class BV>
inline BV
approximateBoundingVolumeOctree(const Vec3T<T>& a_initialLowCorner,
const Vec3T<T>& a_initialHighCorner,
const unsigned int a_maxTreeDepth,
const T& a_safety = 0.0) const noexcept;
};
Signed distance fields inherit from implicit functions as follows:
template <class T>
class SignedDistanceFunction : public ImplicitFunction<T>
{
public:
/*!
@brief Disallowed, use the full constructor
*/
SignedDistanceFunction() = default;
/*!
@brief Destructor (does nothing)
*/
virtual ~SignedDistanceFunction() = default;
/*!
@brief Implementation of ImplicitFunction::value
@param[in] a_point 3D point.
*/
virtual T
value(const Vec3T<T>& a_point) const noexcept override final;
/*!
@brief Signed distance function.
@param[in] a_point 3D point.
*/
virtual T
signedDistance(const Vec3T<T>& a_point) const noexcept = 0;
/*!
@brief Signed distance normal vector.
@details Computed using finite differences with step a_delta
@param[in] a_point 3D point
@param[in] a_delta Finite difference step
*/
inline virtual Vec3T<T>
normal(const Vec3T<T>& a_point, const T& a_delta) const noexcept;
};
Note that T
is a floating point precision, which is supported because DCEL meshes can take up quite a bit of computer memory.
These declarations are found in
Source/EBGeometry_ImplicitFunction.hpp
for implicit functions.Source/EBGeometry_SignedDistanceFunction.hpp
for signed distance field.
Various useful implementations of implicit functions and distance fields are found in:
Source/EBGeometry_AnalyticDistanceFields.hpp
for various pre-defined analytic distance fields.Source/EBGeometry_MeshDistanceFields.hpp
for various distance field representations for DCEL meshes.
Transformations
Various transformations for implicit functions are defined in Source/EBGeometry_Transform.hpp
, such as rotations, translations, etc.
These are also available through functions that automatically cast the resulting implicit function to ImplicitFunction<T>
:
/*!
@brief Convenience function for taking the complement of an implicit function
@param[in] a_implicitFunction Input implicit function
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Complement(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction) noexcept;
/*!
@brief Convenience function for translating an implicit function
@param[in] a_implicitFunction Input implicit function to be translated
@param[in] a_shift Distance to shift
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Translate(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction, const Vec3T<T>& a_shift) noexcept;
/*!
@brief Convenience function for rotating an implicit function.
@param[in] a_implicitFunction Input implicit function to be rotated.
@param[in] a_angle Angle to be rotated by (in degrees)
@param[in] a_axis Axis to rotate about
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Rotate(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction, const T a_angle, const size_t a_axis) noexcept;
/*!
@brief Convenience function for scaling an implicit function.
@param[in] a_implicitFunction Input implicit function to be scaled.
@param[in] a_scale Scaling factor
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Scale(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction, const T a_scale) noexcept;
/*!
@brief Convenience function for offsetting an implicit function
@param[in] a_implicitFunction Input implicit function to be offset
@param[in] a_offset Offset distance
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Offset(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction, const T a_offset) noexcept;
/*!
@brief Convenience function for creating a shell out of an implicit function
@param[in] a_implicitFunction Input implicit function to be shelled.
@param[in] a_delta Shell thickness
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Annular(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction, const T a_delta) noexcept;
/*!
@brief Convenience function for blurring an implicit function
@param[in] a_implicitFunction Input implicit function to be blurred
@param[in] a_blurDistance Smoothing distance
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Blur(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction, const T a_blurDistance) noexcept;
/*!
@brief Convenience function for mollification with an input sphere.
@param[in] a_implicitFunction Input implicit function to be mollifier
@param[in] a_dist Mollification distance.
@param[in] a_mollifierSamples Number of samples for the mollifier
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Mollify(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction,
const T a_dist,
const size_t a_mollifierSamples = 2) noexcept;
/*!
@brief Convenience function for elongating (stretching) an implicit function
@param[in] a_implicitFunction Implicit function to be elongated
@param[in] a_elongation Elongation
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Elongate(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction, const Vec3T<T>& a_elongation) noexcept;
/*!
@brief Convenience function for reflecting an implicit function
@param[in] a_implicitFunction Implicit function to be reflected
@param[in] a_reflectPlane Plane to reflect across (0=yz-plane, 1=xz-plane, 2=xy-plane).
*/
template <class T>
std::shared_ptr<ImplicitFunction<T>>
Reflect(const std::shared_ptr<ImplicitFunction<T>>& a_implicitFunction, const size_t& a_reflectPlane) noexcept;
CSG operations
CSG operations for implicit functions are defined in Source/EBGeometry_CSG.hpp
.
These also include accelerated variants that take advantage of BVH partitioning of the objects.
/*!
@brief Convenience function for taking the union of a bunch of a implicit functions
@param[in] a_implicitFunctions Implicit functions
@note P must derive from ImplicitFunction<T>
*/
template <class T, class P = ImplicitFunction<T>>
std::shared_ptr<ImplicitFunction<T>>
Union(const std::vector<std::shared_ptr<P>>& a_implicitFunctions) noexcept;
/*!
@brief Convenience function for taking the union of two implicit functions
@param[in] a_implicitFunctionA First implicit function.
@param[in] a_implicitFunctionB Second implicit function.
@note P1 and P2 must derive from ImplicitFunction<T>
*/
template <class T, class P1, class P2>
std::shared_ptr<ImplicitFunction<T>>
Union(const std::shared_ptr<P1>& a_implicitFunctionA, const std::shared_ptr<P2>& a_implicitFunctionB) noexcept;
/*!
@brief Convenience function for taking the union of a bunch of a implicit functions
@param[in] a_implicitFunctions Implicit functions
@param[in] a_smooth Smoothing distance.
@note P must derive from ImplicitFunction<T>
*/
template <class T, class P = ImplicitFunction<T>>
std::shared_ptr<ImplicitFunction<T>>
SmoothUnion(const std::vector<std::shared_ptr<P>>& a_implicitFunctions, const T a_smooth) noexcept;
/*!
@brief Convenience function for taking the union of two implicit functions
@param[in] a_implicitFunctionA First implicit function.
@param[in] a_implicitFunctionB Second implicit function.
@param[in] a_smooth Smoothing distance.
@note P1 and P2 must derive from ImplicitFunction<T>
*/
template <class T, class P1, class P2>
std::shared_ptr<ImplicitFunction<T>>
SmoothUnion(const std::shared_ptr<P1>& a_implicitFunctionA,
const std::shared_ptr<P2>& a_implicitFunctionB,
const T a_smooth) noexcept;
/*!
@brief Convenience function for taking the BVH-accelerated union of a bunch of a implicit functions
@param[in] a_implicitFunctions Implicit functions
@param[in] a_boundingVolumes Bounding volumes for implicit functions.
@note P must derive from ImplicitFunction<T>
*/
template <class T, class P, class BV, size_t K>
std::shared_ptr<ImplicitFunction<T>>
FastUnion(const std::vector<std::shared_ptr<P>>& a_implicitFunctions,
const std::vector<BV>& a_boundingVolumes) noexcept;
/*!
@brief Convenience function for taking the BVH-accelerated union of a bunch of a implicit functions
@param[in] a_implicitFunctions Implicit functions
@param[in] a_boundingVolumes Bounding volumes for the implicit functions.
@param[in] a_smoothLen Smoothing length
@note P must derive from ImplicitFunction<T>
*/
template <class T, class P, class BV, size_t K>
std::shared_ptr<ImplicitFunction<T>>
FastSmoothUnion(const std::vector<std::shared_ptr<P>>& a_implicitFunctions,
const std::vector<BV>& a_boundingVolumes,
const T a_smoothLen) noexcept;
/*!
@brief Convenience function for taking the intersection of a bunch of a implicit functions
@param[in] a_implicitFunctions Implicit functions
@note P must derive from ImplicitFunction<T>
*/
template <class T, class P>
std::shared_ptr<ImplicitFunction<T>>
Intersection(const std::vector<std::shared_ptr<P>>& a_implicitFunctions) noexcept;
/*!
@brief Convenience function for taking the intersection of two implicit functions
@param[in] a_implicitFunctionA First implicit function.
@param[in] a_implicitFunctionB Second implicit function.
@note P1 and P2 must derive from ImplicitFunction<T>
*/
template <class T, class P1, class P2>
std::shared_ptr<ImplicitFunction<T>>
Intersection(const std::shared_ptr<std::shared_ptr<P1>>& a_implicitFunctionA,
const std::shared_ptr<std::shared_ptr<P2>>& a_implicitFunctionB) noexcept;
/*!
@brief Convenience function for taking the smooth intersection of a bunch of a implicit functions
@param[in] a_implicitFunctions Implicit functions
@param[in] a_smooth Smoothing distance.
@note P must derive from ImplicitFunction<T>
*/
template <class T, class P>
std::shared_ptr<ImplicitFunction<T>>
SmoothIntersection(const std::vector<std::shared_ptr<P>>& a_implicitFunctions, const T a_smooth) noexcept;
/*!
@brief Convenience function for taking the smooth intersection of two implicit functions
@param[in] a_implicitFunctionA First implicit function.
@param[in] a_implicitFunctionB Second implicit function.
@param[in] a_smooth Smoothing distance.
@note P1 and P2 must derive from ImplicitFunction<T>
*/
template <class T, class P1, class P2>
std::shared_ptr<ImplicitFunction<T>>
SmoothIntersection(const std::shared_ptr<P1>& a_implicitFunctionA,
const std::shared_ptr<P2>& a_implicitFunctionB,
const T a_smooth) noexcept;
/*!
@brief Convenience function for taking the CSG difference.
@param[in] a_implicitFunctionA Implicit function.
@param[in] a_implicitFunctionB Implicit function to subtract.
@note P1 and P2 must derive from ImplicitFunction<T>
*/
template <class T, class P1 = ImplicitFunction<T>, class P2 = ImplicitFunction<T>>
std::shared_ptr<ImplicitFunction<T>>
Difference(const std::shared_ptr<P1>& a_implicitFunctionA, const std::shared_ptr<P2>& a_implicitFunctionB) noexcept;
/*!
@brief Convenience function for taking the smooth CSG difference.
@param[in] a_implicitFunctionA Implicit function.
@param[in] a_implicitFunctionB Implicit function to subtract.
@param[in] a_smoothLen Smoothing length.
@note P1 and P2 must derive from ImplicitFunction<T>. This uses the default smoothMax function.
*/
template <class T, class P1 = ImplicitFunction<T>, class P2 = ImplicitFunction<T>>
std::shared_ptr<ImplicitFunction<T>>
SmoothDifference(const std::shared_ptr<P1>& a_implicitFunctionA,
const std::shared_ptr<P2>& a_implicitFunctionB,
const T a_smoothLen) noexcept;
Bounding volumes
For simple shapes, bounding volumes can be directly constructed given an implicit function.
E.g. one can easily find the bounding volume for a sphere with a known center and radius, or for a DCEL mesh.
However, more complicated implicit functions require us to compute the bounding volume, or at the very least an approximation to it.
ImplicitFunction<T>
has a member function that uses spatial subdivision (based on octrees) for doing this:
// Compute an approximate bounding volume BV.
template <class BV>
inline BV
approximateBoundingVolumeOctree(const Vec3T<T>& a_initialLowCorner,
const Vec3T<T>& a_initialHighCorner,
const unsigned int a_maxTreeDepth,
const T& a_safety = 0.0) const noexcept;
This function initializes a cubic region in space and uses octree refinement near the implicit surface.
At the end of the octree recusion the vertices of the octree leaves are collected and a bounding volume of type BV
that encloses them is computed.
The success of this method relies on the implicit function being a signed distance function (or at least an approximation to it).