pyvista / pymeshfix

Python Wrapper for MeshFix: easily repair holes in surface meshes
http://pymeshfix.pyvista.org
GNU General Public License v3.0
293 stars 29 forks source link

Help: non-volume meshes #8

Closed adurukan closed 4 years ago

adurukan commented 5 years ago

I have install pymeshfix using: pip install pymeshfix on my python 3.6 conda enviroment along some other libraries such as pymesh, pythonOCC, ifcopenshell, and trimesh. I simply want to make sure my meshes are water tight. I am trying to run: meshfix = pymeshfix.MeshFix(vertices, faces) meshfix.repair() pmfv = meshfix.v

However, I always end up with the error below:

File "/home/alpay/PycharmProjects/Hiwi/hi.py", line 98, in pmfv,pmff = pymeshfixfix(cverts,cfaces) File "/home/alpay/PycharmProjects/Hiwi/hi.py", line 58, in pymeshfixfix meshfix.repair() File "/home/alpay/anaconda3/envs/hiwi36/lib/python3.6/site-packages/pymeshfix/meshfix.py", line 133, in repair remove_smallest_components) File "pymeshfix/cython/_meshfix.pyx", line 324, in pymeshfix._meshfix.clean_from_arrays File "pymeshfix/cython/_meshfix.pyx", line 163, in pymeshfix._meshfix.PyTMesh.load_array File "stringsource", line 654, in View.MemoryView.memoryview_cwrapper File "stringsource", line 349, in View.MemoryView.memoryview.cinit ValueError: buffer source array is read-only

Any help would be appreciated :)

banesullivan commented 5 years ago

Hi @adurukan - would you be able to provide the vertices and faces arrays as attachments/data files for us to reproduce this issue?

Also, would you please share your system report using pyvista which is installed with PyMeshFix:

import pyvista as pv
print(pv.Report('pymeshfix'))
banesullivan commented 5 years ago

Also, does the issue remain if you first pass the vertices and faces to PyVista?:

import pyvista as pv
import pymeshfix as mf

mesh = pv.PolyData(vertices, faces)
# Plot to make sure it is what you expect
mesh.plot()

meshfix = mf.MeshFix(mesh)
meshfix.repair()
repaired = meshfix.mesh

# view the repaired mesh
repaired.plot()
adurukan commented 5 years ago

Oh, it seems that I was passing some empty arrays and that's why I was getting that error. Though, I have another issue now. The data I am using is a pretty large one so I will just show you one vertices and faces array. When I try:

(script edited by @banesullivan to be reproducible)

import numpy as np
import pyvista as pv
import pymeshfix as mf

vertices = np.array([[13, 12, -1],
    [13, 12, 0],
    [13, 7, -1],
    [13, 7, 0],
    [13, 7, -1],
    [13, 7, 0],
    [13, 12, -1],
    [13, 12, 0],])

tris = np.array([[1, 0, 2],
    [3, 1, 2],
    [3, 2, 4],
    [5, 3, 4],
    [5, 4, 6],
    [7, 5, 6],
    [7, 6, 0],
    [1, 7, 0],
    [4, 2, 0],
    [6, 4, 0],
    [1, 3, 5],
    [1, 5, 7],])

faces = np.hstack((np.full((len(tris), 1), 3), tris))

mesh = pv.PolyData(vertices, faces)
meshfix = mf.MeshFix(mesh)
meshfix.repair()
print('Faces after fix:',meshfix.f)
print('Vertices after fix:',meshfix.v)

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

SIGSEGV error is, I assume, due to a problem in accessing the array. This is basically an array from Schultz_Residence.ifc file from https://github.com/opensourceBIM/IFC-files/blob/master/OpeningDesign.com/Schultz_Residence.ifc.

Any suggestion will be appreciated :) P.S: I can also share the whole data If needed.

adurukan commented 5 years ago

Hi @adurukan - would you be able to provide the vertices and faces arrays as attachments/data files for us to reproduce this issue?

Also, would you please share your system report using pyvista which is installed with PyMeshFix:

import pyvista as pv
print(pv.Report('pymeshfix'))
--------------------------------------------------------------------------------
  Date: Wed Jul 24 20:53:27 2019 CEST

             Linux : OS
                 1 : CPU(s)
            x86_64 : Machine
             64bit : Architecture
            Python : Environment

  Python 3.6.8 |Anaconda, Inc.| (default, Dec 30 2018, 01:22:34)  [GCC 7.3.0]

   Version unknown : pymeshfix
            0.21.2 : pyvista
             8.1.2 : vtk
            1.16.4 : numpy
             2.5.0 : imageio
             1.4.3 : appdirs
             0.4.3 : scooby
             7.6.1 : IPython
--------------------------------------------------------------------------------
banesullivan commented 5 years ago

This may need @akaszynski's expertise...

My take - the example mesh you give doesn't have any holes (maybe we have a segfaulting issue for meshes without holes?)

Run the script I edited in @adurukan's post above and instead of calling repair(), call extract_holes() to extract the holes and prove there are none

...
meshfix.extract_holes()
PolyDataInformation
N Cells0
N Points0
X Bounds1.000e+00, -1.000e+00
Y Bounds1.000e+00, -1.000e+00
Z Bounds1.000e+00, -1.000e+00
N Arrays0
banesullivan commented 5 years ago

@adurukan , can you please provide a script to read the contents of the linked Schultz_Residence.ifc file into NumPy arrays?

adurukan commented 5 years ago

@banesullivan The script to get contents of Schultz_Residence.ifc is as in the following:

import ifcopenshell.geom
import numpy as np

def convert(verts,faces,vts,fac):
    for i in range(len(vts)):
        verts[i] = vts[i]
    for i in range(len(fac)):
        faces[i] = fac[i]

    return verts, faces

file = ifcopenshell.open("Schultz_Residence.ifc")
settings = ifcopenshell.geom.settings()
settings.set(settings.USE_WORLD_COORDS, True)
settings.set(settings.SEW_SHELLS, True)
products = file.by_type("IfcWall")

for p in products:
        g=ifcopenshell.geom.create_shape(settings, p)
        vts = g.geometry.verts
        fac = g.geometry.faces

        verts = np.zeros((len(vts)), dtype=int)
        faces = np.zeros((len(fac)), dtype=int)

        vertas, facas = convert(verts, faces, vts, fac)
        vv = int(len(vertas) / 3)
        fv = int(len(facas) / 3)
        vertas = np.reshape(vertas,(vv,3) )
        facas = np.reshape(facas, (fv,3))
        # Here vertas and facas are (x,3) shaped arrays.

https://github.com/IfcOpenBot/IfcOpenShell/commit/491dc57098b919135c5984a0084265291af8c77a#comments Download the proper .whl file from here for IfcOpenShell and do pip install xxx.whl. Than, you should be able to run the script.

adurukan commented 5 years ago

This may need @akaszynski's expertise...

My take - the example mesh you give doesn't have any holes (maybe we have a segfaulting issue for meshes without holes?)

Run the script I edited in @adurukan's post above and instead of calling repair(), call extract_holes() to extract the holes and prove there are none

...
meshfix.extract_holes()

PolyData Information N Cells 0 N Points 0 X Bounds 1.000e+00, -1.000e+00 Y Bounds 1.000e+00, -1.000e+00 Z Bounds 1.000e+00, -1.000e+00 N Arrays 0

import pyvista as pv
import numpy as np
import pymeshfix as mf
import trimesh

fcs = np.array([[ 7,  8,  9],
 [ 6 , 7,  9],
 [11  ,9 ,10],
 [11 ,10 , 0],
 [11 ,12  ,6],
 [11 , 6  ,9],
 [ 1 ,11 , 0],
 [14 ,11 , 1],
 [16 ,13 ,14],
 [15 ,16 ,14],
 [15 ,14 , 1],
 [ 5 ,16 ,17],
 [18 , 4 , 5],
 [18 , 5 ,17],
 [ 2 ,18 ,15],
 [ 3 , 4 ,18],
 [ 3 ,18 , 2],
 [ 1 , 2 ,15],
 [ 5 , 6 ,12],
 [ 5 ,12 ,13],
 [ 5 ,13 ,16],
 [22 ,19 ,20],
 [22 ,20 ,21],
 [ 2 ,19 ,23],
 [ 2 ,23 , 3],
 [20 , 1 , 0],
 [20 ,19 , 1],
 [ 1 ,19 , 2],
 [24 ,25 ,26],
 [27 ,24 ,26],
 [27 ,26 , 6],
 [27 , 6 ,28],
 [30 , 5 , 4],
 [31 , 5 ,30],
 [31 ,32 , 5],
 [28 ,33 ,34],
 [28 ,29 ,33],
 [29,  5 ,33],
 [33,  5 ,32],
 [13, 32 ,31],
 [14, 31 ,35],
 [14, 13 ,31],
 [12, 33 ,32],
 [12, 32 ,13],
 [23, 19 ,36],
 [ 3, 23, 36],
 [37,  3, 36],
 [ 4, 37, 30],
 [ 4,  3, 37],
 [ 8, 24, 38],
 [ 8, 38,  9],
 [41, 10 ,39],
 [41, 39 ,40],
 [20, 42 ,21],
 [ 0, 41 ,42],
 [ 0, 42 ,20],
 [ 0, 10, 41],
 [38, 39 ,10],
 [38, 10 , 9],
 [40, 37 ,43],
 [41, 40 ,43],
 [46, 44 ,45],
 [46, 42 ,44],
 [44, 42 ,41],
 [44, 41 ,43],
 [44, 43 ,47],
 [22, 44 ,47],
 [28, 40 ,39],
 [28, 49 ,40],
 [38, 28 ,39],
 [27, 38 ,48],
 [27, 28 ,38],
 [34, 49 ,28],
 [35, 40 ,49],
 [51, 35 ,31],
 [51, 50 ,35],
 [37, 50 ,52],
 [30 ,52 ,53],
 [30 ,53 ,51],
 [30 ,37 ,52],
 [31 ,30 ,51],
 [37 ,40 ,50],
 [50, 40 ,35]],np.int)

vcs = np.array([[-4 , 9  ,4],
 [-3 , 9  ,4],
 [ 2 , 9  ,4],
 [ 2 , 9  ,4],
 [ 2 , 9  ,6],
 [ 2 , 9  ,6],
 [-3 , 9  ,6],
 [-3 , 9  ,6],
 [-4 , 9  ,6],
 [-4 , 9  ,6],
 [-4 , 9  ,6],
 [-3 , 9  ,5],
 [-3 , 9  ,6],
 [-2 , 9  ,6],
 [-2 , 9  ,5],
 [ 0 , 9  ,5],
 [ 0 , 9  ,5],
 [ 1 , 9  ,5],
 [ 1 , 9  ,5],
 [ 2 , 9  ,4],
 [-4 , 9  ,4],
 [-4 , 9  ,4],
 [ 2  ,9  ,4],
 [ 2 , 9  ,4],
 [-4 , 9  ,6],
 [-4 , 9  ,6],
 [-3  ,9  ,6],
 [-3 , 9  ,6],
 [-3  ,9  ,6],
 [-3  ,9  ,6],
 [ 2  ,9  ,6],
 [-2  ,9  ,6],
 [-2  ,9  ,6],
 [-3  ,9  ,6],
 [-3  ,9  ,6],
 [-2  ,9  ,5],
 [ 2  ,9  ,4],
 [ 2  ,9  ,4],
 [-4  ,9  ,6],
 [-4  ,9  ,6],
 [-4  ,9  ,4],
 [-4  ,9  ,4],
 [-4  ,9  ,4],
 [ 2  ,9  ,4],
 [ 2  ,9  ,4],
 [ 2  ,9  ,4],
 [-4  ,9  ,4],
 [ 2  ,9  ,4],
 [-4  ,9  ,6],
 [-3  ,9  ,5],
 [ 0  ,9  ,5],
 [ 0  ,9  ,5],
 [ 1  ,9  ,5],
 [ 1  ,9  ,5]],np.int)

fcs1 = np.hstack((np.full((len(fcs), 1), 3), fcs))

mesh = trimesh.Trimesh(vcs,fcs1,validate=False,process=False)

if mesh.is_watertight == False:
    print ('NOT WATER TIGHT')
trimesh.repair.fill_holes(mesh)
if mesh.is_watertight == False:
    print ('NOT WATER TIGHT')

mesh = pv.PolyData(vcs, fcs1)
meshfix = mf.MeshFix(mesh)
meshfix.repair()
#meshfix.extract_holes()
#print('Faces after fix:',meshfix.f)
#print('Vertices after fix:',meshfix.v)

I made sure this time that the vertices and faces produce non-watertight mesh. I checked it with trimesh as well. However, the error remains the same.

NOT WATER TIGHT NOT WATER TIGHT

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

If I uncomment the meshfix.extract_holes() I get:

Traceback (most recent call last): File "/home/alpay/PycharmProjects/Hiwi/deneme3.py", line 158, in meshfix.extract_holes() AttributeError: 'MeshFix' object has no attribute 'extract_holes'

Thank you in advance for your help again.

adurukan commented 5 years ago

One other thing is that even when I run the bunny.py from examples, I get the same error as before:

Traceback (most recent call last): File "/home/alpay/PycharmProjects/Hiwi/deneme.py", line 26, in holes = meshfix.extract_holes() AttributeError: 'MeshFix' object has no attribute 'extract_holes'

I am guessing that there is something wrong with the way I installed pymeshfix but I did pip install pymeshfix

banesullivan commented 5 years ago

One other thing is that even when I run the bunny.py from examples, I get the same error as before:

Traceback (most recent call last): File "/home/alpay/PycharmProjects/Hiwi/deneme.py", line 26, in holes = meshfix.extract_holes() AttributeError: 'MeshFix' object has no attribute 'extract_holes'

I am guessing that there is something wrong with the way I installed pymeshfix but I did pip install pymeshfix

This is all because of #9 - I'll push this release now

banesullivan commented 5 years ago

I made sure this time that the vertices and faces produce non-watertight mesh. I checked it with trimesh as well. However, the error remains the same.

So this mesh is all kinds of messed up which is why I think its crashing - you need the mesh to make a closed surface

Run most of your script, then...

...

vcs[:, 1] += np.random.random(len(vcs)) * 10

mesh = pv.PolyData(vcs, fcs1)

p = pv.Plotter()
p.add_mesh(mesh, color=True, show_edges=True)
p.add_mesh(mesh.points, point_size=10, color='white')
p.show()

download

I simply added a littlie bit of Y variation to your mesh because MeshFix operates in 3D, not 2D - also a 2D surface can't be "water tight". This crazy looking thing isn't possible to work with... I tried cleaning it up but it's a difficult problem

I'd recommend working with a 3D semi-closed surface with holes in that - something volumetric that could "hold water" if the holes are repaired

banesullivan commented 5 years ago

And I'd recommend bumping up to version 0.13.2 as a few quirks were fixed and new features were added - I'm not sure why we didn't push that at the time - apologies!

pip install --upgrade pymeshfix
akaszynski commented 4 years ago

Closing due to inactivity...