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.

Through-hole plugged, wide opening certified open

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:

  1. the tessellation is repaired into a clean welded surface;

  2. an opening budget is computed per part — the contract the run must account for;

  3. candidate openings are collected from the CAD tessellation topology;

  4. each candidate receives a physical open/blocked verdict and a minimal set of plugs is selected, one per independent opening;

  5. 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.

Cavity mouth plugged

Patch categories#

Each patch name encodes patch_<id>|d<diameter>mm|<source>|<category>:

Category

In figures

Meaning

designed

red

Opening bounded by a drawn CAD contour (drilled hole, slot)

frame

orange

Opening whose only rims are sharp-edge cycles (skeletal bays, struts)

cavity

purple

Orifice into a closed internal void (mouth of a buried pocket)

recovered

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

fist_diameter

0.080

The metric criterion: openings with width below this are plugged

min_width / min_diameter

0.0012 / 0.003

Floor below which rims are noise, not openings

weld_epsilon

1e-5

Vertex welding tolerance

stitch_tolerance

5e-5

Closes hairline BRep slits before analysis

border_angle_deg

35.0

Dihedral angle that makes an edge “sharp” for rim walking

through_fraction_min

0.15

Sensitivity of the open/blocked verdict

grille_min_width / grille_through_fraction

0.020 / 0.03

Relaxed verdict regime for ventilation grilles

min_part_triangles

100

Parts smaller than this are skipped

max_loop_diameter

6.25 x fist

Cap on candidate rim diameter (drops assembly-scale wrappers)

contour_bias

0.15

Recovered rims prefer riding CAD feature edges

recovered_feature_fraction

0.6

Minimum feature-edge share for recovered rims

recovered_through_fraction

0.70

Stricter acceptance for recovered rims

opening_semantics

"intrusion"

"intrusion" also plugs cavity mouths; "through" plugs passages only

plug_frame_openings

True

Keep or drop frame patches

excluded_part_ids / excluded_patch_names

[]

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: False in 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_diameter caps 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 frame or recovered.

  • 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.