Check dimensions
Claim a bounding box, read the measured bounds and pin where the part sits.
toHaveBoundingBox compares the axis-aligned bounds of a subject with the values you expect. It is the first claim most specs make, and the one the quick start uses.
1. Claim one axis
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) .toHaveBoundingBox({ size: { x: 10 } });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.
Expect only the axes you care about: this claim checks the width of the 10 × 20 × 30 mm box and leaves height and depth free. Set x to 12 and the claim fails with GEOSPEC_; add y: 20 to check a second axis.
2. Read the measurement
A passed or failed claim carries its evidence: the measured min, max, center and size, the expectation the engine applied, and the source it measured, brep for STEP and mesh for triangles.
The assertion expectGeo returns holds it under report.evidence. A failed or refused chain throws Geo with the same report under error.report, and error. names the reason.
The report expect_geo returns holds it under report.. A failed or refused claim raises Geo with the same report under error.result, and error.code names the reason.
The box above measures as:
{
"measured": { "center": [5, 10, 15], "max": [10, 20, 30], "min": [0, 0, 0], "size": [10, 20, 30] },
"normalizedExpected": { "size": { "x": 10 }, "tolerance": 0.02 },
"witnesses": { "axisFailures": [], "primitives": [], "source": "brep", "tolerance": 0.02 }
}A failed claim lists each field that missed under axisFailures, in the diagnostic's details and in the witnesses, with its expected and actual values.
3. Pin the position
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) .toHaveBoundingBox({ size: { x: 40, y: 40, z: 20 } });expectGeo(part) .toHaveBoundingBox([0, 0, 0], [40, 40, 20]);expectGeo(part) .toHaveBoundingBox({ center: { x: 0, y: 0 } });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.
size checks extents and ignores where the part sits; two vectors, min and max, check position as well; center fixes position with one point, here on x and y only. The plate is 40 × 40 × 20 mm and centred on the z axis, so the second claim fails on four fields, min.x, min.y, max.x and max.y: change the vectors to [-20, -20, 0] and [20, 20, 20] and it passes.
4. Claim a mesh
const part = await loadModel({ source: 'involute-gear.glb', format: 'glb', sourceUnit: 'mm' });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: 'involute-gear.glb', format: 'glb', sourceUnit: 'mm' });expectGeo(part) .toHaveBoundingBox({ size: { z: 5 } });await loadModel.dispose();engine.close();involute-gear.glb · 52 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 claim reads the same on the gear, a GLB mesh, and the evidence source is mesh. Its 624 triangles span 4.999976634979248 mm in z, inside the default 0.02 mm tolerance: add tolerance: 0 beside size and the claim fails on size.z. A mesh claim charges work units per triangle; Set tolerances and budgets shows this claim refused under a small budget, and states the tolerance rule.
Variations
A negated claim. .not in TypeScript and .not_ in Python ask the engine to show the bounds are not as declared: on the box, not. fails with GEOSPEC_ and passes once x is 12.
Combined and empty expectations. size: { x: 40 } with center: { z: 10 } checks one extent and one position on the plate. An expectation with no bound refuses before anything is measured, with GEOSPEC_.
Units. A STEP file declares its unit. A GLB does not, so load a mesh with sourceUnit: 'mm' (source_unit="mm" in Python); without it the gear is read in metres and its z extent measures 4999.976634979248.
Mass and area. Bounds say nothing about material inside them. Check mass properties measures volume, area and centre of mass; the measurement reference lists every field.