0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-13 11:11:49 +02:00

fix(image_roi): coordinates are emitted correctly when handles are inverted; closes #672

This commit is contained in:
2025-06-10 10:48:40 +02:00
committed by Jan Wyzula
parent b3ce68070d
commit 9ef418bf55

View File

@ -437,6 +437,23 @@ class RectangularROI(BaseROI, pg.RectROI):
self.hoverPen = fn.mkPen(color=(255, 0, 0), width=3, style=QtCore.Qt.DashLine) self.hoverPen = fn.mkPen(color=(255, 0, 0), width=3, style=QtCore.Qt.DashLine)
self.handleHoverPen = fn.mkPen("lime", width=4) self.handleHoverPen = fn.mkPen("lime", width=4)
def _normalized_edges(self) -> tuple[float, float, float, float]:
"""
Return rectangle edges as (left, bottom, right, top) with consistent
ordering even when the ROI has been inverted by its scale handles.
Returns:
tuple: A tuple containing the left, bottom, right, and top edges
of the ROI rectangle in normalized coordinates.
"""
x0, y0 = self.pos().x(), self.pos().y()
w, h = self.state["size"]
x_left = min(x0, x0 + w)
x_right = max(x0, x0 + w)
y_bottom = min(y0, y0 + h)
y_top = max(y0, y0 + h)
return x_left, y_bottom, x_right, y_top
def add_scale_handle(self): def add_scale_handle(self):
""" """
Add scale handles at every corner and edge of the ROI. Add scale handles at every corner and edge of the ROI.
@ -465,17 +482,15 @@ class RectangularROI(BaseROI, pg.RectROI):
def _on_region_changed(self): def _on_region_changed(self):
""" """
Handles ROI region change events. Handles changes to the ROI's region.
This method is called whenever the ROI's position or size changes. This method is called whenever the ROI's position or size changes.
It calculates the new corner coordinates and emits the edgesChanged signal It calculates the new corner coordinates and emits the edgesChanged signal
with the updated coordinates. with the updated coordinates.
""" """
x0, y0 = self.pos().x(), self.pos().y() x_left, y_bottom, x_right, y_top = self._normalized_edges()
w, h = self.state["size"] self.edgesChanged.emit(x_left, y_bottom, x_right, y_top)
self.edgesChanged.emit(x0, y0, x0 + w, y0 + h) self.parent_plot_item.vb.update()
viewBox = self.parent_plot_item.vb
viewBox.update()
def mouseDragEvent(self, ev): def mouseDragEvent(self, ev):
""" """
@ -489,9 +504,8 @@ class RectangularROI(BaseROI, pg.RectROI):
""" """
super().mouseDragEvent(ev) super().mouseDragEvent(ev)
if ev.isFinish(): if ev.isFinish():
x0, y0 = self.pos().x(), self.pos().y() x_left, y_bottom, x_right, y_top = self._normalized_edges()
w, h = self.state["size"] self.edgesReleased.emit(x_left, y_bottom, x_right, y_top)
self.edgesReleased.emit(x0, y0, x0 + w, y0 + h)
def get_coordinates(self, typed: bool | None = None) -> dict | tuple: def get_coordinates(self, typed: bool | None = None) -> dict | tuple:
""" """
@ -510,17 +524,16 @@ class RectangularROI(BaseROI, pg.RectROI):
if typed is None: if typed is None:
typed = self.description typed = self.description
x0, y0 = self.pos().x(), self.pos().y() x_left, y_bottom, x_right, y_top = self._normalized_edges()
w, h = self.state["size"]
x1, y1 = x0 + w, y0 + h
if typed: if typed:
return { return {
"bottom_left": (x0, y0), "bottom_left": (x_left, y_bottom),
"bottom_right": (x1, y0), "bottom_right": (x_right, y_bottom),
"top_left": (x0, y1), "top_left": (x_left, y_top),
"top_right": (x1, y1), "top_right": (x_right, y_top),
} }
return ((x0, y0), (x1, y0), (x0, y1), (x1, y1)) return (x_left, y_bottom), (x_right, y_bottom), (x_left, y_top), (x_right, y_top)
def _lookup_scene_image(self): def _lookup_scene_image(self):
""" """
@ -654,7 +667,7 @@ class CircularROI(BaseROI, pg.CircleROI):
if typed is None: if typed is None:
typed = self.description typed = self.description
d = self.state["size"][0] d = abs(self.state["size"][0])
cx = self.pos().x() + d / 2 cx = self.pos().x() + d / 2
cy = self.pos().y() + d / 2 cy = self.pos().y() + d / 2