Box picking point ids

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Box picking point ids

steve9
This post was updated on .
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()

_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Please keep messages on-topic and check the VTK FAQ at: http://www.vtk.org/Wiki/VTK_FAQ

Search the list archives at: http://markmail.org/search/?q=vtkusers

Follow this link to subscribe/unsubscribe:
https://public.kitware.com/mailman/listinfo/vtkusers