silx icon indicating copy to clipboard operation
silx copied to clipboard

Enable the synchronization of multiple plot3d.SceneWidget's viewpoint

Open t20100 opened this issue 6 years ago • 0 comments

There is no way from the public API to synchronize the viewpoint of multiple SceneWidgets and that is missing.

The following code provides a SyncCameras class that does the job by doing the synchronization at the viewport's camera level. Alternative approaches are:

  • Add a signal to SceneWidget for camera updates and a method to set the camera.
  • Add an object in the public API to control the camera.
import sys
import numpy

from silx.gui import qt
from silx.gui.plot3d.SceneWindow import SceneWindow, items

qapp = qt.QApplication.instance() or qt.QApplication([])


# Create two SceneWindow widgets
def create_plot3d():
    window = SceneWindow()
    sceneWidget = window.getSceneWidget()
    x, y, z = numpy.meshgrid(numpy.linspace(-10, 10, 64),
                             numpy.linspace(-10, 10, 64),
                             numpy.linspace(-10, 10, 64))
    data = numpy.sin(x * y * z) / (x * y * z)

    volume = sceneWidget.addVolume(data)
    volume.addIsosurface(0.2, '#FF000080')
    return window

window1 = create_plot3d()
window2 = create_plot3d()
window3 = create_plot3d()

# Synchronize the 2 cameras
class SyncCameras:
    """Synchronize direction and position of the camera between multiple SceneWidgets
    
    :param List[~silx.gui.plot3d.SceneWidget.SceneWidget] sceneWidgets:
    """

    def __init__(self, *sceneWidgets):
        self.__cameras = [sw.viewport.camera for sw in sceneWidgets]
        self.__updating = False
        for camera in self.__cameras:
            camera.addListener(self._camera_changed)

    def _camera_changed(self, source):
        """Camera changes listener"""
        if self.__updating:
            return

        self.__updating = True
        position = source.extrinsic.position
        direction = source.extrinsic.direction
        up = source.extrinsic.up

        for camera in self.__cameras:
            if camera is source:
                continue
            if not (numpy.array_equal(direction, camera.extrinsic.direction) and
                    numpy.array_equal(up, camera.extrinsic.up)):
                camera.extrinsic.setOrientation(direction, up)
            if not numpy.array_equal(position, camera.extrinsic.position):
                camera.extrinsic.position = position

        self.__updating = False


sync_cam = SyncCameras(
    window1.getSceneWidget(),
    window2.getSceneWidget(),
    window3.getSceneWidget())

# Run example

window1.show()
window2.show()
window3.show()

sys.excepthook = qt.exceptionHandler
qapp.exec_()

t20100 avatar Oct 25 '19 12:10 t20100