Unable to select points without fully selecting cells (VTK 9.3.0)
Below is a minimal working example that showcases this issue in VTK 9.3.0, which I believe didn't happen in previous versions of VTK. (Edit: I can confirm that this was not an issue in VTK 9.2.6)
When using vtkExtractGeometry (USE_EXTRACT_GEOMETRY = True
in the script below), this selection doesn't select anything:
However, this selection works because it selects the whole cell:
When using vtkExtractSelectedFrustum (USE_EXTRACT_GEOMETRY = False
in the script below), this selection selects every point of the intersecting cells, which is not what I want:
Additionally, filter.SetContainingCells
appears to do nothing.
Notes:
- In the images above, the red rectangle represents the rubber band selection.
- When using the script below, press 'r' to start selecting.
- A workaround is possible with
USE_EXTRACT_GEOMETRY = False
andUSE_WORK_AROUND = True
; in this case, the selection works as intended. - To clarify, the objective is to select the points exclusively inside the rubber band, regardless of if a full cell is selected or not; e.g., it is not possible to select the center point only (without the workaround).
Python code that showcases the issue:
import vtkmodules.vtkRenderingContextOpenGL2
from vtkmodules.vtkCommonCore import vtkPoints, vtkCommand
from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid, vtkSelection, vtkPolyData, VTK_QUAD
from vtkmodules.vtkFiltersCore import vtkGlyph3D
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkFiltersGeneral import vtkExtractSelectedFrustum
from vtkmodules.vtkFiltersExtraction import vtkExtractGeometry
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleRubberBandPick
from vtkmodules.vtkRenderingCore import vtkDataSetMapper, vtkActor, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, vtkAreaPicker, vtkPolyDataMapper
# select the filter to use
USE_EXTRACT_GEOMETRY = False
USE_EXTRACT_SELECTED_FRUSTUM = not USE_EXTRACT_GEOMETRY
# work around example
USE_WORK_AROUND = False and USE_EXTRACT_SELECTED_FRUSTUM
class CustomStyle(vtkInteractorStyleRubberBandPick):
def __init__(self):
super().__init__()
self.selecting = False
self.start = (0, 0)
self.stop = (0, 0)
self.AddObserver(vtkCommand.CharEvent, self.onChar)
self.AddObserver(vtkCommand.LeftButtonPressEvent, self.onLeftButtonPress)
self.AddObserver(vtkCommand.LeftButtonReleaseEvent, self.onLeftButtonRelease)
def onChar(self, sender, event):
if self.GetInteractor().GetKeySym() == 'r':
self.selecting = not self.selecting
super().OnChar()
def onLeftButtonPress(self, sender, event):
if self.selecting:
self.start = self.GetInteractor().GetEventPosition()
super().OnLeftButtonDown()
def onLeftButtonRelease(self, sender, event):
if self.selecting:
self.stop = self.GetInteractor().GetEventPosition()
self.pick()
super().OnLeftButtonUp()
def pick(self):
print(f'PICKING FROM {self.start} TO {self.stop}')
# pick
areaPicker = vtkAreaPicker()
areaPicker.AreaPick(*self.start, *self.stop, self.GetCurrentRenderer())
# get data set
for i in range(areaPicker.GetProp3Ds().GetNumberOfItems()):
if (
isinstance(actor := areaPicker.GetProp3Ds().GetItemAsObject(i), vtkActor) and
isinstance(dataSet := actor.GetMapper().GetInput(), vtkUnstructuredGrid)
):
# work around
if USE_WORK_AROUND:
originalDataSet = dataSet
dataSet = vtkUnstructuredGrid()
dataSet.SetPoints(originalDataSet.GetPoints())
# extract selection filter
if USE_EXTRACT_SELECTED_FRUSTUM:
filter = vtkExtractSelectedFrustum()
filter.SetInputData(dataSet)
filter.SetFrustum(areaPicker.GetFrustum())
filter.SetFieldType(vtkSelection.POINT)
filter.SetContainingCells(False) # setting this to True or False changes nothing
filter.Update()
if USE_EXTRACT_GEOMETRY:
filter = vtkExtractGeometry()
filter.SetImplicitFunction(areaPicker.GetFrustum())
filter.SetInputData(dataSet)
filter.Update()
# selection data set
selection = filter.GetOutput()
# debug
print(f'SELECTED POINTS: {selection.GetNumberOfPoints()}')
print(f'SELECTED CELLS: {selection.GetNumberOfCells()}')
# render selection...
polyData = vtkPolyData()
polyData.SetPoints(selection.GetPoints())
sphereSource = vtkSphereSource()
sphereSource.SetRadius(0.1)
glyph = vtkGlyph3D()
glyph.SetInputData(polyData)
glyph.SetSourceConnection(sphereSource.GetOutputPort())
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(glyph.GetOutputPort())
actor = vtkActor()
actor.SetObjectName('__TEMP__')
actor.SetMapper(mapper)
actor.GetProperty().SetColor(1.0, 0.0, 0.0)
for j in range(self.GetCurrentRenderer().GetActors().GetNumberOfItems()):
if (
isinstance(existing_actor := self.GetCurrentRenderer().GetActors().GetItemAsObject(j), vtkActor) and
existing_actor.GetObjectName() == '__TEMP__'
):
self.GetCurrentRenderer().RemoveActor(existing_actor)
self.GetCurrentRenderer().AddActor(actor)
self.GetInteractor().GetRenderWindow().Render()
# end render selection
# points
points = vtkPoints()
points.SetNumberOfPoints(25)
points.SetPoint( 0, 0.0, 0.0, 0.0)
points.SetPoint( 1, 1.0, 0.0, 0.0)
points.SetPoint( 2, 2.0, 0.0, 0.0)
points.SetPoint( 3, 3.0, 0.0, 0.0)
points.SetPoint( 4, 4.0, 0.0, 0.0)
points.SetPoint( 5, 0.0, 1.0, 0.0)
points.SetPoint( 6, 1.0, 1.0, 0.0)
points.SetPoint( 7, 2.0, 1.0, 0.0)
points.SetPoint( 8, 3.0, 1.0, 0.0)
points.SetPoint( 9, 4.0, 1.0, 0.0)
points.SetPoint(10, 0.0, 2.0, 0.0)
points.SetPoint(11, 1.0, 2.0, 0.0)
points.SetPoint(12, 2.0, 2.0, 0.0)
points.SetPoint(13, 3.0, 2.0, 0.0)
points.SetPoint(14, 4.0, 2.0, 0.0)
points.SetPoint(15, 0.0, 3.0, 0.0)
points.SetPoint(16, 1.0, 3.0, 0.0)
points.SetPoint(17, 2.0, 3.0, 0.0)
points.SetPoint(18, 3.0, 3.0, 0.0)
points.SetPoint(19, 4.0, 3.0, 0.0)
points.SetPoint(20, 0.0, 4.0, 0.0)
points.SetPoint(21, 1.0, 4.0, 0.0)
points.SetPoint(22, 2.0, 4.0, 0.0)
points.SetPoint(23, 3.0, 4.0, 0.0)
points.SetPoint(24, 4.0, 4.0, 0.0)
# unstructured grid
ugrid = vtkUnstructuredGrid()
ugrid.SetPoints(points)
ugrid.AllocateExact(25, 4)
ugrid.InsertNextCell(VTK_QUAD, 4, ( 0, 1, 6, 5))
ugrid.InsertNextCell(VTK_QUAD, 4, ( 1, 2, 7, 6))
ugrid.InsertNextCell(VTK_QUAD, 4, ( 2, 3, 8, 7))
ugrid.InsertNextCell(VTK_QUAD, 4, ( 3, 4, 9, 8))
ugrid.InsertNextCell(VTK_QUAD, 4, ( 5, 6, 11, 10))
ugrid.InsertNextCell(VTK_QUAD, 4, ( 6, 7, 12, 11))
ugrid.InsertNextCell(VTK_QUAD, 4, ( 7, 8, 13, 12))
ugrid.InsertNextCell(VTK_QUAD, 4, ( 8, 9, 14, 13))
ugrid.InsertNextCell(VTK_QUAD, 4, (10, 11, 16, 15))
ugrid.InsertNextCell(VTK_QUAD, 4, (11, 12, 17, 16))
ugrid.InsertNextCell(VTK_QUAD, 4, (12, 13, 18, 17))
ugrid.InsertNextCell(VTK_QUAD, 4, (13, 14, 19, 18))
ugrid.InsertNextCell(VTK_QUAD, 4, (15, 16, 21, 20))
ugrid.InsertNextCell(VTK_QUAD, 4, (16, 17, 22, 21))
ugrid.InsertNextCell(VTK_QUAD, 4, (17, 18, 23, 22))
ugrid.InsertNextCell(VTK_QUAD, 4, (18, 19, 24, 23))
ugrid.Squeeze()
# mapper
mapper = vtkDataSetMapper()
mapper.SetInputData(ugrid)
# actor
actor = vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().EdgeVisibilityOn()
# renderer
ren = vtkRenderer()
ren.AddActor(actor)
# render window
renWin = vtkRenderWindow()
renWin.AddRenderer(ren)
# interactor style
istyle = CustomStyle()
# interactor
iren = vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
iren.SetInteractorStyle(istyle)
# start
renWin.Render()
iren.Start()
Edited by Carlos Souto