However, the way the piping works has confused me. It seems that the last vmtkSurfaceViewer not only receive a surface (foo.vtp) from its previous vmtkSurfaceViewer, but also the centerline as a second input.
Is there any way to do the same thing in Python’s object-oriented manner?
To answer my own question,
After reading vmtkSurfaceViewer()'s source code, I still feel its piping too complicated to understand.
However, I use VTK’s functions instead to combine polydata (surfaces and centerlines) first. The combined data is then fed into vmtkRenderer(). VTK’s own Renderer is also available, but I prefer VMTK’s.
The following is my code. Part of it referenced this post. It allows setting color and opacity for each polydata. Readers are vmtkSurfaceReader()s.
class PolydataViewer():
def __init__(self):
self.appendFilter = vtk.vtkAppendPolyData()
def add_polydata(self, polydata, color=[255, 255, 255], opacity=1):
colors = vtk.vtkUnsignedCharArray()
colors.SetNumberOfComponents(4)
colors.SetName("DisplayColor")
colors.SetNumberOfTuples(polydata.GetNumberOfCells())
for c in range(polydata.GetNumberOfCells()):
colors.SetTuple(c, (*color, int(opacity * 255)))
polydata.GetCellData().AddArray(colors)
self.appendFilter.AddInputData(polydata)
def show(self, background=None):
self.appendFilter.Update()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(self.appendFilter.GetOutputPort())
mapper.SetScalarModeToUseCellFieldData()
mapper.SelectColorArray('DisplayColor')
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vmtk.vmtkrenderer.vmtkRenderer()
renderer.Initialize()
if background is not None:
renderer.Renderer.SetBackground(np.array(background) / 255)
renderer.Renderer.AddActor(actor)
renderer.Render()
renderer.Deallocate()
viewer = PolydataViewer()
viewer.add_polydata(reader1.Surface, color=[255, 0, 0], opacity=0.3)
viewer.add_polydata(reader2.Surface, color=[255, 255, 0])
viewer.show()