[vtkusers] (no subject)
Steven Doyle
mesheb82 at gmail.com
Wed Jun 27 16:53:20 EDT 2018
I almost have my code functioning how I'd like it, but it's not quite
there. I'd like to be able to take a vtkUnstructuredGrid and box pick a
set of cells and points and then get their IDs. My code gets the cells
correctly, but gets all the point ids associated with the picked cells
instead of just the ones inside the box.
I read that the AreaPicker is somewhat inaccurate for cells/points, but this
behavior is independent of zoom level. I also read that using a selection
is preferred, but I was unable to figure out how to implement this using a
vtkSelection.
I made an example that sets up a picker. There are two cells. If you box
pick over a single point, I'd expect the code to print a single point ID.
I suspect the error has to do with how I'm using the vtkExtractSelectedFrustum
class, but I'm not positive. Any ideas?
Thanks,
Steve
from __future__ import print_function, division
import signal
import numpy as np
import vtk
from vtk.util.numpy_support import vtk_to_numpy, numpy_to_vtk,
numpy_to_vtkIdTypeArray
# kills the program when you hit Cntl+C from the command line
# doesn't save the current state as presumably there's been an error
signal.signal(signal.SIGINT, signal.SIG_DFL)
class AreaPickStyle(vtk.vtkInteractorStyleRubberBandZoom):
"""Picks nodes & elements with a visible box widget"""
def __init__(self, parent, callback):
"""creates the AreaPickStyle instance"""
self.AddObserver("LeftButtonPressEvent",
self._left_button_press_event)
self.AddObserver("LeftButtonReleaseEvent",
self._left_button_release_event)
self.AddObserver("RightButtonPressEvent",
self.right_button_press_event)
self.parent = parent
self.picker_points = []
self.parent.area_picker.SetRenderer(self.parent.renderer)
self.callback = callback
def _left_button_press_event(self, obj, event):
"""
gets the first point
"""
self.OnLeftButtonDown()
pixel_x, pixel_y =
self.parent.render_window_interactor.GetEventPosition()
self.picker_points.append((pixel_x, pixel_y))
def _left_button_release_event(self, obj, event):
"""
gets the second point and calls _pick_depth_ids
"""
pixel_x, pixel_y =
self.parent.render_window_interactor.GetEventPosition()
self.picker_points.append((pixel_x, pixel_y))
if len(self.picker_points) == 2:
p1x, p1y = self.picker_points[0]
p2x, p2y = self.picker_points[1]
self.picker_points = []
xmin = min(p1x, p2x)
ymin = min(p1y, p2y)
xmax = max(p1x, p2x)
ymax = max(p1y, p2y)
dx = abs(p1x - p2x)
dy = abs(p1y - p2y)
self.picker_points = []
if dx > 0 and dy > 0:
self._pick_depth_ids(xmin, ymin, xmax, ymax)
self.parent.render_window_interactor.Render()
self.picker_points = []
def _pick_depth_ids(self, xmin, ymin, xmax, ymax):
"""
Does an area pick of all the ids inside the box, even the ones
behind the front elements
"""
area_picker = self.parent.area_picker
area_picker.AreaPick(xmin, ymin, xmax, ymax,
self.parent.renderer)
frustum = area_picker.GetFrustum() # vtkPlanes
grid = self.parent.grid
idsname = "Ids"
ids = vtk.vtkIdFilter()
ids.SetInputData(grid)
# default is on; just being explicit
ids.CellIdsOn()
ids.PointIdsOn()
ids.SetIdsArrayName(idsname)
# get the cells/points inside the frustum
selected_frustum = vtk.vtkExtractSelectedFrustum()
selected_frustum.SetFrustum(frustum)
# we just want the ids; don't make an unstructured grid
# return an unstructured grid anyways?
# I think the error is in how I use vtkExtractSelectedFrustum
selected_frustum.PreserveTopologyOn()
selected_frustum.SetInputConnection(ids.GetOutputPort())
selected_frustum.Update()
ugrid = selected_frustum.GetOutput()
cell_ids = None
cells = ugrid.GetCellData()
if cells is not None:
ids = cells.GetArray('Ids')
if ids is not None:
cell_ids = vtk_to_numpy(ids)
assert len(cell_ids) == len(np.unique(cell_ids))
point_ids = None
points = ugrid.GetPointData()
if points is not None:
ids = points.GetArray('Ids')
if ids is not None:
point_ids = vtk_to_numpy(ids)
self.callback(cell_ids, point_ids)
def right_button_press_event(self, obj, event):
"""cancels the button"""
style = vtk.vtkInteractorStyleImage()
self.parent.render_window_interactor.SetInteractorStyle(style)
self.parent.render_window_interactor.Render()
def mixed_type_unstructured_grid():
"""A slightly more complex example of how to generate an
unstructured grid with different cell types. Returns a created
unstructured grid.
"""
pts = np.array([
[0,0,0], [1,0,0], [0,1,0], [0,0,1], # tetra
[2,0,0], [3,0,0], [3,1,0], [2,1,0],
[2,0,1], [3,0,1], [3,1,1], [2,1,1], # Hex
], dtype='float32')
# shift the points so we can show both.
pts[:,1] += 2.0
npoints = len(pts)
# The cells must be int64 because numpy_to_vtkIdTypeArray requires
that.
# I think it depends on what vtkIdTypeArray() was built with.
# nnodes_tetra, (nodes_tetra1)
# nnodes_hexa, (nodes_hexa1)
cells = np.array([
4, 0, 1, 2, 3, # tetra
8, 4, 5, 6, 7, 8, 9, 10, 11 # hex
], dtype='int64')
# The offsets for the cells (i.e., the indices where the cells
start)
# one for each element
cell_offsets = np.array([0, 5], dtype='int32')
# add one element_type for each element
tetra_type = vtk.vtkTetra().GetCellType() # VTK_TETRA == 10
hex_type = vtk.vtkHexahedron().GetCellType() # VTK_HEXAHEDRON == 12
cell_types = np.array([tetra_type, hex_type], dtype='int32')
# Create the array of cells
vtk_cells = vtk.vtkCellArray()
vtk_cells_id_type = numpy_to_vtkIdTypeArray(cells, deep=1)
# ncells = 2
vtk_cells.SetCells(2, vtk_cells_id_type)
# Now create the unstructured grid
ugrid = vtk.vtkUnstructuredGrid()
points_data = numpy_to_vtk(pts, deep=1)
points = vtk.vtkPoints()
points.SetNumberOfPoints(npoints)
points.SetData(points_data)
ugrid.SetPoints(points)
# Now just set the cell types and reuse the ugrid locations and
cells
ugrid.SetCells(
numpy_to_vtk(
cell_types,
deep=1,
array_type=vtk.vtkUnsignedCharArray().GetDataType(),
),
numpy_to_vtk(
cell_offsets,
deep=1,
array_type=vtk.vtkIdTypeArray().GetDataType()
),
vtk_cells,
)
return ugrid
class MyGUI(object):
def __init__(self):
self.area_picker = vtk.vtkAreaPicker()
ugrid = mixed_type_unstructured_grid()
self.grid = ugrid
# Setup render window interactor
self.render_window_interactor = vtk.vtkRenderWindowInteractor()
grid_mapper = vtk.vtkDataSetMapper()
vtk_version = int(vtk.VTK_VERSION[0])
if vtk_version == 5:
grid_mapper.SetInput(ugrid)
elif vtk_version in [6, 7, 8]:
grid_mapper.SetInputData(ugrid)
else:
raise NotImplementedError(vtk.VTK_VERSION)
geom_actor = vtk.vtkActor()
geom_actor.SetMapper(grid_mapper)
# Setup renderer
self.renderer = vtk.vtkRenderer()
self.renderer.AddActor(geom_actor)
self.renderer.ResetCamera()
self.renderer.SetBackground(0.7, 0.8, 1.0)
# Setup render window
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(self.renderer)
# Setup render window
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(self.renderer)
def callback(cell_ids, point_ids):
print('callback: cell_ids = %s' % cell_ids)
print('callback: point_ids = %s' % point_ids)
# Render and start interaction
self.render_window_interactor.SetRenderWindow(render_window)
self.render_window_interactor.Initialize()
style = AreaPickStyle(self, callback)
self.render_window_interactor.SetInteractorStyle(style)
def start(self):
self.render_window_interactor.Start()
def main():
gui = MyGUI()
gui.start()
if __name__ == '__main__':
main()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180627/c9889cd2/attachment.html>
More information about the vtkusers
mailing list