A simple question that hopefully can be answered with a single link:
How to split a polyline into its n linear segments?
Let’s be given a polyline like the one that results from the PolyLine example. Is there a vtk filter producing a vtkPolyData object with n lines from this input? It’s sort of the inverse filter of vtkStripper that is able to join multiple line segments into a single polyline.
Here’s what I came up with, though I’m pretty convinced that there’re better approaches:
def polylineToMultiline(polyline):
# Assumption: points appear in the correct order: p0->p1->p2->p3...
points = polyline.GetPoints()
nPoints = points.GetNumberOfPoints()
cells = vtk.vtkCellArray()
for i in range(nPoints-1):
line = vtk.vtkLine()
line.GetPointIds().SetId(0,i)
line.GetPointIds().SetId(1,i+1)
cells.InsertNextCell(line)
poly = vtk.vtkPolyData()
poly.SetPoints(points)
poly.SetLines(cells)
return poly
The above code assumes that the points from the polyline appear in the correct order. Note that this is not the case in general! To extract the points in the correct order, you would have to do something like the following:
def extractConsecutivePoints(poly):
# Travers the line(s) and add points while keeping their order.
cells = poly.GetLines()
cells.InitTraversal()
idList = vtk.vtkIdList()
points = vtk.vtkPoints()
while cells.GetNextCell(idList):
for i in range(0, idList.GetNumberOfIds()):
pId = idList.GetId(i)
points.InsertNextPoint(poly.GetPoint(pId))
return points
Here is a routine to do it with PyVista since you are using Python. This will work regardless of point ordering.
import pyvista as pv
import numpy as np
def segment_poly_cells(mesh):
"""`mesh` is a PyVista PolyData object
(wrapped vtkPolyData)
"""
if not pv.is_pyvista_dataset(mesh):
mesh = pv.wrap(mesh)
polylines = []
i, offset = 0, 0
cc = mesh.lines # fetch up front
while i < mesh.n_cells:
nn = cc[offset]
polylines.append(cc[offset+1:offset+1+nn])
offset += nn + 1
i += 1
#
lines = []
for poly in polylines:
lines.append(np.column_stack((poly[:-1], poly[1:])))
lines = np.vstack(lines)
cells = np.column_stack((np.full(len(lines), 2), lines))
segmented = pv.PolyData()
segmented.points = mesh.points
segmented.lines = cells
return segmented
So if you have some vtkPolyData already, just do the folling and a new vtkPolyData mesh will be returned.
The lines property on pyvista.PolyData objects is just a NumPy wrapper around vtk.vtkPolyData.GetLines().GetData() and it is exactly what you have listed above. As a way to get all of the point IDs for each line in the mesh
… [vtkTriangleFilter] also generates line segments from polylines unless PassLines is off, and generates individual vertex cells from vtkVertex point lists unless PassVerts is off.
The remaining question: vtkTriangleFilter to apply an operation on a polyline, what the hack?! It’s sometimes so difficult to find the right method in vtk.
import pyvista as pv
from pyvista import examples
# Example mesh with a single PolyLine cell
polyline = examples.load_spline()
# use vtk.vtkTriangleFilter to create lines
lines = polyline.triangulate()