Search code examples
python3dgeometrymayavi.mlab

How to properly plot collection of polygons (stl file)?


I have stl file and numpy-stl library. By it own, mesh class have .x, .y, .z properties, which can be plotted

my_mesh = mesh.Mesh.from_file(file)
x = my_mesh.x
y = my_mesh.y
z = my_mesh.z
mlab.points3d(x, y, z)
mlab.show()

The result is slow and pretty bad visually

plot

Also mesh have vectors property but I have no idea how to work with it. In matplotlib I can use:

figure = plt.figure()
axes = mplot3d.Axes3D(figure)
axes.add_collection3d(mplot3d.art3d.Poly3DCollection(my_mesh.vectors))
plt.show()

The result

img

Is working property but terribly slow and pretty much unusable.

Is there a better ways to plot this?


Solution

  • Numpy-stl library loads stl file as numpy array. 'Vectors' attribute is Nx3x3 numpy array. To put it simply this array is collection of faces of the shape. So N stands for number of faces, 3 is number of point to define face of the figure and final dimension represent point coordinates in 3d space.

    In most libraries to plot 3d shape you need to define two things - coordinates of the points and indexes of the points to draw faces of figure.

    numpy-stl simplifies process because all points are unique and in order. That means that index of points to define face is just index in vertex array.

    Also it worth mentioning that you need to define not points itself but x, y, z separately. Same counts for the faces.

    Based on that we cold write this. I choose plotly because it fast and interactive

    import plotly.graph_objects as go
    from stl import mesh  # numpy-stl
    import numpy as np
    
    data = mesh.Mesh.from_file('fabric.stl')
    
    points = data.vectors.reshape(-1,3)  # reshape Nx3x3 to N*3x3 to convert polygons to points
    faces_index = np.arange(len(points))  # get indexes of points
    
    fig = go.Figure(data=[
        go.Mesh3d(
            x = points[:,0],  # pass first column of points array
            y = points[:,1],  # .. second column
            z = points[:,2],  # .. third column
            # i, j and k give the vertices of triangles
            i = faces_index[0::3],  # indexes of the points. k::3 means pass every third element 
            j = faces_index[1::3],  # starting from k element
            k = faces_index[2::3],  # for example 2::3 in arange would be 2,5,8,...
            opacity = .9
        )
    ])
    
    fig.show()
    

    Which would display: plotly plot

    Image from default windows stl file view tool: windows plot

    Result look correct. Please ignore blue dot on the top of the plotly plot and holes near top ring, its the file artifacts and presented in both variants.