Cavity Filling (intra-part)#
Homology-certified plugging of the openings of a triangulated part that are narrower than the operator fist.
Cavity Filling (intra-part)#
volmdlr_tools.meshes.cavity_filling plugs the openings of a triangulated part that are
narrower than a configurable operator fist: through-holes, grille slats, mouths of buried
cavities. It is the mesh counterpart of BRep defeaturing — instead of editing the CAD model, it
produces separate patch meshes that seal each opening, leaving the input geometry untouched.
The pipeline is certified: every independent opening of the part surface is either
plugged or certified open (wider than the fist). No hole can be silently missed — a
part whose openings cannot all be resolved reports certified: False.

Quick start#
On a DocModel (typically loaded from a STEP file):
from volmdlr.assembly import DocModel
from volmdlr_tools.meshes.cavity_filling import HomologyParameters, fill_homology, print_reports
doc_model = DocModel.from_step("assembly.stp")
parameters = HomologyParameters(fist_diameter=0.080) # lengths in meters
collection, reports = fill_homology(doc_model, parameters, parallel_workers=4)
print_reports(reports)
for patch in collection.patches:
print(patch.mesh.name, f"{patch.area * 1e6:.0f} mm^2")
On a VolumeModel of Mesh3D — e.g. the output of a CAD Import platform workflow — or a plain
list of meshes; each mesh’s topology (CAD faces and edge polylines) is used when present:
collection, reports = fill_homology(volume_model, parameters)
collection, reports = fill_homology([mesh_a, mesh_b], parameters)
On a single raw mesh (no CAD topology available):
import numpy as np
from volmdlr_tools.meshes.cavity_filling import HomologyParameters
from volmdlr_tools.meshes.cavity_filling import find_part_holes_homology
part = {
"identifier": "my_part",
"vertices": vertices, # (n, 3) float array
"triangles": triangles, # (m, 3) int array
"face_starts": None, # CAD topology, optional
"face_counts": None,
"edge_offsets": None,
"edge_indices": None,
}
holes, report = find_part_holes_homology(part, HomologyParameters())
for hole in holes:
patch_vertices, patch_triangles = hole["patch"]
print(hole["category"], f"{hole['diameter'] * 1000:.0f} mm")
fill_homology returns a PatchCollection of Patch models (patch_type = "intra"); each
patch’s enabled flag lets a user strike out false positives from a platform form, and
HomologyParameters.excluded_patch_names replays those exclusions on the next run.
What it does#
The criterion applies to the opening width (its smallest dimension): a long thin slot is plugged however long it is, and openings wider than the fist are functional passages that must stay open. Real tessellations make this hard — duplicate vertices, hairline slits between BRep faces, openings whose rim was smoothed away by fillets — so the pipeline works in five stages:
the tessellation is repaired into a clean welded surface;
an opening budget is computed per part — the contract the run must account for;
candidate openings are collected from the CAD tessellation topology;
each candidate receives a physical open/blocked verdict and a minimal set of plugs is selected, one per independent opening;
the final surfaces are re-validated, and whatever exceeds the fist is certified open in the report.
With the default opening_semantics = "intrusion", the mouths of buried cavities are plugged
too; "through" restricts plugging to genuine passages and leaves recesses untouched. A
dedicated regime keeps ventilation grilles pluggable even though each slat is backed by the
next one.

Patch categories#
Each patch name encodes patch_<id>|d<diameter>mm|<source>|<category>:
Category |
In figures |
Meaning |
|---|---|---|
|
red |
Opening bounded by a drawn CAD contour (drilled hole, slot) |
|
orange |
Opening whose only rims are sharp-edge cycles (skeletal bays, struts) |
|
purple |
Orifice into a closed internal void (mouth of a buried pocket) |
|
blue |
Rim computed automatically where no CAD rim existed |
frame patches can be disabled wholesale with plug_frame_openings=False when skeletal
openings should stay open.
Parameters#
All lengths are in meters. HomologyParameters is a dessia Model, usable directly in
platform forms.
Field |
Default |
Role |
|---|---|---|
|
0.080 |
The metric criterion: openings with width below this are plugged |
|
0.0012 / 0.003 |
Floor below which rims are noise, not openings |
|
1e-5 |
Vertex welding tolerance |
|
5e-5 |
Closes hairline BRep slits before analysis |
|
35.0 |
Dihedral angle that makes an edge “sharp” for rim walking |
|
0.15 |
Sensitivity of the open/blocked verdict |
|
0.020 / 0.03 |
Relaxed verdict regime for ventilation grilles |
|
100 |
Parts smaller than this are skipped |
|
6.25 x fist |
Cap on candidate rim diameter (drops assembly-scale wrappers) |
|
0.15 |
Recovered rims prefer riding CAD feature edges |
|
0.6 |
Minimum feature-edge share for recovered rims |
|
0.70 |
Stricter acceptance for recovered rims |
|
|
|
|
|
Keep or drop |
|
|
Human calibration loop: strike out parts/patches by name |
Reports#
fill_homology returns one report dict per part; print_reports renders them. Key fields:
plugged, certified (every opening plugged or certified open), retriangulated,
final_dropped, seconds.
The fist is the single criterion: with a fist larger than every opening of a part, 100% of its holes get plugged, big ones included, and every plug rides the drawn CAD contours carried by the tessellation topology.
Guarantees and limitations#
Every independent opening of every welded shell is plugged or certified open;
certified: Falsein the report means some opening could not be resolved — never a silent miss.The criterion applies to the opening width: long narrow slots are plugged regardless of length;
max_loop_diametercaps degenerate assembly-scale candidates.Category quality depends on CAD topology: on raw meshes without face/edge information, designed holes are still found but are tagged
frameorrecovered.Patches are separate meshes: the input tessellation is never modified.
Openings between different parts are out of scope here — see the Interspace Filling page for that problem.