Comments (30)
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.
Hi @marcomusy
Thanks a lot for the update!
from slicerbonereconstructionplanner.
@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.
@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.
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.
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.
Andras, thank you for such a complete answer.
I don't understand what is my homework for tomorrow exactly
from slicerbonereconstructionplanner.
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.
@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.
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.
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.
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.
Andras just let me know if you want me to keep working on this
from slicerbonereconstructionplanner.
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.
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.
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.
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.
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()
from slicerbonereconstructionplanner.
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.
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.
@mauigna06 any update on the mentioned problem from @marcomusy?
from slicerbonereconstructionplanner.
@mauigna06 has taken some time off. You can try to ping him again in a week or two.
from slicerbonereconstructionplanner.
@mauigna06 any update?
from slicerbonereconstructionplanner.
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.
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.
Would someone help with c++ code for that purpose ?
from slicerbonereconstructionplanner.
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.
Hi @AndreAhmed.
I never tried again to solve this problem. You are right the code you quoted does not work
Best wishes
from slicerbonereconstructionplanner.
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.
..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)
from slicerbonereconstructionplanner.
Related Issues (20)
- make miterBoxes and biggerMiterBoxes have a slightly different color
- Instrument to hold the fibula pieces together
- BRP for mandibular reconstruction with iliac bone HOT 5
- To do list, perspective from the project first issues HOT 2
- mandible model gets visible after each "Update of the planning" HOT 1
- Assisted selection of fibula flap donor side HOT 4
- again test the workflow instructions completely on latest stable release 5.6.1
- Fix surgical guide bases creation step documentation
- Add fancy surgical simulation
- Fix tests not working in Slicer 5.6.2
- Custom titanium plate with Blender, copy workflow?
- Create better screw fixation holes HOT 1
- Can generic mandible and fibula models be used for accurate reconstruction?
- Allow deep circumflex Iliac artery flap (DCIA)
- Ability to reformat the slice view without switching to the reformat module. (So the curve can be drawn properly) HOT 1
- Update the Readme.md
- Test entire workflow manually on Stable and Preview releases HOT 4
- Automatically create fibula line from fibula segmentation
- Automatically create guideBaseCocoon when creating fibula/mandible models HOT 1
- improve 3D objects tree view
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from slicerbonereconstructionplanner.