Documentation

Support

Asset Transformer SDK


User Manual

Python API

C# API

Changelog

Discussions

Asset Transformer SDK


Remove holes

Use this feature to delete holes in your mesh model to reduce its polygon count, with options to select hole types (through, blind, or surface), maximum size, and sealing material.
Read time 2 minutesLast updated 17 hours ago

API function: algo.removeHoles As part of your mesh optimization process, you can delete holes in your mesh model to reduce its polygon count. This feature deletes holes from identified patch data. This example shows a model before and after processing:
Remove Holes
You can choose which types of holes to delete:
Some holes have depth and others don’t.
  1. Through holes entirely go through the volume of an object and come out on the other side.
  2. Blind holes partly go through the volume of an object.
  3. Surface holes are cut into a surface and don’t have depth. Their edges are boundaries (shown in blue when viewing edges). Read more.
You can choose the maximum size of holes to be processed and the material with which to seal holes. This example illustrates the deletion of holes with a diameter of at most 30 mm. Close-up images show which holes are processed:
Remove Holes
The topology around the processed holes remains unchanged. For example, the polygon count may be unnecessarily high in areas where new polygons are flush with the existing mesh. This example shows the results of decimation with such parameters:
Remove Holes

Code example

The following sample will remove holes and replace them with disk-shaped, instanced meshes to reduce polygon count:
import math# pxz.algo.removeHoles parametersthrough_holes = Trueblind_holes = Truesurfacic_holes = Falsemax_diameter = -1fill_with_material = 0# distance between hole surface and disk to avoid z-fightingz_fighting_offset = 0.1def create_circle(): circle_occ = pxz.scene.createOccurrence("Circle", pxz.scene.getRoot()) part = pxz.scene.addComponent(circle_occ, pxz.scene.ComponentType.Part) model = pxz.cad.createModel() pxz.scene.setPartModel(part, model) matrix = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] circle = pxz.cad.createCircleCurve(0.5, matrix) pxz.cad.setCurveLimits(circle, pxz.cad.Bounds1D(0, 2*math.pi)) edge = pxz.cad.createEdgeFromCurve(circle) coEdge = pxz.cad.createCoEdge(edge, True) loop = pxz.cad.createLoop([coEdge]) plane = pxz.cad.createPlaneSurface(matrix) face = pxz.cad.createFace(plane, [loop]) shell = pxz.cad.createOpenShell([face], [True]) pxz.cad.addOpenShellToModel(shell, model) pxz.algo.tessellate([circle_occ], 0.01, -1, -1, True, 0, 1, 0, False, False, True, False) return circle_occdef replace_holes_with_disks(selection): global z_fighting_offset disks = [] # replace holes with disks original_circle = None occurrence_features_list = pxz.algo.listFeatures(selection, True, True, 10) for occurrence_feature in occurrence_features_list: for feature in occurrence_feature.features: if feature.type == pxz.algo.FeatureType.Unknown: # replace both holes and blind holes continue for feature_input in feature.inputs: circle = None if original_circle is None: original_circle = create_circle() circle = original_circle else: circle = pxz.scene.prototypeSubTree(original_circle) pxz.scene.setParent(circle, pxz.scene.getRoot()) diameter = feature_input.diameter scale = diameter direction = feature_input.direction # transform direction vector to euler length = math.sqrt(direction.x**2 + direction.y**2 + direction.z**2) dx, dy, dz = direction.x/length, direction.y/length, direction.z/length yaw_y = math.atan2(dx, dz) pitch_x = math.atan2(-dy, math.sqrt(dx*dx + dz*dz)) roll_z = 0.0 rad2deg = 180.0 / math.pi euler_deg = pxz.geom.Point3(pitch_x*rad2deg, yaw_y*rad2deg, roll_z) # slight offset to avoid z-fighting position = pxz.geom.Point3(feature_input.position.x + dx*z_fighting_offset, feature_input.position.y + dy*z_fighting_offset, feature_input.position.z + dz*z_fighting_offset) M_TRS = pxz.geom.fromTRS(position, euler_deg, pxz.geom.Point3(scale, scale, scale)) pxz.core.setProperty(circle, "Transform", str(M_TRS)) disks.append(circle) return disksselection = pxz.scene.getChildren(pxz.scene.getRoot())pxz.algo.repairMesh(selection, 0.1, True, True)pxz.algo.identifyPatches(selection, True, 45, True, True, True, False)disks = replace_holes_with_disks(selection)pxz.algo.removeHoles(selection, through_holes, blind_holes, surfacic_holes, max_diameter, fill_with_material)pxz.algo.deletePatches(selection, True)pxz.algo.decimate(selection, 1, -1, 8, -1, False) # this will flatten the mesh