From ceeff2279b4e01dee81aadc67de327515fa49d3d Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 6 Nov 2025 16:27:07 +0100 Subject: [PATCH] jfjoch_viewer: Work in progress --- viewer/widgets/JFJochSimpleImageViewer.cpp | 65 +++++++++++++++------- viewer/widgets/JFJochSimpleImageViewer.h | 9 +++ 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/viewer/widgets/JFJochSimpleImageViewer.cpp b/viewer/widgets/JFJochSimpleImageViewer.cpp index ce49c7aa..92c6f1a8 100644 --- a/viewer/widgets/JFJochSimpleImageViewer.cpp +++ b/viewer/widgets/JFJochSimpleImageViewer.cpp @@ -36,6 +36,11 @@ JFJochSimpleImageViewer::JFJochSimpleImageViewer(QWidget *parent) // Keep overlays in pixel units independent of zoom (for labels font sizing) setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + + // QTimer for smoother movement/updates + repaint_timer_.setInterval(16); // ~60 FPS + repaint_timer_.setSingleShot(false); + connect(&repaint_timer_, &QTimer::timeout, this, &JFJochSimpleImageViewer::onRepaintTimer); } void JFJochSimpleImageViewer::clear() { @@ -463,7 +468,7 @@ void JFJochSimpleImageViewer::updateROI() { roi_box_ = roi_box_.intersected(bounds); } - updateScene(); + scheduleSceneUpdate(); } void JFJochSimpleImageViewer::drawROI(QGraphicsScene* scn) { @@ -534,8 +539,9 @@ JFJochSimpleImageViewer::computeROIStats(const QRect& roi_px) const { const int y1 = std::clamp(roi_px.bottom(), 0, std::max(0, H - 1)); if (x1 < x0 || y1 < y0) return s; - // First pass: min, max, sum - double sum = 0.0L; + // One pass: min, max, sum, sum of squares + double sum = 0.0; + double sumsq = 0.0; s.min = std::numeric_limits::infinity(); s.max = -std::numeric_limits::infinity(); s.count = 0; @@ -549,27 +555,48 @@ JFJochSimpleImageViewer::computeROIStats(const QRect& roi_px) const { if (v < s.min) s.min = v; if (v > s.max) s.max = v; sum += v; + sumsq += v * v; ++s.count; } } if (!s.valid()) return s; - s.avg = double(sum / s.count); - - // Second pass: variance - double var_sum = 0.0L; - for (int y = y0; y <= y1; ++y) { - const size_t base = size_t(y) * size_t(W); - for (int x = x0; x <= x1; ++x) { - const size_t idx = base + size_t(x); - const double v = image_values_[idx]; - if (std::isnan(v)) continue; - const double d = v - s.avg; - var_sum += d * d; - } - } - const double variance = (s.count > 1) ? (var_sum / s.count) : 0.0L; - s.stddev = std::sqrt(double(variance)); + s.avg = sum / double(s.count); + double variance = sumsq / double(s.count) - s.avg * s.avg; + if (variance < 0.0) variance = 0.0; // guard small negatives from FP error + s.stddev = std::sqrt(variance); return s; } + + +void JFJochSimpleImageViewer::onRepaintTimer() { + // Apply any pending pan + if (!qFuzzyIsNull(pan_accum_.x()) || !qFuzzyIsNull(pan_accum_.y())) { + translate(pan_accum_.x(), pan_accum_.y()); + pan_accum_ = QPointF(0.0, 0.0); + } + + // Rebuild scene if requested + if (needs_scene_update_) { + updateScene(); + needs_scene_update_ = false; + } + + // Stop timer if nothing pending + if (qFuzzyIsNull(pan_accum_.x()) && qFuzzyIsNull(pan_accum_.y()) && !needs_scene_update_) { + repaint_timer_.stop(); + } +} + +void JFJochSimpleImageViewer::schedulePanDelta(const QPointF& d) { + pan_accum_ += d; + if (!repaint_timer_.isActive()) + repaint_timer_.start(); +} + +void JFJochSimpleImageViewer::scheduleSceneUpdate() { + needs_scene_update_ = true; + if (!repaint_timer_.isActive()) + repaint_timer_.start(); +} diff --git a/viewer/widgets/JFJochSimpleImageViewer.h b/viewer/widgets/JFJochSimpleImageViewer.h index 387f3a05..7a563a3f 100644 --- a/viewer/widgets/JFJochSimpleImageViewer.h +++ b/viewer/widgets/JFJochSimpleImageViewer.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "../SimpleImage.h" #include "../../common/ColorScale.h" @@ -70,6 +71,14 @@ private: QPoint last_mouse_pos_; bool panning_ = false; + // Smooth movement/repaint + QTimer repaint_timer_; + QPointF pan_accum_{0.0, 0.0}; + bool needs_scene_update_ = false; + void schedulePanDelta(const QPointF& d); + void scheduleSceneUpdate(); + void onRepaintTimer(); + // Settings float background_ = 0.0f; float foreground_ = 10.0f;