RasmahRasmah

Geometry & modeling

Overview

Rasmah represents a shape not as a fixed list of numbers, but as a program. That program is built from small, immutable building blocks — a sphere, a box, a boolean cut — composed into a tree. To change the shape you change a parameter, and the whole downstream pipeline (geometry, mesh, simulation) recomputes from that one change.

This matters for a simple reason: if the model is a program, then its derivatives are programs too. The gradient of "how does the stress change when I move this face" can be computed automatically, which is what makes Rasmah's CAD → mesh → simulation → loss pipeline differentiable end to end.

This chapter introduces the three ideas that make this possible:

  1. the feature graph — the tree of immutable nodes that is the model;
  2. the signed distance field (SDF) — the implicit representation that lets any shape be a single scalar function of position;
  3. the backends — the three ways to evaluate the same feature graph (implicit SDF, exact boundary representation, or a mesh).

A model is a function

A parametric model in Rasmah is a plain Julia function of its free values:

model(r) = sphere(r)

For any radius r this rebuilds the same feature graph. Because the feature nodes are immutable (they cannot be changed after they are built), the model is a pure function: the same r always gives the same shape.

To differentiate the model you use derivative (with respect to a single scalar) or gradient (with respect to a vector of values):

derivative(r -> volume(sphere(r)), 2.0)
50.26548245743669 m^3

Notice the $\mathrm{m}^3$ on the answer. Rasmah carries physical units on its results — a volume is a length cubed, so it is reported in cubic metres — and a bare number like $2.0$ is read in SI units. For now just read the number and trust the tag; the full units system is the Units chapter.

Here $\mathrm{d}V/\mathrm{d}r = 4\pi r^{2}$ is the surface area of the sphere — a good sanity check, because growing a sphere's radius by a tiny $\mathrm{d}r$ adds a thin shell of area $4\pi r^{2}$ and thickness $\mathrm{d}r$.

The feature graph

A feature graph is a tree of immutable nodes. The leaves are primitives (sphere, box, …) and the interior nodes are combinators (difference, translate, scale, …). The abstract supertype of every node is Feature:

Rasmah.FeatureType
Feature

Abstract supertype of all parametric CAD nodes (primitives and combinators). A parametric model is a plain function of its free values, differentiable through derivative/gradient.

source

Each node exposes its children (its free parameters and sub-features) through children, which is how the differentiation machinery walks the tree.

Signed distance fields

A signed distance field is a function $s(\mathbf{x})$ that returns the shortest signed distance from the point $\mathbf{x}$ to the surface of a shape:

  • $s(\mathbf{x}) < 0$ — the point is inside the shape;
  • $s(\mathbf{x}) = 0$ — the point is on the surface;
  • $s(\mathbf{x}) > 0$ — the point is outside the shape;

and $|s(\mathbf{x})|$ is always the actual distance to the nearest surface point. For a sphere of radius $r$ centred at the origin:

\[s(\mathbf{x}) = \|\mathbf{x}\| - r .\]

The magic of the exact SDF is that its gradient has unit length almost everywhere, $\|\nabla s\| = 1$. That makes the field smooth and predictable, so marching-cubes meshing, ray casting, and inside/outside tests all behave well. Rasmah's implicit geometry is exactly this:

Rasmah.ImplicitGeometryType
ImplicitGeometry

Abstract supertype of all signed-distance-field (SDF) geometry.

A signed distance field is a function s(x) whose value at a point x is the shortest signed distance to the surface of a shape: it is negative inside, zero on the surface, and positive outside, and $|s(x)|$ is the distance to the surface. The gradient $\nabla s$ then has unit length wherever it is defined, which is what makes SDFs convenient for meshing (marching cubes/tetrahedra), ray casting, and physics that need an inside/outside test.

A concrete subtype is a callable g(x) returning the signed distance at x, and it supplies bounds(g) for its axis-aligned bounding box (lo, hi).

The feature nodes (sphere, box, …) are converted into ImplicitGeometry values through evaluate with the SDFBackend; the SDF types themselves are the backend's working form.

See also

SDFBackend, field, gradient, bounds.

source
Rasmah.fieldFunction
field(g, x) -> Float64

Evaluate the signed distance field of the implicit geometry g at the point x (an alias for g(x)).

The result is negative inside the shape, zero on its surface, and positive outside, with |field(g, x)| the shortest distance to the surface.

Arguments

  • g: a feature (or implicit geometry) to sample.
  • x: a 3-vector point.

Example

julia> using Rasmah

julia> field(sphere(1), [2.0, 0, 0])
1.0
source
Rasmah.gradientFunction
gradient(f, x) -> Vector / QuantityVector

Gradient ∂f/∂x of a scalar function f with respect to a vector of values x, computed with the default AD backend. Each component carries dimensions udim(f(x)) / udim(x); when that dimension is dimensionless (a plain vector input and a dimensionless output) a plain Vector is returned instead of a QuantityVector.

source

The three backends

The same feature graph can be turned into geometry in three different ways, selected by the backend you pass to evaluate:

BackendResultWhat it stores
SDFBackendImplicitGeometrya signed-distance formula
BRepBackendBRepexact topology — faces, edges, vertices
MeshBackendTriangleMesh / TetMesha discretized surface / volume

The shorthand brep is evaluate(model, BRepBackend()). Because the parameters live in the feature graph and each backend re-derives its geometry from them, the parameters stay differentiable no matter which backend you use.

Rasmah.evaluateFunction
evaluate(model, backend) -> geometry

Evaluate a model (a feature graph, sketch, or implicit geometry) through a geometry backend, returning the corresponding concrete geometry.

evaluate is the shared entry point for Rasmah's three geometry representations:

backendreturnsstores
SDFBackendImplicitGeometrya signed-distance formula
BRepBackendBRepexact topology (faces, edges, vertices)
MeshBackendTriangleMesh/TetMesha discretized surface/volume

The same feature graph can be evaluated through any backend, which is what keeps the CAD → mesh → simulation pipeline differentiable: parameters live in the feature graph, and each backend re-derives its geometry from them.

Arguments

  • model: a Feature (e.g. from sphere, difference), a sketch, or an ImplicitGeometry.
  • backend: the evaluation backend (default shorthand brep is evaluate(model, BRepBackend())).

Example

julia> using Rasmah

julia> s = evaluate(box(2, 2, 2), SDFBackend());

julia> field(s, [0.0, 0.0, 0.0])
-1.0
source
Rasmah.SDFBackendType
SDFBackend

The geometry backend that converts a feature tree (or sketch) into an ImplicitGeometry signed-distance field.

Pass it to evaluate to evaluate a feature graph as a signed distance field — for example evaluate(box(2, 2, 2), SDFBackend()) returns a BoxSDF. The SDF is the implicit representation: it stores a formula, not a mesh, so it stays differentiable in the feature parameters.

See also

evaluate, brep, MeshBackend.

source

Measuring geometry

Every shape can answer two basic questions — how big is it? and where is it? — via its analytic volume / area and its axis-aligned bounds:

Rasmah.volumeFunction
volume(x) -> Quantity

The volume of a geometry or mesh x, as an SI Quantity of volume dimension (D_VOLUME; see the Units chapter).

For primitives and closed-form solids the volume is analytic (exact), e.g. $4\pi r^{3}/3$ for a sphere, $\pi r^{2} h$ for a cylinder, $2\pi^{2}\, R\, r^{2}$ for a torus, and Pappus's area(profile)·path length for sweeps. Translation and rotation preserve volume; uniform scale by s scales it by $|s|^{3}$. For a TetMesh the volume is the signed sum of the tetrahedron volumes.

Arguments

  • x: a feature, ImplicitGeometry, or mesh.

Returns

A Quantity with dimension (or the current display unit).

Example

julia> using Rasmah

julia> volume(sphere(2))
33.510321638291124 m^3

See also: area, surface_area.

source
Rasmah.areaFunction
area(x) -> Quantity

The (surface) area of a 2D geometry x, as an SI Quantity of area dimension (D_AREA; see the Units chapter).

For sketches the area is analytic: $\pi r^{2}$ for a circle, the shoelace formula for a polygon, and the swept area for a slot/ellipse. For surface meshes use surface_area.

Example

julia> using Rasmah

julia> area(circle_2d(2.0))
12.566370614359172 m^2
source
Rasmah.boundsFunction
bounds(g) -> (lo, hi)

The axis-aligned bounding box of the geometry g, as a pair (lo, hi) of 3-vectors giving the minimum and maximum corners.

For primitives the box is tight (e.g. sphere(2)([-2,-2,-2], [2,2,2])); for boolean combinations and patterns it is the (possibly conservative) union or intersection of the operands' boxes. A plane has infinite extent and therefore no bounding box, so bounds throws for it; hand the finite region of interest explicitly to any operation that needs one (meshing or clipping a plane).

Arguments

  • g: an ImplicitGeometry, feature (via evaluate), or mesh.

Example

julia> using Rasmah

julia> bounds(evaluate(torus(2, 0.5), SDFBackend())) == ([-2.5, -2.5, -0.5], [2.5, 2.5, 0.5])
true
source
bounds(f::PlanarBRepField) -> (lo, hi)

Axis-aligned bounding box of f, the implicit signed field of a polyhedral (planar-faced) BRep (see PlanarBRepField). Returns the stored box.

source
volume(cylinder(1, 2))
6.283185307179586 m^3

For a cylinder, $V = \pi r^{2} h = \pi \cdot 1^{2} \cdot 2 \approx 6.283$.

Next steps

Now that you know how a model is represented and evaluated, move on to the shapes themselves: Primitives, SDFs, and CSG.