salad-demo / salad /spaghetti /ui /interactors.py
DveloperY0115's picture
init repo
801501a
from __future__ import annotations
import abc
import vtk
from custom_types import *
from ui import ui_utils, ui_controllers
import colorsys
import options
class CustomTextWidget(vtk.vtkTextWidget):
def set_to_start(self):
# self.EnabledOff()
h, s, v = colorsys.rgb_to_hsv(*ui_utils.button_color)
self.GetTextActor().GetTextProperty().SetColor(*ui_utils.rgb_to_float(colorsys.hsv_to_rgb(h, .3, 255)))
# self.EnabledOn()
self.GetInteractor().Render()
self.on = False
def set_to_stop(self):
# self.EnabledOff()
h, s, v = colorsys.rgb_to_hsv(*ui_utils.button_color)
self.GetTextActor().GetTextProperty().SetColor(*ui_utils.rgb_to_float(colorsys.hsv_to_rgb(h, .9, 255)))
# self.EnabledOn()
self.GetInteractor().Render()
self.on = True
def left_button_press_event(self, obj, event):
self.on_click(self)
def hover(self, obj, event):
print(self.b_type.value)
def toggle_selection(self):
if self.on:
self.set_to_start()
else:
self.set_to_stop()
def __init__(self, b_type: ui_utils.Buttons, position, size, interactor: vtk.vtkRenderWindowInteractor, ren: vtk.vtkRenderer, on_click):
super(CustomTextWidget, self).__init__()
self.ren = ren
self.on_click = on_click
self.SetInteractor(interactor)
text_actor = vtk.vtkTextActor()
text_representation = vtk.vtkTextRepresentation()
self.SetRepresentation(text_representation)
self.SetTextActor(text_actor)
self.GetRepresentation().SetRenderer(self.ren)
self.SetCurrentRenderer(self.ren)
self.GetTextActor().SetInput(b_type.value)
self.GetRepresentation().GetPositionCoordinate().SetValue(*position)
self.set_to_start()
# self.Set
self.SelectableOn()
self.SetResizable(0)
self.EnabledOn()
self.On()
self.AddObserver(vtk.vtkCommand.EndInteractionEvent, self.left_button_press_event)
self.AddObserver(vtk.vtkCommand.HoverEvent, self.hover)
self.on = False
self.b_type = b_type
self.GetRepresentation().GetPosition2Coordinate().SetValue(*size)
def get_selection(self) -> ui_utils.Buttons:
return self.select
class InteractorStyle(vtk.vtkInteractorStyleTrackballCamera, abc.ABC):
@abc.abstractmethod
def init_renders(self) -> List[vtk.vtkRenderer]:
raise NotImplementedError
@abc.abstractmethod
def button_release_event(self, to_do):
raise NotImplementedError
@abc.abstractmethod
def draw_end(self):
raise NotImplementedError
@property
def stage(self) -> ui_controllers.GmmMeshStage:
return self.status.main_stage
@property
def canvas(self):
if self.draw_view == -1:
return None
return self.renders[self.draw_view]
@property
def interactor(self):
return self.GetInteractor()
class MouseStatus:
def update(self, pos: Tuple[int, int], selected_view: int) -> bool:
is_changed = selected_view != self.selected_view or (pos[0] - self.last_pos[0]) ** 2 > 4 and (
pos[1] - self.last_pos[1]) ** 2 > 4
self.selected_view = selected_view
self.last_pos = pos
return is_changed
def __init__(self):
self.last_pos = (0, 0)
self.selected_view = 0
def change_opacity(self, sphere_ids: List[int], is_left: bool, on: bool):
actors = self.renders[self.selected_view].GetActors()
for sphere_ids in sphere_ids:
properties = actors.GetItemAsObject(sphere_ids).GetProperty()
properties.SetOpacity(float(on))
def slider_event(self, slider, event):
value = slider.GetRepresentation().GetValue()
value = value / 100.
self.stage.set_opacity(value)
return
def get_cur_view(self):
cur_render = self.GetCurrentRenderer()
if cur_render is None:
return -1, cur_render
return self.rend_to_view[cur_render.GetAddressAsString("")], cur_render
def update_default(self):
click_pos = self.interactor.GetEventPosition()
picker = vtk.vtkPropPicker()
cur_view, cur_render = self.get_cur_view()
if cur_view != self.selected_view:
# self.SetDefaultRenderer(self.renders[cur_view])
self.selected_view = cur_view
elif cur_render is None:
return None, False, click_pos
picker.Pick(click_pos[0], click_pos[1], 0, cur_render)
return picker, self.mouse_status.update((click_pos[0], click_pos[1]), cur_view), click_pos
def get_trace(self):
picker, is_changed, pos_2d = self.update_default()
if picker is not None:
points = self.canvas.draw(pos_2d)
actors = []
for point in points:
picker.Pick(point[0], point[1], 0, self.canvas)
actors.append(picker.GetActor())
self.status.vote(*actors)
self.interactor.Render()
return 0
def on_key_press(self, obj, event):
key = self.interactor.GetKeySym()
if type(key) is not str:
return
key: str = key.lower()
if self.pondering:
if key in ('g', 'r'):
self.edit_status = {'g': ui_utils.EditType.Translating,
'r': ui_utils.EditType.Rotating,
's': ui_utils.EditType.Scaling}[key]
click_pos = self.interactor.GetEventPosition()
self.status.init_transition(click_pos, self.edit_status)
elif key == 'escape':
if self.status.clear_selection():
self.interactor.Render()
elif self.in_transition:
if key == 'escape':
self.status.temporary_transition()
self.interactor.Render()
self.edit_status = ui_utils.EditType.Pondering
elif key in ('x', 'y', 'z'):
self.status.toggle_edit_direction({'x': ui_utils.EditDirection.X_Axis,
'y': ui_utils.EditDirection.Y_Axis,
'z': ui_utils.EditDirection.Z_Axis}[key])
if key == 'return' or key == 'kp_enter':
self.status.save()
# elif key in ("left", "right", "up", "down", "a", "z"):
# if self.status.update_gmm(ui_utils.Buttons.translate, key):
# self.status.update_mesh()
# self.interactor.Render()
# axis = {"left": 0, "right", "up", "down", "a", "z")
elif key == 'control_l':
self.status.replace_mesh()
self.interactor.Render()
return
def draw_init(self):
self.status.init_draw(self.draw_view)
def left_button_release_event(self, obj, event):
if self.pondering:
# self.button_release_event(self.status.event_manger)
self.OnLeftButtonUp()
def left_button_press_event(self, obj, event):
if self.pondering:
_ = self.update_default()
self.OnLeftButtonDown()
elif self.in_transition:
click_pos = self.interactor.GetEventPosition()
if self.status.end_transition(click_pos):
self.status.update_mesh()
self.edit_status = ui_utils.EditType.Pondering
def right_button_release_event(self, obj, event):
if self.marking:
self.draw_end()
self.edit_status = ui_utils.EditType.Pondering
def right_button_press_event(self, obj, event):
self.OnRightButtonDown()
self.OnRightButtonUp()
_ = self.update_default()
if -1 < self.selected_view and self.pondering:
self.draw_view = self.selected_view
self.draw_init()
self.edit_status = ui_utils.EditType.Marking
def on_mouse_move(self, obj, event):
if self.marking:
self.get_trace()
elif self.in_transition:
click_pos = self.interactor.GetEventPosition()
if self.status.temporary_transition(click_pos):
self.interactor.Render()
else:
super(InteractorStyle, self).OnMouseMove()
def toggle_symmetric(self, _, __):
self.status.toggle_symmetric()
self.interactor.Render()
def toggle_arrows(self, button, __):
self.status.switch_arrows({0: ui_utils.Buttons.translate, 1: ui_utils.Buttons.rotate}[button.GetRepresentation().GetState()])
self.interactor.Render()
def reset(self, obj, event):
self.status.reset()
self.interactor.Render()
def toggle_select_mode(self, button, __):
self.select_mode = button.GetRepresentation().GetState() == 0
self.status.set_brush(self.select_mode)
self.interactor.Render()
def add_buttons(self, interactor):
button_pencil = ui_utils.ImageButton(["../assets/ui_resources/icons-03.png", "../assets/ui_resources/icons-04.png"],
ui_utils.bg_menu_color, interactor, (.1, .1), (0.24, 0.15),
interactor.GetRenderWindow(), self.toggle_select_mode)
button_symmetric = ui_utils.ImageButton(["../assets/ui_resources/icons-08.png", "../assets/ui_resources/icons-09.png"],
ui_utils.bg_menu_color, interactor, (.1, .1), (0.3, 0.15),
interactor.GetRenderWindow(), self.toggle_symmetric)
button_reset = ui_utils.ImageButton(["../assets/ui_resources/icons-05.png"], ui_utils.bg_menu_color, interactor,
(.1, .1), (0.35, .15), interactor.GetRenderWindow(), self.reset)
slider_widget, _ = ui_utils.make_slider(interactor, self.slider_event)
return button_pencil, button_symmetric, button_reset, slider_widget
@property
def marking(self) -> bool:
return self.edit_status == ui_utils.EditType.Marking
@property
def pondering(self) -> bool:
return self.edit_status == ui_utils.EditType.Pondering
@property
def translating(self) -> bool:
return self.edit_status == ui_utils.EditType.Translating
@property
def rotating(self) -> bool:
return self.edit_status == ui_utils.EditType.Rotating
@property
def scaling(self) -> bool:
return self.edit_status == ui_utils.EditType.Scaling
@property
def in_transition(self):
return self.translating or self.rotating or self.scaling
def __init__(self, opt: options.Options, status: ui_controllers.MeshGmmStatuses, interactor: vtk.vtkRenderWindowInteractor):
super(InteractorStyle, self).__init__()
self.mouse_status = self.MouseStatus()
self.opt = opt
self.edit_status = ui_utils.EditType.Pondering
self.edit_direction = ui_utils.EditDirection.X_Axis
self.select_mode = True
self.AddObserver(vtk.vtkCommand.KeyPressEvent, self.on_key_press)
self.AddObserver(vtk.vtkCommand.MouseMoveEvent, self.on_mouse_move)
self.AddObserver(vtk.vtkCommand.LeftButtonReleaseEvent, self.left_button_release_event)
self.AddObserver(vtk.vtkCommand.LeftButtonPressEvent, self.left_button_press_event)
self.AddObserver(vtk.vtkCommand.RightButtonReleaseEvent, self.right_button_release_event)
self.AddObserver(vtk.vtkCommand.RightButtonPressEvent, self.right_button_press_event)
self.AddObserver(vtk.vtkCommand.CharEvent, lambda _, __: None)
self.status = status
self.renders = self.init_renders()
self.rend_to_view = {render.GetAddressAsString(""): i for i, render in enumerate(self.renders)}
self.selected_view = -1
self.draw_view = -1
self.buttons = self.add_buttons(interactor)
class MixInteractorStyle(InteractorStyle):
def draw_end(self):
self.canvas.clear()
if self.status.aggregate_votes(self.select_mode):
self.status.update_mesh()
self.interactor.Render()
def init_renders(self) -> List[vtk.vtkRenderer]:
return [stage.render for stage in self.status.stages] + [self.status.main_stage.render]
# def on_key_press(self, obj, event):
# key = self.interactor.GetKeySym()
# if type(key) is not str:
# return
# key: str = key.lower()
# if key == 'return' or key == 'kp_enter':
# self.status.save()
# if key == 'space':
# self.mark_ready = True
# # if self.status.update_mesh():
# # self.interactor.Render()
# # # if key == 'f' or key == 'F':
# # self.status.flip(1 - int(self.is_left_viewport))
# # if key == 'f':
# # self.status.flip(1 - int(self.is_left_viewport))
# elif key in ("left", "right", "up", "down", "a", "z"):
# if self.status.update_gmm(ui_utils.Buttons.translate, key):
# self.status.update_mesh()
# self.interactor.Render()
# # axis = {"left": 0, "right", "up", "down", "a", "z")
# elif key == 'control_l':
# self.status.replace_mesh()
# self.interactor.Render()
# # if key == 'b' or key == 'B':
# # self.mesh_stage_left.replace_mesh(files_utils.load_mesh(
# # r"C:\Users\t-amhert\PycharmProjects\sdf_gmm\assets\checkpoints\sdformer_sn_chairs_deep\sdfs/samples_953"))
def button_release_event(self, to_do):
picker, is_changed, _ = self.update_default()
if picker is not None and not is_changed:
picked_actor = picker.GetActor()
if picked_actor:
object_id = picked_actor.GetAddressAsString('')
if to_do(object_id):
self.status.update_mesh(128)
class SingleInteractorStyle(InteractorStyle):
def draw_end(self):
self.canvas.clear()
if self.status.aggregate_votes(self.select_mode):
self.interactor.Render()
def init_renders(self) -> List[vtk.vtkRenderer]:
return [stage.render for stage in self.status.stages]
def button_release_event(self, to_do):
picker, is_changed, _ = self.update_default()
if picker is not None and not is_changed:
picked_actor = picker.GetActor()
if picked_actor:
mapper = picked_actor.GetMapper()
object_id = mapper.GetAddressAsString('')
if to_do(object_id):
self.status.update_mesh(128)