Reputation: 83
I have a basic question as i am new to VTK. I have to draw live point cloud data in VTK. I have modified the code given in How to display point cloud in vtk in different colors?.
The pointcloud should update for number of times given in iterations(here 30). I have used Initialize() to avoid blocking control flow as mentioned in some solutions, in every iteration the point cloud is updated, and render() is called so that it can update the window with new data.
I cannot figure out why this is blocking the control flow, and the data is not updated. Only once the iterations are over, after renderWindowInteractor.Start() is called, the interaction is enabled.
import vtk
from numpy import random
class VtkPointCloud:
def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=1e6):
self.maxNumPoints = maxNumPoints
self.vtkPolyData = vtk.vtkPolyData()
self.clearPoints()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(self.vtkPolyData)
mapper.SetColorModeToDefault()
mapper.SetScalarRange(zMin, zMax)
mapper.SetScalarVisibility(1)
self.vtkActor = vtk.vtkActor()
self.vtkActor.SetMapper(mapper)
def addPoint(self, point):
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
pointId = self.vtkPoints.InsertNextPoint(point[:])
self.vtkDepth.InsertNextValue(point[2])
self.vtkCells.InsertNextCell(1)
self.vtkCells.InsertCellPoint(pointId)
else:
r = random.randint(0, self.maxNumPoints)
self.vtkPoints.SetPoint(r, point[:])
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
def clearPoints(self):
self.vtkPoints = vtk.vtkPoints()
self.vtkCells = vtk.vtkCellArray()
self.vtkDepth = vtk.vtkDoubleArray()
self.vtkDepth.SetName('DepthArray')
self.vtkPolyData.SetPoints(self.vtkPoints)
self.vtkPolyData.SetVerts(self.vtkCells)
self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')
def func(pointCloud):
# Renderer
renderer = vtk.vtkRenderer()
renderer.AddActor(pointCloud.vtkActor)
renderer.SetBackground(.2, .3, .4)
renderer.ResetCamera()
# Render Window
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
# Interactor
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
# Begin Interaction
renderWindow.Render()
renderWindowInteractor.Initialize()
return renderWindow,renderWindowInteractor
def main(iter):
while iter > 0:
pointCloud = VtkPointCloud()
for k in xrange(10000):
point = 20*(random.rand(3)-0.5)
pointCloud.addPoint(point)
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
if iter == 30:
renderWindow,renderWindowInteractor = func(pointCloud)
else:
#pointCloud.vtkPolyData.Modified()
renderWindow.Render()
iter -= 1
renderWindowInteractor.Start()
main(30)
Upvotes: 4
Views: 3629
Reputation: 4725
Using suggestion from @nico-vuaille, the solution becomes
import vtk
import numpy as np
from vtk.util.numpy_support import vtk_to_numpy, numpy_to_vtk
from vtk.numpy_interface import dataset_adapter as dsa
class VtkPointCloud:
def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=1e6):
self.maxNumPoints = maxNumPoints
self.vtkPolyData = vtk.vtkPolyData()
self.clearPoints()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(self.vtkPolyData)
mapper.SetColorModeToDefault()
mapper.SetScalarRange(zMin, zMax)
mapper.SetScalarVisibility(1)
self.vtkActor = vtk.vtkActor()
self.vtkActor.SetMapper(mapper)
self.count = 0
def addPoints(self, points):
nPoints = len(points)
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
self.vtkPoints.SetData(dsa.numpyTovtkDataArray(points, "Points"))
depths = points[:,2].flatten()
self.vtkDepth.SetArray(depths,depths.size, True)
self.vtkDepth.array = depths
cells = np.c_[np.ones(nPoints,dtype=np.int64),
np.arange(nPoints)].flatten()
self.vtkCells.SetCells(nPoints, numpy_to_vtk(cells, deep = 1, array_type = vtk.vtkIdTypeArray().GetDataType()))
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
def addPoint(self, point):
# SetNumberOfPoints, SetNumberOfTuples... SetPoint, SetValue
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
pointId = self.vtkPoints.InsertNextPoint(point[:])
self.vtkDepth.InsertNextValue(point[2])
self.vtkCells.InsertNextCell(1)
self.vtkCells.InsertCellPoint(pointId)
else:
r = np.random.randint(0, self.maxNumPoints)
self.vtkPoints.SetPoint(r, point[:])
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
def clearPoints(self):
self.vtkPoints = vtk.vtkPoints()
self.vtkCells = vtk.vtkCellArray()
self.vtkDepth = vtk.vtkDoubleArray()
self.vtkDepth.SetName('DepthArray')
self.vtkPolyData.SetPoints(self.vtkPoints)
self.vtkPolyData.SetVerts(self.vtkCells)
self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')
global lort
class AddPointCloudTimerCallback():
def __init__(self, renderer, iterations):
self.iterations = iterations
self.renderer = renderer
def execute(self, iren, event):
if self.iterations == 0:
iren.DestroyTimer(self.timerId)
pointCloud = VtkPointCloud()
self.renderer.AddActor(pointCloud.vtkActor)
pointCloud.clearPoints()
pointCloud.addPoints(20*(np.random.rand(10000,3) - 0.5))
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
iren.GetRenderWindow().Render()
if self.iterations == 30:
self.renderer.ResetCamera()
self.iterations -= 1
if __name__ == "__main__":
# Renderer
renderer = vtk.vtkRenderer()
renderer.SetBackground(.2, .3, .4)
renderer.ResetCamera()
# Render Window
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
# Interactor
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.Initialize()
# Initialize a timer for the animation
addPointCloudTimerCallback = AddPointCloudTimerCallback(renderer, 100)
renderWindowInteractor.AddObserver('TimerEvent', addPointCloudTimerCallback.execute)
timerId = renderWindowInteractor.CreateRepeatingTimer(10)
addPointCloudTimerCallback.timerId = timerId
# Begin Interaction
renderWindow.Render()
renderWindowInteractor.Start()
Upvotes: 0
Reputation: 333
So you want to do an animation. A better practice is to follow this sample explaining how to do use a TimerEvent.
Here is what it would look like with your code:
import vtk
from numpy import random
class VtkPointCloud:
def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=1e6):
self.maxNumPoints = maxNumPoints
self.vtkPolyData = vtk.vtkPolyData()
self.clearPoints()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(self.vtkPolyData)
mapper.SetColorModeToDefault()
mapper.SetScalarRange(zMin, zMax)
mapper.SetScalarVisibility(1)
self.vtkActor = vtk.vtkActor()
self.vtkActor.SetMapper(mapper)
def addPoint(self, point):
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
pointId = self.vtkPoints.InsertNextPoint(point[:])
self.vtkDepth.InsertNextValue(point[2])
self.vtkCells.InsertNextCell(1)
self.vtkCells.InsertCellPoint(pointId)
else:
r = random.randint(0, self.maxNumPoints)
self.vtkPoints.SetPoint(r, point[:])
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
def clearPoints(self):
self.vtkPoints = vtk.vtkPoints()
self.vtkCells = vtk.vtkCellArray()
self.vtkDepth = vtk.vtkDoubleArray()
self.vtkDepth.SetName('DepthArray')
self.vtkPolyData.SetPoints(self.vtkPoints)
self.vtkPolyData.SetVerts(self.vtkCells)
self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')
class AddPointCloudTimerCallback():
def __init__(self, renderer, iterations):
self.iterations = iterations
self.renderer = renderer
def execute(self, iren, event):
if self.iterations == 0:
iren.DestroyTimer(self.timerId)
pointCloud = VtkPointCloud()
self.renderer.AddActor(pointCloud.vtkActor)
pointCloud.clearPoints()
for k in xrange(10000):
point = 20*(random.rand(3)-0.5)
pointCloud.addPoint(point)
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
pointCloud.addPoint([0,0,0])
iren.GetRenderWindow().Render()
if self.iterations == 30:
self.renderer.ResetCamera()
self.iterations -= 1
if __name__ == "__main__":
# Renderer
renderer = vtk.vtkRenderer()
renderer.SetBackground(.2, .3, .4)
renderer.ResetCamera()
# Render Window
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
# Interactor
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.Initialize()
# Initialize a timer for the animation
addPointCloudTimerCallback = AddPointCloudTimerCallback(renderer, 30)
renderWindowInteractor.AddObserver('TimerEvent', addPointCloudTimerCallback.execute)
timerId = renderWindowInteractor.CreateRepeatingTimer(10)
addPointCloudTimerCallback.timerId = timerId
# Begin Interaction
renderWindow.Render()
renderWindowInteractor.Start()
Note that I renamed iter to iterations because iter is a reserved name in Python.
Upvotes: 3