Search code examples
python3dpolygonpyvistastl-format

Disappearing side walls when merging extruded polygons in PyVista


I have a series of polygons that I'm extruding using PyVista. Each extruded polygon represents a 3D shape with side walls. However, when I merge these extruded polygons together using the merge() function, the side walls seem to disappear in the final result.

Here's a simplified version of the code:

import numpy as np
import pyvista as pv

data_x = np.array([[6, 2, 3, 1],
                   [2, 3, 2],
                   [4, 5, 6, ]], dtype=object)

data_y = np.array([[1, 2, 3, 6],
                   [2, 3, 8],
                   [1, 4, 5, ]], dtype=object)

# Create an empty PolyData object
merged = pv.PolyData()

# Create the 3D point array
z = np.zeros_like(data_x[0])
points_3d = np.column_stack((data_x[0], data_y[0], z))

# Create the polygon and extrude it
face = [len(data_x[0])] + list(range(len(data_x[0])))
polygon = pv.PolyData(points_3d, faces=[face])
extrusion = polygon.extrude((0, 0, 1), capping=True)

merged = extrusion

# Loop to vary the value of x
for x in range(len(data_x)):
    # Create the 3D point array
    z = np.zeros_like(data_x[x])
    points_3d = np.column_stack((data_x[x], data_y[x], z))

    # Create the polygon and extrude it
    face = [len(data_x[x])] + list(range(len(data_x[x])))
    polygon = pv.PolyData(points_3d, faces=[face])
    extrusion = polygon.extrude((0, 0, 1), capping=True)

    # Combine the extruded polygon with the previous one
    merged += extrusion

# Save and download the STL file
merged.save('extrusion.stl')
from google.colab import files
files.download('extrusion.stl')

I'm wondering why the side walls disappear in the merged result, while they are present when the polygons are generated individually, this can be tested deleting the loop part and therefore generating only the first (0) polygon.

I'm using the code in Google Colab.

Any help or suggestions would be greatly appreciated!


Solution

  • As a side note, your example is a bit off because you seem to create the first extrusion, then recreate it in the first iteration of the loop. You can just start from merged = pv.PolyData() and merge each extrusion into this.

    As another side note, don't use a numpy array with dtype=object. This may have just been for the sake of your example, but just use a list of arrays (or list of lists) instead.

    As for your problem, it seems you've run into a bug that's just been fixed! Meshes containing triangle strips (as opposed to only faces) were buggy when merging meshes. And extrusion is the most common way to end up with poly strips. If you change your code to have merged += extrusion.triangulate() (which breaks down triangle strips to give you a triangles-only mesh) the artifacts go away. The fix is already there in the currently newest PyVista release 0.39.1. If you can update to that, you don't even have to change your code.

    Here is your example cleaned up a bit:

    import numpy as np
    import pyvista as pv
    
    data_x = [
        [6, 2, 3, 1],
        [2, 3, 2],
        [4, 5, 6],
    ]
    
    data_y = [
        [1, 2, 3, 6],
        [2, 3, 8],
        [1, 4, 5],
    ]
    
    # Create an empty PolyData object
    merged = pv.PolyData()
    
    # Loop to vary the value of x
    for x, y in zip(data_x, data_y):
        # Create the 3D point array
        z = np.zeros_like(x)
        points_3d = np.column_stack((x, y, z))
    
        # Create the polygon and extrude it
        face = [len(x)] + list(range(len(x)))
        polygon = pv.PolyData(points_3d, faces=face)
        extrusion = polygon.extrude((0, 0, 1), capping=True)
    
        # Combine the extruded polygon with the previous one
        #merged += extrusion  # original, buggy before PyVista 0.39.1
        merged += extrusion.triangulate()  # workaround