GeoSpec
engine 0.4.0
Matcher reference

Measurements

Bounding box, surface area, volume, mass and centre of mass.

Open Markdown

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 GeoSpecAssertionError in TypeScript and raises it in Python. Refusal codes add to the common refusals.

check.ts
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',
});
check.py
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",
    )

toHaveBoundingBox

Asserts the axis-aligned bounds of the subject.

Signature

expectGeo(part).toHaveBoundingBox(first: Vec3 | GeoSpecBoundingBoxExpectation, second?: Vec3): GeoSpecAssertion
expect_geo(part).to_have_bounding_box(min=..., max=..., size=..., center=..., tolerance=...) -> GeoSpecAssertionReport
expect_geo(part).to_have_bounding_box(first, second, /) -> GeoSpecAssertionReport

Two points are min and max.

Fields

FieldTypeDefaultMeaning
min, max, size, center[x, y, z], or { x?, y?, z? } of numbers or numeric expectationsnot checkedCorners, extent and centre; each declared axis is checked on its own
tolerancenumber, 0 or more0.02Allowed 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_BOUNDING_BOX_MISMATCH, naming each axis that missed. A negated claim that matches fails with GEOSPEC_NEGATED_MATCH, or with GEOSPEC_NEGATED_BOUNDING_BOX_MATCH 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})

toHaveSurfaceArea

Asserts the total surface area of the subject.

Signature

expectGeo(part).toHaveSurfaceArea(expected: GeoSpecSurfaceAreaExpectation): GeoSpecAssertion
expect_geo(part).to_have_surface_area(value=..., tolerance=...) -> GeoSpecAssertionReport

Fields

FieldTypeDefaultMeaning
valuenumeric expectation, mm²requiredThe total area
tolerancenumber, 0 or more0.02Allowed 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_MEASUREMENT_MISMATCH, 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)

toHaveVolume

Asserts the enclosed volume of the subject.

Signature

expectGeo(part).toHaveVolume(expected: GeoSpecVolumeExpectation): GeoSpecAssertion
expect_geo(part).to_have_volume(value=..., tolerance=...) -> GeoSpecAssertionReport

Fields

FieldTypeDefaultMeaning
valuenumeric expectation, mm³requiredThe enclosed volume
tolerancenumber, 0 or more0.02Allowed 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_MEASUREMENT_MISMATCH.

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)

toHaveMass

Asserts the mass of the subject, derived as volume × density.

Signature

expectGeo(part).toHaveMass(expected: GeoSpecMassExpectation): GeoSpecAssertion
expect_geo(part).to_have_mass(value=..., density=..., tolerance=...) -> GeoSpecAssertionReport

Fields

FieldTypeDefaultMeaning
valuenumeric expectationrequiredIn the unit density implies: grams per mm³ give grams
densitynumber, 0 or morenoneMass per mm³
tolerancenumber, 0 or more0.02Allowed 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 density refuses on every subject.

Refusal codes

  • GEOSPEC_UNSUPPORTED_EVIDENCE: the claim declares no density.

A failed claim carries GEOSPEC_MEASUREMENT_MISMATCH.

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)

toHaveCenterOfMass

Asserts the centre of mass of the subject, assuming uniform density.

Signature

expectGeo(part).toHaveCenterOfMass(expected: GeoSpecCenterOfMassExpectation): GeoSpecAssertion
expect_geo(part).to_have_center_of_mass(point=..., tolerance=...) -> GeoSpecAssertionReport

Fields

FieldTypeDefaultMeaning
pointpoint of numbersrequiredEach declared axis is compared on its own; { x: 0, y: 0 } leaves z free
tolerancenumber, 0 or more0.02Allowed 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_UNSUPPORTED_EVIDENCE: the subject has no centre of mass, such as a STEP shape with zero volume.

A failed claim carries GEOSPEC_MEASUREMENT_MISMATCH.

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])

On this page