From ebc192dafd5b7114dc2be2bd02b621eb4a2806fe Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 15 Jul 2018 23:26:12 +0100 Subject: [PATCH] InfiniteLine: Fix bounding box for differing x and y ranges Previously, the same pixel -> local transform was used for both direction, which breaks if the displayed coordinate range is not the same for both axes. --- pyqtgraph/graphicsItems/InfiniteLine.py | 38 ++++++++-------- .../graphicsItems/tests/test_InfiniteLine.py | 43 ++++++++++++++++++- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/pyqtgraph/graphicsItems/InfiniteLine.py b/pyqtgraph/graphicsItems/InfiniteLine.py index 37d84c7e..4d810635 100644 --- a/pyqtgraph/graphicsItems/InfiniteLine.py +++ b/pyqtgraph/graphicsItems/InfiniteLine.py @@ -300,28 +300,28 @@ class InfiniteLine(GraphicsObject): vr = self.viewRect() # bounds of containing ViewBox mapped to local coords. if vr is None: return QtCore.QRectF() - - ## add a 4-pixel radius around the line for mouse interaction. - - px = self.pixelLength(direction=Point(1,0), ortho=True) ## get pixel length orthogonal to the line - if px is None: - px = 0 - pw = max(self.pen.width() / 2, self.hoverPen.width() / 2) - w = max(4, self._maxMarkerSize + pw) + 1 - w = w * px - br = QtCore.QRectF(vr) - br.setBottom(-w) - br.setTop(w) - length = br.width() - left = br.left() + length * self.span[0] - right = br.left() + length * self.span[1] - br.setLeft(left) - br.setRight(right) + # Compute width of area around line to use for mouse interaction, in + # pixels (at least 4 for thin lines). + penWidth = max(self.pen.width() / 2, self.hoverPen.width() / 2) + padding = max(4, self._maxMarkerSize + penWidth) + 1 + + br = QtCore.QRectF() + + orthoPadding = padding * (self.pixelLength(direction=Point(1,0), ortho=True) or 0) + br.setBottom(-orthoPadding) + br.setTop(orthoPadding) + + paraPadding = padding * (self.pixelLength(direction=Point(1,0)) or 0) + length = vr.width() + left = vr.left() + length * self.span[0] + right = vr.left() + length * self.span[1] + br.setLeft(left - paraPadding) + br.setRight(right + paraPadding) + br = br.normalized() - + vs = self.getViewBox().size() - if self._bounds != br or self._lastViewSize != vs: self._bounds = br self._lastViewSize = vs diff --git a/pyqtgraph/graphicsItems/tests/test_InfiniteLine.py b/pyqtgraph/graphicsItems/tests/test_InfiniteLine.py index 24438864..c34eeea1 100644 --- a/pyqtgraph/graphicsItems/tests/test_InfiniteLine.py +++ b/pyqtgraph/graphicsItems/tests/test_InfiniteLine.py @@ -44,7 +44,48 @@ def test_InfiniteLine(): px = pg.Point(-0.5, -1.0 / 3**0.5) assert br.containsPoint(pos + 5 * px, QtCore.Qt.OddEvenFill) assert not br.containsPoint(pos + 7 * px, QtCore.Qt.OddEvenFill) - + + +def test_InfiniteLine_scaled_bounding_box(): + # Make plot with unequal axis ranges. + plt = pg.plot() + plt.setXRange(0, 1) + plt.setYRange(0, 1e-3) + plt.resize(400, 400) + + QtTest.QTest.qWaitForWindowShown(plt) + QtTest.QTest.qWait(100) + + # Vertical line. + vline = pg.InfiniteLine(angle=90) + vline.setPos(0.5) + plt.addItem(vline) + + # Make sure there is some padding around the line... + vbr = vline.mapToScene(vline.boundingRect()) + def contains(rect, x, y): + return rect.containsPoint(pg.Point(x, y), QtCore.Qt.OddEvenFill) + assert contains(vbr, 221, -1) + assert contains(vbr, 229, 381) + + # ... but not too much. + assert not contains(vbr, 221, -10) + assert not contains(vbr, 210, -1) + assert not contains(vbr, 229, 390) + assert not contains(vbr, 240, 381) + + # Same for horizontal line. + hline = pg.InfiniteLine(angle=0) + hline.setPos(0.5e-3) + plt.addItem(hline) + hbr = hline.mapToScene(hline.boundingRect()) + assert contains(hbr, 47, 185) + assert contains(hbr, 403, 194) + assert not contains(hbr, 47, 175) + assert not contains(hbr, 37, 185) + assert not contains(hbr, 413, 194) + assert not contains(hbr, 403, 204) + def test_mouseInteraction(): plt = pg.plot()