Skip to content
Shapemetry

Create and Measure Solids

Solid-root B-Rep work goes through the Brep namespace of @huukhanhnguyen/geometry (one-shell documents have their own namespace, Shell). Solids are JSON documents (strings): every function takes documents and returns a fresh one. Inputs are never mutated and there is nothing to free.

Primitives

import { Brep } from '@huukhanhnguyen/geometry'

const box = Brep.box(100, 60, 40)        // dx, dy, dz from the origin corner
const shaft = Brep.cylinder(12, 80)      // radius, height — axis along +Z
const ball = Brep.sphere(25)             // radius

Move and rotate

Translation has a dedicated door. Rotation goes through a 4×4 matrix — there is no Brep.rotate; build the matrix with the Transformation namespace and apply it with Brep.transform:

import { Brep, Transformation } from '@huukhanhnguyen/geometry'

const moved = Brep.translate(box, 10, 20, 30)

const rot = Transformation.fromRotation(0, 0, 1, Math.PI / 4) // axis xyz + angle (rad)
const spun = Brep.transform(box, rot)

// Compose: matrices are Float64Array, flat 4×4, translation at [12..14]
const m = Transformation.multiply(Transformation.fromTranslation(0, 0, 50), rot)
const placed = Brep.transform(box, m)

Measure

Volume and surface area take the document plus a tolerance. Brep.measurementDefaultEps() returns the kernel default — a relative band of 1e-6:

const eps = Brep.measurementDefaultEps()

Brep.volume(box, eps)       // 240_000
Brep.surfaceArea(box, eps)  // 24_800

Planar geometry measures to machine precision; curved booleans carry tessellator sag, so compare curved volumes with a looser band (~1%) rather than 1e-9.

Inspect

Cheap structural checks before you commit to expensive operations:

Brep.isClosed(box)          // true — sealed solid
Brep.freeEdgeCount(box)     // 0 — no open boundaries
const [vertices, edges, , faces] = Brep.entityCounts(box)
// box → vertices 8, edges 12, faces 6

End to end

import { Brep } from '@huukhanhnguyen/geometry'

const eps = Brep.measurementDefaultEps()
const a = Brep.box(2, 2, 2)
const b = Brep.translate(Brep.box(2, 2, 2), 1, 1, 1)
const u = Brep.union(a, b)

console.log(Brep.volume(u, eps)) // 15  (8 + 8 − 1 overlap)

Where next

Last updated: 📖 1 min readEdit on GitHub