123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- import vtk
- class ButtonCallback(object):
- def __init__(self, renderer, actor1):
- self.renderer = renderer
- self.actor1 = actor1
- def execute(self, obj, event):
- print("Button was clicked!")
- # Move actor1
- if self.actor1:
- current_position = self.actor1.GetPosition()
- self.actor1.SetPosition(current_position[0] + 0.1, current_position[1], current_position[2])
- self.renderer.GetRenderWindow().Render()
- class MyInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
- def __init__(self, parent=None):
- super().__init__()
- self.AddObserver("LeftButtonPressEvent", self.left_button_press)
- self.actor1 = None
- self.actor2 = None
- self.label1 = None
- self.label2 = None
- def left_button_press(self, obj, event):
- try:
- click_pos = self.GetInteractor().GetEventPosition()
- print(f'left_button_press({click_pos[0]}, {click_pos[1]})')
- # Get the default renderer
- renderer = self.GetDefaultRenderer()
- if renderer is None:
- print("Error: Default renderer is None")
- return
- # Create a picker and perform picking
- picker = vtk.vtkPropPicker()
- picker.Pick(click_pos[0], click_pos[1], 0, renderer)
- # Get the picked actor
- picked_actor = picker.GetActor()
- if picked_actor is None:
- print("No actor was picked")
- elif picked_actor == self.actor1:
- print("Actor 1 was picked")
- # Define the movement of actor2
- self.actor2.SetPosition(self.actor2.GetPosition()[0] + 0.1,
- self.actor2.GetPosition()[1],
- self.actor2.GetPosition()[2])
- elif picked_actor == self.actor2:
- print("Actor 2 was picked")
- # Define the movement of actor1
- self.actor1.SetPosition(self.actor1.GetPosition()[0] + 0.1,
- self.actor1.GetPosition()[1],
- self.actor1.GetPosition()[2])
- else:
- print("Some other actor was picked")
- self.GetInteractor().Render()
- except Exception as e:
- print(f"An error occurred: {e}")
- def create_button(renderer, callback, position, size, label):
- # Create a TextActor to display the button text
- text_actor = vtk.vtkTextActor()
- text_property = vtk.vtkTextProperty()
- text_property.SetFontFamilyToArial()
- text_property.SetFontSize(12)
- text_property.BoldOn()
- text_property.ItalicOff()
- text_property.ShadowOn()
- text_property.SetJustificationToCentered()
- text_property.SetColor(0, 0, 0) # Text color
- text_actor.SetInput(label)
- text_actor.SetTextProperty(text_property)
- # Calculate text position, center it
- text_actor.SetDisplayPosition(position[0] + size[0] // 2, position[1] + size[1] // 2 - 10)
- # Create an ImageData to create the background image
- width, height = size
- image_data = vtk.vtkImageData()
- image_data.SetDimensions(width, height, 1)
- image_data.SetSpacing(1, 1, 1)
- image_data.SetOrigin(0, 0, 0)
- image_data.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 4)
- colors = vtk.vtkNamedColors()
- background_color = colors.GetColor4ub("LightGray")
- highlight_color = colors.GetColor4ub("LightBlue")
- # Set the default background color
- scalars = image_data.GetPointData().GetScalars()
- for y in range(height):
- for x in range(width):
- offset = y * width + x
- scalars.SetTuple4(offset, background_color[0], background_color[1], background_color[2], background_color[3])
- # Create an ImageMapper to create the background image
- image_mapper = vtk.vtkImageMapper()
- image_mapper.SetInputData(image_data)
- # Create an ImageActor to display the background image
- background_actor = vtk.vtkImageActor()
- background_actor.SetMapper(image_mapper)
- # Set background position
- background_actor.SetDisplayPosition(position[0], position[1])
- # Set interaction representation
- button_rep = vtk.vtkButtonRepresentation2D()
- button_rep.SetPlaceFactor(1.0)
- button_rep.PlaceWidget(position, [size[0], size[1]])
- # Create a ButtonWidget to manage button interaction
- button = vtk.vtkButtonWidget()
- button.SetInteractor(renderer.GetRenderWindow().GetInteractor())
- button.SetRepresentation(button_rep)
- button.AddObserver("StateChangedEvent", callback)
- # Enable the button
- button.On()
- # Update background color to reflect button state
- def update_button_state(obj, event):
- state = button_rep.GetState()
- if state == 0: # Normal state
- color = background_color
- else: # Highlight state
- color = highlight_color
- scalars = image_data.GetPointData().GetScalars()
- for y in range(height):
- for x in range(width):
- offset = y * width + x
- scalars.SetTuple4(offset, color[0], color[1], color[2], color[3])
- image_data.Modified()
- renderer.GetRenderWindow().Render()
- button.AddObserver("StateChangedEvent", update_button_state)
- # Add text and background to renderer
- renderer.AddActor2D(text_actor)
- renderer.AddActor2D(background_actor)
- return button
- def read_and_display_stl(file_path1, file_path2):
- # Read the first STL model
- reader1 = vtk.vtkSTLReader()
- reader1.SetFileName(file_path1)
- mapper1 = vtk.vtkPolyDataMapper()
- mapper1.SetInputConnection(reader1.GetOutputPort())
- actor1 = vtk.vtkActor()
- actor1.SetMapper(mapper1)
- # Create label
- text_property1 = vtk.vtkTextProperty()
- text_property1.SetFontFamilyToArial()
- text_property1.SetFontSize(16)
- text_property1.BoldOn()
- text_property1.ItalicOff()
- text_property1.ShadowOn()
- label1 = vtk.vtkTextActor()
- label1.SetInput("Model 1")
- label1.SetTextProperty(text_property1)
- label1.SetDisplayPosition(50, 50) # Set position
- # Read the second STL model
- reader2 = vtk.vtkSTLReader()
- reader2.SetFileName(file_path2)
- mapper2 = vtk.vtkPolyDataMapper()
- mapper2.SetInputConnection(reader2.GetOutputPort())
- actor2 = vtk.vtkActor()
- actor2.SetMapper(mapper2)
- # Create label
- text_property2 = vtk.vtkTextProperty()
- text_property2.SetFontFamilyToArial()
- text_property2.SetFontSize(16)
- text_property2.BoldOn()
- text_property2.ItalicOff()
- text_property2.ShadowOn()
- label2 = vtk.vtkTextActor()
- label2.SetInput("Model 2")
- label2.SetTextProperty(text_property2)
- label2.SetDisplayPosition(50, 100) # Set position
- renderer = vtk.vtkRenderer()
- renderer.AddActor(actor1)
- renderer.AddActor(actor2)
- renderer.AddActor2D(label1) # Add label to renderer
- renderer.AddActor2D(label2) # Add label to renderer
- render_window = vtk.vtkRenderWindow()
- render_window.AddRenderer(renderer)
- render_window.SetSize(800, 600) # Set window size to 800x600
- interactor = vtk.vtkRenderWindowInteractor()
- interactor.SetRenderWindow(render_window)
- # Set custom interaction style
- style = MyInteractorStyle()
- style.actor1 = actor1
- style.actor2 = actor2
- style.label1 = label1
- style.label2 = label2
- interactor.SetInteractorStyle(style)
- # Set default renderer
- style.SetDefaultRenderer(renderer)
- # Create button
- callback = ButtonCallback(renderer, actor1)
- button1 = create_button(renderer, callback.execute, (100, 550), (100, 30), "Move Actor 1")
- interactor.Initialize()
- interactor.Start()
- if __name__ == "__main__":
- # Replace with your two STL file paths
- stl_file_path1 = "tetrahedron.stl"
- stl_file_path2 = "tetrahedron.stl"
- read_and_display_stl(stl_file_path1, stl_file_path2)
|