kip-hart / MicroStructPy

Microstructure modeling, mesh generation, analysis, and visualization.
https://docs.microstructpy.org
MIT License
74 stars 19 forks source link

2D ply export #34

Closed gundy360 closed 3 years ago

gundy360 commented 3 years ago

I'm not able to work with 2D ply meshes in any of the tools I've tried (paraview, meshio, trimesh).

3D ply meshes appear to work fine.

I don't know the ply standard very well, but by digging through some of the meshio module source code, it appears that ply may need to have 3 dimensions. I'd suspect setting all of the z values to 0 may make it work. Also the last half of the ply file looks to have what I suspect are supposed to be faces that appear to be only 2 points making them lines rather than faces.

kip-hart commented 3 years ago

Thanks for creating this issue, I have started debugging it. Could you check if the file below works with your tools?

ply
format ascii 1.0
element vertex 18
property float32 x
property float32 y
property float32 z
element face 8
property list uchar int vertex_indices
element edge 25
property int vertex1
property int vertex2
end_header
-5.000000e-01 -4.026508e-01  0.000000e+00
-2.009392e-01  6.476981e-02  0.000000e+00
-5.000000e-01  2.393861e-01  0.000000e+00
-3.520034e-01  2.453039e-01  0.000000e+00
-2.186255e-01  1.377927e-01  0.000000e+00
 5.000000e-01 -5.000000e-01  0.000000e+00
 5.000000e-01  1.135080e-01  0.000000e+00
 4.642275e-01 -5.000000e-01  0.000000e+00
 1.750075e-01 -8.620204e-02  0.000000e+00
 1.732977e-01 -1.435951e-01  0.000000e+00
 3.324293e-01  7.525057e-02  0.000000e+00
-3.328115e-01  5.000000e-01  0.000000e+00
-5.000000e-01  5.000000e-01  0.000000e+00
 6.291911e-02  4.295272e-01  0.000000e+00
 6.724301e-02  5.000000e-01  0.000000e+00
 5.000000e-01  5.000000e-01  0.000000e+00
-1.202258e-01 -5.000000e-01  0.000000e+00
-5.000000e-01 -5.000000e-01  0.000000e+00
5 0 2 3 4 1
6 6 5 7 9 8 10
4 3 2 12 11
5 10 6 15 14 13
3 7 9 16
6 9 16 17 0 1 8
5 4 3 11 14 13
5 8 10 13 4 1
0 2
6 5
5 7
3 2
2 12
12 11
10 6
14 15
15 6
7 9
7 16
9 16
8 9
0 1
17 0
16 17
4 3
11 3
11 14
14 13
8 10
8 1
13 4
13 10
1 4
gundy360 commented 3 years ago

Thanks for looking into this so quickly. When I load it into paraview, it looks reasonable. If I use the trimesh python library, just a few chunks of it appear to work.

This is the original mesh imported into paraview OriginalMesh

This is the mesh converted into an OBJ mesh using the python library trimesh. Trimesh_OBJ_Export

gundy360 commented 3 years ago

After importing it and exporting it again, the ply file is:

ply format ascii 1.0 comment github.com/mikedh/trimesh element vertex 7 property float x property float y property float z element face 3 property list uchar int vertex_indices end_header 0.17329770 -0.14359510 0.00000000 -0.50000000 0.23938610 0.00000000 -0.50000000 0.50000000 0.00000000 -0.33281150 0.50000000 0.00000000 -0.35200340 0.24530390 0.00000000 -0.12022580 -0.50000000 0.00000000 0.46422750 -0.50000000 0.00000000 3 6 0 5 3 4 1 2 3 2 3 4

gundy360 commented 3 years ago

Also, attempting to read it in the python meshio library gives the following error:

In [1]: import meshio

In [2]: meshio.read("/home/gundy360/GenCFD/Test3D/test.ply", file_format="ply")

ReadError Traceback (most recent call last)

in ----> 1 meshio.read("/home/gundy360/GenCFD/Test3D/test.ply", file_format="ply") ~/GenCFD/GenEnv/lib/python3.8/site-packages/meshio/_helpers.py in read(filename, file_format) 66 raise ReadError(msg) 67 ---> 68 return reader_map[file_format](filename) 69 70 ~/GenCFD/GenEnv/lib/python3.8/site-packages/meshio/ply/_ply.py in read(filename) 67 def read(filename): 68 with open_file(filename, "rb") as f: ---> 69 mesh = read_buffer(f) 70 return mesh 71 ~/GenCFD/GenEnv/lib/python3.8/site-packages/meshio/ply/_ply.py in read_buffer(f) 140 line = _next_line(f) 141 else: --> 142 raise ReadError( 143 "Expected `element vertex` or `element face` or `obj_info`, " 144 f"got `{line}`" ReadError: Expected `element vertex` or `element face` or `obj_info`, got `element edge 25` Digging into the _pl.py file. It doesn't appear that meshio supports edges, only vertices and faces. I don't know ply well enough to know if edges are supposed to be supported or not. Looking at a 3D ply mesh generated by microstructpy I don't see any edge elements in the header.
kip-hart commented 3 years ago

No worries, thanks for checking the file. I've removed the edge definition, which results in this file:

ply
format ascii 1.0
element vertex 18
property float32 x
property float32 y
property float32 z
element face 8
property list uchar int vertex_indices
end_header
-5.000000e-01 -4.026508e-01  0.000000e+00
-2.009392e-01  6.476981e-02  0.000000e+00
-5.000000e-01  2.393861e-01  0.000000e+00
-3.520034e-01  2.453039e-01  0.000000e+00
-2.186255e-01  1.377927e-01  0.000000e+00
 5.000000e-01 -5.000000e-01  0.000000e+00
 5.000000e-01  1.135080e-01  0.000000e+00
 4.642275e-01 -5.000000e-01  0.000000e+00
 1.750075e-01 -8.620204e-02  0.000000e+00
 1.732977e-01 -1.435951e-01  0.000000e+00
 3.324293e-01  7.525057e-02  0.000000e+00
-3.328115e-01  5.000000e-01  0.000000e+00
-5.000000e-01  5.000000e-01  0.000000e+00
 6.291911e-02  4.295272e-01  0.000000e+00
 6.724301e-02  5.000000e-01  0.000000e+00
 5.000000e-01  5.000000e-01  0.000000e+00
-1.202258e-01 -5.000000e-01  0.000000e+00
-5.000000e-01 -5.000000e-01  0.000000e+00
5 0 2 3 4 1
6 6 5 7 9 8 10
4 3 2 12 11
5 10 6 15 14 13
3 7 9 16
6 9 16 17 0 1 8
5 4 3 11 14 13
5 8 10 13 4 1

When I run this script:

import matplotlib.pyplot as plt
import meshio
import trimesh

f = 'minimal/polymesh.ply'
m1 = meshio.read(f, file_format='ply')
m2 = trimesh.load(f, file_type='ply')

print('---- meshio')
print(m1)
print('---- trimesh')
print(m2)

# Plot trimesh
plt.clf()
plt.triplot(m2.vertices[:, 0], m2.vertices[:, 1], m2.faces)
plt.plot(m2.vertices[:, 0], m2.vertices[:, 1], '.', color='C1')
plt.axis('equal')
plt.show()

I get the following output:

$ python3.7 plot_ply.py 
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/trimesh/exchange/ply.py:667: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  element_data[name] = np.array(element_data[name]).squeeze()
---- meshio
<meshio mesh object>
  Number of points: 18
  Number of cells:
    polygon5: 4
    polygon6: 2
    quad: 1
    triangle: 1
---- trimesh
<trimesh.Trimesh(vertices.shape=(7, 3), faces.shape=(3, 3))>
Screen Shot 2020-11-11 at 9 27 58 AM

It looks like trimesh is only reading the 3 and 4 sided polygons, and only reading the points connected to them (7 points instead of 18). I can update the ply write function and create a new release, but it looks like trimesh might have a bug with reading ply files with arbitrary polygons.

gundy360 commented 3 years ago

I suppose the tri in trimesh is for triangle. Looks like I'll have to change my tool chain. Thanks for fixing this!

kip-hart commented 3 years ago

I've created a new release with the updated code, v1.4.3, and the ply files should be properly formatted now. It may be the case that trimesh is supposed to accept arbitrary polygons but doesn't really work. There's some evidence of that here (https://github.com/mikedh/trimesh/blob/d72bbd5ac19f8db1c3be8c10c4ce5813d043356c/trimesh/exchange/ply.py#L735-L741). Feel free to re-open the issue if there's a bug in v1.4.3.