pyvista / pyvista

3D plotting and mesh analysis through a streamlined interface for the Visualization Toolkit (VTK)
https://docs.pyvista.org
MIT License
2.71k stars 495 forks source link

Error wrapping Trimesh objects with pyVista #3481

Open gofmans opened 2 years ago

gofmans commented 2 years ago

Describe the bug, what's wrong, and what you expected.

I encountered an error while trying to plot a mesh after loading it with Trimesh package and wrapping with pyvista . Oddly, when I plot the mesh without the "silhouette=True" parameter everything works just fine.

Moreover, I noticed a mismatch between the resulting number of faces after the "wrapping" by pyvista in comparison with native loading of the mesh directly with pyvista (see Screenshots section).

I found a similar problem in this discussion but the solution did not work for me: https://github.com/pyvista/pyvista/issues/966

This problem only happens to one specific STL object that I use, and for all other objects the number of faces is similar in both ways of loading, plus, I can plot them with silhouette==True without any issues....

Any help would be greatly appreciated :) Thanks for the awsome work so far!

Steps to reproduce the bug.

import trimesh
import pyvista as pv

# loading mesh with trimesh and wrapping with pv
trimesh_mesh = trimesh.load(problematic_case_path)
pv_wraped = pv.wrap(trimesh_mesh)

# loading mesh using pv
pv_mesh = pv.read(problematic_case_path)

# this code crashes
pltr = pv.Plotter()
pltr.add_mesh(pv_wraped,silhouette=True)
pltr.show()

# this code works fine
pltr = pv.Plotter()
pltr.add_mesh(pv_wraped)
pltr.show()

# this also works fine
pltr = pv.Plotter()
pltr.add_mesh(pv_mesh, silhouette=True)
pltr.show()

System Information.

--------------------------------------------------------------------------------
  Date: Mon Oct 17 13:35:07 2022 FLE Daylight Time

                OS : Windows
            CPU(s) : 12
           Machine : AMD64
      Architecture : 64bit
               RAM : 15.8 GB
       Environment : Jupyter
        GPU Vendor : Intel
      GPU Renderer : Intel(R) UHD Graphics
       GPU Version : 4.5.0 - Build 27.20.100.9664

  Python 3.8.5 (default, Sep  3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]

           pyvista : 0.36.1
               vtk : 9.1.0
             numpy : 1.23.3
           imageio : 2.16.2
           appdirs : 1.4.4
            scooby : 0.5.6
        matplotlib : 3.6.0
             PyQt5 : 5.9.2
           IPython : 8.4.0
        ipyvtklink : 0.2.1
             scipy : 1.9.1
              tqdm : 4.64.0
            meshio : 5.3.2
        jupyterlab : 3.4.4
--------------------------------------------------------------------------------

Screenshots

image

banesullivan commented 2 years ago

Can you share the one specific STL mesh that you see the issue with? Otherwise, it's tough for us to reproduce this.

adeak commented 2 years ago

Handling Trimesh in pv.wrap has some strong assumptions: https://github.com/pyvista/pyvista/blob/b709dcee6b7ef0c6eb1341c491b9552cdb866044/pyvista/utilities/helpers.py#L973-L980

If Trimesh can have anything other than triangle faces (triangle strips perhaps? any cell type not exposed through its .faces attribute) we'd be missing out on those.

gofmans commented 2 years ago

Thanks for your comments, I looked into the resulting mesh and came across a solution.

It seems like wrapping the mesh by pyvista results in a set of "open edges" that have to be removed before plotting with the silhouette parameter.

This could be done by using "clean" operation followed by "triangulate":

import trimesh
import pyvista as pv

# loading mesh with trimesh and wrapping with pv
trimesh_mesh = trimesh.load(problematic_case_path)
pv_wrapped = pv.wrap(trimesh_mesh)

# loading mesh using pv
pv_mesh = pv.read(problematic_case_path)

# this code crashes
pltr = pv.Plotter()
pltr.add_mesh(pv_wrapped,silhouette=True)   
pltr.show()

# this is the solution
pltr = pv.Plotter()
clean_pv_wrapped = pv_wrapped.clean()
triangulated_clean_pv_wrapped = clean_pv_wrapped.triangulate()
pltr.add_mesh(triangulated_clean_pv_wrapped,silhouette=True)   
pltr.show()

This way, after wrapping the trimesh object cleaning and triangulating, the resulting number of cells matches the one from the original pv mesh:

image

Any thoughts on why this works?