Compare 3D CAD models using boolean operations (IoU, Dice, precision/recall). Use when evaluating generated models against gold references, diffing CAD revisions, or computing similarity metrics for ML training. Triggers on: model diff, compare models, IoU, intersection over union, model similarity, CAD comparison, STEP diff, 3D evaluation, gold reference, generated model, precision recall 3D.
/plugin marketplace add rawwerks/VibeCAD/plugin install build123d@vibecadThis skill inherits all available tools. When active, it can use any tool Claude has access to.
scripts/model_diff.pyCompare CAD models using boolean operations to compute similarity metrics like IoU, Dice, precision, and recall. Useful for:
# Compare two STEP files
uvx --from build123d python scripts/model_diff.py reference.step generated.step
# JSON output for training pipelines
uvx --from build123d python scripts/model_diff.py ref.step gen.step --json --no-export
# Demo mode (no files needed)
uvx --from build123d python scripts/model_diff.py --demo
| Format | Extension | Notes |
|---|---|---|
| STEP | .step, .stp | Recommended - full CAD fidelity |
| BREP | .brep | OpenCASCADE native format |
| STL | .stl | Mesh format - may have boolean issues |
| Metric | Range | Description |
|---|---|---|
| IoU (Jaccard) | 0-1 | ` |
| Dice (F1) | 0-1 | `2 |
| Precision | 0-1 | ` |
| Recall | 0-1 | ` |
| Metric | Description |
|---|---|
volume_ratio | B/A volume ratio (1.0 = same size) |
center_offset | Distance between centers of mass |
bbox_iou | Bounding box IoU (coarse alignment) |
size_ratio_x/y/z | Per-axis scale comparison |
surface_ratio | Surface area comparison |
The tool provides automatic interpretation:
usage: model_diff.py [-h] [-o OUTPUT_DIR] [--json] [--no-export] [--demo]
[reference] [generated]
positional arguments:
reference Reference/gold model file (STEP, BREP, or STL)
generated Generated/predicted model file to compare
options:
-o, --output-dir Output directory for GLB files (default: .)
--json Output only JSON metrics (for pipelines)
--no-export Skip exporting GLB visualization files
--demo Run with built-in demo models
When --no-export is not set, produces GLB files for visualization:
| File | Description |
|---|---|
diff_reference.glb | The reference model (A) |
diff_generated.glb | The generated model (B) |
diff_missing.glb | Geometry in A but not B (under-generation) |
diff_extra.glb | Geometry in B but not A (over-generation) |
diff_common.glb | Geometry in both (correct match) |
# Batch evaluation
for gen in outputs/*.step; do
uvx --from build123d python model_diff.py gold.step "$gen" --json --no-export
done | jq -s '{
avg_iou: (map(.iou) | add / length),
avg_precision: (map(.precision) | add / length),
avg_recall: (map(.recall) | add / length)
}'
# In your training code, use metrics for loss:
loss = (
(1 - metrics['iou']) * 1.0 + # Primary shape match
abs(1 - metrics['volume_ratio']) * 0.5 + # Scale accuracy
metrics['center_offset'] * 0.1 # Position accuracy
)
The tool uses boolean operations from OpenCASCADE (via build123d):
Missing = Reference - Generated (A - B)
Extra = Generated - Reference (B - A)
Common = Reference & Generated (A ∩ B)
Union = Reference + Generated (A ∪ B)
IoU = volume(Common) / volume(Union)
Dice = 2 * volume(Common) / (volume(A) + volume(B))
Precision = volume(Common) / volume(B)
Recall = volume(Common) / volume(A)
=================================================================
3D MODEL COMPARISON REPORT
Reference (A) vs Generated (B)
=================================================================
──────────────────────────── VOLUMES ────────────────────────────
Reference (A): 51,433.629
Generated (B): 45,904.426
Intersection (A∩B): 42,292.031
Missing (A-B): 9,141.598 (17.8% of A)
Extra (B-A): 3,612.395 (7.9% of B)
──────────────────────── PRIMARY METRICS ────────────────────────
IoU (Jaccard): 0.7683 (1.0 = identical)
Dice (F1): 0.8690 (1.0 = identical)
Precision: 0.9213 (correctness of B)
Recall: 0.8223 (coverage of A)
──────────────────────── INTERPRETATION ─────────────────────────
△ Partial match (IoU > 50%)
→ Under-generating: 17.8% of A is missing
→ Undersized by 10.8%
=================================================================