Skip to main content

fill_holes

Function fill_holes 

Source
pub fn fill_holes(
    tx: &mut Transaction<'_>,
    options: &FillOptions,
) -> Result<FillReport>
Expand description

Fills boundary loops with triangle patches, chosen by size or by id.

  • Selection: the loops of tx.mesh() (as boundary_loops finds them) that meet every bound that is set: max_edges, max_perimeter and max_area (against BoundaryLoop::area). With loops, only those loops are candidates, still subject to any bound that is set; the ids are matched by content, so an id whose loop changed or vanished, also through an earlier operation in the same transaction, fails the call. Loops that are open chains, or not clean unless allow_unclean, are skipped. An open mesh’s intended border (a hemisphere’s rim) is kept by a bound below its size. A loop that crosses an orientation seam (a flipped triangle on its rim) is not clean, so run orient() first on meshes that may contain flipped triangles.
  • Each selected loop is triangulated on its own: up to dp_limit edges by Liepa’s minimum-weight search (the worst dihedral angle to the neighbouring triangles first, then area), above it by projection onto the loop’s best-fit plane and ear clipping, which fails with FailReason::ProjectionFolds when the projection folds. With max_dihedral, a search whose best triangulation folds past it fails with FailReason::NoValidTriangulation. No new edge duplicates one the mesh has, so the patch never makes an edge non-manifold, and the patch triangles are wound to agree with their neighbours. A loop whose patch would reuse a diagonal planned for an earlier loop of the same call fails too. Two holes sharing a vertex are two loops, each filled.
  • The patch is refined to the density of the mesh around the loop (Liepa’s rule: centroid splits while a triangle is coarse for the mean edge length at its corners, with Delaunay edge flips between rounds of splits), up to max_refine_vertices new vertices when set. Each new vertex has its triangle’s corners as creation parents, 1/3 each.
  • With fair, the new vertices are moved to minimise bending, holding the loop and the ring of mesh vertices around it fixed: the discrete bi-Laplacian, cotangent weights falling back to uniform ones (FilledLoop::weights), factored once as a sparse LDLᵀ and solved for the three coordinates. A solve that does not reach its tolerance reports converged: false; one that is not finite fails the loop with FailReason::Solver.
  • Every selected loop is planned before the first write; the new vertices of the successful patches are then added in creation order, with their parents, and the triangles in one add_triangles call. A failed loop is reported and writes nothing.

§Errors

Nothing is written in any of these cases.