Remove non-manifold edges from decimated polydata

Hope this script is useful for someone…

It’s done to be executed on Slicer but you can easily adapt it to pure vtk.

guide_dec = getNode('guide-dec')

idFilter = vtk.vtkIdFilter()
idFilter.SetInputData(guide_dec.GetMesh());
idFilter.SetPointIds(True)
idFilter.SetCellIds(False)
idFilter.SetPointIdsArrayName("PointIds")
idFilter.SetCellIdsArrayName("CellIds")
idFilter.Update()

nonManifoldEdgesFilter = vtk.vtkFeatureEdges()
nonManifoldEdgesFilter.SetInputData(idFilter.GetOutput())
nonManifoldEdgesFilter.BoundaryEdgesOff()
nonManifoldEdgesFilter.FeatureEdgesOff()
nonManifoldEdgesFilter.ManifoldEdgesOff()
nonManifoldEdgesFilter.NonManifoldEdgesOn()
nonManifoldEdgesFilter.Update()

nonManifoldPointids = nonManifoldEdgesFilter.GetOutput().GetPointData().GetArray("PointIds")
nonManifoldPointids.GetNumberOfValues()

edgesFilter = vtk.vtkFeatureEdges()
edgesFilter.SetInputData(idFilter.GetOutput())
edgesFilter.BoundaryEdgesOff()
edgesFilter.FeatureEdgesOff()
edgesFilter.ManifoldEdgesOn()
edgesFilter.NonManifoldEdgesOn()
edgesFilter.Update()

allPointids = edgesFilter.GetOutput().GetPointData().GetArray("PointIds")

ids = vtk.vtkIdTypeArray()
ids.SetNumberOfComponents(1)
for i in range(nonManifoldPointids.GetNumberOfValues()):
    nonManifoldPointIDFound = True
    for j in range(allPointids.GetNumberOfValues()):
        if int(nonManifoldPointids.GetTuple1(i)) == int(allPointids.GetTuple1(i)):
            nonManifoldPointIDFound = False
            break
    ids.InsertNextValue(int(nonManifoldPointids.GetTuple1(i)))

selectionNode = vtk.vtkSelectionNode()
selectionNode.SetFieldType(vtk.vtkSelectionNode.POINT)
selectionNode.SetContentType(vtk.vtkSelectionNode.INDICES)
selectionNode.SetSelectionList(ids);
selectionNode.GetProperties().Set(vtk.vtkSelectionNode.CONTAINING_CELLS(), 1)
selectionNode.GetProperties().Set(vtk.vtkSelectionNode.INVERSE(), 1)

selection = vtk.vtkSelection()
selection.AddNode(selectionNode);

extractSelection = vtk.vtkExtractSelection()
extractSelection.SetInputConnection(0, guide_dec.GetPolyDataConnection())
extractSelection.SetInputData(1, selection)
extractSelection.Update()

geometryFilter = vtk.vtkGeometryFilter()
geometryFilter.SetInputData(extractSelection.GetOutput())
geometryFilter.Update()

# test if the removal of non manifold edges did work
featureEdges2 = vtk.vtkFeatureEdges()
featureEdges2.SetInputData(geometryFilter.GetOutput())
featureEdges2.BoundaryEdgesOff()
featureEdges2.FeatureEdgesOff()
featureEdges2.ManifoldEdgesOff()
featureEdges2.NonManifoldEdgesOn()
featureEdges2.Update()
featureEdges2.GetOutput().GetNumberOfPoints()

# save the model without non-manifold edges
guide_dec.SetAndObserveMesh(geometryFilter.GetOutput())

Source: Remove non-manifold edges before Boolean mesh operation · Issue #35 · SlicerIGT/SlicerBoneReconstructionPlanner · GitHub

The code has bugs, I’ll try to correct it… There must be a way to discriminate nonManifold (floating) points of nonManifoldEdges from its manifold points. And do an inverse selection to keep the manifold data