三维显示与二维共用深度色标,配置名改为 Finger

箭头阈值写入设置;去掉网格告警。三维色标改为立刻采用二维量程(不再 P5/P95 缓变)。选择器显示 Finger。已用 pane UI、shared-scale 与 catalog 单测验证。
This commit is contained in:
ykcheungab
2026-10-08 16:10:58 +08:00
parent f2d7b3e83c
commit 19ae1f4968
9 changed files with 85 additions and 22 deletions
@@ -263,6 +263,24 @@ def shader_source(profile: Profile, program: str) -> tuple[str, str]:
return header + vertex, header + body
def _finite_minmax(scalar, valid) -> tuple[float, float] | None:
"""Finite minimum and maximum — the same interval ``FrameView.frame_depth_span`` uses."""
import numpy as np
values = np.asarray(scalar, dtype=np.float64).reshape(-1)
mask = np.asarray(valid, dtype=bool).reshape(-1)
if values.size != mask.size:
return None
usable = values[mask & np.isfinite(values)]
if usable.size == 0:
return None
lo = float(np.min(usable))
hi = float(np.max(usable))
if hi <= lo:
hi = lo + 1.0
return lo, hi
def _valid_scalar_range(
scalar, valid, *, signed: bool = False
) -> tuple[float, float] | None:
@@ -379,6 +397,10 @@ def _field_scalar_range(
hi = float(shared_depth_scale[1])
if hi > lo and not (math.isnan(lo) or math.isnan(hi)):
return lo, hi
if quantity == "depth_response":
# Same interval as the 2D canvas (finite min/max). A P5/P95 blend here
# made the 3D colour bar crawl toward a different number than the 2D label.
return _finite_minmax(field.scalar, field.valid)
measured = _valid_scalar_range(
field.scalar,
field.valid,
+37 -11
View File
@@ -159,6 +159,9 @@ class ThreeDPanel(QFrame):
#: prefs (or the dataclass defaults) so a colour-scale click cannot reset them.
self._flow_grid_spacing = 10
self._max_arrows = 400
#: Depth colour span published by the 2D canvas. Shown here immediately so the
#: two legends do not wait on the next GL paint (which is rate-limited).
self._shared_depth_span: tuple[float, float] | None = None
root = QVBoxLayout(self)
root.setContentsMargins(8, 6, 8, 6)
@@ -490,7 +493,16 @@ class ThreeDPanel(QFrame):
if quantity.startswith("scene3d."):
quantity = descriptor.quantity
quality = t(f"scene3d.quality_{descriptor.quality}")
if effective is None or effective.scale_mode == "":
shared = (
self._shared_depth_span
if str(descriptor.quantity) == "depth_response"
else None
)
if shared is not None:
lo, hi = shared
elif effective is not None and effective.scale_mode:
lo, hi = effective.scale_lower, effective.scale_upper
else:
self._set_legend(
t(
"scene3d.legend",
@@ -503,7 +515,7 @@ class ThreeDPanel(QFrame):
return
mode = t(
"scene3d.legend_auto"
if effective.scale_mode == "automatic"
if (effective is None or effective.scale_mode != "fixed")
else "scene3d.legend_fixed"
)
self._set_legend(
@@ -512,15 +524,25 @@ class ThreeDPanel(QFrame):
quantity=quantity,
unit=descriptor.unit,
mode=mode,
# Three significant digits: the footer is one line, and "0.033 – 0.90"
# says as much as "0.03337 – 0.8993" while leaving room for the rest.
lower=f"{effective.scale_lower:.3g}",
upper=f"{effective.scale_upper:.3g}",
lower=self._format_bound(lo),
upper=self._format_bound(hi),
quality=quality,
)
)
self.legend_label.setVisible(self._show_diagnostics)
def set_shared_depth_scale(self, span: tuple[float, float] | None) -> None:
"""Adopt the 2D canvas's depth colour span and refresh the legend now."""
if span is None:
self._shared_depth_span = None
else:
self._shared_depth_span = (float(span[0]), float(span[1]))
self._render_scale_bounds()
self._render_legend()
def _format_bound(self, value: float) -> str:
return f"{float(value):.3f}"
def _render_scale_bounds(self) -> None:
"""Show only the numeric bounds needed to read the color ramp."""
descriptor = self._descriptor
@@ -531,16 +553,20 @@ class ThreeDPanel(QFrame):
upper = ""
mode = str(self.scale_combo.currentData() or "fixed")
effective = self._effective_scale
if visible and mode == "fixed":
lower = f"{self.lower_spin.value():.3g}"
upper = f"{self.upper_spin.value():.3g}"
quantity = "" if descriptor is None else str(descriptor.quantity)
if visible and quantity == "depth_response" and self._shared_depth_span is not None:
lower = self._format_bound(self._shared_depth_span[0])
upper = self._format_bound(self._shared_depth_span[1])
elif visible and mode == "fixed":
lower = self._format_bound(self.lower_spin.value())
upper = self._format_bound(self.upper_spin.value())
elif (
visible
and effective is not None
and effective.scale_mode == "automatic"
):
lower = f"{effective.scale_lower:.3g}"
upper = f"{effective.scale_upper:.3g}"
lower = self._format_bound(effective.scale_lower)
upper = self._format_bound(effective.scale_upper)
self.scale_lower_label.setText(lower)
self.scale_upper_label.setText(upper)
self.scale_lower_label.setVisible(visible)
@@ -317,6 +317,8 @@ class Scene3DView(QWidget):
"""Colour depth with the 2D canvas's latched ``(lo, hi)``."""
if self._widget is not None:
self._widget.set_shared_depth_scale(span)
if self._panel is not None:
self._panel.set_shared_depth_scale(span)
def set_theme(self, theme: str) -> None:
"""Adopt the application theme's colour ramp.