Find holes and features
Claim holes, faces, edge treatments and wall thickness from the exact BRep of a STEP part.
Feature claims read the exact BRep of a STEP file: the faces, their surfaces and how they meet. A mesh carries none of that, so every claim on this page is refused on a mesh subject rather than guessed; Read a refusal covers what a refusal asks for.
1. Find the bore
const part = await loadModel({ source: 'plate-with-through-bore.step', format: 'step' });Tab indents. Press Escape, then Tab, to leave the editor.
The spec as a file, with the model loaded over the native addon
import { readFile } from 'node:fs/promises';import { expectGeo } from 'geospec';import { createModelLoader } from 'geospec/model';import { Engine } from 'geospec-engine/node';const engine = new Engine();const loadModel = createModelLoader({ engine, readSource: async (source) => new Uint8Array(await readFile(source as string)) });const part = await loadModel({ source: 'plate-with-through-bore.step', format: 'step' });expectGeo(part) .toHaveCircularHole({ diameter: 10, axis: 'z' });expectGeo(part) .toHavePlanarFace({ normal: [0, 0, 1], offset: 20 });expectGeo(part) .toHaveCylindricalFace({ radius: 5, axis: 'z' });await loadModel.dispose();engine.close();plate-with-through-bore.step · 19 KB · copied from an engine test fixture
Run the spec to see what the engine answers for each claim. Then change an expected value and run it again.
The plate has one 10 mm hole through its centre along z. Set diameter to 12 and the hole claim fails, listing the hole it did find. Switch the model to the gear, a GLB mesh with a 4 mm centre hole, and all three are refused with GEOSPEC_: the mesh has no faces to classify, so neither a pass nor a failure would be an answer.
2. Read a hole result
A failed hole claim carries GEOSPEC_, and the diagnostic's details list the holes the engine qualified:
{
"circularHoles": [
{
"axis": "z",
"axisRange": { "max": 20, "min": 0 },
"center": [3.2862601528904634e-13, 5.731384959986079e-17, 10],
"diameter": 10,
"through": true
}
],
"expected": { "diameter": 12, "tolerance": 0.02 },
"matcher": "toHaveCircularHole"
}diameter is measured within the tolerance; axis, center and through narrow which hole may match. through compares the engine's reading of the bore's two ends, each a mouth or a floor, so through: false fails on the plate. A bore the engine cannot qualify refuses the claim with GEOSPEC_ when no qualified hole matches, because the unqualified bore could be the one.
3. Claim a pattern, a chamfer and a fillet
const part = await loadModel({ source: 'plate-with-through-bore.step', format: 'step' });Tab indents. Press Escape, then Tab, to leave the editor.
The spec as a file, with the model loaded over the native addon
import { readFile } from 'node:fs/promises';import { expectGeo } from 'geospec';import { createModelLoader } from 'geospec/model';import { Engine } from 'geospec-engine/node';const engine = new Engine();const loadModel = createModelLoader({ engine, readSource: async (source) => new Uint8Array(await readFile(source as string)) });const part = await loadModel({ source: 'plate-with-through-bore.step', format: 'step' });expectGeo(part) .toHaveCircularHolePattern({ count: 2, holeDiameter: 10 });expectGeo(part) .toHaveChamferFeature({ distance: 1 });expectGeo(part) .toHaveFilletFeature({ radius: 1 });await loadModel.dispose();engine.close();plate-with-through-bore.step · 19 KB · copied from an engine test fixture
Run the spec to see what the engine answers for each claim. Then change an expected value and run it again.
The plate has one hole and sharp edges, so each claim fails with GEOSPEC_ and its message says what it looked for: No circular-hole pattern has 2 holes of diameter 10 within 0.02 mm. A pattern needs two or more qualified holes with the same axis and diameter, count must match exactly, and boltCircleDiameter checks the spacing. The chamfer and fillet failures carry mismatchKind: 'geometricMismatch'; selection names one feature by the label its STEP source gives it, and a face whose membership the engine cannot settle refuses with GEOSPEC_.
4. Claim wall thickness
const part = await loadModel({ source: 'box-10x20x30.step', format: 'step' });Tab indents. Press Escape, then Tab, to leave the editor.
The spec as a file, with the model loaded over the native addon
import { readFile } from 'node:fs/promises';import { expectGeo } from 'geospec';import { createModelLoader } from 'geospec/model';import { Engine } from 'geospec-engine/node';const engine = new Engine();const loadModel = createModelLoader({ engine, readSource: async (source) => new Uint8Array(await readFile(source as string)) });const part = await loadModel({ source: 'box-10x20x30.step', format: 'step' });expectGeo(part) .toHaveMinimumWallThickness({ value: { greaterThanOrEqual: 2 } });await loadModel.dispose();engine.close();box-10x20x30.step · 17 KB · copied from an engine test fixture
Run the spec to see what the engine answers for each claim. Then change an expected value and run it again.
The engine computes the exact minimum over the whole part for a complete box or a right circular cylinder only; it does not estimate thickness from samples or from a mesh. The 10 × 20 × 30 mm box is 10 mm thin across x: set greaterThanOrEqual to 12 and it fails with The minimum wall thickness is 10 mm, which does not satisfy >= 12. The plate, with its bore, is outside that domain and is refused with GEOSPEC_: The subject is outside the qualified continuous wall-thickness domains.
Variations
A planar face with an area. Add area: 1521.46 to the top-face claim: the plate's top is 40 × 40 mm less the bore's 78.54 mm². A face whose normal points the other way matches when both the normal and the offset flip: normal: [0, 0, -1], offset: -20 passes too.
Boss or bore. to matches any cylindrical face of the radius on the axis; it does not tell a boss from a bore. Claim the hole when the hole is what you mean.
The inventory without a claim. analyzeBrep reports every hole, face, chamfer and fillet the engine found in one query; Query geometry shows it on the plate. The features reference lists every field and refusal code.