1

Just to replicate the error, let's consider the succession of points describing a nonconvex polygon:

[0. , 0. , 0. ],
[1. , 0. , 0. ],
[1. , 0.5, 0. ],
[0.5, 0.5, 0. ],
[0.5, 1. , 0. ],
[1. , 1. , 0. ],
[1. , 1.5, 0. ],
[0. , 1.5, 0. ]

This data should represent a nonconvex polygon looking like c shape polygon

But when trying to set this up using PyVista's PolyData constructor, as:

import numpy as np
import pyvista

b = 0.5
c = 0.5
points = np.array([
    [0, 0, 0],
    [1, 0, 0],
    [1, b, 0],
    [1-b, b, 0],
    [1-b, b+c, 0],
    [1, b+c, 0],
    [1, 2*b+c, 0],
    [0, 2*b+c, 0],
])

face = np.concatenate([
    [9],
    np.arange(9),
    [0],
])
polygon = pyvista.PolyData(
    points,
    face)

polygon.plot()

I somehow get a distorted version of it:

c shaped polygon with a triangular artifact in the hole of the "c"

Is there something I'm missing from pyvista documentation?

Franco Milanese
  • 402
  • 3
  • 7

1 Answers1

1

There's a bug in your code but that's not the reason you're seeing this artifact.

The bug in your code is that you have 8 points but use np.arange(9) which has the wrong length and the wrong maximum value (it contains point index 8 at the end which doesn't exist). You can suspect that something's not right from

>>> polygon.n_cells
2

The faces you passed have a trailing zero, which would mean a cell of size 0. The larger issue is the reference to a non-existent point 8 in the first face; I suspect this might even lead to segfaults later.

You can fix this bug by using np.arange(8), or with some future-proofing, with

import numpy as np
import pyvista

b = 0.5
c = 0.5
points = np.array([
    [0, 0, 0],
    [1, 0, 0],
    [1, b, 0],
    [1-b, b, 0],
    [1-b, b+c, 0],
    [1, b+c, 0],
    [1, 2*b+c, 0],
    [0, 2*b+c, 0],
])

face = np.concatenate([
    [points.shape[0] + 1],
    np.arange(points.shape[0]),
    [0],
])
polygon = pyvista.PolyData(points, face)

polygon.plot()

Now, the problem is that the artifact is still there. I've run into this occasionally, and I don't know if it's a PyVista bug or a VTK one (probably the latter). You can switch between a wireframe and a surface model in the plot window by pressing w and s, respectively; it's evident that something's not right because the wireframe looks correct.

But anyway you can get around the issue by breaking down your concave polygon face into triangles using the triangulate() filter:

polygon = pyvista.PolyData(points, face).triangulate()
polygon.plot()

Now this polygon looks correct in a surface render. But of course instead of a single cell it now contains multiple (6) triangles. For most applications this is perfectly fine, in fact there are even filters which only work with triangulated inputs. So this might be a perfectly fine solution to your problem.