06. Voussoir Geometry & Stereotomy¶
The Voussoir tab (ribbon Frahan > Voussoir, 5 components) is the
repository's top-down stereotomy front end. Stereotomy is the art of cutting
solids, classically stone, so that the cut faces alone hold an arch or a vault
in compression without mortar (Frezier 1737; Monge 1798). The tab makes that
art executable. Two generators turn a designed form into cut-stone cells: Arch
Voussoirs builds a planar arch as radial wedge solids, and Pendentive Vault
Voussoirs builds a sail dome tessellated along the sphere's lines of curvature.
Three downstream components (Voussoir Ingest, Voussoir Stone Matcher, Voussoir
Pack Into Block) then assign and pack those cells against found or quarried
stone. This chapter covers the two generators and their shared cell factory;
the matcher and packer are Hungarian and bin-pack facades documented with the
quarry assignment layer.
The design framing is the load-bearing point. The other design tabs let
material be sovereign (rubble walls, Trencadis mosaics, edge-matched
fragments). The Voussoir generators are the opposite pole: the form is
sovereign, and the system cuts stone to realise it. Both [DesignApplication]
attributes tag DesignFlow.TopDown explicitly
(ArchVoussoirsComponent.cs:37, PendentiveVaultVoussoirsComponent.cs:35).
The geometry here is pure trigonometry and curve sampling. Where the
repository turned a classical stereotomic rule into an algorithm, or fixed a
real bug, the derivation is shown, not only the formula. Every originality
claim is anchored to a file:line, an [Algorithm] attribute, or a measured
example.
6.1 The stereotomy lineage and the front-end gap¶
The classical literature gives two laws the generators obey. First, the
radial bed-joint rule: in an arch the bed joints (the faces between
neighbouring voussoirs) are normal to the intrados, the inner soffit curve;
for a circular arch they point at the centre of curvature. Each wedge then
turns the thrust aside, stone to stone, so the whole ring stands in pure
compression (Frezier 1737, who coined stereotomie; the funicular reading is
Hooke's 1675 inverted-catenary insight, made a limit-state theorem by Heyman
1966). Second, Monge's lines-of-curvature rule for vaults: orient the bed
joints along the lines of curvature of the doubly-curved surface; for a sphere
these are the meridians and parallels (Monge 1798). Both laws are recorded in
source as [Algorithm] citations on the two components
(ArchVoussoirsComponent.cs:34-36,
PendentiveVaultVoussoirsComponent.cs:32-34).
The repository already shipped a voussoir back end: Voussoir Ingest reads
cells produced by an external Grasshopper plugin (Varela and Sousa's Voussoir,
food4rhino), then Voussoir Stone Matcher and Voussoir Pack Into Block assign
and pack them (VoussoirRecord.cs:11-21). What was missing was the
generation step. Without it the top-down flow began outside Frahan, in a
third-party tool. The VoussoirCellFactory closes that gap: it generates the
cut-stone cells from first principles so the whole top-down chain lives inside
the repository (VoussoirCellFactory.cs:9-20):
VoussoirCellFactory.BuildArch / BuildPendentiveVault (this chapter)
-> VoussoirAssembly (typed)
-> Voussoir Stone Matcher (Hungarian) / Rubble Evolved Fit
-> CGAL trim (digital ravalement)
The shared engine is a static class, VoussoirCellFactory, with two public
entry points (BuildArch, BuildPendentiveVault) and one shared solid
builder (MakeHexahedron). It depends on RhinoCommon for Mesh, Curve, and
Plane, but needs no Rhino document, so it runs in the headless harness
(VoussoirCellFactory.cs:39-41).
6.2 The arch: radial voussoir cells¶
ArchVoussoirsComponent (GUID
D5F10012-ED9E-4ED9-A012-ED9EED9E0012, :57-58) generates an arch as N
radial wedge solids. The construction has three stages: build the intrados
curve for the chosen profile, station it by equal arc length, then loft a
closed wedge between each pair of stations.
6.2.1 Stationing the intrados¶
The intrados is built in the world XZ plane with the springers on \(z = 0\) and
the width running along \(Y\). For the count \(N\) the curve is divided into \(N+1\)
equal-arc-length stations, giving \(N\) wedges (VoussoirCellFactory.cs:119-121):
Equal arc length, not equal angle, is the right division: it keeps the intrados face of every voussoir the same physical width even when the profile is not circular (a catenary or a pointed arch), which is the fabrication constraint a mason cares about.
6.2.2 The outward normal and the radial bed joint¶
At each station the bed-joint direction is the outward normal to the
intrados. The code takes the in-plane tangent \(\mathbf{T}(t_k)\), projects it
into the XZ plane, and rotates it ninety degrees in plane
(VoussoirCellFactory.cs:136-146):
The rotation \((T_x, T_z) \mapsto (T_z, -T_x)\) is the planar perpendicular. Its sign is then fixed to point away from the arch interior by testing against the radial vector \(\mathbf{r}_k = p_k - \bar{p}\) from the station to the centroid of the station cloud, flipping \(\mathbf{n}\) when \(\mathbf{n} \cdot \mathbf{r}_k < 0\):
Why this is exactly the radial rule for a circular arch. For a circle of centre \(O\) the tangent at any point is perpendicular to the radius \(O p_k\), so the in-plane perpendicular of the tangent is collinear with that radius. Rotating the tangent ninety degrees therefore yields the radial direction, and the centroid sign-fix orients it outward, away from \(O\). The bed joint built on \(\mathbf{n}_k\) is then normal to the intrados and points at the centre of curvature, which is Frezier's rule verbatim. For a non-circular profile (catenary, pointed) the centre of curvature varies along the curve, and \(\mathbf{n}_k\) is the local intrados normal, the correct generalisation: the bed joint stays perpendicular to the soffit at the joint, which is what keeps the contact face square to the local thrust.
6.2.3 The wedge solid¶
Each voussoir spans stations \(i\) and \(i+1\). Its four in-plane corners are the
two intrados points and the two extrados points; the extrados is the intrados
offset outward by the ring thickness \(t\) along the per-station normal
(VoussoirCellFactory.cs:152-174):
Because the extrados rides on the same outward normals, a circular arch
gives an exactly concentric extrados: each extrados point sits at radius
\(R + t\) on the same ray as its intrados point. The in-plane quad is then swept
the half-width \(\tfrac{w}{2}\) each way along \(Y\) to give the front and back
rings, and MakeHexahedron welds them into a closed eight-vertex solid. The
lower bed-joint plane is emitted with origin at the mid-thickness of the lower
face and axes \((\mathbf{n}_i,\ \mathbf{Y})\), so its own normal is the
tangential thrust direction (:179-182).
The result is faceted: straight chords between arc-length stations. The
component tolerance note states this plainly and gives the remedy, raise the
count (ArchVoussoirsComponent.cs:41). The error is the chord sagitta of the
intrados arc, which falls as \(O(1/N^2)\); the circular extrados, by the
concentric construction above, carries the same relative facet error as the
intrados, not a worse one.
6.2.4 The keystone¶
The keystone is the voussoir nearest the apex. The factory finds it by a
combined height-and-symmetry score: among cells with positive \(z\), minimise
\(|x_c| + |z_{\text{apex}} - z_c|\) over the centroid \((x_c, z_c)\), so the winner
is the highest cell closest to the plane of symmetry \(x = 0\)
(NearestToApex, :526-538). Its JointClass is then set to "key"
(:189-193), and the springer course (the lowest 5% height band) is tagged
"ground" as the install-DAG anchors (:509-515).
6.2.5 Four profiles, one path¶
The profile families are Semicircular, Segmental, Pointed (equilateral
two-centred Gothic), and Catenary (ArchProfile, :45-55). The
wiki note that "catenary and pointed are a drop-in change of the intrados
curve" is made concrete: each profile builds only its intrados Curve, and
the single shared path of 6.2.1 to 6.2.3 stations and lofts it
(BuildIntrados, :315-336).
- Semicircular and Segmental are circular arcs. The centre is placed at
\(z_c = -R\cos(\tfrac{a}{2})\) so the springers land on \(z = 0\) for the
included angle \(a\), and the arc passes through left springer, apex, right
springer (
BuildArcIntrados,:338-352). The span is \(S = 2R\sin(\tfrac{a}{2})\). - Pointed is the equilateral two-centred arch: span \(S = R\), each half an
arc of radius \(S\) swung from the opposite springer, apex at
\(h = \tfrac{\sqrt 3}{2}S\) (
BuildPointedIntrados,:354-382). The two arcs are appended into onePolyCurve. - Catenary is the inverted hanging chain, the funicular line of a
pure arch (Hooke 1675; Heyman 1966). A chain of parameter \(a\) hangs as
\(y = a\cosh(x/a)\) with sag \(a\cosh(\tfrac{S}{2a}) - a\) over the span \([-S/2,
S/2]\). Given a target rise \(H\) the factory solves for \(a\) such that the sag
equals \(H\), then inverts the curve so the sag becomes the rise
(
BuildCatenaryIntrados,:390-410).
Original derivation: the catenary parameter solve. The shape parameter \(a\) has no closed form for a prescribed span \(S\) and rise \(H\); it is the root of
\(f\) is monotone decreasing in \(a\) from \(+\infty\) (as \(a \to 0^{+}\) the chain
sags arbitrarily deep) toward \(-H\) (as \(a \to \infty\) the chain straightens
and the sag vanishes), so it crosses zero exactly once and bisection is
guaranteed to converge. The factory brackets the root on \([10^{-4}S,\ 10^{4}S]\)
and bisects to a residual of \(10^{-9}\) or interval collapse, capped at 200
iterations (SolveCatenaryA, :412-432). The inverted profile is then sampled
(\(z = H - (a\cosh(x/a) - a)\), floored at zero) and fitted with a cubic
interpolating curve. Building the true funicular intrados is what makes the
catenary arch a structural object, not a decorative pointed shape: the bed
joints normal to it are normal to the thrust line, so the ring is in pure
axial compression by construction (the safe theorem, Heyman 1966).
Originality. Arch Voussoirs is clean-room stereotomy. The radial bed-joint construction is built from the published rule, cited in source by two
[Algorithm]attributes: the Frahan-original cell construction (intrados curve to arc-length stations to eight-vertex wedge solids with radial bed joints,ArchVoussoirsComponent.cs:31-33), and the geometric law it obeys credited to Frezier (1737) and Monge (1798) (:34-36). No external stereotomy source sits in the tree; the upstream Voussoir plugin (Varela and Sousa) is a cited precedent in the[DesignApplication]attribute (:40), not a dependency, and its cells are consumed only through the separate Voussoir Ingest path. The catenary parameter solve and the concentric-extrados construction are the small clean-room deltas over a naive radial sweep.

6.3 The pendentive vault: lines-of-curvature cells¶
PendentiveVaultVoussoirsComponent (GUID
D5F10013-ED9E-4ED9-A013-ED9EED9E0013,
PendentiveVaultVoussoirsComponent.cs:55-56) is the doubly-curved
counterpart. A pendentive (sail) dome is a single spherical surface springing
from the four corners of a square plan up to the apex. The factory tessellates
it on a \(U \times V\) grid into wedge cells whose bed joints follow the sphere's
lines of curvature, then extrudes each cell radially by the shell thickness
(BuildPendentiveVault, :216-304).
6.3.1 Lifting the square grid onto the sphere¶
The square plan of half-width \(h\) is gridded uniformly in \((x, y)\), and each
node is lifted onto the sphere of radius \(R\) centred at the origin
(:244-256):
The corner-on-sphere constraint. The plan corners \((\pm h, \pm h)\) must lie on the sphere, which requires \(z\) real at the corner:
The factory enforces \(2h^2 < R^2\) as a hard precondition and throws a
descriptive error otherwise (:230-234); the component repeats the same guard
before calling Core and surfaces it as a canvas error
(PendentiveVaultVoussoirsComponent.cs:130-136). The springing height (the \(z\)
of the four corners) is \(z_{\text{corner}} = \sqrt{R^2 - 2h^2}\), and an
optional drop-to-ground shift translates the whole vault so the springers rest
on \(z = 0\) (:236-238).
6.3.2 The radial frustum cell¶
Each grid cell is the patch between four lifted intrados points
\((c_{00}, c_{10}, c_{11}, c_{01})\) and their radial projections to the
outer sphere of radius \(R + t\). The extrados corner of an intrados point \(p\) is
the scaling of \(p\) about the sphere centre by the radius ratio
(Radial, :308-313; cell :269-277):
Because both faces are radial scalings about the same centre, the side walls of
the cell run along sphere radii, which are the surface normals. The bed joint
between two neighbouring cells therefore sits in a plane containing the sphere
radius, exactly Monge's lines-of-curvature rule for a sphere: the cell edges
run along meridians and parallels, and the joints are radial. The bed plane is
emitted with origin at the intrados patch centre and normal along the outward
radial \(\widehat{(\text{mid} - O_{\text{sph}})}\) (:280-289). The vault has no
single keystone, so KeystoneIndex is left at \(-1\) (:294).
Originality. Pendentive Vault Voussoirs is clean-room. The sphere-over-square construction and the radial-frustum cell are built from the lines-of-curvature rule, cited in source by the Frahan-original cell
[Algorithm](square grid lifted by \(z = \sqrt{R^2 - x^2 - y^2}\) then radially extruded,PendentiveVaultVoussoirsComponent.cs:29-31) and the Monge tessellation law it obeys (:32-34). The cited design precedents are Rippmann and Block (2011) Digital Stereotomy and the Block Research Group RhinoVAULT pipeline (:38); these are named precedents in the[DesignApplication]attribute, not in-tree dependencies. The sphere is the closed-form special case; a general form-found funicular shell would arrive through the compas-RV reference pipeline noted in 6.5.

6.4 The inward-orientation fix (original derivation)¶
Both generators feed their cells into a CGAL Boolean trim downstream (the digital ravalement of examples 21 and 22, section 6.5). A mesh-mesh Boolean is sensitive to face orientation: the kernel reads a closed mesh's inside from its face winding. If a cell's faces wind inward, the kernel reads the solid as "all of space except the cell", and the intersection of a stone with that inverted cell returns the stone minus the cell rather than the carved voussoir. The failure is silent: the trim returns a closed mesh, just the wrong one.
The fix lives in the shared solid builder. After MakeHexahedron welds the two
rings, unifies the winding, and rebuilds normals, it tests the signed
volume of the mesh and flips every face if the volume is negative
(MakeHexahedron, :452-464):
Why signed volume is the correct orientation test. For a closed triangulated mesh the signed volume is the sum over faces of the signed tetrahedron each face spans with the origin,
and its sign is determined entirely by the global face winding: outward-wound
faces give \(V_{\text{signed}} > 0\), inward-wound give \(V_{\text{signed}} < 0\).
The magnitude is the true enclosed volume regardless of sign. So the single
test \(V_{\text{signed}} < 0\) detects an inverted solid exactly, and one global
flip corrects it. This is necessary because Mesh.UnifyNormals only makes the
winding consistent across faces, not necessarily outward: a fully
consistent mesh can still be uniformly inside-out, which is the case the flip
catches (:456-461). The factory then stores the absolute mesh volume on each
record (VoussoirRecord.cs:37-39; Math.Abs(cell.Volume()) at
VoussoirCellFactory.cs:476), so the volume metric is sign-independent and a
flipped or unflipped cell reports the same number.
This bug and fix were a live-validated correctness gate. The memory note for
the voussoir generators records that the inward-orientation bug "silently broke
CGAL booleans" and that the flip-if-signed-volume-under-zero guard is what made
examples 21 and 22 regenerate from raw rubble with no raw boulders surviving
the trim. The closedness of every emitted cell is checked (Mesh.IsClosed) and
surfaced as a component warning if any cell is open
(ArchVoussoirsComponent.cs:163-165,
PendentiveVaultVoussoirsComponent.cs:150-152).
Originality. The orientation fix is a clean-room correctness guard on the shared
MakeHexahedronbuilder (VoussoirCellFactory.cs:452-464). It is elementary geometry (signed volume sign as an orientation oracle), and its contribution is robustness: it is the precondition that makes the downstream CGAL trim of section 6.5 return the carved voussoir rather than its complement. The downstream trim itself runs through the in-repoCgalMeshBooleanprimitive (the GPL CGAL kernel in Rhino, a managed BSP fallback headless), which is facade-over-primitives and out of scope for this tab; this chapter owns only the generator that produces a correctly oriented input to it.

6.5 The top-down flow end to end: examples 21 and 22¶
The two generators are the entry point of a top-down stereotomy chain that ends in carved stone. Examples 21 (arch) and 22 (pendentive vault) run it whole, with a measured coverage metric.
The flow is the classical ravalement method made digital: cut a voussoir
oversize, mount it, trim the excess to the final surface (Frezier; the method
is recorded in the example READMEs). Operationally: the generator emits the
target cell, a volume-feasible ETH1100 rubble stone is matched and posed to
envelop it (the evolved matcher adds rotation seeds and an SE(3) containment
search over the cell's real vertices), and CgalMeshBoolean.Intersection
trims the stone to the cell. A validity guard keeps only closed trims within
the cell volume, else falls back to the clean cut cell, never the raw boulder.
Stability in stereotomy comes from the carved geometry, not mortar, so the cut
faces are what matter.
The measured results (regenerated 2026-06-07, 21_arch_metrics.json,
22_vault_metrics.json):
| Example | Form | Cells | Source | Real rubble trims | Coverage |
|---|---|---|---|---|---|
| 21 | Semicircular arch, \(R = 2.0\) m, ring \(0.55\) m, span \(4.0\) m | 11 | Arch Voussoirs (D5F10012) | 11 / 11, 0 clean fallback | 94.9% |
| 22 | Pendentive dome, \(R = 2.5\) m, \(2h = 3.2\) m, \(t = 0.4\) m | 36 | Pendentive Vault Voussoirs (D5F10013) | 36 / 36, 0 clean fallback | 98.3% |
Coverage is recovered carved volume over the target ring or shell volume: \(2.2079 / 2.3266\ \text{m}^3 = 94.9\%\) for the arch (per-cell 0.85 to 0.99), \(5.5996 / 5.6941\ \text{m}^3 = 98.3\%\) for the vault. Both runs are visually validated in Rhino (criterion c) with one coloured mesh per voussoir. The reported bug the regeneration fixed is exactly the orientation-and-fallback issue of section 6.4: the earlier version kept a raw un-trimmed boulder on a failed trim, so oversized stones overshot the ring; no raw boulders remain in either example.
For a general form-found doubly-curved vault (not the closed-form sphere), the documented reference pipeline is compas-RV (Block Research Group RhinoVAULT in COMPAS): pattern to form-and-force diagrams to a compression-only funicular shell, tessellated into voussoir courses with bed joints along the lines of curvature, then the same match-and-trim. Equilibrium of the assembled ring or shell is then checked by Frahan Masonry Stability (RBE and CRA, chapter 5), closing the top-down stereotomy loop onto the contact-equilibrium chapter.
6.6 Status and what is left¶
- Funicular form-finding is external. The arch supports a true catenary
intrados, but the pendentive generator is the closed-form sphere only. A
general form-found shell must arrive through the compas-RV reference pipeline
named in 6.5; there is no in-repo form-finder. The funicular
ThrustCurvefield onVoussoirAssemblyis defined but not populated by either generator (VoussoirAssembly.cs:23-27). Severity: medium (scope boundary, documented). - Faceted cells by construction. Both generators emit straight-chord
facets; curvature accuracy is bought only by raising the count or the grid,
and the tolerance note states this (
ArchVoussoirsComponent.cs:41,PendentiveVaultVoussoirsComponent.cs:39). The intrados facet error falls as \(O(1/N^2)\), but a true NURBS-faced voussoir would need a different cell builder. Severity: low (stated, count-controllable). - No equilibrium check inside the tab. The generators produce geometry and
a typed assembly with ground anchors and
LoadAxisper cell, but do not run a stability verdict; that requires wiring the assembly into the Masonry Stability components (chapter 5). The[DesignApplication]precedent names the link, but the canvas does not enforce it. Severity: low (cross-tab by design). - Adjacency graph not auto-built by the factory.
FinalizeResultleavesAdjacencyPairsempty (VoussoirCellFactory.cs:520); the install-DAG adjacency is detected downstream in Voussoir Ingest by shared-face area (VoussoirAssembly.cs:29-33). A generator that already knows its station-to-station and grid neighbour topology could emit the adjacency losslessly, as the polygonal-wall assembler does for masonry (chapter 5.5). Severity: low (refactor opportunity). - Citation hygiene. The example READMEs cite Sakarovitch (stereotomy
history) and Galletti (2020, mortarless stability) and Hooke (1675), which
are not yet keyed in
99_references.md; the in-source[Algorithm]citations (Frezier 1737, Monge 1798, Rippmann-Block 2011) are present and keyed. Add the missing keys before external review perAGENTS.mdยง9. Severity: low (provenance, not copyleft).
References (this chapter)¶
- Frezier, A.-F. (1737-1739). La theorie et la pratique de la coupe des pierres et des bois (the stereotomy treatise that coined stereotomie; the radial bed-joint rule). [R148]
- Monge, G. (1798). Geometrie descriptive. Baudouin, Paris (lines of curvature for vault tessellation). [R149]
- Hooke, R. (1675). A description of helioscopes (the inverted-catenary
anagram: the funicular line of a pure arch). Cited in source for the catenary
profile; not yet keyed in
99_references.md. - Heyman, J. (1966). The stone skeleton (limit-state / safe theorem of masonry; thrust line within the section). International Journal of Solids and Structures 2(2):249-279. DOI 10.1016/0020-7683(66)90018-7. [R57]
- Rippmann, M., Block, P. (2011). Digital stereotomy: voussoir geometry for freeform masonry-like vaults informed by structural and fabrication constraints. Proceedings of IABSE-IASS 2011, London. [R64]
- Varela, P.A.A., Sousa, J.P. Voussoir: stereotomy plug-in for Grasshopper. FAUP Porto Digital Fabrication Laboratory. https://www.food4rhino.com/en/app/voussoir (cited precedent for the voussoir-ingest back end; not a dependency of the generators). [R132]
- Block Research Group. RhinoVAULT / compas-RV funicular form-finding (the reference pipeline for general form-found shells). [R64, R65]