# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
"""
This script displays the different items of :class:`~silx.gui.plot3d.SceneWindow`.

It shows the different visualizations of :class:`~silx.gui.plot3d.SceneWindow`
and :class:`~silx.gui.plot3d.SceneWidget`.
It illustrates the API to set those items.

It features:

- 2D images: data and RGBA images
- 2D scatter data, displayed either as markers, wireframe or surface.
- 3D scatter plot
- 3D scalar field with iso-surface and cutting plane.
- A clipping plane.

"""

__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/11/2017"


import sys
import numpy

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

SIZE = 1024

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

# Create a SceneWindow widget
window = SceneWindow()

# Get the SceneWidget contained in the window and set its colors
sceneWidget = window.getSceneWidget()
sceneWidget.setBackgroundColor((0.8, 0.8, 0.8, 1.0))
sceneWidget.setForegroundColor((1.0, 1.0, 1.0, 1.0))
sceneWidget.setTextColor((0.1, 0.1, 0.1, 1.0))


# 2D Image ###

# Add a dummy RGBA image
img = numpy.random.random(3 * SIZE**2).reshape(SIZE, SIZE, 3)  # Dummy image

imageRgba = sceneWidget.addImage(img)  # Add ImageRgba item to the scene
imageRgba.setLabel("Random RGBA image")  # Set name displayed in parameter tree

# Set imageRgba transform
imageRgba.setTranslation(SIZE * 0.15, SIZE * 0.15, 0.0)  # Translate the image
# Rotate the image by 45 degrees around its center
imageRgba.setRotationCenter("center", "center", 0.0)
imageRgba.setRotation(45.0, axis=(0.0, 0.0, 1.0))
imageRgba.setScale(0.7, 0.7, 0.7)  # Scale down image


# Add a data image
data = numpy.arange(SIZE**2).reshape(SIZE, SIZE)  # Dummy data
imageData = sceneWidget.addImage(data)  # Add ImageData item to the scene

# Set imageData transform
imageData.setTranslation(0.0, SIZE, 0.0)  # Translate the image

# Set imageData properties
imageData.setInterpolation("linear")  # 'linear' or 'nearest' interpolation
imageData.getColormap().setName("magma")  # Use magma colormap


# 2D scatter data ###

# Create 2D scatter dummy data
x = numpy.random.random(10**3)
y = numpy.random.random(len(x))
values = numpy.exp(-11.0 * ((x - 0.5) ** 2 + (y - 0.5) ** 2))

# Add 2D scatter data with 6 different visualisations
for row, heightMap in enumerate((False, True)):
    for col, mode in enumerate(("points", "lines", "solid")):
        # Add a new scatter
        item = sceneWidget.add2DScatter(x, y, values)

        # Set 2D scatter item tranform
        item.setTranslation(SIZE + col * SIZE, row * SIZE, 0.0)
        item.setScale(SIZE, SIZE, SIZE)

        # Set 2D scatter item properties
        item.setHeightMap(heightMap)
        item.setVisualization(mode)
        item.getColormap().setName("viridis")
        item.setLineWidth(2.0)


# Group  ###

# Create a group item and add it to the scene
# The group children share the group transform
group = items.GroupItem()  # Create a new group item
group.setTranslation(SIZE * 4, 0.0, 0.0)  # Translate the group


# Clipping plane ###

# Add a clipping plane to the group (and thus to the scene)
# This item hides part of other items in the half space defined by the plane.
# Clipped items are those belonging to the same group (i.e., brothers) that
# comes after the clipping plane.
clipPlane = items.ClipPlane()  # Create a new clipping plane item
clipPlane.setNormal((1.0, -0.35, 0.0))  # Set its normal
clipPlane.setPoint((0.0, 0.0, 0.0))  # Set a point on the plane
group.addItem(clipPlane)  # Add clipping plane to the group


# 3D scatter data ###

# Create dummy data
x = numpy.random.random(10**3)
y = numpy.random.random(len(x))
z = numpy.random.random(len(x))
values = numpy.random.random(len(x))

# Create a 3D scatter item and set its data
scatter3d = items.Scatter3D()
scatter3d.setData(x, y, z, values)

# Set scatter3d transform
scatter3d.setScale(SIZE, SIZE, SIZE)

# Set scatter3d properties
scatter3d.getColormap().setName("magma")  # Use 'magma' colormap
scatter3d.setSymbol("d")  # Use diamond markers
scatter3d.setSymbolSize(11)  # Set the size of the markers

# Add scatter3d to the group (and thus to the scene)
group.addItem(scatter3d)


# 3D scalar volume ###

# Create dummy 3D array data
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)

# Create a 3D scalar field item and set its data
volume = items.ScalarField3D()  # Create a new 3D volume item
volume.setData(data)  # Set its data
group.addItem(volume)  # Add it to the group (and thus to the scene)

# Set volume tranform
volume.setTranslation(0.0, SIZE, 0.0)
volume.setScale(SIZE / data.shape[2], SIZE / data.shape[1], SIZE / data.shape[0])

# Add isosurfaces to the volume item given isolevel and color
volume.addIsosurface(0.2, "#FF000080")
volume.addIsosurface(0.5, "#0000FFFF")

# Set the volume cut plane
cutPlane = volume.getCutPlanes()[0]  # Get the volume's cut plane
cutPlane.setVisible(True)  # Set it to be visible
cutPlane.getColormap().setName("jet")  # Set cut plane's colormap
cutPlane.setNormal((0.0, 0.0, 1.0))  # Set cut plane's normal
cutPlane.moveToCenter()  # Place the cut plane at the center of the volume

sceneWidget.addItem(group)  # Add the group as an item of the scene

# Show the SceneWidget widget
window.show()

# Display exception in a pop-up message box
sys.excepthook = qt.exceptionHandler

# Run Qt event loop
qapp.exec()
