The capture() module and the geometry-introspection function family are
BCad-specific extensions to the OpenSCAD language, intended for testing and
debugging SCL scripts: they let you "store" the result of a build into a
variable and then inspect its geometric properties (face count, volume,
bounding box, BRep validity).
capture(name)
Stores the geometry of the child node(s) into the variable name in the
parent scope.
capture("cube1") cube([1, 2, 3]);
echo(str("Volume = ", volume(cube1)));
Semantics:
name— a string; only string names are accepted (otherwise a warning is emitted).- After
capture("x") <child>, the variablexholds the SCLShape of the child. - A single child with geometry → the variable holds its shape as-is.
- Multiple children → the variable holds a Compound with merged face colors.
- If the child has no geometry → the variable equals
undef(None). - The variable is written into the parent scope, i.e. it is available after the
block where
capture()was invoked.
Example:
capture("t360") linear_extrude(height=2, twist=360)
translate([20, 0, 0])
rotate([90, -90, 0])
square(2);
Diagnostic functions
All functions take a geometry argument (usually a variable filled by capture())
and return a number or a vector:
| Function | Returns | Notes |
|---|---|---|
num_faces(geom) |
number | number of faces |
num_edges(geom) |
number | number of edges |
num_vertices(geom) |
number | number of vertices |
volume(geom) |
number | volume (VolumeProperties().Mass()) |
surface_area(geom) |
number | surface area |
centroid(geom) |
[x, y, z] |
center of mass |
bbox_min(geom) |
[x, y, z] |
bounding box min corner |
bbox_max(geom) |
[x, y, z] |
bounding box max corner |
is_valid(geom) |
true/false |
BRep validity (BRepCheck_Analyzer.IsValid()) |
Note on
is_valid:BRepCheck_Analyzervalidates topology strictly. Degenerate geometry (for example, extruding a profile that was rotated out of the XY plane — a "sheet" with zero thickness) is reported invalid, even though geometrically it is a legitimate 2D surface. This is expected behavior, not a bug.
Example:
capture("cyl") cylinder(h=5, r=3, $fn=12);
echo(str("faces = ", num_faces(cyl))); // 14 (dodecagonal prism)
echo(str("valid = ", is_valid(cyl))); // true
echo(str("bbox = ", bbox_min(cyl), " .. ", bbox_max(cyl)));
assert(condition, message)
Available both as a module and as a function. When the condition is false, it aborts the script with the given message (visible as a Traceback in test mode).
capture("sq") square([2, 2]);
assert(num_faces(sq) == 1, "a square must have 1 face");
Together with capture() and the diagnostic functions it forms the standard
test template (see the existing tests in tests/).
Library tests/lib/testing.scad
Included via use <lib/testing.scad>; provides an approximate-comparison helper:
function check_approx(a, b, eps=0.01) = ...
- Compares numbers and vectors with tolerance
eps(default0.01). check_approx(a, b)→truewhen|a - b| <= eps(vectors vianorm()).
Typical test:
```scl
use
capture("m1") cube([1, 1, 1]); assert(check_approx(bbox_min(m1), [0, 0, 0]), "bbox_min"); assert(check_approx(volume(m1), 1), "volume"); assert(is_valid(m1), "valid");
echo("--- OK ---"); ```
Running a test:
bcad-launcher --test tests/test_xxx.scad
The test is considered failed if the output contains a Traceback (from assert()).