EllipticalButton
Repository source: EllipticalButton
Description¶
This example creates a 3D button using vtkEllipsoidalButton. Interaction is done by assigning the button to a vtkProp3DButtonRepresentation. Then a callback for a vtkButtonWidget controls the color of the button and the displayed geometry. Click on the button to see the color of both the button and geometry change.
Warning
There is a bug in vtkEllipticalButtonSource. If CircumferentialResolution is odd, improper geometry is created.
Warning
Values close to 1.0 for RadialRatio can cause shading artifacts at the corners of the button.
Other languages
See (Cxx)
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
EllipticalButton.py
#!/usr/bin/env python3
from dataclasses import dataclass
from pathlib import Path
# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingFreeType
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonExecutionModel import vtkAlgorithm
from vtkmodules.vtkFiltersSources import (
vtkEllipticalButtonSource,
vtkSuperquadricSource
)
from vtkmodules.vtkIOImage import vtkImageReader2Factory
from vtkmodules.vtkInteractionWidgets import (
vtkButtonWidget,
vtkProp3DButtonRepresentation
)
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderer,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkTexture
)
def get_program_parameters():
import argparse
description = 'Elliptical Button.'
epilogue = '''
'''
parser = argparse.ArgumentParser(description=description, epilog=epilogue,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('file_name', help='The image filename e.g. YinYang.png')
args = parser.parse_args()
return args.file_name
def main():
color = vtkNamedColors()
file_name = get_program_parameters()
fn = Path(file_name)
if not fn.is_file():
print(f'{fn}\nNot found.')
return
source = vtkSuperquadricSource(phi_resolution=64, theta_resolution=64, theta_roundness=1.5, thickness=1.5, size=2)
mapper = vtkPolyDataMapper()
source >> mapper
actor = vtkActor(mapper=mapper)
renderer = vtkRenderer(background=color.GetColor3d('Burlywood'))
renderer.AddActor(actor)
render_window = vtkRenderWindow(size=(200, 200), window_name='EllipticalButton')
render_window.AddRenderer(renderer)
render_window_interactor = vtkRenderWindowInteractor()
render_window_interactor.render_window = render_window
# Create the widget and its representation.
button_actor1 = create_button_actor(fn)
button_actor1.property.color = color.GetColor3d('Tomato')
button_actor2 = create_button_actor(fn)
button_actor2.property.color = color.GetColor3d('Banana')
button_representation = vtkProp3DButtonRepresentation(follow_camera=True)
button_representation.SetNumberOfStates(2)
button_representation.SetButtonProp(0, button_actor1)
button_representation.SetButtonProp(1, button_actor2)
render_window_interactor.Initialize()
button_callback = ButtonCallback(actor)
actor.property.color = button_representation.GetButtonProp(0).property.color
button_widget = vtkButtonWidget(interactor=render_window_interactor, representation=button_representation,
enabled=True)
button_widget.AddObserver('StateChangedEvent', button_callback.on_button_callback)
renderer.ResetCamera()
renderer.Render()
render_window_interactor.Start()
def create_button_actor(texture_file):
# Read the image.
reader = vtkImageReader2Factory().CreateImageReader2(str(texture_file))
reader.file_name = texture_file
reader.update()
# Aspect ratio of the image.
dims = reader.output.dimensions
aspect = float(dims[0]) / float(dims[1])
texture = vtkTexture()
reader >> texture
elliptical_button_source = vtkEllipticalButtonSource(
circumferential_resolution=50, shoulder_resolution=10, texture_resolution=10,
radial_ratio=1.05, shoulder_texture_coordinate=(0.0, 0.0),
texture_dimensions=(dims[0], dims[1]),
texture_style=ButtonSource.TextureStyle.VTK_TEXTURE_STYLE_PROPORTIONAL,
two_sided=True, width=aspect, height=1.0, depth=0.15, center=(2, 2, 0),
output_points_precision=vtkAlgorithm.SINGLE_PRECISION)
button_mapper = vtkPolyDataMapper()
elliptical_button_source >> button_mapper
button_actor = vtkActor(mapper=button_mapper, texture=texture)
return button_actor
class ButtonCallback:
def __init__(self, actor):
self.actor = actor
def on_button_callback(self, caller, event):
button_widget = caller
rep = button_widget.representation
state = rep.state
self.actor.property.color = rep.GetButtonProp(state).property.color
print(f'State: {state}')
@dataclass(frozen=True)
class ButtonSource:
@dataclass(frozen=True)
class TextureStyle:
VTK_TEXTURE_STYLE_FIT_IMAGE: int = 0
VTK_TEXTURE_STYLE_PROPORTIONAL: int = 1
if __name__ == '__main__':
main()