From 56c2b8f2fc0bc768a04a55ebe66f4fdcf55a7f5b Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sat, 8 Nov 2025 18:19:04 +0100 Subject: [PATCH 01/15] contourview display is now always a perfect 1:1 aspect ratio --- contourplot.cpp | 10 ++++++++++ contourplot.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/contourplot.cpp b/contourplot.cpp index fa16d270..304a5889 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -472,6 +472,11 @@ void ContourPlot::setSurface(wavefront * wf) { setFooter(name + QString(" %1 rms %2 X %3").arg(wf->std, 6, 'f', 3).arg(wf->data.cols).arg(wf->data.rows)); plotLayout()->setAlignCanvasToScales(true); + + // Update rescaler reference interval to match data dimensions + d_rescaler->setIntervalHint(QwtPlot::xBottom, QwtInterval(0, wf->data.cols)); + d_rescaler->setIntervalHint(QwtPlot::yLeft, QwtInterval(0, wf->data.rows)); + showContoursChanged(contourRange); tracker_->setZoomBase(true); replot(); @@ -507,6 +512,11 @@ ContourPlot::ContourPlot( QWidget *parent, ContourTools *tools, bool minimal ): m_radialDeg = settings.value("contourRulerRadialDeg", 30).toInt(); m_linkProfile = settings.value("linkProfilePlot", true).toBool(); plotLayout()->setAlignCanvasToScales( true ); + + // Setup rescaler to maintain aspect ratio + d_rescaler = new QwtPlotRescaler(canvas()); + d_rescaler->setRescalePolicy(QwtPlotRescaler::Fitting); + initPlot(); } diff --git a/contourplot.h b/contourplot.h index 5ce87170..dcd4d6f1 100644 --- a/contourplot.h +++ b/contourplot.h @@ -27,6 +27,7 @@ #include "wavefront.h" #include #include +#include #include class MyZoomer; @@ -112,6 +113,7 @@ public slots: QColor m_contourPen; + QwtPlotRescaler *d_rescaler; // Added to maintain 1:1 aspect ratio void ruler(); double m_min; From 643cc44b4a4a7397ba2bb1cfbad36fc643d305dc Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sun, 9 Nov 2025 16:07:51 +0100 Subject: [PATCH 02/15] add d_rescaler->rescale(); to fix loading raw wavefronts --- contourplot.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index 304a5889..d8c8e1f7 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -471,11 +471,16 @@ void ContourPlot::setSurface(wavefront * wf) { setFooter(name + QString(" %1 rms %2 X %3").arg(wf->std, 6, 'f', 3).arg(wf->data.cols).arg(wf->data.rows)); - plotLayout()->setAlignCanvasToScales(true); - // Update rescaler reference interval to match data dimensions d_rescaler->setIntervalHint(QwtPlot::xBottom, QwtInterval(0, wf->data.cols)); d_rescaler->setIntervalHint(QwtPlot::yLeft, QwtInterval(0, wf->data.rows)); + // Force an immediate rescale + d_rescaler->rescale(); + + // Set canvas alignment after rescale + plotLayout()->setAlignCanvasToScales(true); + + spdlog::get("logger")->trace("ContourPlot::setSurface {}x{}", wf->data.cols, wf->data.rows); showContoursChanged(contourRange); tracker_->setZoomBase(true); @@ -491,6 +496,7 @@ double ContourPlot::m_zOffset = 0.; ContourPlot::ContourPlot( QWidget *parent, ContourTools *tools, bool minimal ): QwtPlot( parent ),m_wf(0),m_tools(tools), m_autoInterval(false),m_minimal(minimal), m_linkProfile(true),m_contourPen(Qt::white) { + spdlog::get("logger")->trace("ContourPlot::ContourPlot"); d_spectrogram = new QwtPlotSpectrogram(); picker_ = new QwtPlotPicker(this->canvas()); picker_->setStateMachine(new QwtPickerClickPointMachine); From fc18f55b5e14dccdc8f9f0ab788aab88751de1d1 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 16 Nov 2025 08:46:39 +0100 Subject: [PATCH 03/15] moved spectrogramdata to cpp file --- contourplot.cpp | 44 ++++++++++++++++++++++++++++++++++++-------- contourplot.h | 20 -------------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index d8c8e1f7..0b789005 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -39,15 +39,22 @@ #include #include #include "utils.h" +#include #include #include #include +#include +#include #include "spdlog/spdlog.h" double zOffset = 0; double lastx = -1.; double lasty = -1.; + +// ============================================================================ +// MyZommer - Custom zoomer to show data value at cursor +// ============================================================================ class MyZoomer: public QwtPlotZoomer { public: @@ -100,6 +107,30 @@ class MyZoomer: public QwtPlotZoomer void select(QString); }; +// ============================================================================ +// SpectrogramData - Raster data provider for the spectrogram display +// ============================================================================ +class SpectrogramData: public QwtRasterData +{ +public: + SpectrogramData(); + wavefront *m_wf; + void setSurface(wavefront *surface); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + // keep compatibility with newer version of QWT used in QT6 + QwtInterval interval(Qt::Axis axis) const override; + void setInterval(Qt::Axis axis, const QwtInterval &interval); +#endif + virtual double value( double x, double y ) const override; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + // keep compatibility with newer version of QWT used in QT6 +private: + QwtInterval m_xInterval; + QwtInterval m_yInterval; + QwtInterval m_zInterval; +#endif +}; SpectrogramData::SpectrogramData(): m_wf(0) { @@ -155,8 +186,7 @@ void SpectrogramData::setSurface(wavefront *surface) { setInterval( Qt::YAxis, QwtInterval(0, m_wf->workData.rows)); #endif } -#include -extern double g_angle; + double SpectrogramData::value( double x, double y ) const { @@ -173,6 +203,10 @@ double SpectrogramData::value( double x, double y ) const } +// ============================================================================ +// ContourPlot - Main contour plot class +// ============================================================================ + void ContourPlot::setColorMap(int ndx){ QwtInterval iz = d_spectrogram->data()->interval( Qt::ZAxis ); d_spectrogram->setColorMap( new dftColorMap(ndx,m_wf,!m_useMiddleOffset )); @@ -182,8 +216,6 @@ void ContourPlot::setColorMap(int ndx){ setAxisScale( QwtPlot::yRight, iz.minValue() ,iz.maxValue() ); } - - void ContourPlot::ContourMapColorChanged(int ndx) { m_colorMapNdx = ndx; QSettings set; @@ -299,10 +331,6 @@ void ContourPlot::drawCanvas(QPainter* p) QwtPlot::drawCanvas( p ); // <<--- } -#include -#include -#include - void ContourPlot::ruler(){ detachItems(QwtPlotItem::Rtti_PlotShape); diff --git a/contourplot.h b/contourplot.h index dcd4d6f1..79eed65c 100644 --- a/contourplot.h +++ b/contourplot.h @@ -31,27 +31,7 @@ #include class MyZoomer; -class SpectrogramData: public QwtRasterData -{ -public: - SpectrogramData(); - wavefront *m_wf; - void setSurface(wavefront *surface); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - // keep compatibility with newer version of QWT used in QT6 - QwtInterval interval(Qt::Axis axis) const override; - void setInterval(Qt::Axis axis, const QwtInterval &interval); -#endif - virtual double value( double x, double y ) const override; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - // keep compatibility with newer version of QWT used in QT6 -private: - QwtInterval m_xInterval; - QwtInterval m_yInterval; - QwtInterval m_zInterval; -#endif -}; class ContourPlot: public QwtPlot { Q_OBJECT From 5fdf1bb59d87df39a52693e277e96f0f8fe69b80 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 16 Nov 2025 10:49:29 +0100 Subject: [PATCH 04/15] whitespaces and comments --- contourplot.cpp | 31 +++++++++++++------------------ contourview.cpp | 1 + contourview.h | 6 +++--- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index 0b789005..0e229571 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -65,6 +65,7 @@ class MyZoomer: public QwtPlotZoomer setTrackerMode( AlwaysOn ); } + // when holding shift key, show data value at cursor virtual QwtText trackerTextF( const QPointF &pos ) const { if (thePlot->m_wf == 0) @@ -173,7 +174,7 @@ void SpectrogramData::setInterval(Qt::Axis axis, const QwtInterval &interval) } #endif -void SpectrogramData::setSurface(wavefront *surface) { +void SpectrogramData::setSurface(wavefront *surface) { //TODO check if we can const as much as possible m_wf = surface; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // keep compatibility with newer version of QWT used in QT6 @@ -230,8 +231,6 @@ void ContourPlot::contourWaveRangeChanged(double val ){ replot(); } - - void ContourPlot::showContoursChanged(double val){ QSettings set; set.setValue("contourRange",val); @@ -400,9 +399,6 @@ void ContourPlot::ruler(){ xAxis->setYValue(m_wf->data.rows/2); xAxis->setLinePen(Qt::black,2); xAxis->attach(this); - - - } } @@ -422,7 +418,6 @@ void ContourPlot::selected(QPointF pos){ if (m_linkProfile) emit sigPointSelected(pos); m_lastAngle = angle; - } } @@ -479,11 +474,10 @@ void ContourPlot::setSurface(wavefront * wf) { rightAxis->setColorBarEnabled( true ); rightAxis->setColorBarWidth(30); if (!m_minimal){ - enableAxis( QwtPlot::yRight ); + enableAxis(QwtPlot::yRight); enableAxis(QwtPlot::yLeft); } - else - { + else{ enableAxis(QwtPlot::yLeft, false); enableAxis(QwtPlot::xBottom, false); } @@ -504,23 +498,25 @@ void ContourPlot::setSurface(wavefront * wf) { d_rescaler->setIntervalHint(QwtPlot::yLeft, QwtInterval(0, wf->data.rows)); // Force an immediate rescale d_rescaler->rescale(); - + // Set canvas alignment after rescale plotLayout()->setAlignCanvasToScales(true); - + spdlog::get("logger")->trace("ContourPlot::setSurface {}x{}", wf->data.cols, wf->data.rows); - - showContoursChanged(contourRange); - tracker_->setZoomBase(true); + + showContoursChanged(contourRange); //TODO setSurface should not have to call showContoursChanged + tracker_->setZoomBase(true); //TODO I need to detect when canva moves to set zoom base replot(); //resize(QSize(width()-1,height()-1)); //resize(QSize(width()+1,height()+1)); } + double ContourPlot::m_waveRange; bool ContourPlot::m_useMiddleOffset = true; int ContourPlot::m_colorMapNdx = 0; QString ContourPlot::m_zRangeMode("Auto"); double ContourPlot::m_zOffset = 0.; + ContourPlot::ContourPlot( QWidget *parent, ContourTools *tools, bool minimal ): QwtPlot( parent ),m_wf(0),m_tools(tools), m_autoInterval(false),m_minimal(minimal), m_linkProfile(true),m_contourPen(Qt::white) { @@ -546,11 +542,11 @@ ContourPlot::ContourPlot( QWidget *parent, ContourTools *tools, bool minimal ): m_radialDeg = settings.value("contourRulerRadialDeg", 30).toInt(); m_linkProfile = settings.value("linkProfilePlot", true).toBool(); plotLayout()->setAlignCanvasToScales( true ); - + // Setup rescaler to maintain aspect ratio d_rescaler = new QwtPlotRescaler(canvas()); d_rescaler->setRescalePolicy(QwtPlotRescaler::Fitting); - + initPlot(); } @@ -672,4 +668,3 @@ void ContourPlot::printPlot() } #endif - diff --git a/contourview.cpp b/contourview.cpp index 0b51f56e..2d1981e9 100644 --- a/contourview.cpp +++ b/contourview.cpp @@ -81,6 +81,7 @@ void contourView::showContextMenu(QPoint pos) // Show context menu at handling position myMenu.exec(globalPos); } + ContourPlot *contourView::getPlot(){ return ui->widget; } diff --git a/contourview.h b/contourview.h index 980d97e4..bd48c02c 100644 --- a/contourview.h +++ b/contourview.h @@ -35,18 +35,18 @@ class contourView : public QWidget ~contourView(); ContourPlot *getPlot(); void setSurface(wavefront * wf); - bool zoomed; + bool zoomed; // this is not about zooming in the plot, but zooming the contour view to full screen QImage getPixstatsImage(); pixelStats *getPixelstats(){ return ps;} signals: void lineSpacingChanged(double); void showAllContours(); - void zoomMe(bool); + void zoomMe(bool); // full screen related private slots: void on_doubleSpinBox_valueChanged(double arg1); void showContextMenu(QPoint pos); void on_pushButton_pressed(); - void zoom(); + void zoom(); // full screen related void on_histogram_clicked(); From 0b5db8305505f0890b7001e2e0262fefe79154b5 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sat, 6 Dec 2025 15:19:57 +0100 Subject: [PATCH 05/15] manual management of aspect ratio --- contourplot.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++------- contourplot.h | 3 ++- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index 0e229571..b7d763f3 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -32,7 +32,6 @@ #include #include "wavefront.h" #include -#include #include #include #include "dftcolormap.h" @@ -493,11 +492,11 @@ void ContourPlot::setSurface(wavefront * wf) { setFooter(name + QString(" %1 rms %2 X %3").arg(wf->std, 6, 'f', 3).arg(wf->data.cols).arg(wf->data.rows)); - // Update rescaler reference interval to match data dimensions - d_rescaler->setIntervalHint(QwtPlot::xBottom, QwtInterval(0, wf->data.cols)); - d_rescaler->setIntervalHint(QwtPlot::yLeft, QwtInterval(0, wf->data.rows)); - // Force an immediate rescale - d_rescaler->rescale(); + setAxisScale(QwtPlot::xBottom, 0, wf->data.cols); + setAxisScale(QwtPlot::yLeft, 0, wf->data.rows); + + // Enforce aspect ratio on first draw + updateAspectRatio(); // Set canvas alignment after rescale plotLayout()->setAlignCanvasToScales(true); @@ -543,11 +542,8 @@ ContourPlot::ContourPlot( QWidget *parent, ContourTools *tools, bool minimal ): m_linkProfile = settings.value("linkProfilePlot", true).toBool(); plotLayout()->setAlignCanvasToScales( true ); - // Setup rescaler to maintain aspect ratio - d_rescaler = new QwtPlotRescaler(canvas()); - d_rescaler->setRescalePolicy(QwtPlotRescaler::Fitting); - initPlot(); + canvas()->installEventFilter(this); } void ContourPlot::initPlot(){ @@ -641,6 +637,62 @@ void ContourPlot::setAlpha( int alpha ) replot(); } +void ContourPlot::updateAspectRatio() +{ + if (!m_wf) + return; + + QWidget *c = canvas(); + int w = c->width(); + int h = c->height(); + if (w <= 0 || h <= 0) + return; + + // Current ranges + double x1 = axisScaleDiv(QwtPlot::xBottom).lowerBound(); + double x2 = axisScaleDiv(QwtPlot::xBottom).upperBound(); + double y1 = axisScaleDiv(QwtPlot::yLeft).lowerBound(); + double y2 = axisScaleDiv(QwtPlot::yLeft).upperBound(); + + double dx = x2 - x1; + double dy = y2 - y1; + + double ratioData = dx / dy; + double ratioPix = double(w) / double(h); + + if (ratioData > ratioPix) + { + // expand Y + double newDy = dx / ratioPix; + double cy = (y1 + y2) * 0.5; + y1 = cy - newDy * 0.5; + y2 = cy + newDy * 0.5; + } + else + { + // expand X + double newDx = dy * ratioPix; + double cx = (x1 + x2) * 0.5; + x1 = cx - newDx * 0.5; + x2 = cx + newDx * 0.5; + } + + setAxisScale(QwtPlot::xBottom, x1, x2); + setAxisScale(QwtPlot::yLeft, y1, y2); + + replot(); +} + + +bool ContourPlot::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == canvas() && event->type() == QEvent::Resize) + { + updateAspectRatio(); + return false; + } + return QwtPlot::eventFilter(obj, event); +} #ifndef QT_NO_PRINTER diff --git a/contourplot.h b/contourplot.h index 79eed65c..c4439ffd 100644 --- a/contourplot.h +++ b/contourplot.h @@ -90,10 +90,11 @@ public slots: private: void drawCanvas(QPainter* p); void initPlot(); + void updateAspectRatio(); + bool eventFilter(QObject *obj, QEvent *event); QColor m_contourPen; - QwtPlotRescaler *d_rescaler; // Added to maintain 1:1 aspect ratio void ruler(); double m_min; From 6571c921f7fa49f54481b0d95ac7e2d6ab15478b Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sat, 6 Dec 2025 16:30:48 +0100 Subject: [PATCH 06/15] fix crash on fast update --- contourplot.cpp | 56 ++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index b7d763f3..5af45250 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -639,51 +639,63 @@ void ContourPlot::setAlpha( int alpha ) void ContourPlot::updateAspectRatio() { + static bool isReentering = false; + if (!m_wf) return; + // Prevent re-entrancy + if (isReentering) + return; + isReentering = true; + QWidget *c = canvas(); int w = c->width(); int h = c->height(); - if (w <= 0 || h <= 0) + if (w <= 0 || h <= 0){ + isReentering = false; return; + } - // Current ranges - double x1 = axisScaleDiv(QwtPlot::xBottom).lowerBound(); - double x2 = axisScaleDiv(QwtPlot::xBottom).upperBound(); - double y1 = axisScaleDiv(QwtPlot::yLeft).lowerBound(); - double y2 = axisScaleDiv(QwtPlot::yLeft).upperBound(); + double imgWidth = m_wf->data.cols; + double imgHeight = m_wf->data.rows; - double dx = x2 - x1; - double dy = y2 - y1; + double dataRatio = imgWidth / imgHeight; + double pixRatio = double(w) / double(h); - double ratioData = dx / dy; - double ratioPix = double(w) / double(h); + double x1, x2, y1, y2; - if (ratioData > ratioPix) + if (pixRatio > dataRatio) { - // expand Y - double newDy = dx / ratioPix; - double cy = (y1 + y2) * 0.5; - y1 = cy - newDy * 0.5; - y2 = cy + newDy * 0.5; + // Canvas is wider → Y fits perfectly, X must be expanded + double scaledWidth = imgHeight * pixRatio; // what X must become + double extra = (scaledWidth - imgWidth) * 0.5; + x1 = -extra; + x2 = imgWidth + extra; + + y1 = 0; + y2 = imgHeight; } else { - // expand X - double newDx = dy * ratioPix; - double cx = (x1 + x2) * 0.5; - x1 = cx - newDx * 0.5; - x2 = cx + newDx * 0.5; + // Canvas is taller → X fits perfectly, Y must be expanded + double scaledHeight = imgWidth / pixRatio; + double extra = (scaledHeight - imgHeight) * 0.5; + y1 = -extra; + y2 = imgHeight + extra; + + x1 = 0; + x2 = imgWidth; } setAxisScale(QwtPlot::xBottom, x1, x2); setAxisScale(QwtPlot::yLeft, y1, y2); replot(); + + isReentering = false; } - bool ContourPlot::eventFilter(QObject *obj, QEvent *event) { if (obj == canvas() && event->type() == QEvent::Resize) From a4140c2b5d8ebea81808ad5b2289e1474d668737 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sat, 6 Dec 2025 16:54:23 +0100 Subject: [PATCH 07/15] fix scaling of zooming out --- contourplot.cpp | 35 +++++++++++++++++++++++------------ contourplot.h | 2 +- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index 5af45250..ee5fc72d 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -64,27 +64,38 @@ class MyZoomer: public QwtPlotZoomer setTrackerMode( AlwaysOn ); } + // Override zoom state change to reapply aspect ratio when unzooming + virtual void rescale() + { + QwtPlotZoomer::rescale(); + // Check if we're back at the base zoom level + if (thePlot && zoomRectIndex() == 0) + { + thePlot->updateAspectRatio(); + } + } + // when holding shift key, show data value at cursor virtual QwtText trackerTextF( const QPointF &pos ) const { if (thePlot->m_wf == 0) - return QwtText(""); + return QwtText(""); if(!QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) return QwtText(""); if (pos.x() == lastx && pos.y() == lasty){ - double v = thePlot->d_spectrogram->data()->value(pos.x(),pos.y()); - QString t = QString("%1").arg(v, 0, 'f'); + double v = thePlot->d_spectrogram->data()->value(pos.x(),pos.y()); + QString t = QString("%1").arg(v, 0, 'f'); - QwtText label(t); + QwtText label(t); - label.setColor(QColor(255,255,255)); - label.setBorderPen(QPen(QColor(100,0,0), 3)); - label.setBorderRadius(5); - label.setBackgroundBrush(QColor(65, 177, 225, 150)); + label.setColor(QColor(255,255,255)); + label.setBorderPen(QPen(QColor(100,0,0), 3)); + label.setBorderRadius(5); + label.setBackgroundBrush(QColor(65, 177, 225, 150)); - QFont font("MS Shell Dlg 2", 18); - label.setFont(font); - return QwtText(label); + QFont font("MS Shell Dlg 2", 18); + label.setFont(font); + return QwtText(label); } lastx = pos.x(); lasty = pos.y(); @@ -692,7 +703,7 @@ void ContourPlot::updateAspectRatio() setAxisScale(QwtPlot::yLeft, y1, y2); replot(); - + isReentering = false; } diff --git a/contourplot.h b/contourplot.h index c4439ffd..191b72a1 100644 --- a/contourplot.h +++ b/contourplot.h @@ -55,6 +55,7 @@ class ContourPlot: public QwtPlot void setZRange(); void setColorMap(int ndx); void setTool(ContourTools* tool); + void updateAspectRatio(); bool m_autoInterval; bool m_minimal; bool m_linkProfile; @@ -90,7 +91,6 @@ public slots: private: void drawCanvas(QPainter* p); void initPlot(); - void updateAspectRatio(); bool eventFilter(QObject *obj, QEvent *event); From c2eee21c3a4007fa3f7c328205d939c86807deb9 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sat, 6 Dec 2025 17:19:50 +0100 Subject: [PATCH 08/15] zoom also ensure correct picture ratio --- contourplot.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/contourplot.cpp b/contourplot.cpp index ee5fc72d..20795907 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -64,6 +64,56 @@ class MyZoomer: public QwtPlotZoomer setTrackerMode( AlwaysOn ); } + // Override zoom rectangle to maintain image aspect ratio + virtual void zoom(const QRectF &rect) + { + if (!thePlot || !thePlot->m_wf) + { + QwtPlotZoomer::zoom(rect); + return; + } + + // Get the canvas dimensions and aspect ratio (accounts for axes, labels, colorbar, etc.) + QWidget *canvas = thePlot->canvas(); + double canvasWidth = canvas->width(); + double canvasHeight = canvas->height(); + if (canvasWidth <= 0 || canvasHeight <= 0) + { + QwtPlotZoomer::zoom(rect); + return; + } + double canvasRatio = canvasWidth / canvasHeight; + + // Get the selected zoom rectangle dimensions and its aspect ratio + double selWidth = rect.width(); + double selHeight = rect.height(); + double selRatio = selWidth / selHeight; + + QRectF adjustedRect = rect; + + // The zoom rectangle should have the same aspect ratio as the canvas + // to ensure no distortion when displayed + if (selRatio > canvasRatio) + { + // Selected rect is wider than canvas → expand height to match canvas ratio + double newHeight = selWidth / canvasRatio; + double extra = (newHeight - selHeight) / 2.0; + adjustedRect.setTop(rect.top() - extra); + adjustedRect.setBottom(rect.bottom() + extra); + } + else if (selRatio < canvasRatio) + { + // Selected rect is taller than canvas → expand width to match canvas ratio + double newWidth = selHeight * canvasRatio; + double extra = (newWidth - selWidth) / 2.0; + adjustedRect.setLeft(rect.left() - extra); + adjustedRect.setRight(rect.right() + extra); + } + // If ratios match, no adjustment needed + + QwtPlotZoomer::zoom(adjustedRect); + } + // Override zoom state change to reapply aspect ratio when unzooming virtual void rescale() { From c41fdf1fcb89ec77363a21e1d7ee609719be6859 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sat, 6 Dec 2025 18:01:02 +0100 Subject: [PATCH 09/15] add some constness --- contourplot.cpp | 10 +++++----- contourplot.h | 4 ++-- contourview.cpp | 2 +- contourview.h | 2 +- dftcolormap.cpp | 2 +- dftcolormap.h | 4 ++-- pixelstats.cpp | 7 +++---- pixelstats.h | 4 ++-- 8 files changed, 17 insertions(+), 18 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index 20795907..1bb126e3 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -175,8 +175,8 @@ class SpectrogramData: public QwtRasterData { public: SpectrogramData(); - wavefront *m_wf; - void setSurface(wavefront *surface); + const wavefront *m_wf; + void setSurface(const wavefront *surface); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // keep compatibility with newer version of QWT used in QT6 QwtInterval interval(Qt::Axis axis) const override; @@ -234,7 +234,7 @@ void SpectrogramData::setInterval(Qt::Axis axis, const QwtInterval &interval) } #endif -void SpectrogramData::setSurface(wavefront *surface) { //TODO check if we can const as much as possible +void SpectrogramData::setSurface(const wavefront *surface) { m_wf = surface; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // keep compatibility with newer version of QWT used in QT6 @@ -511,7 +511,7 @@ void ContourPlot::drawProfileLine(const double angle){ } -void ContourPlot::setSurface(wavefront * wf) { +void ContourPlot::setSurface(const wavefront * wf) { m_wf = wf; if (wf == 0) return; @@ -565,7 +565,7 @@ void ContourPlot::setSurface(wavefront * wf) { spdlog::get("logger")->trace("ContourPlot::setSurface {}x{}", wf->data.cols, wf->data.rows); showContoursChanged(contourRange); //TODO setSurface should not have to call showContoursChanged - tracker_->setZoomBase(true); //TODO I need to detect when canva moves to set zoom base + tracker_->setZoomBase(true); replot(); //resize(QSize(width()-1,height()-1)); //resize(QSize(width()+1,height()+1)); diff --git a/contourplot.h b/contourplot.h index 191b72a1..07284ed6 100644 --- a/contourplot.h +++ b/contourplot.h @@ -41,7 +41,7 @@ class ContourPlot: public QwtPlot public: QwtPlotSpectrogram *d_spectrogram; - wavefront* m_wf; + const wavefront* m_wf; ContourTools *m_tools; static bool m_useMiddleOffset; static int m_colorMapNdx; @@ -50,7 +50,7 @@ class ContourPlot: public QwtPlot double contourRange; static QString m_zRangeMode; ContourPlot(QWidget * = NULL, ContourTools *tools = 0, bool minimal = false); - void setSurface(wavefront * mat); + void setSurface(const wavefront * mat); void applyZeroOffset(bool useMiddle); void setZRange(); void setColorMap(int ndx); diff --git a/contourview.cpp b/contourview.cpp index 2d1981e9..5970c6c5 100644 --- a/contourview.cpp +++ b/contourview.cpp @@ -63,7 +63,7 @@ QImage contourView::getPixstatsImage(){ } -void contourView::setSurface(wavefront *wf){ +void contourView::setSurface(const wavefront *wf){ getPlot()->setSurface(wf); ps->setData(wf); } diff --git a/contourview.h b/contourview.h index bd48c02c..876f20bd 100644 --- a/contourview.h +++ b/contourview.h @@ -34,7 +34,7 @@ class contourView : public QWidget explicit contourView(QWidget *parent = 0, ContourTools *tools = 0); ~contourView(); ContourPlot *getPlot(); - void setSurface(wavefront * wf); + void setSurface(const wavefront * wf); bool zoomed; // this is not about zooming in the plot, but zooming the contour view to full screen QImage getPixstatsImage(); pixelStats *getPixelstats(){ return ps;} diff --git a/dftcolormap.cpp b/dftcolormap.cpp index 0786ea6a..9838f51c 100644 --- a/dftcolormap.cpp +++ b/dftcolormap.cpp @@ -26,7 +26,7 @@ QList dftColorMap::userStops; -dftColorMap::dftColorMap(int type, wavefront *wf, bool zeroBased, double errorMargin, double scale, +dftColorMap::dftColorMap(int type, const wavefront *wf, bool zeroBased, double errorMargin, double scale, QColor less, QColor more): QwtLinearColorMap( less, more ),m_wf(wf) { diff --git a/dftcolormap.h b/dftcolormap.h index 43d7d69b..c9c6ef33 100644 --- a/dftcolormap.h +++ b/dftcolormap.h @@ -24,11 +24,11 @@ class dftColorMap: public QwtLinearColorMap { public: - dftColorMap(int type = 0, wavefront *wf= 0, bool zeroBased = true, + dftColorMap(int type = 0, const wavefront *wf= 0, bool zeroBased = true, double errorMargin = .125, double scale = 1., QColor less = Qt::black, QColor more = Qt::white); void setRange(double low, double high); - wavefront *m_wf; + const wavefront *m_wf; static QList userStops; }; #endif // DFTCOLORMAP_H diff --git a/pixelstats.cpp b/pixelstats.cpp index a7e38f0d..f3f58c73 100644 --- a/pixelstats.cpp +++ b/pixelstats.cpp @@ -20,7 +20,6 @@ #include #include #include -#include "contourplot.h" #include "wavefront.h" #include "math.h" #include "utils.h" @@ -296,7 +295,7 @@ pixelStats::~pixelStats() } -void pixelStats::setData(wavefront *w){ +void pixelStats::setData(const wavefront *w){ m_wf = w; g_ub = m_wf->min + (m_wf->max-m_wf->min) * .9; g_lb = m_wf->min + (m_wf->max-m_wf->min) * .1; @@ -312,7 +311,7 @@ cv::Mat mat2gray(const cv::Mat& src) return dst; } -cv::Mat slope(wavefront * wf){ +cv::Mat slope(const wavefront * wf){ int half = wf->data.cols/2; cv::Mat gradx = cv::Mat::zeros(wf->data.rows,wf->data.cols, CV_64FC1); cv::Mat grady = cv::Mat::zeros(wf->data.rows,wf->data.cols, CV_64FC1); @@ -406,7 +405,7 @@ cv::Mat slope(wavefront * wf){ */ return mag; } -#include "dftarea.h" + void pixelStats::updateSurface(){ try { cv::Mat sur = cv::Mat::zeros(m_wf->data.rows, m_wf->data.cols, CV_8UC3); diff --git a/pixelstats.h b/pixelstats.h index eacd0406..60541f58 100644 --- a/pixelstats.h +++ b/pixelstats.h @@ -19,7 +19,7 @@ class pixelStats : public QWidget public: explicit pixelStats(QWidget *parent = 0); ~pixelStats(); - void setData(wavefront *w); + void setData(const wavefront *w); private slots: void bounds_valueChanged(); @@ -33,7 +33,7 @@ private slots: private: Ui::pixelStats *ui; - wavefront *m_wf; + const wavefront *m_wf; cv::Mat mask; void updateHisto(); void updateSurface(); From 2cbc1696d804fbfc14940006cf33407176ba7a51 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sun, 7 Dec 2025 17:31:23 +0100 Subject: [PATCH 10/15] showAllContours displays clean squares wfts --- contourplot.h | 4 ++-- surfacemanager.cpp | 32 ++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/contourplot.h b/contourplot.h index 07284ed6..de27614d 100644 --- a/contourplot.h +++ b/contourplot.h @@ -49,7 +49,7 @@ class ContourPlot: public QwtPlot static double m_waveRange; double contourRange; static QString m_zRangeMode; - ContourPlot(QWidget * = NULL, ContourTools *tools = 0, bool minimal = false); + ContourPlot(QWidget *parent = NULL, ContourTools *tools = 0, bool minimal = false); void setSurface(const wavefront * mat); void applyZeroOffset(bool useMiddle); void setZRange(); @@ -57,7 +57,7 @@ class ContourPlot: public QwtPlot void setTool(ContourTools* tool); void updateAspectRatio(); bool m_autoInterval; - bool m_minimal; + bool m_minimal; // when true, hide axes and colorbar bool m_linkProfile; QPen m_rulerPen; int m_radialDeg; diff --git a/surfacemanager.cpp b/surfacemanager.cpp index d594de2c..a6612311 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -2738,24 +2738,24 @@ void SurfaceManager::saveAllContours(){ m_allContours.save( fName ); } -#include "showallcontoursdlg.h" -void SurfaceManager::showAllContours(){ - showAllContoursDlg dlg; +#include "showallcontoursdlg.h" //TODO move +void SurfaceManager::showAllContours(){ //TODO move to contourview would make more sense as use only there + showAllContoursDlg dlg; //TODO not closing on app close if (!dlg.exec()) { return; } QRect rec = QGuiApplication::primaryScreen()->geometry(); QApplication::setOverrideCursor(Qt::WaitCursor); - ContourPlot *plot =new ContourPlot(0,0);//m_contourPlot; - //plot->m_minimal = true; - int cols = dlg.getColumns(); + ContourPlot *plot =new ContourPlot(0,0);//m_contourPlot; //TODO leaking ? + //plot->m_minimal = true; + int cols = dlg.getColumns(); //TODO parameter number of pixels unused here. update the dlg ui int width = rec.width()/cols; int height = width * .82; surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); QList list = saTools->SelectedWaveFronts(); - int rows = ceil((double)list.size()/cols); - int columns = std::min((int)list.size(),int(ceil((double)list.size()/rows))); + int rows = ceil((float)list.size()/cols); + int columns = std::min((int)list.size(),int(ceil((float)list.size()/rows))); const QSizeF size(columns * (width + 10), rows * (height + 10)); const QRect imageRect = QRect(0,0,size.width(),size.height()); qDebug() << "save all" << imageRect; @@ -2774,11 +2774,27 @@ void SurfaceManager::showAllContours(){ { wavefront * wf = m_wavefronts[list[i]]; plot->setSurface(wf); + + //All these replots and updates are necessary to get the canvas updateAspectRatio to work properly. + + // Resize the outer plot so its internal canvas area will match + // the requested image size. + plot->resize(width, height); + QCoreApplication::processEvents(); + // Now ensure the canvas is the target size + if (plot->canvas()) + plot->canvas()->resize(width, height); + plot->updateAspectRatio(); + plot->replot(); + plot->updateAspectRatio(); plot->replot(); + + int y_offset = height * (i/columns) + 10; int x_offset = width * (i%columns) + 10; const QRectF topRect( x_offset, y_offset, width, height ); renderer.render( plot, &painter, topRect ); + } painter.end(); From 4be683a10f157f9ba0b31402d772241a7447034e Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sun, 7 Dec 2025 18:20:57 +0100 Subject: [PATCH 11/15] take into account some clang-tidy reviews --- contourplot.cpp | 23 ++++++++++++++--------- contourplot.h | 3 +-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index 1bb126e3..61081d41 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -65,9 +65,9 @@ class MyZoomer: public QwtPlotZoomer } // Override zoom rectangle to maintain image aspect ratio - virtual void zoom(const QRectF &rect) + void zoom(const QRectF &rect) override { - if (!thePlot || !thePlot->m_wf) + if ((thePlot == nullptr) || (thePlot->m_wf == nullptr)) { QwtPlotZoomer::zoom(rect); return; @@ -115,18 +115,18 @@ class MyZoomer: public QwtPlotZoomer } // Override zoom state change to reapply aspect ratio when unzooming - virtual void rescale() + void rescale() override { QwtPlotZoomer::rescale(); // Check if we're back at the base zoom level - if (thePlot && zoomRectIndex() == 0) + if ((thePlot!=nullptr) && zoomRectIndex() == 0) { thePlot->updateAspectRatio(); } } // when holding shift key, show data value at cursor - virtual QwtText trackerTextF( const QPointF &pos ) const + QwtText trackerTextF( const QPointF &pos ) const override { if (thePlot->m_wf == 0) return QwtText(""); @@ -578,7 +578,7 @@ QString ContourPlot::m_zRangeMode("Auto"); double ContourPlot::m_zOffset = 0.; ContourPlot::ContourPlot( QWidget *parent, ContourTools *tools, bool minimal ): - QwtPlot( parent ),m_wf(0),m_tools(tools), m_autoInterval(false),m_minimal(minimal), m_linkProfile(true),m_contourPen(Qt::white) + QwtPlot( parent ),m_wf(0),m_tools(tools),m_minimal(minimal), m_linkProfile(true),m_contourPen(Qt::white) { spdlog::get("logger")->trace("ContourPlot::ContourPlot"); d_spectrogram = new QwtPlotSpectrogram(); @@ -702,12 +702,14 @@ void ContourPlot::updateAspectRatio() { static bool isReentering = false; - if (!m_wf) + if (m_wf == nullptr){ return; + } // Prevent re-entrancy - if (isReentering) + if (isReentering){ return; + } isReentering = true; QWidget *c = canvas(); @@ -724,7 +726,10 @@ void ContourPlot::updateAspectRatio() double dataRatio = imgWidth / imgHeight; double pixRatio = double(w) / double(h); - double x1, x2, y1, y2; + double x1; + double x2; + double y1; + double y2; if (pixRatio > dataRatio) { diff --git a/contourplot.h b/contourplot.h index de27614d..67cc1a18 100644 --- a/contourplot.h +++ b/contourplot.h @@ -50,13 +50,12 @@ class ContourPlot: public QwtPlot double contourRange; static QString m_zRangeMode; ContourPlot(QWidget *parent = NULL, ContourTools *tools = 0, bool minimal = false); - void setSurface(const wavefront * mat); + void setSurface(const wavefront * wft); void applyZeroOffset(bool useMiddle); void setZRange(); void setColorMap(int ndx); void setTool(ContourTools* tool); void updateAspectRatio(); - bool m_autoInterval; bool m_minimal; // when true, hide axes and colorbar bool m_linkProfile; QPen m_rulerPen; From c1f0c57a6256892eb82894fde28280b073b97c27 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sun, 14 Dec 2025 13:28:52 +0100 Subject: [PATCH 12/15] fixed race condition preventing zoom in some cases --- contourplot.cpp | 29 +++++++++++++++++++++++------ contourplot.h | 2 ++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index 61081d41..c301f0b4 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -45,6 +45,7 @@ #include #include #include "spdlog/spdlog.h" +#include double zOffset = 0; @@ -109,20 +110,28 @@ class MyZoomer: public QwtPlotZoomer adjustedRect.setLeft(rect.left() - extra); adjustedRect.setRight(rect.right() + extra); } - // If ratios match, no adjustment needed - + // Set guard to prevent intermediate aspect-ratio updates while zooming + thePlot->m_inZoomOperation = true; QwtPlotZoomer::zoom(adjustedRect); + // Ensure guard is cleared on next event loop tick in case rescale() isn't called + QTimer::singleShot(0, thePlot, SLOT(clearZoomFlag())); } // Override zoom state change to reapply aspect ratio when unzooming void rescale() override { QwtPlotZoomer::rescale(); + // Check if we're back at the base zoom level - if ((thePlot!=nullptr) && zoomRectIndex() == 0) + if ((thePlot != nullptr) && zoomRectIndex() == 0) { thePlot->updateAspectRatio(); } + + // Clear zoom guard (may have been set in zoom()) + if (thePlot != nullptr){ + thePlot->clearZoomFlag(); + } } // when holding shift key, show data value at cursor @@ -578,7 +587,7 @@ QString ContourPlot::m_zRangeMode("Auto"); double ContourPlot::m_zOffset = 0.; ContourPlot::ContourPlot( QWidget *parent, ContourTools *tools, bool minimal ): - QwtPlot( parent ),m_wf(0),m_tools(tools),m_minimal(minimal), m_linkProfile(true),m_contourPen(Qt::white) + QwtPlot( parent ),m_wf(0),m_tools(tools),m_minimal(minimal), m_linkProfile(true),m_contourPen(Qt::white), m_inZoomOperation(false) { spdlog::get("logger")->trace("ContourPlot::ContourPlot"); d_spectrogram = new QwtPlotSpectrogram(); @@ -701,7 +710,7 @@ void ContourPlot::setAlpha( int alpha ) void ContourPlot::updateAspectRatio() { static bool isReentering = false; - + if (m_wf == nullptr){ return; } @@ -715,6 +724,7 @@ void ContourPlot::updateAspectRatio() QWidget *c = canvas(); int w = c->width(); int h = c->height(); + if (w <= 0 || h <= 0){ isReentering = false; return; @@ -766,12 +776,19 @@ bool ContourPlot::eventFilter(QObject *obj, QEvent *event) { if (obj == canvas() && event->type() == QEvent::Resize) { - updateAspectRatio(); + if (!m_inZoomOperation) { + updateAspectRatio(); + } return false; } return QwtPlot::eventFilter(obj, event); } +void ContourPlot::clearZoomFlag() +{ + m_inZoomOperation = false; +} + #ifndef QT_NO_PRINTER void ContourPlot::printPlot() diff --git a/contourplot.h b/contourplot.h index 67cc1a18..c950d635 100644 --- a/contourplot.h +++ b/contourplot.h @@ -61,6 +61,7 @@ class ContourPlot: public QwtPlot QPen m_rulerPen; int m_radialDeg; bool m_do_fill; + bool m_inZoomOperation; signals: @@ -83,6 +84,7 @@ public slots: void contourFillChanged(int); void newDisplayErrorRange(double min, double max); void drawProfileLine(const double ang); + void clearZoomFlag(); #ifndef QT_NO_PRINTER void printPlot(); #endif From 8ad3499db9b4c184f240b8cf53e9fde22e525f20 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sun, 14 Dec 2025 14:55:30 +0100 Subject: [PATCH 13/15] factorize resize maths --- contourplot.cpp | 110 ++++++++++++++++++++++-------------------------- contourplot.h | 3 +- 2 files changed, 52 insertions(+), 61 deletions(-) diff --git a/contourplot.cpp b/contourplot.cpp index c301f0b4..8e9179ce 100644 --- a/contourplot.cpp +++ b/contourplot.cpp @@ -74,7 +74,7 @@ class MyZoomer: public QwtPlotZoomer return; } - // Get the canvas dimensions and aspect ratio (accounts for axes, labels, colorbar, etc.) + // Get the canvas dimensions QWidget *canvas = thePlot->canvas(); double canvasWidth = canvas->width(); double canvasHeight = canvas->height(); @@ -83,36 +83,24 @@ class MyZoomer: public QwtPlotZoomer QwtPlotZoomer::zoom(rect); return; } - double canvasRatio = canvasWidth / canvasHeight; - // Get the selected zoom rectangle dimensions and its aspect ratio + // Get the selected zoom rectangle dimensions double selWidth = rect.width(); double selHeight = rect.height(); - double selRatio = selWidth / selHeight; - QRectF adjustedRect = rect; + // Use shared aspect ratio adjustment logic to match canvas aspect ratio + QRectF adjustedRect = thePlot->adjustRectToAspectRatio( + selWidth, selHeight, canvasWidth, canvasHeight); + + // Translate adjusted dimensions back to rect position + QRectF zoomRect(rect.left() + adjustedRect.left(), + rect.top() + adjustedRect.top(), + adjustedRect.width(), + adjustedRect.height()); - // The zoom rectangle should have the same aspect ratio as the canvas - // to ensure no distortion when displayed - if (selRatio > canvasRatio) - { - // Selected rect is wider than canvas → expand height to match canvas ratio - double newHeight = selWidth / canvasRatio; - double extra = (newHeight - selHeight) / 2.0; - adjustedRect.setTop(rect.top() - extra); - adjustedRect.setBottom(rect.bottom() + extra); - } - else if (selRatio < canvasRatio) - { - // Selected rect is taller than canvas → expand width to match canvas ratio - double newWidth = selHeight * canvasRatio; - double extra = (newWidth - selWidth) / 2.0; - adjustedRect.setLeft(rect.left() - extra); - adjustedRect.setRight(rect.right() + extra); - } // Set guard to prevent intermediate aspect-ratio updates while zooming thePlot->m_inZoomOperation = true; - QwtPlotZoomer::zoom(adjustedRect); + QwtPlotZoomer::zoom(zoomRect); // Ensure guard is cleared on next event loop tick in case rescale() isn't called QTimer::singleShot(0, thePlot, SLOT(clearZoomFlag())); } @@ -587,7 +575,7 @@ QString ContourPlot::m_zRangeMode("Auto"); double ContourPlot::m_zOffset = 0.; ContourPlot::ContourPlot( QWidget *parent, ContourTools *tools, bool minimal ): - QwtPlot( parent ),m_wf(0),m_tools(tools),m_minimal(minimal), m_linkProfile(true),m_contourPen(Qt::white), m_inZoomOperation(false) + QwtPlot( parent ),m_wf(0),m_tools(tools),m_minimal(minimal), m_linkProfile(true), m_inZoomOperation(false), m_contourPen(Qt::white) { spdlog::get("logger")->trace("ContourPlot::ContourPlot"); d_spectrogram = new QwtPlotSpectrogram(); @@ -707,6 +695,37 @@ void ContourPlot::setAlpha( int alpha ) replot(); } +// Helper: Adjust rect to match aspect ratio of canvas, given wavefront data +// Takes wavefront dimensions and canvas, returns adjusted rect maintaining aspect ratio +QRectF ContourPlot::adjustRectToAspectRatio( + double baseWidth, double baseHeight, double canvasWidth, double canvasHeight) const +{ + double dataRatio = baseWidth / baseHeight; + double canvasRatio = canvasWidth / canvasHeight; + + double x1 = 0, x2 = baseWidth; + double y1 = 0, y2 = baseHeight; + + if (canvasRatio > dataRatio) + { + // Canvas is wider → expand X symmetrically + double newWidth = baseHeight * canvasRatio; + double extra = (newWidth - baseWidth) / 2.0; + x1 = -extra; + x2 = baseWidth + extra; + } + else if (canvasRatio < dataRatio) + { + // Canvas is taller → expand Y symmetrically + double newHeight = baseWidth / canvasRatio; + double extra = (newHeight - baseHeight) / 2.0; + y1 = -extra; + y2 = baseHeight + extra; + } + + return QRectF(x1, y1, x2 - x1, y2 - y1); +} + void ContourPlot::updateAspectRatio() { static bool isReentering = false; @@ -722,10 +741,10 @@ void ContourPlot::updateAspectRatio() isReentering = true; QWidget *c = canvas(); - int w = c->width(); - int h = c->height(); + int canvas_w = c->width(); + int canvas_h = c->height(); - if (w <= 0 || h <= 0){ + if (canvas_w <= 0 || canvas_h <= 0){ isReentering = false; return; } @@ -733,39 +752,10 @@ void ContourPlot::updateAspectRatio() double imgWidth = m_wf->data.cols; double imgHeight = m_wf->data.rows; - double dataRatio = imgWidth / imgHeight; - double pixRatio = double(w) / double(h); - - double x1; - double x2; - double y1; - double y2; - - if (pixRatio > dataRatio) - { - // Canvas is wider → Y fits perfectly, X must be expanded - double scaledWidth = imgHeight * pixRatio; // what X must become - double extra = (scaledWidth - imgWidth) * 0.5; - x1 = -extra; - x2 = imgWidth + extra; - - y1 = 0; - y2 = imgHeight; - } - else - { - // Canvas is taller → X fits perfectly, Y must be expanded - double scaledHeight = imgWidth / pixRatio; - double extra = (scaledHeight - imgHeight) * 0.5; - y1 = -extra; - y2 = imgHeight + extra; - - x1 = 0; - x2 = imgWidth; - } + QRectF adjustedRect = adjustRectToAspectRatio(imgWidth, imgHeight, canvas_w, canvas_h); - setAxisScale(QwtPlot::xBottom, x1, x2); - setAxisScale(QwtPlot::yLeft, y1, y2); + setAxisScale(QwtPlot::xBottom, adjustedRect.left(), adjustedRect.right()); + setAxisScale(QwtPlot::yLeft, adjustedRect.top(), adjustedRect.bottom()); replot(); diff --git a/contourplot.h b/contourplot.h index c950d635..cf86c67c 100644 --- a/contourplot.h +++ b/contourplot.h @@ -55,6 +55,8 @@ class ContourPlot: public QwtPlot void setZRange(); void setColorMap(int ndx); void setTool(ContourTools* tool); + QRectF adjustRectToAspectRatio(double baseWidth, double baseHeight, + double canvasWidth, double canvasHeight) const; void updateAspectRatio(); bool m_minimal; // when true, hide axes and colorbar bool m_linkProfile; @@ -94,7 +96,6 @@ public slots: void initPlot(); bool eventFilter(QObject *obj, QEvent *event); - QColor m_contourPen; void ruler(); From 0441de09581ec290cf21db467d7fe03bb51c0753 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Thu, 20 Nov 2025 13:53:22 +0100 Subject: [PATCH 14/15] adding clang-tidy --- .github/workflows/build-linux.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index fae9f13d..0901dfcd 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -12,6 +12,9 @@ env: jobs: build-linux: + permissions: + contents: read + pull-requests: write strategy: fail-fast: false matrix: @@ -20,7 +23,7 @@ jobs: steps: - uses: actions/checkout@v4 - run: sudo apt update - - run: sudo apt install -y apt-utils build-essential wget qt6-base-dev-tools qt6-declarative-dev qt6-multimedia-dev libqt6charts6-dev libqt6datavisualization6-dev libqt6svg6-dev libopencv-core-dev libopencv-dev libqwt-qt5-6 libqwt-qt5-dev libarmadillo-dev libgl1-mesa-dev libglu1-mesa-dev + - run: sudo apt install -y apt-utils build-essential wget qt6-base-dev-tools qt6-declarative-dev qt6-multimedia-dev libqt6charts6-dev libqt6datavisualization6-dev libqt6svg6-dev libopencv-core-dev libopencv-dev libqwt-qt5-6 libqwt-qt5-dev libarmadillo-dev libgl1-mesa-dev libglu1-mesa-dev bear - run: wget -O qwt-${{env.QWT_version}}.zip https://sourceforge.net/projects/qwt/files/qwt/${{env.QWT_version}}/qwt-${{env.QWT_version}}.zip/download?use_mirror=pilotfiber - run: 7z x qwt-${{env.QWT_version}}.zip - run: cd qwt-${{env.QWT_version}} ; /usr/lib/qt6/bin/qmake @@ -29,5 +32,20 @@ jobs: - run: /usr/lib/qt6/bin/qmake DFTFringe.pro - uses: ammaraskar/gcc-problem-matcher@master - run: echo "::add-matcher::.github/matcher/uic_matcher.json" - - run: make -j4 + + - name: capture compile_commands.json from build + run: bear -- make -j4 - run: echo "::remove-matcher owner=uic-problem-matcher::" + + - name: Run C++ Linter (clang-tidy) + if: strategy.job-index == 0 #run only for first OS of the matrix + uses: cpp-linter/cpp-linter-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + style: '' # we don't want check from clang-format + lines-changed-only: 'true' # Only lines in the diff that contain additions are analyzed. Avoid noise from existing code. + thread-comments: 'update' + tidy-review: true + passive-reviews: true + ignore: 'bezier|boost|SingleApplication|spdlog|zernike|moc_*|ui_*|qwt*' From c263477ba09dcd09af541502b174d62b83201ec8 Mon Sep 17 00:00:00 2001 From: Julien Staub Date: Sun, 14 Dec 2025 15:20:00 +0100 Subject: [PATCH 15/15] update clang-tidy to only enable most important checks --- .clang-tidy | 6 ++++++ .github/workflows/build-linux.yml | 1 + 2 files changed, 7 insertions(+) create mode 100644 .clang-tidy diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..bd8a620d --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,6 @@ +Checks: > + clang-analyzer-* + bugprone-* + performance-unnecessary-* + modernize-use-nullptr + modernize-use-nodiscard diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 0901dfcd..701c888f 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -46,6 +46,7 @@ jobs: style: '' # we don't want check from clang-format lines-changed-only: 'true' # Only lines in the diff that contain additions are analyzed. Avoid noise from existing code. thread-comments: 'update' + tidy-checks: '' # rely solely on .clang-tidy file tidy-review: true passive-reviews: true ignore: 'bezier|boost|SingleApplication|spdlog|zernike|moc_*|ui_*|qwt*'