Code Monkey home page Code Monkey logo

Comments (30)

mauigna06 avatar mauigna06 commented on August 11, 2024 1

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

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024 1

Hi @marcomusy
Thanks a lot for the update!

from slicerbonereconstructionplanner.

lassoan avatar lassoan commented on August 11, 2024

@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?

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

@lassoan I'm out of town today. Tomorrow I can start working on this. I hope that's okey.
I looked for examples of vtkCleanPolyData and there aren't so I plan to use it with all the optional flags on.
I haven't researched how vtkFeatureEdges and vtkFillHolesFilter are used. But after that, if I have doubts I'll ask you if you don't mind

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

OK, thans for the clarification. I'll check if vtkFeatureEdges can correctly detect this edge and if we can fix this by removing the edge and fill holes.

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?

from slicerbonereconstructionplanner.

lassoan avatar lassoan commented on August 11, 2024

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.

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

Andras, thank you for such a complete answer.

I don't understand what is my homework for tomorrow exactly

from slicerbonereconstructionplanner.

lassoan avatar lassoan commented on August 11, 2024

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.

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

@lassoan, this is my code to try do that:

fibula = getNode('fibula')
guide_dec = getNode('guide-dec')
featureEdges = vtk.vtkFeatureEdges()
featureEdges.SetInputData(guide_dec.GetPolyData())
featureEdges.BoundaryEdgesOff()
featureEdges.FeatureEdgesOff()
featureEdges.ManifoldEdgesOff()
featureEdges.NonManifoldEdgesOn()
featureEdges.Update()
nonManifoldEdgesPolyData = featureEdges.GetOutput()

nonManifoldEdges = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode','non-manifold edges of guide-dec')
nonManifoldEdges.CreateDefaultDisplayNodes()
nonManifoldEdges.SetAndObservePolyData(featureEdges.GetOutput())

ids = vtk.vtkIdTypeArray()
ids.SetNumberOfComponents(1)

for i in range(nonManifoldEdgesPolyData.GetNumberOfPoints()):
  pointOfNonManifoldEdges = nonManifoldEdges.GetPolyData().GetPoints().GetPoint(i)
  pointIdInOriginal = guide_dec.GetPolyData().FindPoint(pointOfNonManifoldEdges)
  ids.InsertNextValue(pointIdInOriginal)

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()

selectedTriangles = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode','selected triangles')
selectedTriangles.CreateDefaultDisplayNodes()
selectedTriangles.SetAndObservePolyData(geometryFilter.GetOutput())

filler = vtk.vtkFillHolesFilter()
filler.SetInputData(geometryFilter.GetOutput())
filler.SetHoleSize(10)
filler.Update()

filledHoles = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode','filled holes')
filledHoles.CreateDefaultDisplayNodes()
filledHoles.SetAndObservePolyData(filler.GetOutput())

cleanFilter = vtk.vtkCleanPolyData()
cleanFilter.SetInputData(filler.GetOutput())
cleanFilter.ConvertLinesToPointsOn()
cleanFilter.ConvertPolysToLinesOn()
cleanFilter.ConvertStripsToPolysOn()
cleanFilter.Update()

cleaned = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelNode','cleaned')
cleaned.CreateDefaultDisplayNodes()
cleaned.SetAndObservePolyData(filler.GetOutput())

featureEdges2 = vtk.vtkFeatureEdges()
featureEdges2.SetInputData(cleaned.GetPolyData())
featureEdges2.BoundaryEdgesOff()
featureEdges2.FeatureEdgesOff()
featureEdges2.ManifoldEdgesOff()
featureEdges2.NonManifoldEdgesOn()
featureEdges2.Update()
featureEdges2.GetOutput().GetNumberOfPoints()

I was able to delete the cells that contained the points of the non-manifold edges.
Triangles from filled holes have inverted normals (I don't know if that's a problem).
If filler parameter is bigger than 15, it fills the slit of the surgicalGuide so you have to be careful with that. But it doesn't fill all the holes made by the selection.

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

from slicerbonereconstructionplanner.

lassoan avatar lassoan commented on August 11, 2024

This is very nice, thanks for diving into this.

Triangles from filled holes have inverted normals (I don't know if that's a problem).

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?

  • Use vtkSelectionNode (without INVERSE) to get the list of cells that potentially need to be removed
  • Iterate through these cells and check if they contain a non-manifold edge (list of cell points contain the two non-manifold edge points right next to each other). If they actually contain a non-manifold edge then add the cell ID (the "pedigree ID" - cell ID in the input mesh) to the list of cells that are confirmed that are needed to be removed.
  • Remove cells that are confirmed for removal (using selection or threshold filter)

I'll follow up on the discourse post once we see how well your script can solve this.

from slicerbonereconstructionplanner.

lassoan avatar lassoan commented on August 11, 2024

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.

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

I've been looking at the models and I'm wondering if we bring the problems upon to ourselves by suboptimal processing.

Yes. I think we can leave this for now

Specifically, the non-manifold edges seem to be created by decimation.

Do you know if these non-manifold edges will affect the dynamic modeler plane cuts when we replace the fibulaMesh by the decimatedFibulaMesh?

not performing Boolean mesh operations for preview

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"

lower the segmentation resolution

It is an option

decimate the bone mesh and not the combined meshes

Would these meshes need to be processed (delete non-manifold edges, vtkCleanPolyData, etc)?

we use full-resolution, non-decimated meshes for generating the final guide then maybe we will not run into meshing problems.

I agree

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

Andras just let me know if you want me to keep working on this

from slicerbonereconstructionplanner.

lassoan avatar lassoan commented on August 11, 2024

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.

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

Thank you Andras.
I downloaded the latest version of the Sandbox Extension and I'm using Slicer 4.13.0-2012-03-09 preview release.
vktbool has improved a lot but still there are a few errors in the "result" of difference of "FibulaSurgicalGuidePrototype_3" with "fibula".
Here is a link to the meshes: https://gofile.io/d/cT8Pw8

P.S. We can make mandible surgical guides now with our module, checkout the last pull request

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

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

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

Just in case someone needs it, here is a script that removes non-manifold edges added by decimation.

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())

from slicerbonereconstructionplanner.

marcomusy avatar marcomusy commented on August 11, 2024

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
if int(nonManifoldPointids.GetTuple1(i)) == int(allPointids.GetTuple1(j)):
And how is nonManifoldPointIDFound used in the code? (it seems it's not used!)
I tried it on a sample mesh (you can find it in the vedo issue) and i get this:

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()

Screenshot from 2022-07-25 12-24-56

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

Hi @marcomusy. Thank you for testing. Please try this updated version (it should be more understandable) and tell me if it works:

guide_dec = getNode("FibulaSurgicalGuidePrototype_1_1")

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()

manifoldEdgesFilter = vtk.vtkFeatureEdges()
manifoldEdgesFilter.SetInputData(idFilter.GetOutput())
manifoldEdgesFilter.BoundaryEdgesOff()
manifoldEdgesFilter.FeatureEdgesOff()
manifoldEdgesFilter.ManifoldEdgesOn()
manifoldEdgesFilter.NonManifoldEdgesOff()
manifoldEdgesFilter.Update()

manifoldPointids = manifoldEdgesFilter.GetOutput().GetPointData().GetArray("PointIds")

ids = vtk.vtkIdTypeArray()
ids.SetNumberOfComponents(1)
for i in range(nonManifoldPointids.GetNumberOfValues()):
    sharedPointIDFound = False
    for j in range(manifoldPointids.GetNumberOfValues()):
        if int(nonManifoldPointids.GetTuple1(i)) == int(manifoldPointids.GetTuple1(j)):
            nonManifoldPointIDFound = True
            break
    if not sharedPointIDFound:
          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())

from slicerbonereconstructionplanner.

marcomusy avatar marcomusy commented on August 11, 2024

Hi Mauro, I basically get the same output..

Maybe the problem is in vtkSelectionNode.CONTAINING_CELLS(), if 2 non-manifold points from 2 independent cells are so close that the are part of another same cell, then that cell is dropped too, causing a hole. That's because CONTAINING_CELLS flags cells for ANY not ALL points.

from slicerbonereconstructionplanner.

ttsesm avatar ttsesm commented on August 11, 2024

@mauigna06 any update on the mentioned problem from @marcomusy?

from slicerbonereconstructionplanner.

lassoan avatar lassoan commented on August 11, 2024

@mauigna06 has taken some time off. You can try to ping him again in a week or two.

from slicerbonereconstructionplanner.

ttsesm avatar ttsesm commented on August 11, 2024

@mauigna06 any update?

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

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

from slicerbonereconstructionplanner.

ttsesm avatar ttsesm commented on August 11, 2024

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.

from slicerbonereconstructionplanner.

AndreAhmed avatar AndreAhmed commented on August 11, 2024

Would someone help with c++ code for that purpose ?

from slicerbonereconstructionplanner.

AndreAhmed avatar AndreAhmed commented on August 11, 2024

I tried to convert the above python code to c++
but still have very bad output

	vtkNew<vtkIdFilter> idFilter;
	idFilter->SetInputData(extrude_vornoi->GetOutput());
	idFilter->SetPointIds(true);
	idFilter->SetCellIds(false);
	idFilter->SetPointIdsArrayName("PointIds");
	idFilter->SetCellIdsArrayName("CellIds");
	idFilter->Update();


	vtkNew<vtkFeatureEdges> nonManifoldEdgesFilter;
	nonManifoldEdgesFilter->SetInputData(idFilter->GetOutput());
	nonManifoldEdgesFilter->BoundaryEdgesOff();
	nonManifoldEdgesFilter->FeatureEdgesOff();
	nonManifoldEdgesFilter->ManifoldEdgesOff();
	nonManifoldEdgesFilter->NonManifoldEdgesOn();
	nonManifoldEdgesFilter->Update();

	vtkDataArray* nonManifoldPointids = nonManifoldEdgesFilter->GetOutput()->GetPointData()->GetArray("PointIds");
	
	vtkNew<vtkFeatureEdges> manifoldEdgesFilter;
	manifoldEdgesFilter->SetInputData(idFilter->GetOutput());
	manifoldEdgesFilter->BoundaryEdgesOff();
	manifoldEdgesFilter->FeatureEdgesOff();
	manifoldEdgesFilter->ManifoldEdgesOff();
	manifoldEdgesFilter->NonManifoldEdgesOn();
	manifoldEdgesFilter->Update();

	vtkDataArray* manifoldPointids = manifoldEdgesFilter->GetOutput()->GetPointData()->GetArray("PointIds");

	vtkNew<vtkIdTypeArray> ids;
	ids->SetNumberOfComponents(1);
	for (int i = 0; i < nonManifoldPointids->GetNumberOfValues(); i++)
	{
		bool sharedPointIDFound = false;
		bool nonManifoldPointIDFound = false;
		for (int j = 0; j < manifoldPointids->GetNumberOfValues(); j++)
		{
			if ((int)nonManifoldPointids->GetTuple1(i) == (int)manifoldPointids->GetTuple1(j))
			{
				nonManifoldPointIDFound = true;
				break;
			}
			if (!sharedPointIDFound)
			{
				ids->InsertNextValue((int)nonManifoldPointids->GetTuple1(i));
			}
		}
	}

	vtkNew<vtkSelectionNode> selectionNode;
	selectionNode->SetFieldType(vtkSelectionNode::POINT);
	selectionNode->SetContentType(vtkSelectionNode::INDICES);
	selectionNode->SetSelectionList(ids);
	selectionNode->GetProperties()->Set(vtkSelectionNode::CONTAINING_CELLS(), 1);
	selectionNode->GetProperties()->Set(vtkSelectionNode::INVERSE(), 1);

	vtkNew<vtkSelection> selection;
	selection->AddNode(selectionNode);

	vtkNew<vtkExtractSelection> extractSelection;
	extractSelection->SetInputConnection(0, extrude_vornoi->GetOutputPort());
	extractSelection->SetInputData(1, selection);
	extractSelection->Update();

	vtkNew<vtkGeometryFilter> geometryFilter;
	geometryFilter->SetInputData(extractSelection->GetOutput());
	geometryFilter->Update();

	vtkNew<vtkOBJWriter> plyWriter;

	plyWriter->SetFileName("curve2.obj");
	plyWriter->SetInputData(geometryFilter->GetOutput());
	plyWriter->Write();```

from slicerbonereconstructionplanner.

mauigna06 avatar mauigna06 commented on August 11, 2024

Hi @AndreAhmed.

I never tried again to solve this problem. You are right the code you quoted does not work

Best wishes

from slicerbonereconstructionplanner.

marcomusy avatar marcomusy commented on August 11, 2024

I developed this function for vedo, in case you're interested - should be easy to unpack the logic to translate it to pure vtk
marcomusy/vedo#813 (comment)
it seems to work fine in relatively simple situations.

from slicerbonereconstructionplanner.

marcomusy avatar marcomusy commented on August 11, 2024

..and this is better version which also does repairing (not 100% perfect, but not so bad!):
https://github.com/marcomusy/vedo/blob/204bf357a43d7c476f55e24d37f8aa2300e3fdf2/vedo/mesh.py#L749

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)

Screenshot 2023-02-25 at 03 25 28

piece_1.obj.zip

from slicerbonereconstructionplanner.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.