Interspace Filling (inter-part)#

Watertight plugs for the sub-fist pockets between the parts of an assembly.

Interspace Filling (inter-part)#

volmdlr_tools.meshes.cavity_filling also seals the pockets between parts: the interstices of an assembly that an operator fist cannot reach. Where the intra-part pipeline (see the Cavity Filling page) plugs the openings of one part, interspace filling produces watertight plugs for the inaccessible volume between several parts — the gap under a duct, the channel between a housing and its bracket, the labyrinth behind two stacked panels.

Two plates sealed by a blob

Quick start#

On DocModels (one group per file/DocModel, the business unit for the fist rule):

from volmdlr.assembly import DocModel
from volmdlr_tools.meshes.cavity_filling import InterspaceParameters, fill_interspace, print_inter_reports

doc_models = [DocModel.from_step(path) for path in ("housing.stp", "duct.stp", "bracket.stp")]
parameters = InterspaceParameters(fist_diameter=0.080)  # lengths in meters

collection, reports = fill_interspace(doc_models, parameters, parallel_workers=4)
print_inter_reports(reports)

The same call accepts VolumeModels of Mesh3D — e.g. one CAD Import workflow output per file, each model being one group — bare Mesh3D elements (single-mesh groups), or any mix of the three:

collection, reports = fill_interspace([traverse_vm, hvac_vm, env_vm], parameters)

On raw part dicts (any meshes, no DocModel needed):

from volmdlr_tools.meshes.cavity_filling import InterspaceParameters, fill_interspace_parts

parts = [
    {"identifier": "housing", "vertices": vertices_a, "triangles": triangles_a},
    {"identifier": "duct", "vertices": vertices_b, "triangles": triangles_b},
]
collection, reports = fill_interspace_parts(parts, InterspaceParameters())

Patches come back as the same Patch/PatchCollection models as intra filling, with patch_type = "inter" and source_part_ids naming the two parts each plug is attributed to.

Intra first#

Run intra filling first and merge its patches into each part’s mesh before calling interspace filling: the intra plugs become matter, so designed openings already sealed at the part level are never re-detected as inter-part pockets, and pockets that leak through a part’s own holes are closed before the between-parts analysis runs.

What it does#

Parts closer than a fist are grouped into proximity clusters, and each cluster is analyzed on a voxel lattice (pitch = fist_diameter / 16 by default). The pockets — the free space the fist can never reach — are detected, judged, and each genuine one is sealed by a closed, watertight surface of the pocket volume itself: no boundary, hence no possible hole, even on labyrinthine interstices. The plug sits flush against both walls, bulges across every opening, and blocks the fist by definition — it is the region the fist cannot reach.

Each detected pocket is judged before sealing; the drops are reported per cluster:

Verdict

Meaning

Reported as

contact

too tight to matter (below minimum_gap)

dropped_contact

single-part

bounded by one part only: intra territory, never an inter patch

dropped_single_part

sealed shell

hollow interior of a closed part: no mouth, nothing to seal

sealed

concave wedge

mostly open boundary (fillet along a crease, not a passage)

dropped_open

genuine pocket

everything else: sealed

pockets

U-channel sealed

Plugs smaller than minimum_patch_area are dropped as slivers; each surviving plug is attributed to the two parts it hugs, and its gap width is encoded in the patch name: ipatch_012|g34mm|housing+duct|inter.

On a full vehicle-zone assembly (three groups, millions of triangles, intra plugs merged first), the 80 mm fist detects the inter-group pockets and seals them with a few dozen watertight blobs in about a minute.

Parameters#

All lengths are in meters. InterspaceParameters is a dessia Model, usable directly in platform forms.

Field

Default

Role

fist_diameter

0.080

The metric criterion: pockets this fist cannot reach are sealed

voxel_size

None

Lattice pitch; None derives fist_diameter / 16

minimum_gap

0.005

Pockets with a narrower widest gap are unusable contacts, dropped

minimum_patch_area

0.0004

Plugs below this area are slivers, dropped

minimum_enclosure

0.7

Pockets whose boundary is more open than this are concave wedges, dropped

max_grid_voxels

40e6

Memory budget: larger cluster grids get a coarser lattice, not a crash

groups

None

Participating DocModel names for fill_interspace; None = all provided

granularity

"group"

"group": one DocModel = one part; "mesh": every mesh is its own part

Reports#

One report dict per proximity cluster; print_inter_reports renders one line per cluster plus aggregate totals: pockets, patches, sealed, dropped_contact, dropped_open, dropped_single_part, dropped_sliver, the grid shape, the resolved voxel_size and per-stage timings.

Guarantees and limitations#

  • A plug is watertight by construction (closed surface) and blocks the fist by definition — it is the inaccessible volume itself, not a fitted membrane.

  • Detection resolution is the lattice pitch: gaps thinner than ~2 voxels may register as contacts; lower voxel_size for finer assemblies (at cubic memory cost, bounded by max_grid_voxels).

  • Plug geometry is lattice-born: flush against walls within one voxel, smoothed but not exact CAD offsets. For openings within a single part, use the intra pipeline — its patches ride the actual CAD rims.

  • granularity="group" applies the fist rule between named groups only; self-pockets of a group (between its own meshes) are intentionally out of scope there.