bwoodsend / vtkplotlib

VTK (C++ 3D graphics library) wrapped into an easy to use 3D equivalent of matplotlib
MIT License
40 stars 6 forks source link

Object manipulation with draggable arrows #11

Closed MarcelHeu closed 2 years ago

MarcelHeu commented 2 years ago

Hey,

first i have to say thank you for this library. It is working really good and easy to use. Now my issue:

Is there any easy to user opportunity to implement something like an object manipulation (only translation) with draggable arrows for an object? So in case of clicking on an object, these arrows will appear around the model and i can move it along either the x, y or z axis.

I attached an example image below. example_objectManipulation

bwoodsend commented 2 years ago

Hmm, it looks like if you want arrows, you'll have to implement it from scratch. The closest, most native VTK thing I can find is vtkInteractorStyleTrackballActor() which replaces the default mouse/keyboard interaction:

from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballActor
import vtkplotlib as vpl

fig = vpl.figure()
fig.style = vtkInteractorStyleTrackballActor()  # <- this line does the magic

vpl.quick_test_plot()
vpl.show()

With it, click and drag rotates an object and shift + click and drag moves it. But... you can no longer move the camera!

If you need both object and camera movement then I guess you'll have to toggle between the two. That requires a bit more boilerplate.

from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballActor
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
import vtkplotlib as vpl

fig = vpl.figure()

# Create one instance of each VTK interaction style.
move_camera = vtkInteractorStyleTrackballCamera()
move_actor = vtkInteractorStyleTrackballActor()

# Add something to show which style we're currently on.
mode_display = vpl.text("Move camera mode. Press 'a' to switch to actor mode.", color="k")

# And a keypress callback to toggle between the two.
def key_press_callback(invoker, _):
    pick = vpl.interactive.pick(invoker)
    if pick.key_text == "c":
        fig.style = move_camera
        mode_display.text = "Move camera mode. Press 'a' to switch to actor mode."
    if pick.key_text == "a":
        fig.style = move_actor
        mode_display.text = "Move actor mode. Press 'c' to switch to camera mode."
    fig.update()

# Because the same object that handles mouse interaction also handles keyboard interaction,
# we need to attach the keyboard callback to both vtkInteractorStyles.
move_camera.AddObserver("KeyPressEvent", key_press_callback)
move_actor.AddObserver("KeyPressEvent", key_press_callback)

fig.style = move_camera

vpl.quick_test_plot()
vpl.show()

If you specifically want independent movement control along the x, y and z axes then you'd probably be best going down the PyQt5 route and having external slider or combo-box widgets which control movement along each axis.

MarcelHeu commented 2 years ago

Hey Brénainn,

thanks for your detailed answer! The function vtkInteractorStyleTrackballActor() is actually a nice feature. I did not know this until now! But i am looking for something to control each axis seperately. The combo-box widget sounds good to get this job done. I will take a deeper look into the boxWidget feature from the vtk library. Maybe i can implement some kind of sliders this way.

MarcelHeu commented 2 years ago

Hey Brénainn,

so i could implement the BoxWidget (https://kitware.github.io/vtk-examples/site/Python/Widgets/BoxWidget/) and it is working quite good. I can move and rotate the model with a good performance. I still have the problem that it would be more comfortable to rotate the model by one axis at one time.

In the vtk library i found some 3D linear Slider (https://kitware.github.io/vtk-examples/site/Cxx/Widgets/Slider/), but i could not find a 3D circular Slider. Is there a way to implement a 3D circular Slider within the vtkplotlib library or do you maybe know some way?

Best regards, Marcel

bwoodsend commented 2 years ago

What would a 3D circular slider look like? The same a the 3D linear slider but it bends round and forms a loop?

MarcelHeu commented 2 years ago

Correct, like you described it. As an addition i would say that it would be good to just have an invisible start/end point where the current value of the slider just switching from minimal to maximal and vice versa.

bwoodsend commented 2 years ago

Honestly, I haven't a clue. You can get pretty low level and build it from scratch using Qt. There's a joystick example here which isn't miles away from what you want. There's also this but I've no idea how practical it is to port Qt extensions into Python. You probably can do something similar with VTK but I doubt I'd ever work out how.

MarcelHeu commented 2 years ago

Thank you for your answer, but i think i will just working with the 2D Slider of vtk and implement it within the vpl QtFigure! I think the rest is too complicated for now to get along with.