summaryrefslogtreecommitdiff
path: root/silx/gui/plot3d
diff options
context:
space:
mode:
authorPicca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>2018-07-31 16:22:25 +0200
committerPicca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>2018-07-31 16:22:25 +0200
commit159ef14fb9e198bb0066ea14e6b980f065de63dd (patch)
treebc37c7d4ba09ee59deb708897fa0571709aec293 /silx/gui/plot3d
parent270d5ddc31c26b62379e3caa9044dd75ccc71847 (diff)
New upstream version 0.8.0+dfsg
Diffstat (limited to 'silx/gui/plot3d')
-rw-r--r--silx/gui/plot3d/Plot3DWidget.py6
-rw-r--r--silx/gui/plot3d/SFViewParamTree.py8
-rw-r--r--silx/gui/plot3d/ScalarFieldView.py10
-rw-r--r--silx/gui/plot3d/SceneWidget.py6
-rw-r--r--silx/gui/plot3d/SceneWindow.py13
-rw-r--r--silx/gui/plot3d/_model/items.py20
-rw-r--r--silx/gui/plot3d/actions/io.py11
-rw-r--r--silx/gui/plot3d/items/__init__.py2
-rw-r--r--silx/gui/plot3d/items/mesh.py396
-rw-r--r--silx/gui/plot3d/items/mixins.py4
-rw-r--r--silx/gui/plot3d/items/volume.py4
-rw-r--r--silx/gui/plot3d/scene/primitives.py10
-rw-r--r--silx/gui/plot3d/scene/text.py4
-rw-r--r--silx/gui/plot3d/scene/utils.py9
-rw-r--r--silx/gui/plot3d/scene/viewport.py4
-rw-r--r--silx/gui/plot3d/tools/GroupPropertiesWidget.py6
16 files changed, 456 insertions, 57 deletions
diff --git a/silx/gui/plot3d/Plot3DWidget.py b/silx/gui/plot3d/Plot3DWidget.py
index 15e2356..53ff895 100644
--- a/silx/gui/plot3d/Plot3DWidget.py
+++ b/silx/gui/plot3d/Plot3DWidget.py
@@ -28,15 +28,15 @@ from __future__ import absolute_import
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "26/01/2017"
+__date__ = "24/04/2018"
import logging
from silx.gui import qt
-from silx.gui.plot.Colors import rgba
+from silx.gui.colors import rgba
from . import actions
-from .._utils import convertArrayToQImage
+from ..utils._image import convertArrayToQImage
from .. import _glutils as glu
from .scene import interaction, primitives, transform
diff --git a/silx/gui/plot3d/SFViewParamTree.py b/silx/gui/plot3d/SFViewParamTree.py
index 314e5a1..bb81465 100644
--- a/silx/gui/plot3d/SFViewParamTree.py
+++ b/silx/gui/plot3d/SFViewParamTree.py
@@ -30,7 +30,7 @@ from __future__ import absolute_import
__authors__ = ["D. N."]
__license__ = "MIT"
-__date__ = "02/10/2017"
+__date__ = "24/04/2018"
import logging
import sys
@@ -40,7 +40,7 @@ import numpy
from silx.gui import qt
from silx.gui.icons import getQIcon
-from silx.gui.plot.Colormap import Colormap
+from silx.gui.colors import Colormap
from silx.gui.widgets.FloatEdit import FloatEdit
from .ScalarFieldView import Isosurface
@@ -1024,13 +1024,13 @@ class IsoSurfaceAddRemoveWidget(qt.QWidget):
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
- addBtn = qt.QToolButton()
+ addBtn = qt.QToolButton(self)
addBtn.setText('+')
addBtn.setToolButtonStyle(qt.Qt.ToolButtonTextOnly)
layout.addWidget(addBtn)
addBtn.clicked.connect(self.__addClicked)
- removeBtn = qt.QToolButton()
+ removeBtn = qt.QToolButton(self)
removeBtn.setText('-')
removeBtn.setToolButtonStyle(qt.Qt.ToolButtonTextOnly)
layout.addWidget(removeBtn)
diff --git a/silx/gui/plot3d/ScalarFieldView.py b/silx/gui/plot3d/ScalarFieldView.py
index a41999b..e5e680c 100644
--- a/silx/gui/plot3d/ScalarFieldView.py
+++ b/silx/gui/plot3d/ScalarFieldView.py
@@ -32,7 +32,7 @@ from __future__ import absolute_import
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "10/01/2017"
+__date__ = "14/06/2018"
import re
import logging
@@ -42,8 +42,8 @@ from collections import deque
import numpy
from silx.gui import qt, icons
-from silx.gui.plot.Colors import rgba
-from silx.gui.plot.Colormap import Colormap
+from silx.gui.colors import rgba
+from silx.gui.colors import Colormap
from silx.math.marchingcubes import MarchingCubes
from silx.math.combo import min_max
@@ -643,7 +643,7 @@ class CutPlane(qt.QObject):
"""Returns the colormap set by :meth:`setColormap`.
:return: The colormap
- :rtype: ~silx.gui.plot.Colormap.Colormap
+ :rtype: ~silx.gui.colors.Colormap
"""
return self._colormap
@@ -660,7 +660,7 @@ class CutPlane(qt.QObject):
:param name: Name of the colormap in
'gray', 'reversed gray', 'temperature', 'red', 'green', 'blue'.
Or Colormap object.
- :type name: str or ~silx.gui.plot.Colormap.Colormap
+ :type name: str or ~silx.gui.colors.Colormap
:param str norm: Colormap mapping: 'linear' or 'log'.
:param float vmin: The minimum value of the range or None for autoscale
:param float vmax: The maximum value of the range or None for autoscale
diff --git a/silx/gui/plot3d/SceneWidget.py b/silx/gui/plot3d/SceneWidget.py
index 4e75515..f005dec 100644
--- a/silx/gui/plot3d/SceneWidget.py
+++ b/silx/gui/plot3d/SceneWidget.py
@@ -28,14 +28,14 @@ from __future__ import absolute_import
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "26/10/2017"
+__date__ = "24/04/2018"
import numpy
import weakref
from silx.third_party import enum
from .. import qt
-from ..plot.Colors import rgba
+from ..colors import rgba
from .Plot3DWidget import Plot3DWidget
from . import items
@@ -567,7 +567,7 @@ class SceneWidget(Plot3DWidget):
def clearItems(self):
"""Remove all item from :class:`SceneWidget`."""
- return self.getSceneGroup().clear()
+ return self.getSceneGroup().clearItems()
# Colors
diff --git a/silx/gui/plot3d/SceneWindow.py b/silx/gui/plot3d/SceneWindow.py
index 5121a17..56fb21f 100644
--- a/silx/gui/plot3d/SceneWindow.py
+++ b/silx/gui/plot3d/SceneWindow.py
@@ -163,6 +163,13 @@ class SceneWindow(qt.QMainWindow):
"""
return self._sceneWidget
+ def getGroupResetWidget(self):
+ """Returns the :class:`GroupPropertiesWidget` of this window.
+
+ :rtype: GroupPropertiesWidget
+ """
+ return self._sceneGroupResetWidget
+
def getParamTreeView(self):
"""Returns the :class:`ParamTreeView` of this window.
@@ -173,20 +180,20 @@ class SceneWindow(qt.QMainWindow):
def getInteractiveModeToolBar(self):
"""Returns the interactive mode toolbar.
- :rtype: InteractiveModeToolBar
+ :rtype: ~silx.gui.plot3d.tools.InteractiveModeToolBar
"""
return self._interactiveModeToolBar
def getViewpointToolBar(self):
"""Returns the viewpoint toolbar.
- :rtype: ViewpointToolBar
+ :rtype: ~silx.gui.plot3d.tools.ViewpointToolBar
"""
return self._viewpointToolBar
def getOutputToolBar(self):
"""Returns the output toolbar.
- :rtype: OutputToolBar
+ :rtype: ~silx.gui.plot3d.tools.OutputToolBar
"""
return self._outputToolBar
diff --git a/silx/gui/plot3d/_model/items.py b/silx/gui/plot3d/_model/items.py
index 7009ea1..02485fe 100644
--- a/silx/gui/plot3d/_model/items.py
+++ b/silx/gui/plot3d/_model/items.py
@@ -30,18 +30,19 @@ from __future__ import absolute_import, division
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "11/01/2018"
+__date__ = "24/04/2018"
import functools
+import logging
import weakref
import numpy
from silx.third_party import six
-from ..._utils import convertArrayToQImage
-from ...plot.Colormap import preferredColormaps
+from ...utils._image import convertArrayToQImage
+from ...colors import preferredColormaps
from ... import qt, icons
from .. import items
from ..items.volume import Isosurface, CutPlane
@@ -50,6 +51,9 @@ from ..items.volume import Isosurface, CutPlane
from .core import AngleDegreeRow, BaseRow, ColorProxyRow, ProxyRow, StaticRow
+_logger = logging.getLogger(__name__)
+
+
class _DirectionalLightProxy(qt.QObject):
"""Proxy to handle directional light with angles rather than vector.
"""
@@ -472,7 +476,11 @@ class DataItem3DTransformRow(StaticRow):
"""
item = self.item()
if item is not None:
- item.setScale(scale.x(), scale.y(), scale.z())
+ sx, sy, sz = scale.x(), scale.y(), scale.z()
+ if sx == 0. or sy == 0. or sz == 0.:
+ _logger.warning('Cannot set scale to 0: ignored')
+ else:
+ item.setScale(scale.x(), scale.y(), scale.z())
class GroupItemRow(Item3DRow):
@@ -519,7 +527,7 @@ class GroupItemRow(Item3DRow):
# Find item
for row in self.children():
- if row.item() is item:
+ if isinstance(row, Item3DRow) and row.item() is item:
self.removeRow(row)
break # Got it
else:
@@ -764,7 +772,7 @@ class ColormapRow(_ColormapBaseProxyRow):
def _getName(self):
"""Proxy for :meth:`Colormap.getName`"""
- if self._colormap is not None:
+ if self._colormap is not None and self._colormap.getName() is not None:
return self._colormap.getName().title()
else:
return ''
diff --git a/silx/gui/plot3d/actions/io.py b/silx/gui/plot3d/actions/io.py
index 5126000..f30abeb 100644
--- a/silx/gui/plot3d/actions/io.py
+++ b/silx/gui/plot3d/actions/io.py
@@ -39,12 +39,11 @@ import os
import numpy
-from silx.gui import qt
-from silx.gui.plot.actions.io import PrintAction as _PrintAction
+from silx.gui import qt, printer
from silx.gui.icons import getQIcon
from .Plot3DAction import Plot3DAction
from ..utils import mng
-from ..._utils import convertQImageToArray
+from ...utils._image import convertQImageToArray
_logger = logging.getLogger(__name__)
@@ -157,11 +156,7 @@ class PrintAction(Plot3DAction):
:rtype: QPrinter
"""
- # TODO This is a hack to sync with silx plot PrintAction
- # This needs to be centralized
- if _PrintAction._printer is None:
- _PrintAction._printer = qt.QPrinter()
- return _PrintAction._printer
+ return printer.getDefaultPrinter()
def _triggered(self, checked=False):
plot3d = self.getPlot3DWidget()
diff --git a/silx/gui/plot3d/items/__init__.py b/silx/gui/plot3d/items/__init__.py
index b50ea5a..b2a9dab 100644
--- a/silx/gui/plot3d/items/__init__.py
+++ b/silx/gui/plot3d/items/__init__.py
@@ -38,6 +38,6 @@ from .mixins import (ColormapMixIn, InterpolationMixIn, # noqa
PlaneMixIn, SymbolMixIn) # noqa
from .clipplane import ClipPlane # noqa
from .image import ImageData, ImageRgba # noqa
-from .mesh import Mesh # noqa
+from .mesh import Mesh, Box, Cylinder, Hexagon # noqa
from .scatter import Scatter2D, Scatter3D # noqa
from .volume import ScalarField3D # noqa
diff --git a/silx/gui/plot3d/items/mesh.py b/silx/gui/plot3d/items/mesh.py
index 8535728..12a3941 100644
--- a/silx/gui/plot3d/items/mesh.py
+++ b/silx/gui/plot3d/items/mesh.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 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
@@ -35,6 +35,7 @@ import numpy
from ..scene import primitives
from .core import DataItem3D, ItemChangedType
+from ..scene.transform import Rotate
class Mesh(DataItem3D):
@@ -143,3 +144,396 @@ class Mesh(DataItem3D):
:rtype: str
"""
return self._mesh.drawMode
+
+
+class _CylindricalVolume(DataItem3D):
+ """Class that represents a volume with a rotational symmetry along z
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ def __init__(self, parent=None):
+ DataItem3D.__init__(self, parent=parent)
+ self._mesh = None
+
+ def _setData(self, position, radius, height, angles, color, flatFaces,
+ rotation):
+ """Set volume geometry data.
+
+ :param numpy.ndarray position:
+ Center position (x, y, z) of each volume as (N, 3) array.
+ :param float radius: External radius ot the volume.
+ :param float height: Height of the volume(s).
+ :param numpy.ndarray angles: Angles of the edges.
+ :param numpy.array color: RGB color of the volume(s).
+ :param bool flatFaces:
+ If the volume as flat faces or not. Used for normals calculation.
+ """
+
+ self._getScenePrimitive().children = [] # Remove any previous mesh
+
+ if position is None or len(position) == 0:
+ self._mesh = 0
+ else:
+ volume = numpy.empty(shape=(len(angles) - 1, 12, 3),
+ dtype=numpy.float32)
+ normal = numpy.empty(shape=(len(angles) - 1, 12, 3),
+ dtype=numpy.float32)
+
+ for i in range(0, len(angles) - 1):
+ """
+ c6
+ /\
+ / \
+ / \
+ c4|------|c5
+ | \ |
+ | \ |
+ | \ |
+ | \ |
+ c2|------|c3
+ \ /
+ \ /
+ \/
+ c1
+ """
+ c1 = numpy.array([0, 0, -height/2])
+ c1 = rotation.transformPoint(c1)
+ c2 = numpy.array([radius * numpy.cos(angles[i]),
+ radius * numpy.sin(angles[i]),
+ -height/2])
+ c2 = rotation.transformPoint(c2)
+ c3 = numpy.array([radius * numpy.cos(angles[i+1]),
+ radius * numpy.sin(angles[i+1]),
+ -height/2])
+ c3 = rotation.transformPoint(c3)
+ c4 = numpy.array([radius * numpy.cos(angles[i]),
+ radius * numpy.sin(angles[i]),
+ height/2])
+ c4 = rotation.transformPoint(c4)
+ c5 = numpy.array([radius * numpy.cos(angles[i+1]),
+ radius * numpy.sin(angles[i+1]),
+ height/2])
+ c5 = rotation.transformPoint(c5)
+ c6 = numpy.array([0, 0, height/2])
+ c6 = rotation.transformPoint(c6)
+
+ volume[i] = numpy.array([c1, c3, c2,
+ c2, c3, c4,
+ c3, c5, c4,
+ c4, c5, c6])
+ if flatFaces:
+ normal[i] = numpy.array([numpy.cross(c3-c1, c2-c1), # c1
+ numpy.cross(c2-c3, c1-c3), # c3
+ numpy.cross(c1-c2, c3-c2), # c2
+ numpy.cross(c3-c2, c4-c2), # c2
+ numpy.cross(c4-c3, c2-c3), # c3
+ numpy.cross(c2-c4, c3-c4), # c4
+ numpy.cross(c5-c3, c4-c3), # c3
+ numpy.cross(c4-c5, c3-c5), # c5
+ numpy.cross(c3-c4, c5-c4), # c4
+ numpy.cross(c5-c4, c6-c4), # c4
+ numpy.cross(c6-c5, c5-c5), # c5
+ numpy.cross(c4-c6, c5-c6)]) # c6
+ else:
+ normal[i] = numpy.array([numpy.cross(c3-c1, c2-c1),
+ numpy.cross(c2-c3, c1-c3),
+ numpy.cross(c1-c2, c3-c2),
+ c2-c1, c3-c1, c4-c6, # c2 c2 c4
+ c3-c1, c5-c6, c4-c6, # c3 c5 c4
+ numpy.cross(c5-c4, c6-c4),
+ numpy.cross(c6-c5, c5-c5),
+ numpy.cross(c4-c6, c5-c6)])
+
+ # Multiplication according to the number of positions
+ vertices = numpy.tile(volume.reshape(-1, 3), (len(position), 1))\
+ .reshape((-1, 3))
+ normals = numpy.tile(normal.reshape(-1, 3), (len(position), 1))\
+ .reshape((-1, 3))
+
+ # Translations
+ numpy.add(vertices, numpy.tile(position, (1, (len(angles)-1) * 12))
+ .reshape((-1, 3)), out=vertices)
+
+ # Colors
+ if numpy.ndim(color) == 2:
+ color = numpy.tile(color, (1, 12 * (len(angles) - 1)))\
+ .reshape(-1, 3)
+
+ self._mesh = primitives.Mesh3D(
+ vertices, color, normals, mode='triangles', copy=False)
+ self._getScenePrimitive().children.append(self._mesh)
+
+ self.sigItemChanged.emit(ItemChangedType.DATA)
+
+
+class Box(_CylindricalVolume):
+ """Description of a box.
+
+ Can be used to draw one box or many similar boxes.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ def __init__(self, parent=None):
+ super(Box, self).__init__(parent)
+ self.position = None
+ self.size = None
+ self.color = None
+ self.rotation = None
+ self.setData()
+
+ def setData(self, size=(1, 1, 1), color=(1, 1, 1),
+ position=(0, 0, 0), rotation=(0, (0, 0, 0))):
+ """
+ Set Box geometry data.
+
+ :param numpy.array size: Size (dx, dy, dz) of the box(es).
+ :param numpy.array color: RGB color of the box(es).
+ :param numpy.ndarray position:
+ Center position (x, y, z) of each box as a (N, 3) array.
+ :param tuple(float, array) rotation:
+ Angle (in degrees) and axis of rotation.
+ If (0, (0, 0, 0)) (default), the hexagonal faces are on
+ xy plane and a side face is aligned with x axis.
+ """
+ self.position = numpy.atleast_2d(numpy.array(position, copy=True))
+ self.size = numpy.array(size, copy=True)
+ self.color = numpy.array(color, copy=True)
+ self.rotation = Rotate(rotation[0],
+ rotation[1][0], rotation[1][1], rotation[1][2])
+
+ assert (numpy.ndim(self.color) == 1 or
+ len(self.color) == len(self.position))
+
+ diagonal = numpy.sqrt(self.size[0]**2 + self.size[1]**2)
+ alpha = 2 * numpy.arcsin(self.size[1] / diagonal)
+ beta = 2 * numpy.arcsin(self.size[0] / diagonal)
+ angles = numpy.array([0,
+ alpha,
+ alpha + beta,
+ alpha + beta + alpha,
+ 2 * numpy.pi])
+ numpy.subtract(angles, 0.5 * alpha, out=angles)
+ self._setData(self.position,
+ numpy.sqrt(self.size[0]**2 + self.size[1]**2)/2,
+ self.size[2],
+ angles,
+ self.color,
+ True,
+ self.rotation)
+
+ def getPosition(self, copy=True):
+ """Get box(es) position(s).
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: Position of the box(es) as a (N, 3) array.
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self.position, copy=copy)
+
+ def getSize(self):
+ """Get box(es) size.
+
+ :return: Size (dx, dy, dz) of the box(es).
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self.size, copy=True)
+
+ def getColor(self, copy=True):
+ """Get box(es) color.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: RGB color of the box(es).
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self.color, copy=copy)
+
+
+class Cylinder(_CylindricalVolume):
+ """Description of a cylinder.
+
+ Can be used to draw one cylinder or many similar cylinders.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ def __init__(self, parent=None):
+ super(Cylinder, self).__init__(parent)
+ self.position = None
+ self.radius = None
+ self.height = None
+ self.color = None
+ self.nbFaces = 0
+ self.rotation = None
+ self.setData()
+
+ def setData(self, radius=1, height=1, color=(1, 1, 1), nbFaces=20,
+ position=(0, 0, 0), rotation=(0, (0, 0, 0))):
+ """
+ Set the cylinder geometry data
+
+ :param float radius: Radius of the cylinder(s).
+ :param float height: Height of the cylinder(s).
+ :param numpy.array color: RGB color of the cylinder(s).
+ :param int nbFaces:
+ Number of faces for cylinder approximation (default 20).
+ :param numpy.ndarray position:
+ Center position (x, y, z) of each cylinder as a (N, 3) array.
+ :param tuple(float, array) rotation:
+ Angle (in degrees) and axis of rotation.
+ If (0, (0, 0, 0)) (default), the hexagonal faces are on
+ xy plane and a side face is aligned with x axis.
+ """
+ self.position = numpy.atleast_2d(numpy.array(position, copy=True))
+ self.radius = float(radius)
+ self.height = float(height)
+ self.color = numpy.array(color, copy=True)
+ self.nbFaces = int(nbFaces)
+ self.rotation = Rotate(rotation[0],
+ rotation[1][0], rotation[1][1], rotation[1][2])
+
+ assert (numpy.ndim(self.color) == 1 or
+ len(self.color) == len(self.position))
+
+ angles = numpy.linspace(0, 2*numpy.pi, self.nbFaces + 1)
+ self._setData(self.position,
+ self.radius,
+ self.height,
+ angles,
+ self.color,
+ False,
+ self.rotation)
+
+ def getPosition(self, copy=True):
+ """Get cylinder(s) position(s).
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: Position(s) of the cylinder(s) as a (N, 3) array.
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self.position, copy=copy)
+
+ def getRadius(self):
+ """Get cylinder(s) radius.
+
+ :return: Radius of the cylinder(s).
+ :rtype: float
+ """
+ return self.radius
+
+ def getHeight(self):
+ """Get cylinder(s) height.
+
+ :return: Height of the cylinder(s).
+ :rtype: float
+ """
+ return self.height
+
+ def getColor(self, copy=True):
+ """Get cylinder(s) color.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: RGB color of the cylinder(s).
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self.color, copy=copy)
+
+
+class Hexagon(_CylindricalVolume):
+ """Description of a uniform hexagonal prism.
+
+ Can be used to draw one hexagonal prim or many similar hexagonal
+ prisms.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ def __init__(self, parent=None):
+ super(Hexagon, self).__init__(parent)
+ self.position = None
+ self.radius = 0
+ self.height = 0
+ self.color = None
+ self.rotation = None
+ self.setData()
+
+ def setData(self, radius=1, height=1, color=(1, 1, 1),
+ position=(0, 0, 0), rotation=(0, (0, 0, 0))):
+ """
+ Set the uniform hexagonal prism geometry data
+
+ :param float radius: External radius of the hexagonal prism
+ :param float height: Height of the hexagonal prism
+ :param numpy.array color: RGB color of the prism(s)
+ :param numpy.ndarray position:
+ Center position (x, y, z) of each prism as a (N, 3) array
+ :param tuple(float, array) rotation:
+ Angle (in degrees) and axis of rotation.
+ If (0, (0, 0, 0)) (default), the hexagonal faces are on
+ xy plane and a side face is aligned with x axis.
+ """
+ self.position = numpy.atleast_2d(numpy.array(position, copy=True))
+ self.radius = float(radius)
+ self.height = float(height)
+ self.color = numpy.array(color, copy=True)
+ self.rotation = Rotate(rotation[0], rotation[1][0], rotation[1][1],
+ rotation[1][2])
+
+ assert (numpy.ndim(self.color) == 1 or
+ len(self.color) == len(self.position))
+
+ angles = numpy.linspace(0, 2*numpy.pi, 7)
+ self._setData(self.position,
+ self.radius,
+ self.height,
+ angles,
+ self.color,
+ True,
+ self.rotation)
+
+ def getPosition(self, copy=True):
+ """Get hexagonal prim(s) position(s).
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: Position(s) of hexagonal prism(s) as a (N, 3) array.
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self.position, copy=copy)
+
+ def getRadius(self):
+ """Get hexagonal prism(s) radius.
+
+ :return: Radius of hexagon(s).
+ :rtype: float
+ """
+ return self.radius
+
+ def getHeight(self):
+ """Get hexagonal prism(s) height.
+
+ :return: Height of hexagonal prism(s).
+ :rtype: float
+ """
+ return self.height
+
+ def getColor(self, copy=True):
+ """Get hexagonal prism(s) color.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: RGB color of the hexagonal prism(s).
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self.color, copy=copy)
diff --git a/silx/gui/plot3d/items/mixins.py b/silx/gui/plot3d/items/mixins.py
index 41ad3c3..8e96441 100644
--- a/silx/gui/plot3d/items/mixins.py
+++ b/silx/gui/plot3d/items/mixins.py
@@ -27,7 +27,7 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "15/11/2017"
+__date__ = "24/04/2018"
import collections
@@ -38,7 +38,7 @@ from silx.math.combo import min_max
from ...plot.items.core import ItemMixInBase
from ...plot.items.core import ColormapMixIn as _ColormapMixIn
from ...plot.items.core import SymbolMixIn as _SymbolMixIn
-from ...plot.Colors import rgba
+from ...colors import rgba
from ..scene import primitives
from .core import Item3DChangedType, ItemChangedType
diff --git a/silx/gui/plot3d/items/volume.py b/silx/gui/plot3d/items/volume.py
index a1f40f7..a7b5923 100644
--- a/silx/gui/plot3d/items/volume.py
+++ b/silx/gui/plot3d/items/volume.py
@@ -29,7 +29,7 @@ from __future__ import absolute_import
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "15/11/2017"
+__date__ = "24/04/2018"
import logging
import time
@@ -39,7 +39,7 @@ from silx.math.combo import min_max
from silx.math.marchingcubes import MarchingCubes
from ... import qt
-from ...plot.Colors import rgba
+from ...colors import rgba
from ..scene import cutplane, primitives, transform
diff --git a/silx/gui/plot3d/scene/primitives.py b/silx/gui/plot3d/scene/primitives.py
index abf7dd4..af00b6d 100644
--- a/silx/gui/plot3d/scene/primitives.py
+++ b/silx/gui/plot3d/scene/primitives.py
@@ -27,7 +27,7 @@ from __future__ import absolute_import, division, unicode_literals
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "25/07/2016"
+__date__ = "24/04/2018"
import collections
@@ -38,7 +38,7 @@ import string
import numpy
-from silx.gui.plot.Colors import rgba
+from silx.gui.colors import rgba
from ... import _glutils
from ..._glutils import gl
@@ -1246,12 +1246,12 @@ class _Points(Geometry):
$clippingCall(vCameraPosition);
float alpha = alphaSymbol(gl_PointCoord, vSize);
- if (alpha == 0.0) {
- discard;
- }
gl_FragColor = $valueToColorCall(vValue);
gl_FragColor.a *= alpha;
+ if (gl_FragColor.a == 0.0) {
+ discard;
+ }
}
"""))
diff --git a/silx/gui/plot3d/scene/text.py b/silx/gui/plot3d/scene/text.py
index 903fc21..c2983d5 100644
--- a/silx/gui/plot3d/scene/text.py
+++ b/silx/gui/plot3d/scene/text.py
@@ -28,13 +28,13 @@ from __future__ import absolute_import, division, unicode_literals
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "17/10/2016"
+__date__ = "24/04/2018"
import logging
import numpy
-from silx.gui.plot.Colors import rgba
+from silx.gui.colors import rgba
from ... import _glutils
from ..._glutils import gl
diff --git a/silx/gui/plot3d/scene/utils.py b/silx/gui/plot3d/scene/utils.py
index 04abd04..3752289 100644
--- a/silx/gui/plot3d/scene/utils.py
+++ b/silx/gui/plot3d/scene/utils.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 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
@@ -227,12 +227,7 @@ def trianglesNormal(positions):
positions[:, 2] - positions[:, 0])
# Normalize normals
- if numpy.version.version < '1.8.0':
- # Debian 7 support: numpy.linalg.norm has no axis argument
- norms = numpy.array(tuple(numpy.linalg.norm(vec) for vec in normals),
- dtype=normals.dtype)
- else:
- norms = numpy.linalg.norm(normals, axis=1)
+ norms = numpy.linalg.norm(normals, axis=1)
norms[norms == 0] = 1
return normals / norms.reshape(-1, 1)
diff --git a/silx/gui/plot3d/scene/viewport.py b/silx/gui/plot3d/scene/viewport.py
index 0cacbf0..41aa999 100644
--- a/silx/gui/plot3d/scene/viewport.py
+++ b/silx/gui/plot3d/scene/viewport.py
@@ -33,12 +33,12 @@ from __future__ import absolute_import, division, unicode_literals
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "25/07/2016"
+__date__ = "24/04/2018"
import numpy
-from silx.gui.plot.Colors import rgba
+from silx.gui.colors import rgba
from ..._glutils import gl
diff --git a/silx/gui/plot3d/tools/GroupPropertiesWidget.py b/silx/gui/plot3d/tools/GroupPropertiesWidget.py
index 30e11de..5b0bcdb 100644
--- a/silx/gui/plot3d/tools/GroupPropertiesWidget.py
+++ b/silx/gui/plot3d/tools/GroupPropertiesWidget.py
@@ -28,11 +28,11 @@ from __future__ import absolute_import
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "11/01/2018"
+__date__ = "24/04/2018"
from ....gui import qt
-from ....gui.plot.Colormap import Colormap
-from ....gui.plot.ColormapDialog import ColormapDialog
+from ....gui.colors import Colormap
+from ....gui.dialog.ColormapDialog import ColormapDialog
from ..items import SymbolMixIn, ColormapMixIn