Equilateral Triangle ROI (#1581)
* feature TriangleROI Added equilateral TriangleROI. getArrayRegion is not working yet * show off (and implicitly test) our new TriangleROI * the PolyLineROI.getArrayRegion can be used by TriangleROI refactor the actual logic to live on ROI * refactors for readability * variable names * lint * docstring type and purpose Co-authored-by: Fekete Imre <feketeimre87@gmail.com>
This commit is contained in:
parent
a5a41cf8eb
commit
5210c55e67
|
@ -58,6 +58,7 @@ rois = []
|
||||||
rois.append(pg.RectROI([20, 20], [20, 20], pen=(0,9)))
|
rois.append(pg.RectROI([20, 20], [20, 20], pen=(0,9)))
|
||||||
rois[-1].addRotateHandle([1,0], [0.5, 0.5])
|
rois[-1].addRotateHandle([1,0], [0.5, 0.5])
|
||||||
rois.append(pg.LineROI([0, 60], [20, 80], width=5, pen=(1,9)))
|
rois.append(pg.LineROI([0, 60], [20, 80], width=5, pen=(1,9)))
|
||||||
|
rois.append(pg.TriangleROI([80, 75], 20, pen=(5, 9)))
|
||||||
rois.append(pg.MultiRectROI([[20, 90], [50, 60], [60, 90]], width=5, pen=(2,9)))
|
rois.append(pg.MultiRectROI([[20, 90], [50, 60], [60, 90]], width=5, pen=(2,9)))
|
||||||
rois.append(pg.EllipseROI([60, 10], [30, 20], pen=(3,9)))
|
rois.append(pg.EllipseROI([60, 10], [30, 20], pen=(3,9)))
|
||||||
rois.append(pg.CircleROI([80, 50], [20, 20], pen=(4,9)))
|
rois.append(pg.CircleROI([80, 50], [20, 20], pen=(4,9)))
|
||||||
|
|
|
@ -30,7 +30,7 @@ __all__ = [
|
||||||
'ROI',
|
'ROI',
|
||||||
'TestROI', 'RectROI', 'EllipseROI', 'CircleROI', 'PolygonROI',
|
'TestROI', 'RectROI', 'EllipseROI', 'CircleROI', 'PolygonROI',
|
||||||
'LineROI', 'MultiLineROI', 'MultiRectROI', 'LineSegmentROI', 'PolyLineROI',
|
'LineROI', 'MultiLineROI', 'MultiRectROI', 'LineSegmentROI', 'PolyLineROI',
|
||||||
'CrosshairROI',
|
'CrosshairROI','TriangleROI'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1182,6 +1182,35 @@ class ROI(GraphicsObject):
|
||||||
mapped = fn.transformCoordinates(img.transform(), coords)
|
mapped = fn.transformCoordinates(img.transform(), coords)
|
||||||
return result, mapped
|
return result, mapped
|
||||||
|
|
||||||
|
def _getArrayRegionForArbitraryShape(self, data, img, axes=(0,1), **kwds):
|
||||||
|
"""
|
||||||
|
Return the result of :meth:`~pyqtgraph.ROI.getArrayRegion`, masked by
|
||||||
|
the shape of the ROI. Values outside the ROI shape are set to 0.
|
||||||
|
|
||||||
|
See :meth:`~pyqtgraph.ROI.getArrayRegion` for a description of the
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
Note: ``returnMappedCoords`` is not yet supported for this ROI type.
|
||||||
|
"""
|
||||||
|
br = self.boundingRect()
|
||||||
|
if br.width() > 1000:
|
||||||
|
raise Exception()
|
||||||
|
sliced = ROI.getArrayRegion(self, data, img, axes=axes, fromBoundingRect=True, **kwds)
|
||||||
|
|
||||||
|
if img.axisOrder == "col-major":
|
||||||
|
mask = self.renderShapeMask(sliced.shape[axes[0]], sliced.shape[axes[1]])
|
||||||
|
else:
|
||||||
|
mask = self.renderShapeMask(sliced.shape[axes[1]], sliced.shape[axes[0]])
|
||||||
|
mask = mask.T
|
||||||
|
|
||||||
|
# reshape mask to ensure it is applied to the correct data axes
|
||||||
|
shape = [1] * data.ndim
|
||||||
|
shape[axes[0]] = sliced.shape[axes[0]]
|
||||||
|
shape[axes[1]] = sliced.shape[axes[1]]
|
||||||
|
mask = mask.reshape(shape)
|
||||||
|
|
||||||
|
return sliced * mask
|
||||||
|
|
||||||
def getAffineSliceParams(self, data, img, axes=(0,1), fromBoundingRect=False):
|
def getAffineSliceParams(self, data, img, axes=(0,1), fromBoundingRect=False):
|
||||||
"""
|
"""
|
||||||
Returns the parameters needed to use :func:`affineSlice <pyqtgraph.affineSlice>`
|
Returns the parameters needed to use :func:`affineSlice <pyqtgraph.affineSlice>`
|
||||||
|
@ -2102,34 +2131,8 @@ class PolyLineROI(ROI):
|
||||||
p.lineTo(self.handles[0]['item'].pos())
|
p.lineTo(self.handles[0]['item'].pos())
|
||||||
return p
|
return p
|
||||||
|
|
||||||
def getArrayRegion(self, data, img, axes=(0,1), **kwds):
|
def getArrayRegion(self, *args, **kwds):
|
||||||
"""
|
return self._getArrayRegionForArbitraryShape(*args, **kwds)
|
||||||
Return the result of :meth:`~pyqtgraph.ROI.getArrayRegion`, masked by
|
|
||||||
the shape of the ROI. Values outside the ROI shape are set to 0.
|
|
||||||
|
|
||||||
See :meth:`~pyqtgraph.ROI.getArrayRegion` for a description of the
|
|
||||||
arguments.
|
|
||||||
|
|
||||||
Note: ``returnMappedCoords`` is not yet supported for this ROI type.
|
|
||||||
"""
|
|
||||||
br = self.boundingRect()
|
|
||||||
if br.width() > 1000:
|
|
||||||
raise Exception()
|
|
||||||
sliced = ROI.getArrayRegion(self, data, img, axes=axes, fromBoundingRect=True, **kwds)
|
|
||||||
|
|
||||||
if img.axisOrder == 'col-major':
|
|
||||||
mask = self.renderShapeMask(sliced.shape[axes[0]], sliced.shape[axes[1]])
|
|
||||||
else:
|
|
||||||
mask = self.renderShapeMask(sliced.shape[axes[1]], sliced.shape[axes[0]])
|
|
||||||
mask = mask.T
|
|
||||||
|
|
||||||
# reshape mask to ensure it is applied to the correct data axes
|
|
||||||
shape = [1] * data.ndim
|
|
||||||
shape[axes[0]] = sliced.shape[axes[0]]
|
|
||||||
shape[axes[1]] = sliced.shape[axes[1]]
|
|
||||||
mask = mask.reshape(shape)
|
|
||||||
|
|
||||||
return sliced * mask
|
|
||||||
|
|
||||||
def setPen(self, *args, **kwds):
|
def setPen(self, *args, **kwds):
|
||||||
ROI.setPen(self, *args, **kwds)
|
ROI.setPen(self, *args, **kwds)
|
||||||
|
@ -2344,3 +2347,44 @@ class RulerROI(LineSegmentROI):
|
||||||
return r
|
return r
|
||||||
pxw = 50 * pxl
|
pxw = 50 * pxl
|
||||||
return r.adjusted(-50, -50, 50, 50)
|
return r.adjusted(-50, -50, 50, 50)
|
||||||
|
|
||||||
|
|
||||||
|
class TriangleROI(ROI):
|
||||||
|
"""
|
||||||
|
Equilateral triangle ROI subclass with one scale handle and one rotation handle.
|
||||||
|
Arguments
|
||||||
|
pos (length-2 sequence) The position of the ROI's origin.
|
||||||
|
size (float) The length of an edge of the triangle.
|
||||||
|
\**args All extra keyword arguments are passed to ROI()
|
||||||
|
============== =============================================================
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pos, size, **args):
|
||||||
|
ROI.__init__(self, pos, [size, size], **args)
|
||||||
|
self.aspectLocked = True
|
||||||
|
angles = np.linspace(0, np.pi * 4 / 3, 3)
|
||||||
|
verticies = (np.array((np.sin(angles), np.cos(angles))).T + 1.0) / 2.0
|
||||||
|
self.poly = QtGui.QPolygonF()
|
||||||
|
for pt in verticies:
|
||||||
|
self.poly.append(QtCore.QPointF(*pt))
|
||||||
|
self.addRotateHandle(verticies[0], [0.5, 0.5])
|
||||||
|
self.addScaleHandle(verticies[1], [0.5, 0.5])
|
||||||
|
|
||||||
|
def paint(self, p, *args):
|
||||||
|
r = self.boundingRect()
|
||||||
|
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
|
p.scale(r.width(), r.height())
|
||||||
|
p.setPen(self.currentPen)
|
||||||
|
p.drawPolygon(self.poly)
|
||||||
|
|
||||||
|
def shape(self):
|
||||||
|
self.path = QtGui.QPainterPath()
|
||||||
|
r = self.boundingRect()
|
||||||
|
# scale the path to match whats on the screen
|
||||||
|
t = QtGui.QTransform()
|
||||||
|
t.scale(r.width(), r.height())
|
||||||
|
self.path.addPolygon(self.poly)
|
||||||
|
return t.map(self.path)
|
||||||
|
|
||||||
|
def getArrayRegion(self, *args, **kwds):
|
||||||
|
return self._getArrayRegionForArbitraryShape(*args, **kwds)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user