Measurements
Bounding box, surface area, volume, mass and centre of mass.
These assertions measure the whole subject. A STEP subject is measured from its BRep; a mesh, from its triangles. The engine picks the evidence from the subject, and the report's evidence names the source it used (brep or mesh).
plate and box are the site's demo models; tessellated is a repository fixture, a STEP box whose faces carry no surface. Python matchers are snake_case; their keywords keep the camelCase field names (toleranceMm=). A failed or refused call throws Geo in TypeScript and raises it in Python. Refusal codes add to the common refusals.
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 plate = await loadModel({ source: 'plate-with-through-bore.step', format: 'step' });
const box = await loadModel({ source: 'box-10x20x30.step', format: 'step' });
const tessellated = await loadModel({
source: 'packages/geospec-engine/native/occt/rust/tests/fixtures/read-profile/box-tessellated-only.step',
format: 'step',
});from geospec import GeoSpecEngine, expect_geo, load_model
with GeoSpecEngine(model_root="."):
plate = load_model(file="plate-with-through-bore.step", format="step")
box = load_model(file="box-10x20x30.step", format="step")
tessellated = load_model(
file="packages/geospec-engine/native/occt/rust/tests/fixtures/read-profile/box-tessellated-only.step",
format="step",
)to Have Bounding Box
Asserts the axis-aligned bounds of the subject.
Signature
expectGeo(part).toHaveBoundingBox(first: Vec3 | GeoSpecBoundingBoxExpectation, second?: Vec3): GeoSpecAssertionexpect_geo(part).to_have_bounding_box(min=..., max=..., size=..., center=..., tolerance=...) -> GeoSpecAssertionReport
expect_geo(part).to_have_bounding_box(first, second, /) -> GeoSpecAssertionReportTwo points are min and max.
Fields
| Field | Type | Default | Meaning |
|---|---|---|---|
min, max, size, center | [x, y, z], or { x?, y?, z? } of numbers or numeric expectations | not checked | Corners, extent and centre; each declared axis is checked on its own |
tolerance | number, 0 or more | 0.02 | Allowed error per axis |
Admitted geometry
- STEP: the BRep bounds.
- Mesh and glTF/GLB: the bounds of the triangle vertices. An open mesh still has bounds, so the claim passes on one triangle.
Refusal codes
The common refusals only. A failed claim carries GEOSPEC_, naming each axis that missed. A negated claim that matches fails with GEOSPEC_, or with GEOSPEC_ on a mesh-buffer-v1 subject.
Examples
// passed: plate, 40 × 40 × 20 mm with the bore inside the box
expectGeo(plate).toHaveBoundingBox({ size: { x: 40, y: 40, z: 20 } });
// refused (GEOSPEC_UNSUPPORTED_EVIDENCE): tessellated, its six faces have no surface
expectGeo(tessellated).toHaveBoundingBox({ size: { x: 10, y: 20, z: 30 } });# passed: plate, 40 × 40 × 20 mm with the bore inside the box
expect_geo(plate).to_have_bounding_box(size={"x": 40, "y": 40, "z": 20})
# refused (GEOSPEC_UNSUPPORTED_EVIDENCE): tessellated, its six faces have no surface
expect_geo(tessellated).to_have_bounding_box(size={"x": 10, "y": 20, "z": 30})to Have Surface Area
Asserts the total surface area of the subject.
Signature
expectGeo(part).toHaveSurfaceArea(expected: GeoSpecSurfaceAreaExpectation): GeoSpecAssertionexpect_geo(part).to_have_surface_area(value=..., tolerance=...) -> GeoSpecAssertionReportFields
| Field | Type | Default | Meaning |
|---|---|---|---|
value | numeric expectation, mm² | required | The total area |
tolerance | number, 0 or more | 0.02 | Allowed error on value |
Admitted geometry
- STEP: the BRep surface area.
- Mesh and glTF/GLB: the sum of the triangle areas. A mesh approximates curved faces, so its area differs from the BRep area of the same part.
Refusal codes
The common refusals only. A failed claim carries GEOSPEC_, with the measured value and its evidence source.
Examples
// passed: box, 2 × (200 + 300 + 600) mm²
expectGeo(box).toHaveSurfaceArea({ value: 2200 });
// refused (GEOSPEC_UNSUPPORTED_EVIDENCE): tessellated, its six faces have no surface
expectGeo(tessellated).toHaveSurfaceArea({ value: 2200 });# passed: box, 2 × (200 + 300 + 600) mm²
expect_geo(box).to_have_surface_area(value=2200)
# refused (GEOSPEC_UNSUPPORTED_EVIDENCE): tessellated, its six faces have no surface
expect_geo(tessellated).to_have_surface_area(value=2200)to Have Volume
Asserts the enclosed volume of the subject.
Signature
expectGeo(part).toHaveVolume(expected: GeoSpecVolumeExpectation): GeoSpecAssertionexpect_geo(part).to_have_volume(value=..., tolerance=...) -> GeoSpecAssertionReportFields
| Field | Type | Default | Meaning |
|---|---|---|---|
value | numeric expectation, mm³ | required | The enclosed volume |
tolerance | number, 0 or more | 0.02 | Allowed error on value |
Admitted geometry
- STEP: the BRep volume.
- Mesh and glTF/GLB: the absolute signed volume of the triangles. An open mesh still yields a number, so pair the claim with
toBeWatertight.
Refusal codes
The common refusals only. A failed claim carries GEOSPEC_.
Examples
// passed: plate, 32,000 mm³ less the bore is 30,429.2 to one decimal
expectGeo(plate).toHaveVolume({ value: 30429.2, tolerance: 0.5 });
// refused (GEOSPEC_UNSUPPORTED_EVIDENCE): tessellated, its six faces enclose no exact volume
expectGeo(tessellated).toHaveVolume({ value: 6000 });# passed: plate, 32,000 mm³ less the bore is 30,429.2 to one decimal
expect_geo(plate).to_have_volume(value=30429.2, tolerance=0.5)
# refused (GEOSPEC_UNSUPPORTED_EVIDENCE): tessellated, its six faces enclose no exact volume
expect_geo(tessellated).to_have_volume(value=6000)to Have Mass
Asserts the mass of the subject, derived as volume × density.
Signature
expectGeo(part).toHaveMass(expected: GeoSpecMassExpectation): GeoSpecAssertionexpect_geo(part).to_have_mass(value=..., density=..., tolerance=...) -> GeoSpecAssertionReportFields
| Field | Type | Default | Meaning |
|---|---|---|---|
value | numeric expectation | required | In the unit density implies: grams per mm³ give grams |
density | number, 0 or more | none | Mass per mm³ |
tolerance | number, 0 or more | 0.02 | Allowed error on value |
Admitted geometry
- The volume comes from the same evidence as
toHaveVolume. - No admitted subject carries a material mass, so a claim without
densityrefuses on every subject.
Refusal codes
GEOSPEC_: the claim declares noUNSUPPORTED_ EVIDENCE density.
A failed claim carries GEOSPEC_.
Examples
// passed: box, 6,000 mm³ of aluminium at 0.0027 g/mm³ is 16.2 g
expectGeo(box).toHaveMass({ value: 16.2, density: 0.0027 });
// refused (GEOSPEC_UNSUPPORTED_EVIDENCE): box, no density declared
expectGeo(box).toHaveMass({ value: 16.2 });# passed: box, 6,000 mm³ of aluminium at 0.0027 g/mm³ is 16.2 g
expect_geo(box).to_have_mass(value=16.2, density=0.0027)
# refused (GEOSPEC_UNSUPPORTED_EVIDENCE): box, no density declared
expect_geo(box).to_have_mass(value=16.2)to Have Center Of Mass
Asserts the centre of mass of the subject, assuming uniform density.
Signature
expectGeo(part).toHaveCenterOfMass(expected: GeoSpecCenterOfMassExpectation): GeoSpecAssertionexpect_geo(part).to_have_center_of_mass(point=..., tolerance=...) -> GeoSpecAssertionReportFields
| Field | Type | Default | Meaning |
|---|---|---|---|
point | point of numbers | required | Each declared axis is compared on its own; { x: 0, y: 0 } leaves z free |
tolerance | number, 0 or more | 0.02 | Allowed error per axis |
Admitted geometry
- STEP: the BRep centre of mass of a solid with nonzero volume.
- Mesh and glTF/GLB: the centroid of the enclosed volume. An open mesh still yields a point, so pair the claim with
toBeWatertight.
Refusal codes
GEOSPEC_: the subject has no centre of mass, such as a STEP shape with zero volume.UNSUPPORTED_ EVIDENCE
A failed claim carries GEOSPEC_.
Examples
// passed: plate, centred on the z axis with z from 0 to 20
expectGeo(plate).toHaveCenterOfMass({ point: [0, 0, 10] });
// refused (GEOSPEC_UNSUPPORTED_EVIDENCE): tessellated, its six faces enclose no exact volume
expectGeo(tessellated).toHaveCenterOfMass({ point: [5, 10, 15] });# passed: plate, centred on the z axis with z from 0 to 20
expect_geo(plate).to_have_center_of_mass(point=[0, 0, 10])
# refused (GEOSPEC_UNSUPPORTED_EVIDENCE): tessellated, its six faces enclose no exact volume
expect_geo(tessellated).to_have_center_of_mass(point=[5, 10, 15])