ImplicitGeometries.jl

This package enables construction of implicit geometries by composition of primitive shapes described by signed distance functions. It supports evaluation of gradients and normals of such implicit representations.

To represent the construction tree structure, parts of the AbstractTrees.jl interface are implemented.

The articles by Inigo Quilez are a great resource about implicit geometry representations via signed distance functions. This package uses ideas presented in these articles.

ImplicitGeometries.SDFType
abstract type SDF{Dim,T}

A signed distance function (SDF) represents a geometry implicitly by giving the signed distance from any point in space to the surface of the geometry.

For a region Ω in ℝⁿ with boundary ∂Ω, the signed distance function ϕ(x) returns:

  • a negative value if x is inside Ω,
  • zero if x lies on the boundary ∂Ω,
  • a positive value if x is outside Ω.

Strictly speaking, the value of ϕ(x) is equal to the shortest (Euclidean) distance to the boundary ∂Ω, with a sign that indicates whether the point is inside or outside the region Ω.

Note, that not all operations implemented in ImplicitGeometries.jl return a true signed distance function. The (Euclidean) distance property is not always preserved.

All data types subtyping SDF are intended to act as functors. They are callable with a single argument of type SVector{Dim,T} where Dim is the dimension of the domain and T is the used number type.

source

Shapes

Types subtyping Shape serve as building blocks for construction of more complex geometries. These are typically true signed distance functions, i.e. they return the minimal Euclidean distance to the shape boundary.

The following primitive shapes are currently implemented:

ImplicitGeometries.QuadraticBezierMethod
QuadraticBezier(; v::Vector{SVector{2,T}}) where {T<:Real}

Initialize QuadraticBezier. The control points for all Bezier segments are collected in the vector v. Typically, the first and the last control point will coincide. The orientation of each segment must be consistent.

source

Operations

Types subtyping Operation are compositions of two or more signed distance functions. Not all operations are described by a true signed distance function.

The following operations are currently implemented:

ImplicitGeometries.BooleanUnionMethod
BooleanUnion(shape1::S1, shape2::S2) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing boolean union of shape1 and shape2.

source
Base.:∪Function
Base.:∪(shape1::S1, shape2::S2) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing boolean union of shape1 and shape2.

source
ImplicitGeometries.BooleanIntersectionMethod
BooleanIntersection(shape1::S1, shape2::S2) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing boolean intersection of shape1 and shape2.

source
Base.:∩Function
Base.:∩(shape1::S1, shape2::S2) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing boolean intersection of shape1 and shape2.

source
ImplicitGeometries.BooleanSubtractionMethod
BooleanSubtraction(shape1::S1, shape2::S2) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing boolean subtraction of shape1 and shape2.

source
Base.:-Function
Base.:-(shape1::S1, shape2::S2) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing boolean subtraction of shape1 and shape2.

source
ImplicitGeometries.BooleanDifferenceMethod
BooleanDifference(shape1::S1, shape2::S2) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing boolean difference of shape1 and shape2.

source
Base.:\Function
Base.:\(shape1::S1, shape2::S2) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing boolean difference of shape1 and shape2.

source
ImplicitGeometries.SmoothMinimumMethod
SmoothMinimum(shape1::S1, shape2::S2; k::T = 0.1) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing smooth minimum of shape1 and shape2. The parameter k control the smoothness.

source
ImplicitGeometries.SmoothUnionMethod
SmoothUnion(shape1::S1, shape2::S2; k::T = 0.1) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing smooth union of shape1 and shape2. The parameter k controls the smoothness.

source
ImplicitGeometries.SmoothIntersectionMethod
SmoothIntersection(shape1::S1, shape2::S2; k::T = 0.1) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing smooth intersection of shape1 and shape2. The parameter k controls the smoothness.

source
ImplicitGeometries.SmoothSubtractionMethod
SmoothSubtraction(shape1::S1, shape2::S2; k::T = 0.1) where {Dim,T,S1<:SDF{Dim,T},S2<:SDF{Dim,T}}

Initialize signed distance function representing smooth subtraction of shape1 and shape2. The parameter k controls the smoothness.

source

Transformations

Types subtyping Transformation operate on a single signed distance function. Most transformations are described by a true signed distance function.

The following transformations are currently implemented:

ImplicitGeometries.TranslationMethod
Translation(shape::S; dx::T = 0.0, dy::T = 0.0) where {T,S<:SDF{2,T}}

Initialize Translation from shape. Parameters dx and dy control the translation amount in x and y direction.

source
Translation(shape::S; dx::T = 0.0, dy::T = 0.0, dz::T = 0.0) where {T,S<:SDF{3,T}}

Initialize Translation from shape. Parameters dx, dy and dz control the translation amount in x, y and z direction.

source
ImplicitGeometries.RotationMethod
Rotation(shape::S; θ::T = 0.0, dx::T = 0.0, dy::T = 0.0) where {T,S<:SDF{2,T}}

Initialize Rotation from shape rotated by angle θ. The parameters dx and dy control the center of rotation.

source
Rotation(shape::S; ϕ::T = 0.0, θ::T = 0.0, ψ::T = 0.0, dx::T = 0.0, dy::T = 0.0, dz::T = 0.0) where {T,S<:SDF{3,T}}

Initialize Rotation from shape. The parameters ϕ, θ and ψ are rotation angles around the first, second and third axis. The parameters dx, dy and dz control the center of rotation.

source
ImplicitGeometries.ElongationMethod
Elongation(op::S; dx::T = 0.0, dy::T = 0.0, dz::T = 0.0) where {T,S<:SDF{3,T}}

Initialize Elongation from three dimensional shape. Parameters dx, dy, dz the amount of elongation in x, y and z.

source

Gradients

ImplicitGeometries.jl supports evaluation of gradients of signed distance functions. Currently, the gradients in two dimensions are approximated by second order finite differences with a 4-point cross stencil. The gradients in three dimensions are approximated by first order finite differences with a 4-point tetrahedron stencil. The Gradient is a functor similar to SDF. It can be evaluated a some position p.

ImplicitGeometries.GradientMethod
Gradient(shape::S; h::T = 1e-4) where {Dim,T,S<:SDF{Dim,T}}

Initialize Gradient for a signed distance function shape. The parameter h controls the width of the finite difference stencil.

source
Automatic differentiation

Automatic differentiation can also be used to evaluate gradients of signed distance functions and, depending on the application, might also be preferable to the finite differencing used in Gradient. In the following example we use Zygote.jl to evaluate the gradient using automatic differentiation.

julia> using Zygote, StaticArrays

julia> geometry = Ring(Rectangle() - Circle(; r=0.25); r=0.1);

julia> print_tree(geometry)
Ring (r = 0.1)
└─ BooleanSubtraction
    ├─ Rectangle (w = 1.0, h = 1.0)
    └─ Circle (r = 0.25)

julia> Zygote.gradient(geometry, p)[1]
2-element SVector{2, Float64} with indices SOneTo(2):
0.7071067811865476
0.7071067811865476

julia> Gradient(geometry)(p)
2-element SVector{2, Float64} with indices SOneTo(2):
0.7071067811870169
0.7071067811881271

Note: ForwardDiff.jl seems to struggle with some signed distance functions.

Normals

A normal on the boundary of a region described by a constant levelset of a signed distance function is nothing more than the normalized Gradient evaluated on that boundary. The same approximations as in Gradient are used here.

ImplicitGeometries.NormalMethod
Normal(shape::S; h::T = 1e-4) where {Dim,T,S<:SDF{Dim,T}}

Initialize Normal for a signed distance function shape. The parameter h controls the width of the finite difference stencil.

source