Skip to content

CompassWidget

web-test/Python/Widgets/CompassWidget

Description

This example creates a compass widget in the top right corner of the window. The widget can be used to modify the camera position via its distance and tilt sliders and its heading compass wheel.

Note for this example to work correctly VTK with version >= 9.2.20220831 is required.

Other languages

See (Cxx)

Question

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

Code

CompassWidget.py

#!/usr/bin/env python3

import math
# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonCore import (
    VTK_VERSION_NUMBER,
    vtkCommand,
    vtkMath,
    vtkVersion
)
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkRenderingAnnotation import vtkAnnotatedCubeActor
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkRenderingCore import (
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)

try:
    from vtkmodules.vtkInteractionWidgets import (
        vtkCompassRepresentation,
        vtkCompassWidget
    )
except:
    from vtkmodules.vtkGeovisCore import (
        vtkCompassRepresentation,
        vtkCompassWidget
    )

def vtk_version_ok(major, minor, build):
    """
    Check the VTK version.

    :param major: Major version.
    :param minor: Minor version.
    :param build: Build version.
    :return: True if the requested VTK version is greater or equal to the actual VTK version.
    """
    needed_version = 10000000000 * int(major) \
                     + 100000000 * int(minor) \
                     + int(build)
    try:
        vtk_version_number = VTK_VERSION_NUMBER
    except AttributeError:
        # Expand component-wise comparisons for VTK versions < 8.90.
        ver = vtkVersion()
        vtk_version_number = 10000000000 * ver.GetVTKMajorVersion() \
                             + 100000000 * ver.GetVTKMinorVersion() \
                             + ver.GetVTKBuildVersion()
    if vtk_version_number >= needed_version:
        return True
    else:
        return False

def CompassWidgetValueChangedCallback(widget, event):
    """
    Callback to set the camera position according to the position parameters given by the vtkCompassWidget.
    """
    try:
        camera = widget.GetCurrentRenderer().GetActiveCamera()
    except AttributeError:
        return

    # calculate new camera position from compass widget parameters
    distance = widget.GetDistance()
    tilt = widget.GetTilt()
    heading = widget.GetHeading()

    x = distance * math.cos(vtkMath.RadiansFromDegrees(heading)) * math.cos(vtkMath.RadiansFromDegrees(tilt))
    y = distance * math.sin(vtkMath.RadiansFromDegrees(heading)) * math.cos(vtkMath.RadiansFromDegrees(tilt))
    z = distance * math.sin(vtkMath.RadiansFromDegrees(tilt))

    camera.SetPosition(x, y, z)
    camera.SetFocalPoint(0, 0, 0)
    camera.SetViewUp(0, 0, 1)
    camera.SetClippingRange(0.1, distance + 1)

    widget.GetCurrentRenderer().Render()



def main():
    use_improved_compass_widget = vtk_version_ok(9, 2, 20220831)

    colors = vtkNamedColors()

    actor = vtkAnnotatedCubeActor()
    actor.GetCubeProperty().SetColor(colors.GetColor3d('PeachPuff'))

    # a renderer and render window
    renderer = vtkRenderer()
    renderWindow = vtkRenderWindow()
    renderWindow.AddRenderer(renderer)

    # an interactor
    renderWindowInteractor = vtkRenderWindowInteractor()
    renderWindowInteractor.SetRenderWindow(renderWindow)

    # create the widget and its representation
    compassRepresentation = vtkCompassRepresentation()

    compassWidget = vtkCompassWidget()
    compassWidget.SetInteractor(renderWindowInteractor)
    compassWidget.SetRepresentation(compassRepresentation)

    # add a callback to update the camera position on vtkCommand::WidgetValueChangedEvent
    compassWidget.AddObserver(vtkCommand.WidgetValueChangedEvent, CompassWidgetValueChangedCallback)

    if use_improved_compass_widget:
        compassRepresentation.SetMinimumDistance(2)
        compassRepresentation.SetMaximumDistance(10)
        compassWidget.SetDistance(5)
        compassWidget.SetTiltSpeed(45)
        compassWidget.SetDistanceSpeed(2)

    # add the actors to the scene
    renderer.AddActor(actor)
    renderer.SetBackground(colors.GetColor3d('MidnightBlue'))

    renderWindow.SetSize(640, 480)
    renderWindow.SetWindowName('CompassWidget')

    renderWindow.Render()
    compassWidget.EnabledOn()

    if use_improved_compass_widget:
        # no interactor style - camera is moved by widget callback
        renderWindowInteractor.SetInteractorStyle(None)
        # set camera to initial position
        compassWidget.InvokeEvent(vtkCommand.WidgetValueChangedEvent)

    # begin interaction
    renderWindowInteractor.Start()


if __name__ == '__main__':
    main()