This commit is contained in:
Ayzen
2026-05-05 15:45:52 +03:00
parent 5a70235ef3
commit e86f30023e
29 changed files with 1743 additions and 1797 deletions
@@ -39,7 +39,7 @@ class AppWindowGprPlotMixin:
if self._gpr_region_centers_item is not None:
self._gpr_region_centers_item.setData(x=[], y=[])
self._gpr_region_centers_item.hide()
self._gpr_plot.setTitle(f"GPR {self._gpr_config_mode.currentText()}")
self._gpr_plot.setTitle("GPR coherent BP")
def _configure_gpr_plot_axes(self) -> None:
"""Apply persistent GPR plot axis labels and base view settings."""
@@ -53,6 +53,29 @@ class AppWindowGprPlotMixin:
view_box = plot.getViewBox()
view_box.invertY(False)
view_box.enableAutoRange(x=False, y=False)
self._disable_gpr_plot_interaction(plot, view_box)
@staticmethod
def _disable_gpr_plot_interaction(plot: pg.PlotWidget, view_box: pg.ViewBox) -> None:
"""Disable mouse-driven GPR pan/zoom; ranges are controlled by widgets."""
AppWindowGprPlotMixin._call_if_present(plot, "setMouseEnabled", x=False, y=False)
AppWindowGprPlotMixin._call_if_present(plot, "setMenuEnabled", False)
AppWindowGprPlotMixin._call_if_present(plot.getPlotItem(), "hideButtons")
AppWindowGprPlotMixin._call_if_present(view_box, "setMouseEnabled", x=False, y=False)
AppWindowGprPlotMixin._call_if_present(view_box, "setMenuEnabled", False)
for axis_name in ("bottom", "left"):
AppWindowGprPlotMixin._call_if_present(
plot.getPlotItem().getAxis(axis_name),
"setMouseEnabled",
False,
)
@staticmethod
def _call_if_present(obj: object, method_name: str, *args, **kwargs) -> None:
"""Call optional pyqtgraph API when available in the installed version."""
method = getattr(obj, method_name, None)
if method is not None:
method(*args, **kwargs)
def _ensure_gpr_plot_items(self) -> None:
"""Create persistent GPR plot items once and reuse them on redraw."""
@@ -209,8 +232,9 @@ class AppWindowGprPlotMixin:
self._gpr_image_item.setLevels((float(np.min(image)), float(np.max(image) + 1e-6)))
self._gpr_image_item.show()
plot.setXRange(x_min, x_max, padding=0.02)
plot.setYRange(self._gpr_display_y_min(y_min, y_max), y_max, padding=0.02)
visible_x_min, visible_x_max, visible_z_min, visible_z_max = self._gpr_visible_bounds()
plot.setXRange(visible_x_min, visible_x_max, padding=0.0)
plot.setYRange(self._gpr_display_y_min(visible_z_min, visible_z_max), visible_z_max, padding=0.0)
self._draw_gpr_geometry_markers()
@@ -227,7 +251,7 @@ class AppWindowGprPlotMixin:
)
self._gpr_points_item.show()
for x_value, y_value, score in points:
label = pg.TextItem(text=f"{float(score):.0f}", color="#ffffff", anchor=(0.0, 1.0))
label = pg.TextItem(text=f"{float(score):.2f}", color="#ffffff", anchor=(0.0, 1.0))
label.setZValue(40)
label.setPos(float(x_value), float(y_value))
plot.addItem(label)
@@ -273,7 +297,7 @@ class AppWindowGprPlotMixin:
self._gpr_region_mask_items.append(mask_image)
self._gpr_region_contours.append(contour)
plot.setTitle(f"GPR {self._gpr_config_mode.currentText()}")
plot.setTitle("GPR coherent BP")
finally:
plot.setUpdatesEnabled(True)
return True
@@ -289,8 +313,8 @@ class AppWindowGprPlotMixin:
half_span = 0.5 * minimum_span
return center - half_span, center + half_span
def _gpr_visible_object_bounds(self) -> tuple[float, float, float, float]:
"""Return normalized object-only visible X/Z bounds from GUI controls."""
def _gpr_visible_bounds(self) -> tuple[float, float, float, float]:
"""Return normalized GPR visible X/Z bounds from GUI controls."""
x_min, x_max = self._normalized_display_range(
float(self._gpr_visible_x_min_m.value()),
float(self._gpr_visible_x_max_m.value()),
@@ -303,11 +327,17 @@ class AppWindowGprPlotMixin:
)
return x_min, x_max, z_min, z_max
def _gpr_visible_object_bounds(self) -> tuple[float, float, float, float]:
"""Return normalized object/locator visible X/Z bounds from GUI controls."""
return self._gpr_visible_bounds()
@staticmethod
def _gpr_display_y_min(z_min: float, z_max: float) -> float:
"""Return lower GPR display bound with a small negative margin for antenna markers."""
lower = min(0.0, float(z_min))
span = max(float(z_max) - float(z_min), 1e-6)
"""Return lower display bound, preserving surface markers only when surface is visible."""
lower = float(z_min)
if lower > 0.0:
return lower
span = max(float(z_max) - lower, 1e-6)
marker_margin = max(span * 0.03, 0.06)
return lower - marker_margin
@@ -343,9 +373,9 @@ class AppWindowGprPlotMixin:
self._gpr_rx_item.hide()
@staticmethod
def _format_gpr_object_label(x_m: float, z_m: float, pair_count: float) -> str:
"""Format object-only annotation text with pair count and coordinates."""
return f"{int(round(pair_count))} | x={x_m:.1f} | z={z_m:.1f}"
def _format_gpr_object_label(x_m: float, z_m: float, score: float) -> str:
"""Format object-only annotation text with normalized BP score and coordinates."""
return f"{score:.2f} | x={x_m:.1f} | z={z_m:.1f}"
@staticmethod
def _expanded_scene_rect(rect: QRectF, *, padding_px: float = 4.0) -> QRectF:
@@ -411,7 +441,7 @@ class AppWindowGprPlotMixin:
occupied_scene_rects.append(last_rect)
def _gpr_object_rows(self, collection: ResultCollection) -> np.ndarray:
"""Return object rows as `[x_m, z_m, pair_count]` from current GPR result payload."""
"""Return object rows as `[x_m, z_m, score]` from current GPR result payload."""
return extract_gpr_object_rows(collection)
def _filtered_gpr_object_rows(self, collection: ResultCollection) -> np.ndarray:
@@ -421,11 +451,11 @@ class AppWindowGprPlotMixin:
return rows
x_min, x_max, z_min, z_max = self._gpr_visible_object_bounds()
min_pair_count = float(self._gpr_min_visible_pair_count.value())
min_score = float(self._gpr_min_visible_score.value())
finite_mask = np.all(np.isfinite(rows[:, :3]), axis=1)
visible_mask = (
finite_mask
& (rows[:, 2] >= min_pair_count)
& (rows[:, 2] >= min_score)
& (rows[:, 0] >= x_min)
& (rows[:, 0] <= x_max)
& (rows[:, 1] >= z_min)
@@ -470,12 +500,12 @@ class AppWindowGprPlotMixin:
occupied_scene_rects: list[QRectF] = []
x_span = x_max - x_min
z_span = z_max - z_min
for x_value, z_value, pair_count in object_rows:
for x_value, z_value, score in object_rows:
label = pg.TextItem(
text=self._format_gpr_object_label(
float(x_value),
float(z_value),
float(pair_count),
float(score),
),
color="#ffd6d9",
anchor=(0.0, 1.0),
@@ -497,7 +527,7 @@ class AppWindowGprPlotMixin:
plot.setXRange(x_min, x_max, padding=0.0)
plot.setYRange(self._gpr_display_y_min(z_min, z_max), z_max, padding=0.0)
plot.setTitle(f"GPR {self._gpr_config_mode.currentText()} Objects Only")
plot.setTitle("GPR coherent BP Objects Only")
finally:
plot.setUpdatesEnabled(True)
return True