vtkTubeFilter: radius data not used correctly when pointdata changes

Hi there,

I have an issue when using the vtkTubeFilter, it works fine and I am able to render a proper tube with a varying radius. After changing the underlying spline and points, which work fine, the next rendering shows the tube with a constant radius of 0.5. Somehow the radius information must have gotten lost, despite the fact that the polydata still has the active scalar set to the propper array with correct radius values in it.

Here is my code:

import vtk
import time

colors = vtk.vtkNamedColors()
points = vtk.vtkPoints()
points.InsertNextPoint(0, 0, 0)
points.InsertNextPoint(1, 0, 0)
points.InsertNextPoint(2.5, 0, 0)
points.InsertNextPoint(3, 0, 0)


# Fit a spline to the points.
spline = vtk.vtkParametricSpline()
spline.SetPoints(points)
spline.ParameterizeByLengthOff()
functionSource = vtk.vtkParametricFunctionSource()
functionSource.SetParametricFunction(spline)
functionSource.SetUResolution(10 * points.GetNumberOfPoints())
functionSource.Update()

# Interpolate the scalars.
interpolatedRadius = vtk.vtkTupleInterpolator()
interpolatedRadius.SetInterpolationTypeToLinear()
interpolatedRadius.SetNumberOfComponents(1)
interpolatedRadius.AddTuple(0, [.2])
interpolatedRadius.AddTuple(1, [.2])
interpolatedRadius.AddTuple(2, [.2])
interpolatedRadius.AddTuple(3, [.01])

# Generate the radius scalars.
tubeRadius = vtk.vtkDoubleArray()
tubeRadius.SetNumberOfComponents(1)
tubeRadius.SetName("TubeRadius")
num_points = functionSource.GetOutput().GetNumberOfPoints()
tubeRadius.SetNumberOfTuples(num_points)
tMin = interpolatedRadius.GetMinimumT()
tMax = interpolatedRadius.GetMaximumT()
r = [0]
for i in range(num_points):
    t = (tMax - tMin) / (num_points - 1) * i + tMin
    interpolatedRadius.InterpolateTuple(t, r)
    
    tubeRadius.SetTuple1(i, r[0])

# Add the scalars to the polydata.
tube_poly_data = functionSource.GetOutput()
tube_poly_data.GetPointData().AddArray(tubeRadius)
tube_poly_data.GetPointData().SetActiveScalars("TubeRadius")


# Create the tubes.
tube_filter = vtk.vtkTubeFilter()
tube_filter.SetInputData(tube_poly_data)
tube_filter.SetNumberOfSides(64)
tube_filter.SetVaryRadiusToVaryRadiusByAbsoluteScalar()

# Setup actors and mappers.
tube_mapper = vtk.vtkPolyDataMapper()
tube_mapper.SetInputConnection(tube_filter.GetOutputPort())
tube_mapper.ScalarVisibilityOff()

point_colors = vtk.vtkUnsignedCharArray()
point_colors.SetNumberOfComponents(3)
point_colors.SetName('Colors')
point_colors.InsertNextTuple(vtk.vtkNamedColors().GetColor3ub("Blue"))
point_colors.InsertNextTuple(vtk.vtkNamedColors().GetColor3ub("Blue"))
point_colors.InsertNextTuple(vtk.vtkNamedColors().GetColor3ub("Blue"))
point_colors.InsertNextTuple(vtk.vtkNamedColors().GetColor3ub("Blue"))


points_polydata = vtk.vtkPolyData()
points_polydata.SetPoints(points)
points_polydata.GetPointData().SetScalars(point_colors)
points_vertex_glyph_filter = vtk.vtkVertexGlyphFilter()  
points_vertex_glyph_filter.SetInputData(points_polydata)  
points_polydata_mapper = vtk.vtkPolyDataMapper()
points_polydata_mapper.SetInputConnection(points_vertex_glyph_filter.GetOutputPort())


pointActor = vtk.vtkActor()
pointActor.SetMapper(points_polydata_mapper)
pointActor.GetProperty().SetPointSize(10)


line_mapper = vtk.vtkPolyDataMapper()
line_mapper.SetInputConnection(functionSource.GetOutputPort())

lineActor = vtk.vtkActor()
lineActor.SetMapper(line_mapper)
lineActor.GetProperty().SetLineWidth(3)
lineActor.GetProperty().SetColor(colors.GetColor3d("Pink"))

tubeActor = vtk.vtkActor()
tubeActor.SetMapper(tube_mapper)
tubeActor.GetProperty().SetOpacity(0.5)
tubeActor.GetProperty().SetColor(colors.GetColor3d("Green"))

# Setup render window, renderer, and interactor.
renderer = vtk.vtkRenderer()
renderer.UseHiddenLineRemovalOn()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindow.SetSize(640, 480)
renderWindow.SetWindowName("TubesFromSplines")

renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderer.AddActor(lineActor)
renderer.AddActor(tubeActor)
renderer.AddActor(pointActor)

renderer.SetBackground(colors.GetColor3d("SlateGray"))

renderWindow.Render()

print("done....")
time.sleep(1)
print("change points...")

points.SetPoint(1, 1, 0.25, 0.25)

points.Modified()
spline.Modified()

renderWindow.Render()
print("change points...ok")
renderWindowInteractor.Start()

There’s a lot going on in your script … but your title says “when pointdata changes,” makes me think that perhaps you need to update your tube filter? Read David Doria’s answer on SO.

I believe the issue you are having is because of this bit. Here, you are accessing a GetOutput(), which is the data object produced as the output of the tube filter.

With VTK pipelines, whenever the pipeline re-executes, the data objects potentially change. So when you edit the input points to the spline, that means the tube filter produces a different data object. So the points that you added to the data object are no longer there in the pipeline that is displayed.

If you can add the scalar data to the input of a filter, it should be passed through. In your simple example, after calling spline.Modified(), (and you may need to call functionSource.Update(), I’m not sure), if you re-execute those three lines I quoted above, you should see the display you expect. Hope that makes sense!
-Aron

Thanks for the reply,
really appreciate all the answers and effort you (and the previous responder) put in to solve VTK questions.

In the meantime, I did get to the same point by trial and error myself ;0). Although “tube_filter.SetInputData(tube_poly_data)” needs still to be called, since tube_poly_data has changed as well.
Slowly but surely I’m getting the hang of this pipeline thing in VTK.
Will definitely ask questions sooner next time. Took me a while to sign up here in this forum.

Again thanks a lot

Thomas