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[-1].addRotateHandle([1,0], [0.5, 0.5])
|
||||
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.EllipseROI([60, 10], [30, 20], pen=(3,9)))
|
||||
rois.append(pg.CircleROI([80, 50], [20, 20], pen=(4,9)))
|
||||
|
@ -30,7 +30,7 @@ __all__ = [
|
||||
'ROI',
|
||||
'TestROI', 'RectROI', 'EllipseROI', 'CircleROI', 'PolygonROI',
|
||||
'LineROI', 'MultiLineROI', 'MultiRectROI', 'LineSegmentROI', 'PolyLineROI',
|
||||
'CrosshairROI',
|
||||
'CrosshairROI','TriangleROI'
|
||||
]
|
||||
|
||||
|
||||
@ -1182,6 +1182,35 @@ class ROI(GraphicsObject):
|
||||
mapped = fn.transformCoordinates(img.transform(), coords)
|
||||
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):
|
||||
"""
|
||||
Returns the parameters needed to use :func:`affineSlice <pyqtgraph.affineSlice>`
|
||||
@ -2102,34 +2131,8 @@ class PolyLineROI(ROI):
|
||||
p.lineTo(self.handles[0]['item'].pos())
|
||||
return p
|
||||
|
||||
def getArrayRegion(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 getArrayRegion(self, *args, **kwds):
|
||||
return self._getArrayRegionForArbitraryShape(*args, **kwds)
|
||||
|
||||
def setPen(self, *args, **kwds):
|
||||
ROI.setPen(self, *args, **kwds)
|
||||
@ -2344,3 +2347,44 @@ class RulerROI(LineSegmentROI):
|
||||
return r
|
||||
pxw = 50 * pxl
|
||||
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