New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove non-manifold edges before Boolean mesh operation #35
Comments
@mauigna06 please try this as soon as possible. It is really unique that maintainer of vtkbool is personally willing to investigate issues with our data sets, so we need to do everything we can to keep him interested and respond to him quickly. Can you try this today, or latest tomorrow? |
@lassoan I'm out of town today. Tomorrow I can start working on this. I hope that's okey. |
So you want me to use vtkFeatureEdges to detect non manifold edges in the mesh "guide-dec.vtk" that we know has non manifold edges because of paraview? Should I check if the output of that filter has a different than zero point count to be sure we detect the non manifold edges? How do I remove that non manifold edges? Should I use the output of vtkFeatureEdges as input for vtkRemovePolyData? After that I should use vtkFillHolesFilter? What benefit would make using vtkCleanPolyData for this mesh? |
We already knew that decimated meshes may contain non-manifold edges, we just did not know how much vtkbool is sensitive to presence of those. Now we know that it is sensitive (which is not surprising) and we need to take care of it. Removing duplicate points, removing non-manifold edges, and filling small holes are the most commonly needed mesh cleaning operations and probably users have asked about it on the VTK mailing list/forum many times, so I would start with some web searching. I've also asked on the VTK forum, hopefully we'll hear back (but I don't have high hopes): https://discourse.vtk.org/t/remove-faces-in-contact-with-non-manifold-edges/4116/2 Removing an edge is not trivial, because you need to remove all cells that has that edge. So, you need to find the edges, then find the cells, and then use vtkExtractSelection or vtkThreshold to filter out those cells from the mesh. Since removing cells opens holes in the mesh, we probably need to apply hole filling to eliminate these holes (hopefully the hole filling does not introduce non-manifold edges). Duplicate points (multiple points at the same position) may confuse mesh processing algorithms. vtkCleanPolyData removes these duplicate points. This may be needed because for example vtkPolyDataNormals duplicates points at sharp edges to allow sharp changes in normal directions at edges. |
Andras, thank you for such a complete answer. I don't understand what is my homework for tomorrow exactly |
Task for tomorrow: test if you can remove non-manifold edges with combination of VTK filters so that the resulting mesh can be processed correctly using Combine models module. |
@lassoan, this is my code to try do that:
I was able to delete the cells that contained the points of the non-manifold edges. Making boolean difference (using the CombineModels module) to 'cleaned' with 'fibula' fails There were answers to this post: https://discourse.vtk.org/t/remove-faces-in-contact-with-non-manifold-edges/4116/2 |
This is very nice, thanks for diving into this.
You can fix that by running vtkPolyDataNormals (with SplittingOff, to prevent point duplication). Can you attach a few screenshots that show the non-manifold edges (zoomed out to show where they are, zoomed in to show its size and shape)? Have you tried combining meshes on the result of removal of non-manifold edges, without hole filling? The code cuts out bigger holes than needed. Now the script removes all the cells that contains any of the points that are used in a feature edge. But a point may be used in many edges and only a very few of them are removed. Could you update the script with an additional filtering step?
I'll follow up on the discourse post once we see how well your script can solve this. |
I've been looking at the models and I'm wondering if we bring the problems upon to ourselves by suboptimal processing. Specifically, the non-manifold edges seem to be created by decimation. If we can find other ways to speed up previews (e.g., not performing Boolean mesh operations for preview, or lower the segmentation resolution or decimate the bone mesh and not the combined meshes) and we use full-resolution, non-decimated meshes for generating the final guide then maybe we will not run into meshing problems. |
Yes. I think we can leave this for now
Do you know if these non-manifold edges will affect the dynamic modeler plane cuts when we replace the fibulaMesh by the decimatedFibulaMesh?
I think this is okey since the surgicalGuide is created only after all the surgicalPlanning and after all the miterBoxes positioning so the user can check if the position of the miterBoxes is okey before clicking "Make boolean operations to surgical guide base with screwHolesCylinders and miterBoxes"
It is an option
Would these meshes need to be processed (delete non-manifold edges, vtkCleanPolyData, etc)?
I agree |
Andras just let me know if you want me to keep working on this |
Yes, please test if latest Combine models works well for non-decimated meshes. If you find any errors then upload the meshes somewhere and post the link here. I'll take care of the rest. |
Thank you Andras. P.S. We can make mandible surgical guides now with our module, checkout the last pull request |
Andras tell me if you could open the meshes because I created them with a preview release of Slicer and I found stable releases couldn't open one of those files and Slicer crashed |
Just in case someone needs it, here is a script that removes non-manifold edges added by decimation.
|
Hi @mauigna06 thanks for sharing this code, I've been struggling with this problem lately in marcomusy/vedo#663 and could not find a satisfactory solution. I'm not sure if there's any typo in the code you posted, shouldn't it be instead import vtk
import vedo
poly = vedo.Mesh('small_dino.obj').polydata()
idFilter = vtk.vtkIdFilter()
idFilter.SetInputData(poly);
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()
#vedo.show(nonManifoldEdgesFilter.GetOutput()).close()
nonManifoldPointids = nonManifoldEdgesFilter.GetOutput().GetPointData().GetArray("PointIds")
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(j)):
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.SetInputData(0, poly)
extractSelection.SetInputData(1, selection)
extractSelection.Update()
geometryFilter = vtk.vtkGeometryFilter()
geometryFilter.SetInputData(extractSelection.GetOutput())
geometryFilter.Update()
vedo.show(geometryFilter.GetOutput()).close() |
Hi @marcomusy. Thank you for testing. Please try this updated version (it should be more understandable) and tell me if it works:
|
Hi Mauro, I basically get the same output.. Maybe the problem is in |
Yeah. I checked on the testing data of the issue of vedo and I couldn't get it yet... I'll keep trying on my free time |
@mauigna06 any update on the mentioned problem from @marcomusy? |
@mauigna06 has taken some time off. You can try to ping him again in a week or two. |
@mauigna06 any update? |
Hi @ttsesm. I couldn't solve it yet and it's not a feature that is essencial to any of my projects so maybe I'll try again on weekends but it's not probable |
Thanks for the reply Mauro. I do not understand though, is this a vtk issue? Also did you check what Marco is suggesting. |
Would someone help with c++ code for that purpose ? |
I tried to convert the above python code to c++
|
Hi @AndreAhmed. I never tried again to solve this problem. You are right the code you quoted does not work Best wishes |
I developed this function for vedo, in case you're interested - should be easy to unpack the logic to translate it to pure vtk |
Hi @marcomusy |
..and this is better version which also does repairing (not 100% perfect, but not so bad!): from vedo import *
msh = Mesh('piece_1.obj')
# msh = Mesh('small_dino.obj')
msh.backcolor("purple5").linewidth(1)
print("msh is_manifold?", msh.is_manifold())
msh.non_manifold_faces(tol=0.2, remove=True)
print("msh is_manifold?", msh.is_manifold())
# msh.cmap("Reds", "NonManifoldCell", on="cells")
bb = msh.boundaries(non_manifold_edges=True, boundary_edges=False)
show(msh, bb, axes=1) |
vtkbool fails (returns empty mesh or meshes with errors) for some Boolean mesh operations. We work together with vtkbool developer to identify and fix the issues.
It seems that vtkbool expects input meshes to not have any non-manifold edges (which is completely reasonable). We need to test if we detect non-manifold edges using vtkCleanPolyData and vtkFeatureEdges and then maybe stitch the holes using vtkFillHolesFilter solves the problem - see zippy84/vtkbool#40 (comment).
The text was updated successfully, but these errors were encountered: