Skip to content

BoxWidget2

Repository source: BoxWidget2

Description

This example uses a vtkBoxWidget2 to manipulate an actor. The widget only contains the interaction logic; the actual box is drawn by the accompanying vtkBoxRepresentation. Contrary to the older vtkBoxWidget, this widget doesn't provide functionality to assign it to one or more actors, so that has to be implemented manually. The box is dimensioned and positioned by passing a bounding box to the PlaceWidget method, with the SetPlaceFactor method providing a scaling factor in relation to that bounding box. These methods are found in vtkBoxRepresentation. The transformations applied to the box can be used to manipulate any number of object(s), via a custom callback class or function, which is passed to the box widget through the AddObserver method.

The older implementation vtkBoxWidget provides functionality to receive a vtkProp3D for the initial positioning and sizing, but the transformation synchronization still needs to be done manually. See BoxWidget for a simple example of how to use it.

Other languages

See (Cxx)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

BoxWidget2.py

#!/usr/bin/env python3

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonTransforms import vtkTransform
from vtkmodules.vtkFiltersSources import vtkConeSource
from vtkmodules.vtkInteractionWidgets import (
    vtkBoxWidget2,
    vtkBoxRepresentation
)
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)


def get_program_parameters():
    import argparse
    description = 'Demonstrate two ways of using callbacks.'
    epilogue = '''
    '''
    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('-f', '--fn_cb', action='store_false',
                        help='Use a function callback instead of a class callback.')
    args = parser.parse_args()
    return args.fn_cb


def main():
    #  Decide what approach to use.
    use_class_callback = get_program_parameters()

    colors = vtkNamedColors()

    # Create a Cone.
    cone = vtkConeSource(resolution=20)
    cone_mapper = vtkPolyDataMapper()
    cone >> cone_mapper
    cone_actor = vtkActor(mapper=cone_mapper)
    cone_actor.property.color = colors.GetColor3d('BurlyWood')

    # A renderer and render window.
    renderer = vtkRenderer(background=colors.GetColor3d('Blue'))
    renderer.AddActor(cone_actor)

    ren_win = vtkRenderWindow(window_name='BoxWidget2')
    ren_win.AddRenderer(renderer)
    ren_win.SetWindowName('BoxWidget')

    # An interactor.
    interactor = vtkRenderWindowInteractor()
    interactor.render_window = ren_win

    # Define a representation to add to the box widget.
    # Of course, if we create the box widget first, we can bypass this step
    # and use the default representation like this:
    # box_widget.representation.SetPlaceFactor(1.0)
    # box_widget.representation.PlaceWidget(cone_actor.bounds)
    # We use a place_factor of 1.0 to make the box 1.0x larger than the actor.
    representation = vtkBoxRepresentation(place_factor=1.0)
    representation.PlaceWidget(cone_actor.bounds)

    # A Box widget.
    box_widget = vtkBoxWidget2(interactor=interactor, representation=representation)

    # Set up and register the callback with the object that it is observing.
    if use_class_callback:
        box_widget.AddObserver('InteractionEvent', BoxCallback(cone_actor))
        # Or:
        # box_callback = BoxCallback(cone_actor)
        # box_widget.AddObserver('InteractionEvent', box_callback)
    else:
        # We are going to update the cone actor when the event
        #   is triggered, so we add the cone actor as an attribute.
        box_callback.actor = cone_actor
        box_widget.AddObserver('EndInteractionEvent', box_callback)

    # Start
    ren_win.Render()
    # After the render we can turn on the box widget.
    box_widget.On()

    interactor.Start()


class BoxCallback:
    def __init__(self, actor):
        self.actor = actor

    def __call__(self, caller, ev):
        # Just do this to demonstrate who called callback and the event that triggered it.
        # print(caller.class_name, 'Event Id:', ev)
        t = vtkTransform()
        caller.representation.GetTransform(t)
        self.actor.user_transform = t


def box_callback(obj, ev):
    # Just do this to demonstrate who called callback and the event that triggered it.
    # print(obj.class_name, 'Event Id:', ev)
    t = vtkTransform()
    obj.representation.GetTransform(t)
    # Remember to add the actor as an attribute before registering
    # this callback with the object that it is observing.
    box_callback.actor.user_transform = t


if __name__ == '__main__':
    main()