From f7da5c52a6c08076f4040689970566ea05369b90 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 08:12:59 +0200 Subject: [PATCH 01/20] WIP single source of truth for QSettings --- DFTFringe.pro | 11 +++---- DFTFringe_Dale.pro | 5 ++++ DFTFringe_QT5.pro | 11 +++---- settingsfacade.cpp | 37 ++++++++++++++++++++++++ settingsfacade.h | 41 ++++++++++++++++++++++++++ settingsstores.cpp | 60 +++++++++++++++++++++++++++++++++++++++ settingsstores.h | 52 +++++++++++++++++++++++++++++++++ settingsstores_fields.inc | 47 ++++++++++++++++++++++++++++++ usercolormapdlg.cpp | 2 +- 9 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 settingsfacade.cpp create mode 100644 settingsfacade.h create mode 100644 settingsstores.cpp create mode 100644 settingsstores.h create mode 100644 settingsstores_fields.inc diff --git a/DFTFringe.pro b/DFTFringe.pro index e94e9cab..d781a12c 100644 --- a/DFTFringe.pro +++ b/DFTFringe.pro @@ -265,6 +265,8 @@ SOURCES += SingleApplication/singleapplication.cpp \ zernikepolar.cpp \ zernikeprocess.cpp \ zernikes.cpp \ + settingsfacade.cpp \ + settingsstores.cpp \ zernikesmoothingdlg.cpp HEADERS += bezier/bezier.h \ @@ -356,6 +358,8 @@ HEADERS += bezier/bezier.h \ settingsGeneral2.h \ settingsigram.h \ settingsigramimportconfig.h \ + settingsfacade.h \ + settingsstores.h \ settingsprofile.h \ showaliasdlg.h \ showallcontoursdlg.h \ @@ -550,8 +554,5 @@ DISTFILES += buildingDFTFringe64.txt \ COPYING.LESSER.txt \ COPYING.txt \ README.md \ - RevisionHistory.html - - - - + RevisionHistory.html \ + settingsstores_fields.inc diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index 76fd813f..36b6e654 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -141,6 +141,8 @@ SOURCES += main.cpp \ outlinedialog.cpp \ psitiltoptions.cpp \ contourrulerparams.cpp \ + settingsfacade.cpp \ + settingsstores.cpp \ zernikesmoothingdlg.cpp \ zernike/zapm.cpp \ SingleApplication/singleapplication.cpp \ @@ -262,6 +264,8 @@ HEADERS += mainwindow.h \ outlinedialog.h \ psitiltoptions.h \ contourrulerparams.h \ + settingsfacade.h \ + settingsstores.h \ zernikesmoothingdlg.h \ bezier/bezier.h \ zernike/zapm_interface.h \ @@ -498,6 +502,7 @@ DISTFILES += \ COPYING.txt \ RevisionHistory.html \ README.md \ + settingsstores_fields.inc TRANSLATIONS = dftfringe_fr.ts diff --git a/DFTFringe_QT5.pro b/DFTFringe_QT5.pro index 65573323..58d60aac 100644 --- a/DFTFringe_QT5.pro +++ b/DFTFringe_QT5.pro @@ -264,6 +264,8 @@ SOURCES += SingleApplication/singleapplication.cpp \ zernikepolar.cpp \ zernikeprocess.cpp \ zernikes.cpp \ + settingsfacade.cpp \ + settingsstores.cpp \ zernikesmoothingdlg.cpp HEADERS += bezier/bezier.h \ @@ -355,6 +357,8 @@ HEADERS += bezier/bezier.h \ settingsGeneral2.h \ settingsigram.h \ settingsigramimportconfig.h \ + settingsfacade.h \ + settingsstores.h \ settingsprofile.h \ showaliasdlg.h \ showallcontoursdlg.h \ @@ -549,8 +553,5 @@ DISTFILES += buildingDFTFringe64.txt \ COPYING.LESSER.txt \ COPYING.txt \ README.md \ - RevisionHistory.html - - - - + RevisionHistory.html \ + settingsstores_fields.inc diff --git a/settingsfacade.cpp b/settingsfacade.cpp new file mode 100644 index 00000000..e765494a --- /dev/null +++ b/settingsfacade.cpp @@ -0,0 +1,37 @@ +#include "settingsfacade.h" + +SettingsFacade &SettingsFacade::instance() +{ + static SettingsFacade facade; + return facade; +} + +MirrorSettingsStore &SettingsFacade::mirrorStore() +{ + return m_mirrorStore; +} + +const MirrorSettingsStore &SettingsFacade::mirrorStore() const +{ + return m_mirrorStore; +} + +GeneralProcessingSettingsStore &SettingsFacade::generalProcessingStore() +{ + return m_generalProcessingStore; +} + +const GeneralProcessingSettingsStore &SettingsFacade::generalProcessingStore() const +{ + return m_generalProcessingStore; +} + +ContourSettingsStore &SettingsFacade::contourStore() +{ + return m_contourStore; +} + +const ContourSettingsStore &SettingsFacade::contourStore() const +{ + return m_contourStore; +} diff --git a/settingsfacade.h b/settingsfacade.h new file mode 100644 index 00000000..07a028ef --- /dev/null +++ b/settingsfacade.h @@ -0,0 +1,41 @@ +#ifndef SETTINGSFACADE_H +#define SETTINGSFACADE_H + +#include "settingsstores.h" + +/** + * @brief Thin entry point that delegates to domain-specific settings stores. + * + * This class intentionally stays small; domain behavior belongs in internal + * stores such as MirrorSettingsStore or ContourSettingsStore. + */ +class SettingsFacade +{ +public: + /** @brief Returns process-wide facade instance. */ + static SettingsFacade &instance(); + + /** @brief Accessor for mirror settings persistence. */ + MirrorSettingsStore &mirrorStore(); + /** @brief Const accessor for mirror settings persistence. */ + const MirrorSettingsStore &mirrorStore() const; + + /** @brief Accessor for general processing settings persistence. */ + GeneralProcessingSettingsStore &generalProcessingStore(); + /** @brief Const accessor for general processing settings persistence. */ + const GeneralProcessingSettingsStore &generalProcessingStore() const; + + /** @brief Accessor for contour settings persistence. */ + ContourSettingsStore &contourStore(); + /** @brief Const accessor for contour settings persistence. */ + const ContourSettingsStore &contourStore() const; + +private: + SettingsFacade() = default; + + MirrorSettingsStore m_mirrorStore; + GeneralProcessingSettingsStore m_generalProcessingStore; + ContourSettingsStore m_contourStore; +}; + +#endif // SETTINGSFACADE_H diff --git a/settingsstores.cpp b/settingsstores.cpp new file mode 100644 index 00000000..c088cf2c --- /dev/null +++ b/settingsstores.cpp @@ -0,0 +1,60 @@ +#include "settingsstores.h" + +#include + +#define SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS(type, name, defaultValue, key, converter) \ + value.name = s.value(key, defaultValue).converter(); + +#define SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS(type, name, defaultValue, key, converter) \ + s.setValue(key, value.name); + +MirrorSettings MirrorSettingsStore::load() const +{ + QSettings s; + + MirrorSettings value{}; + SETTINGS_STORE_FOR_EACH_MIRROR_FIELD(SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS) + + return value; +} + +void MirrorSettingsStore::save(const MirrorSettings &value) const +{ + QSettings s; + SETTINGS_STORE_FOR_EACH_MIRROR_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) +} + +GeneralProcessingSettings GeneralProcessingSettingsStore::load() const +{ + QSettings s; + + GeneralProcessingSettings value{}; + SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS) + + return value; +} + +void GeneralProcessingSettingsStore::save(const GeneralProcessingSettings &value) const +{ + QSettings s; + SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) +} + +ContourSettings ContourSettingsStore::load() const +{ + QSettings s; + + ContourSettings value{}; + SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS) + + return value; +} + +void ContourSettingsStore::save(const ContourSettings &value) const +{ + QSettings s; + SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) +} + +#undef SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS +#undef SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS diff --git a/settingsstores.h b/settingsstores.h new file mode 100644 index 00000000..1bbb6834 --- /dev/null +++ b/settingsstores.h @@ -0,0 +1,52 @@ +#ifndef SETTINGSSTORES_H +#define SETTINGSSTORES_H + +#include + +class QSettings; + +#include "settingsstores_fields.inc" + +#define SETTINGS_STORE_DECLARE_STRUCT_FIELD(type, name, defaultValue, key, converter) type name = defaultValue; + + +struct MirrorSettings { + SETTINGS_STORE_FOR_EACH_MIRROR_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) +}; + +class MirrorSettingsStore { +public: + + MirrorSettings load() const; + void save(const MirrorSettings &value) const; +}; + + + +struct GeneralProcessingSettings { + SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) +}; + +class GeneralProcessingSettingsStore { +public: + + GeneralProcessingSettings load() const; + void save(const GeneralProcessingSettings &value) const; +}; + + + +struct ContourSettings { + SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) +}; + +class ContourSettingsStore { +public: + + ContourSettings load() const; + void save(const ContourSettings &value) const; +}; + +#undef SETTINGS_STORE_DECLARE_STRUCT_FIELD + +#endif // SETTINGSSTORES_H diff --git a/settingsstores_fields.inc b/settingsstores_fields.inc new file mode 100644 index 00000000..d34146e2 --- /dev/null +++ b/settingsstores_fields.inc @@ -0,0 +1,47 @@ +// Shared settings schema list. +// Entry format for callbacks: +// FIELD(type, memberName, defaultValue, key, converter) + +#define SETTINGS_STORE_FOR_EACH_MIRROR_FIELD(FIELD) \ + FIELD(QString, mirrorName, QStringLiteral("default"), "config mirror name", toString) \ + FIELD(bool, doNull, true, "config doNull", toBool) \ + FIELD(double, diameter, 200.0, "config diameter", toDouble) \ + FIELD(double, roc, 2000.0, "config roc", toDouble) \ + FIELD(double, obstruction, 0.0, "config obstruction", toDouble) \ + FIELD(double, cc, -1.0, "config cc", toDouble) \ + FIELD(double, lambda, 640.0, "config lambda", toDouble) \ + FIELD(double, fringeSpacing, 1.0, "config fringe spacing", toDouble) \ + FIELD(bool, flipH, false, "flipH", toBool) \ + FIELD(bool, useAnnulus, false, "md use annulus", toBool) \ + FIELD(double, annulusPercent, 0.0, "md annulus percent", toDouble) \ + FIELD(bool, annulusToObstruction, false, "md Annulus to obs", toBool) \ + FIELD(int, outlineShape, 0, "outlineShape", toInt) \ + FIELD(double, ellipseMinorAxis, 50.0, "ellipseMinorAxis", toDouble) \ + FIELD(bool, apertureReductionEnabled, false, "configAperatureReductionChecked", toBool) \ + FIELD(double, apertureReduction, 0.0, "config aperatureReduction", toDouble) \ + FIELD(QString, projectPath, QString(), "projectPath", toString) \ + FIELD(QString, mirrorConfigFile, QString(), "mirrorConfigFile", toString) + +#define SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(FIELD) \ + FIELD(bool, useMakeStarTest, false, "useMakeStarTest", toBool) \ + FIELD(int, wavefrontDownSizeValue, 650, "wavefrontDownSizeValue", toInt) \ + FIELD(bool, wavefrontShouldDownsize, false, "wavefrontShouldDownsize", toBool) \ + FIELD(double, outputLambda, 550.0, "outputLambda", toDouble) \ + FIELD(bool, applyOffsets, false, "applyOffsets", toBool) \ + FIELD(int, astigDistGraphWidth, 0, "AstigDistGraphWidth", toInt) \ + FIELD(bool, gaussianBlurEnabled, true, "GBlur", toBool) \ + FIELD(int, gaussianBlurValue, 20, "GBValue", toInt) \ + FIELD(bool, gaussianRadiusConverted, false, "gaussianRadiusConverted", toBool) \ + FIELD(int, lowMemoryThreshold, 0, "lowMemoryThreshold", toInt) \ + FIELD(bool, deletePrevWave, false, "deletePrevWave", toBool) + +#define SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(FIELD) \ + FIELD(double, contourRange, 0.100, "contourRange", toDouble) \ + FIELD(bool, contourShowFill, true, "contourShowFill", toBool) \ + FIELD(bool, contourShowLines, true, "contourShowLines", toBool) \ + FIELD(bool, contourShowRuler, false, "contourShowRuler", toBool) \ + FIELD(int, colorMapType, 0, "colorMapType", toInt) \ + FIELD(int, colorMapIndex, 1, "colorMap ndx", toInt) \ + FIELD(QString, contourLineColor, QStringLiteral("grey"), "ContourLineColor", toString) \ + FIELD(QString, contourRulerColor, QStringLiteral("grey"), "ContourRulerColor", toString) \ + FIELD(double, contourRulerRadialDeg, 0.0, "contourRulerRadialDeg", toDouble) diff --git a/usercolormapdlg.cpp b/usercolormapdlg.cpp index ed627550..3a2f8672 100644 --- a/usercolormapdlg.cpp +++ b/usercolormapdlg.cpp @@ -283,7 +283,7 @@ void userColorMapDlg::on_pb10_clicked() ui->pb10->setStyleSheet(s); ui->pb10->update(); QSettings set; - set.setValue("userColorStopColor09",c.name()); + set.setValue("userColorStopColor10",c.name()); setColorMap(); emit colorMapChanged(5); } From ed905ba04d6cfd5bfe6f00a5d88a88ce13cce006 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 09:45:44 +0200 Subject: [PATCH 02/20] force facade usage with friend class --- settingsfacade.h | 11 +++-------- settingsstores.h | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/settingsfacade.h b/settingsfacade.h index 07a028ef..e1f54cd7 100644 --- a/settingsfacade.h +++ b/settingsfacade.h @@ -12,27 +12,22 @@ class SettingsFacade { public: - /** @brief Returns process-wide facade instance. */ + static SettingsFacade &instance(); - /** @brief Accessor for mirror settings persistence. */ MirrorSettingsStore &mirrorStore(); - /** @brief Const accessor for mirror settings persistence. */ const MirrorSettingsStore &mirrorStore() const; - /** @brief Accessor for general processing settings persistence. */ GeneralProcessingSettingsStore &generalProcessingStore(); - /** @brief Const accessor for general processing settings persistence. */ const GeneralProcessingSettingsStore &generalProcessingStore() const; - /** @brief Accessor for contour settings persistence. */ ContourSettingsStore &contourStore(); - /** @brief Const accessor for contour settings persistence. */ const ContourSettingsStore &contourStore() const; private: - SettingsFacade() = default; + SettingsFacade() = default; // Enforce singleton + // Only facade owns these MirrorSettingsStore m_mirrorStore; GeneralProcessingSettingsStore m_generalProcessingStore; ContourSettingsStore m_contourStore; diff --git a/settingsstores.h b/settingsstores.h index 1bbb6834..bb167bb0 100644 --- a/settingsstores.h +++ b/settingsstores.h @@ -15,8 +15,11 @@ struct MirrorSettings { }; class MirrorSettingsStore { -public: +private: + friend class SettingsFacade; // Only facade can construct + MirrorSettingsStore() = default; +public: MirrorSettings load() const; void save(const MirrorSettings &value) const; }; @@ -28,8 +31,11 @@ struct GeneralProcessingSettings { }; class GeneralProcessingSettingsStore { +private: + friend class SettingsFacade; + GeneralProcessingSettingsStore() = default; + public: - GeneralProcessingSettings load() const; void save(const GeneralProcessingSettings &value) const; }; @@ -41,8 +47,11 @@ struct ContourSettings { }; class ContourSettingsStore { +private: + friend class SettingsFacade; + ContourSettingsStore() = default; + public: - ContourSettings load() const; void save(const ContourSettings &value) const; }; From 681c56d3462517b9a5c0a5afcf082fe33af307bc Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 10:21:49 +0200 Subject: [PATCH 03/20] use draft mirror config to fix cancel button --- mirrordlg.cpp | 99 +++++++++++++++++++++++++++++++++++++++------------ mirrordlg.h | 15 ++++++++ 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 95403981..d9260bdd 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -19,6 +19,7 @@ #include "ui_mirrordlg.h" #include "spdlog/spdlog.h" #include +#include #include #include #include @@ -134,6 +135,59 @@ mirrorDlg::~mirrorDlg() spdlog::get("logger")->trace("mirrorDlg::~mirrorDlg"); delete ui; } + +void mirrorDlg::loadDraftFromSettings() +{ + // Load mirror settings from persistent storage via facade into working draft. + // This ensures every dialog open/show starts with the last-saved state. + m_draft = SettingsFacade::instance().mirrorStore().load(); + + // Sync public member variables with draft for backward compatibility. + m_name = m_draft.mirrorName; + diameter = m_draft.diameter; + roc = m_draft.roc; + obs = m_draft.obstruction; + cc = m_draft.cc; + lambda = m_draft.lambda; + fringeSpacing = m_draft.fringeSpacing; + fliph = m_draft.flipH; + doNull = m_draft.doNull; + m_useAnnular = m_draft.useAnnulus; + m_annularObsPercent = m_draft.annulusPercent; + m_connectAnnulusToObs = m_draft.annulusToObstruction; + m_outlineShape = (outlineShape)m_draft.outlineShape; + m_verticalAxis = m_draft.ellipseMinorAxis; + aperatureReduction = m_draft.apertureReduction; + m_aperatureReductionEnabled = m_draft.apertureReductionEnabled; + m_projectPath = m_draft.projectPath; +} + +void mirrorDlg::showEvent(QShowEvent *event) +{ + // Reload draft from persistent settings before dialog becomes visible. + // This ensures Cancel always reverts to the last-saved state. + loadDraftFromSettings(); + + // Sync UI with reloaded draft values + ui->name->setText(m_draft.mirrorName); + ui->diameter->setText(QString("%1").arg(diameter, 6, 'f', 2)); + ui->roc->setText(QString("%1").arg(roc, 6, 'f', 2)); + ui->obs->setText(QString("%1").arg(obs, 6, 'f', 2)); + ui->lambda->setText(QString("%1").arg(lambda, 6, 'f', 1)); + ui->cc->setText(QString("%1").arg(cc, 6, 'f', 2)); + ui->flipH->setChecked(m_draft.flipH); + ui->nullCB->setChecked(m_draft.doNull); + ui->fringeSpacingEdit->setText(QString("%1").arg(fringeSpacing, 6, 'f', 3)); + ui->ellipseShape->setChecked(m_outlineShape == ELLIPSE); + ui->minorAxisEdit->setText(QString::number(m_verticalAxis)); + ui->ReducApp->setChecked(m_aperatureReductionEnabled); + ui->reduceValue->setValue(aperatureReduction); + ui->useAnnulus->setChecked(m_useAnnular); + ui->annulusPercent->setValue(m_annularObsPercent * 100); + + QDialog::showEvent(event); +} + bool mirrorDlg::shouldFlipH(){ return ui->flipH->isChecked(); } @@ -617,7 +671,6 @@ void mirrorDlg::on_unitsCB_clicked(bool checked) void mirrorDlg::on_buttonBox_accepted() { - QSettings settings; setclearAp(); updateZ8(); @@ -627,32 +680,32 @@ void mirrorDlg::on_buttonBox_accepted() updateAutoInvertStatus(); } - settings.setValue("config mirror name", ui->name->text()); - settings.setValue("config roc", roc); - settings.setValue("config lambda",lambda); - settings.setValue("config diameter",diameter); - settings.setValue("config obstruction", obs); - settings.setValue("config cc", cc); - settings.setValue("flipH", ui->flipH->isChecked()); - settings.setValue("md Annulus to obs", m_useAnnular); - - settings.setValue("outlineShape", m_outlineShape); - fringeSpacing = ui->fringeSpacingEdit->text().toDouble(); - settings.setValue("config fringe spacing", fringeSpacing); - //settings.setValue("config unitsMM", mm); - settings.setValue("config doNull",doNull); - settings.setValue("outlineShape",(int)m_outlineShape); - settings.setValue("ellipseMinorAxis",m_verticalAxis); - settings.setValue("configAperatureReductionChecked", m_aperatureReductionEnabled); - settings.setValue("config aperatureReduction", aperatureReduction); - settings.setValue("md annulus percent", m_annularObsPercent); - settings.setValue("md use annulus", m_useAnnular); - if (m_obsChanged) + // Update draft with current UI values + m_draft.mirrorName = ui->name->text(); + m_draft.diameter = diameter; + m_draft.roc = roc; + m_draft.obstruction = obs; + m_draft.cc = cc; + m_draft.lambda = lambda; + m_draft.fringeSpacing = ui->fringeSpacingEdit->text().toDouble(); + m_draft.flipH = ui->flipH->isChecked(); + m_draft.doNull = doNull; + m_draft.useAnnulus = m_useAnnular; + m_draft.annulusPercent = m_annularObsPercent; + m_draft.annulusToObstruction = m_connectAnnulusToObs; + m_draft.outlineShape = (int)m_outlineShape; + m_draft.ellipseMinorAxis = m_verticalAxis; + m_draft.apertureReductionEnabled = m_aperatureReductionEnabled; + m_draft.apertureReduction = aperatureReduction; + m_draft.projectPath = m_projectPath; + + // Persist draft to QSettings via facade (single atomic save) + SettingsFacade::instance().mirrorStore().save(m_draft); + if (m_obsChanged) emit obstructionChanged(); emit recomputeZerns(); if (m_aperatureReductionValueChanged){ - QMessageBox::warning(0, tr("Aperature Reduction value was changed."), tr("Aperature Reduction was changed.\n" "The wave front will not be correct until it is recomputed from the interferogram.")); diff --git a/mirrordlg.h b/mirrordlg.h index a810e1e8..64130d11 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -21,6 +21,7 @@ #include #include #include "autoinvertdlg.h" +#include "settingsfacade.h" namespace Ui { class mirrorDlg; @@ -133,15 +134,29 @@ private slots: void recomputeZerns(); void aperatureChanged(); +protected: + /** @brief Reload draft settings before dialog becomes visible. + * Ensures Cancel always reverts to the last-saved state (issue #121). */ + void showEvent(QShowEvent *event) override; + private: explicit mirrorDlg(QWidget *parent = 0); void setclearAp(); + + /** @brief Load draft from persistent settings before dialog is shown. + * Ensures Cancel always reverts to the last saved state. */ + void loadDraftFromSettings(); Ui::mirrorDlg *ui; bool m_aperatureReductionValueChanged; QTimer spacingChangeTimer; void saveJson(const QString &fileName); void enableAnnular(bool enable); + + /** @brief Working copy of mirror settings during dialog edit. + * All UI modifications update this draft. On OK, it persists via facade. + * On Cancel, it's discarded, leaving member variables unchanged. */ + MirrorSettings m_draft; }; #endif // MIRRORDLG_H From 004ff48830055ebe0ad733aa85e865eeb7ef6ef7 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 10:28:59 +0200 Subject: [PATCH 04/20] all mirror configs are accessed though settingsStore. No more qsettings duplication --- mirrordlg.cpp | 102 ++++++++++++-------------------------------------- 1 file changed, 24 insertions(+), 78 deletions(-) diff --git a/mirrordlg.cpp b/mirrordlg.cpp index d9260bdd..bd7684b5 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -46,88 +46,29 @@ mirrorDlg::mirrorDlg(QWidget *parent) : m_useAnnular = false; m_connectAnnulusToObs = false; ui->setupUi(this); - QSettings settings; - m_name = settings.value("config mirror name", "default").toString(); - ui->name->setText(m_name); - doNull = settings.value("config doNull", true).toBool(); - m_useAnnular = settings.value("md use annulus", false).toBool(); - ui->useAnnulus->setChecked(m_useAnnular); - enableAnnular(m_useAnnular); - ui->annulusPercent->setValue(settings.value("md annulus percent",0.).toDouble() * 100 ); - - ui->nullCB->setChecked(doNull); - diameter = settings.value("config diameter", 200.).toDouble(); - aperatureReduction = settings.value("config aperatureReduction", 0.).toDouble(); - m_aperatureReductionEnabled = settings.value("configAperatureReductionChecked",false).toBool(); - - roc = settings.value("config roc", 2000.).toDouble(); - FNumber = roc/(2. * diameter); + + // Initialize defaults only; loadDraftFromSettings() called in showEvent() populates UI + FNumber = 0.0; ui->FNumber->blockSignals(true); ui->roc->blockSignals(true); ui->lambda->blockSignals(true); ui->cc->blockSignals(true); ui->unitsCB->blockSignals(true); ui->fringeSpacingEdit->blockSignals(true); - - if (!doNull){ - ui->roc->hide(); - ui->rocLab->hide(); - ui->FNumber->hide(); - ui->fnumberLab->hide(); - } - else - { ui->roc->show(); - ui->rocLab->show(); - ui->fnumberLab->show(); - ui->FNumber->show(); - ui->roc->setText(QString("%1").arg(roc, 6, 'f', 2)); - ui->FNumber->setText(QString("%1").arg(FNumber, 6, 'f', 2)); - } - lambda = settings.value("config lambda", 640).toDouble(); - - ui->lambda->setText(QString("%1").arg(lambda, 6 ,'f' ,1)); - - obs = settings.value("config obstruction", 0.).toDouble(); - - cc = settings.value("config cc", -1.).toDouble(); - - ui->cc->setText(QString("%1").arg(cc, 6, 'f', 2)); - - ui->ReducApp->setChecked( m_aperatureReductionEnabled); - if ( m_aperatureReductionEnabled) - ui->reduceValue->setEnabled(true); - - ui->reduceValue->setValue(aperatureReduction); - - + ui->minorAxisEdit->blockSignals(true); + ui->unitsCB->setChecked(mm); - - ui->FNumber->blockSignals(false); - ui->flipH->setChecked((settings.value( "flipH", false).toBool())); - m_projectPath = settings.value("projectPath", "").toString(); - fringeSpacing = settings.value("config fringe spacing", 1.).toDouble(); - - ui->fringeSpacingEdit->setText(QString("%1").arg(fringeSpacing, 6, 'f', 3)); - ui->fringeSpacingEdit->blockSignals(false); - m_outlineShape = (outlineShape)settings.value("outlineShape", CIRCLE).toInt(); - ui->minorAxisEdit->setText(QString::number(settings.value("ellipseMinorAxis", 50.).toDouble())); connect(&spacingChangeTimer, &QTimer::timeout, this, &mirrorDlg::spacingChangeTimeout); - if (m_verticalAxis == 0) - m_verticalAxis = diameter; - ui->ellipseShape->setChecked(m_outlineShape == ELLIPSE); - ui->minorAxisEdit->setText(QString().number(m_verticalAxis)); - ui->diameter->setText(QString("%1").arg(diameter, 6, 'f', 2)); - ui->obs->setText(QString("%1").arg(obs, 6, 'f', 2)); + ui->FNumber->blockSignals(false); ui->roc->blockSignals(false); ui->lambda->blockSignals(false); ui->cc->blockSignals(false); ui->unitsCB->blockSignals(false); ui->fringeSpacingEdit->blockSignals(false); - ui->ClearAp->setVisible( m_aperatureReductionEnabled); - ui->clearApLabel->setVisible( m_aperatureReductionEnabled); + ui->minorAxisEdit->blockSignals(false); + m_aperatureReductionValueChanged = false; - setclearAp(); } mirrorDlg::~mirrorDlg() @@ -238,8 +179,7 @@ void mirrorDlg::saveJson(const QString &fileName){ } void mirrorDlg:: on_saveBtn_clicked() { - QSettings settings; - QString path = settings.value("mirrorConfigFile").toString(); + QString path = m_draft.mirrorConfigFile; QString extensionTypes("config file (*.json)"); QString fileName = QFileDialog::getSaveFileName(this, tr("Save config file"), path, @@ -256,9 +196,11 @@ void mirrorDlg:: on_saveBtn_clicked() } saveJson(fileName); QFileInfo info(fileName); - settings.setValue("mirrorConfigFile", fileName); - settings.setValue("projectPath", info.absolutePath()); - m_projectPath = info.absolutePath(); + + // Update draft with new file path, then persist via facade + m_draft.mirrorConfigFile = fileName; + m_draft.projectPath = info.absolutePath(); + m_projectPath = m_draft.projectPath; } void mirrorDlg::loadFile(QString & fileName){ @@ -267,13 +209,16 @@ void mirrorDlg::loadFile(QString & fileName){ ui->ellipseShape->setChecked(false); m_outlineShape = CIRCLE; QFileInfo info(fileName); + + // Only persist non-mirror-settings to QSettings (lastPath) QSettings settings; - settings.setValue("lastPath", info.absolutePath()); + emit newPath(info.absolutePath()); - m_projectPath = info.absolutePath(); - settings.setValue("mirrorConfigFile",fileName); - settings.setValue("lastPath", info.absolutePath()); + + // Update draft with new file path and project path via facade + m_draft.projectPath = info.absolutePath(); + m_draft.mirrorConfigFile = fileName; if (fileName.endsWith(".json")){ @@ -661,8 +606,9 @@ void mirrorDlg::on_unitsCB_clicked(bool checked) ui->annularDiameter->blockSignals(true); ui->annularDiameter->setValue(diameter * m_annularObsPercent * ((mm)? 1.: 1./25.4)); ui->annularDiameter->blockSignals(false); - QSettings set; - aperatureReduction = set.value("config aperatureReduction",0.).toDouble(); + + // Get aperatureReduction from draft (already loaded from persistent storage) + aperatureReduction = m_draft.apertureReduction; ui->reduceValue->setValue(aperatureReduction * ((mm) ? 1. : 1./25.4)); ui->reduceValue->blockSignals(false); From 5bbac225aaaa85f3191422dc5db8729d3d7cfee2 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 10:43:21 +0200 Subject: [PATCH 05/20] separate some conveniance path from mirror settings --- astigstatsdlg.cpp | 4 ++-- igramarea.cpp | 4 +++- igramintensity.cpp | 4 ++-- mainwindow.cpp | 4 +++- percentcorrectiondlg.cpp | 14 ++++++++------ settingsfacade.cpp | 10 ++++++++++ settingsfacade.h | 6 ++++++ settingsstores.cpp | 16 ++++++++++++++++ settingsstores.h | 16 ++++++++++++++++ settingsstores_fields.inc | 7 +++++-- standastigwizard.cpp | 6 ++++-- statsview.cpp | 10 ++++------ surfacemanager.cpp | 3 ++- unwraperrorsview.cpp | 3 ++- 14 files changed, 83 insertions(+), 24 deletions(-) diff --git a/astigstatsdlg.cpp b/astigstatsdlg.cpp index 9992af56..1301e2f9 100644 --- a/astigstatsdlg.cpp +++ b/astigstatsdlg.cpp @@ -1,5 +1,6 @@ #include "astigstatsdlg.h" #include "ui_astigstatsdlg.h" +#include "settingsfacade.h" #include "circleutils.h" #include "circle.h" #include @@ -489,8 +490,7 @@ void astigStatsDlg::showItem(const QVariant &item, bool on, int /*ndx*/){ void astigStatsDlg::on_zernikePB_pressed() { - QSettings set; - QString path = set.value("mirrorConfigFile").toString(); + QString path = SettingsFacade::instance().appStore().load().mirrorConfigFile; QFile fn(path); QFileInfo info(fn.fileName()); QString dd = info.dir().absolutePath(); diff --git a/igramarea.cpp b/igramarea.cpp index 9f05a970..a58cf5d6 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -22,6 +22,7 @@ #endif #include "IgramArea.h" +#include "settingsfacade.h" #include "Circleoutline.h" #include #include @@ -2481,7 +2482,8 @@ void IgramArea::save(){ mimeTypeFilters.append(mimeTypeName); mimeTypeFilters.sort(); QSettings settings; - QString lastPath = settings.value("projectPath",".").toString(); + QString lastPath = SettingsFacade::instance().appStore().load().projectPath; + if (lastPath.isEmpty()) lastPath = "."; QString filters = QStringList(mimeTypeFilters.mid(1,6)).join(" "); diff --git a/igramintensity.cpp b/igramintensity.cpp index c074fc0b..055a1898 100644 --- a/igramintensity.cpp +++ b/igramintensity.cpp @@ -17,6 +17,7 @@ ****************************************************************************/ #include "igramintensity.h" #include "ui_igramintensity.h" +#include "settingsfacade.h" #include #include #include @@ -58,8 +59,7 @@ void igramIntensity::on_showGreen_clicked(bool checked) void igramIntensity::on_pushButton_clicked() { - QSettings set; - QString path = set.value("mirrorConfigFile").toString(); + QString path = SettingsFacade::instance().appStore().load().mirrorConfigFile; QFile fn(path); QFileInfo info(fn.fileName()); QString dd = info.dir().absolutePath(); diff --git a/mainwindow.cpp b/mainwindow.cpp index fcac91b9..363b13f2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -18,6 +18,7 @@ #include "mainwindow.h" #include "ui_mainwindow.h" #include "spdlog/spdlog.h" +#include "settingsfacade.h" #include #include #include @@ -1996,7 +1997,8 @@ void MainWindow::on_actionSave_curent_profile_triggered() if (m_profilePlot->m_wf == 0) return; QSettings settings; - QString lastPath = settings.value("projectPath",".").toString(); + QString lastPath = SettingsFacade::instance().appStore().load().projectPath; + if (lastPath.isEmpty()) lastPath = "."; QString fName = QFileDialog::getSaveFileName(0, tr("Save Profile"), lastPath + "//profile.txt"); if (fName.isEmpty()) diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 20816d84..8ace9092 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -1,5 +1,6 @@ #include "percentcorrectiondlg.h" #include "ui_percentcorrectiondlg.h" +#include "settingsfacade.h" #include "qwt_plot_grid.h" #include "qwt_scale_div.h" #include "qwt_plot_barchart.h" @@ -715,9 +716,7 @@ void percentCorrectionDlg::on_help_clicked() void percentCorrectionDlg::on_loadZones_clicked() { - - QSettings set; - QString path = set.value("projectPath").toString(); + QString path = SettingsFacade::instance().appStore().load().projectPath; QString extensionTypes(tr( "zone file (*.zones)")); QString fileName = QFileDialog::getOpenFileName(0, tr("Read zone file"), path, @@ -754,8 +753,7 @@ void percentCorrectionDlg::on_loadZones_clicked() void percentCorrectionDlg::on_saveZones_clicked() { - QSettings set; - QString path = set.value("projectPath").toString(); + QString path = SettingsFacade::instance().appStore().load().projectPath; QString extensionTypes(tr( "zone file (*.zones)")); QString fileName = QFileDialog::getSaveFileName(0, tr("Save zone file"), path, @@ -774,7 +772,11 @@ void percentCorrectionDlg::on_saveZones_clicked() out << jsonString; file.close(); - set.setValue("projectPath", QFileInfo(fileName).absolutePath()); + + // Update and persist application settings via facade + ApplicationSettings appSettings = SettingsFacade::instance().appStore().load(); + appSettings.projectPath = QFileInfo(fileName).absolutePath(); + SettingsFacade::instance().appStore().save(appSettings); } diff --git a/settingsfacade.cpp b/settingsfacade.cpp index e765494a..f3b887d1 100644 --- a/settingsfacade.cpp +++ b/settingsfacade.cpp @@ -35,3 +35,13 @@ const ContourSettingsStore &SettingsFacade::contourStore() const { return m_contourStore; } + +ApplicationSettingsStore &SettingsFacade::appStore() +{ + return m_appStore; +} + +const ApplicationSettingsStore &SettingsFacade::appStore() const +{ + return m_appStore; +} diff --git a/settingsfacade.h b/settingsfacade.h index e1f54cd7..f9ae4085 100644 --- a/settingsfacade.h +++ b/settingsfacade.h @@ -24,6 +24,11 @@ class SettingsFacade ContourSettingsStore &contourStore(); const ContourSettingsStore &contourStore() const; + /** @brief Accessor for application-wide path settings (project path, file paths, etc.). */ + ApplicationSettingsStore &appStore(); + /** @brief Const accessor for application-wide path settings. */ + const ApplicationSettingsStore &appStore() const; + private: SettingsFacade() = default; // Enforce singleton @@ -31,6 +36,7 @@ class SettingsFacade MirrorSettingsStore m_mirrorStore; GeneralProcessingSettingsStore m_generalProcessingStore; ContourSettingsStore m_contourStore; + ApplicationSettingsStore m_appStore; }; #endif // SETTINGSFACADE_H diff --git a/settingsstores.cpp b/settingsstores.cpp index c088cf2c..1829cd91 100644 --- a/settingsstores.cpp +++ b/settingsstores.cpp @@ -56,5 +56,21 @@ void ContourSettingsStore::save(const ContourSettings &value) const SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) } +ApplicationSettings ApplicationSettingsStore::load() const +{ + QSettings s; + + ApplicationSettings value{}; + SETTINGS_STORE_FOR_EACH_APPLICATION_FIELD(SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS) + + return value; +} + +void ApplicationSettingsStore::save(const ApplicationSettings &value) const +{ + QSettings s; + SETTINGS_STORE_FOR_EACH_APPLICATION_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) +} + #undef SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS #undef SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS diff --git a/settingsstores.h b/settingsstores.h index bb167bb0..12c26b88 100644 --- a/settingsstores.h +++ b/settingsstores.h @@ -56,6 +56,22 @@ class ContourSettingsStore { void save(const ContourSettings &value) const; }; + + +struct ApplicationSettings { + SETTINGS_STORE_FOR_EACH_APPLICATION_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) +}; + +class ApplicationSettingsStore { +private: + friend class SettingsFacade; + ApplicationSettingsStore() = default; + +public: + ApplicationSettings load() const; + void save(const ApplicationSettings &value) const; +}; + #undef SETTINGS_STORE_DECLARE_STRUCT_FIELD #endif // SETTINGSSTORES_H diff --git a/settingsstores_fields.inc b/settingsstores_fields.inc index d34146e2..70a84ca8 100644 --- a/settingsstores_fields.inc +++ b/settingsstores_fields.inc @@ -18,9 +18,12 @@ FIELD(int, outlineShape, 0, "outlineShape", toInt) \ FIELD(double, ellipseMinorAxis, 50.0, "ellipseMinorAxis", toDouble) \ FIELD(bool, apertureReductionEnabled, false, "configAperatureReductionChecked", toBool) \ - FIELD(double, apertureReduction, 0.0, "config aperatureReduction", toDouble) \ + FIELD(double, apertureReduction, 0.0, "config aperatureReduction", toDouble) + +#define SETTINGS_STORE_FOR_EACH_APPLICATION_FIELD(FIELD) \ FIELD(QString, projectPath, QString(), "projectPath", toString) \ - FIELD(QString, mirrorConfigFile, QString(), "mirrorConfigFile", toString) + FIELD(QString, mirrorConfigFile, QString(), "mirrorConfigFile", toString) \ + FIELD(QString, lastPath, QString(), "lastPath", toString) #define SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(FIELD) \ FIELD(bool, useMakeStarTest, false, "useMakeStarTest", toBool) \ diff --git a/standastigwizard.cpp b/standastigwizard.cpp index 4f7b9489..e3395b6b 100644 --- a/standastigwizard.cpp +++ b/standastigwizard.cpp @@ -17,6 +17,7 @@ ****************************************************************************/ #include "standastigwizard.h" #include "ui_standastigwizard.h" +#include "settingsfacade.h" #include "spdlog/spdlog.h" #include #include @@ -133,7 +134,8 @@ makeAverages::makeAverages(QWidget *parent) } void define_input::pdfNamesPressed(){ QSettings set; - QString standReportPath = set.value("stand report path", mirrorDlg::get_Instance()->getProjectPath()).toString(); + QString standReportPath = SettingsFacade::instance().appStore().load().projectPath; + if (standReportPath.isEmpty()) standReportPath = mirrorDlg::get_Instance()->getProjectPath(); QString fileName = QFileDialog::getSaveFileName((QWidget* )0, "Export PDF", standReportPath + "/stand.pdf" , "*.pdf"); if (fileName.isEmpty()) @@ -227,7 +229,7 @@ define_input::define_input(QWidget *parent) connect(runpb, &QAbstractButton::pressed, this, &define_input::compute); QSettings settings; - QString lastPath = settings.value("projectPath","").toString(); + QString lastPath = SettingsFacade::instance().appStore().load().projectPath; basePath = new QLineEdit(settings.value("rotation base path",lastPath).toString()); basePath->setToolTip("Directory were rotation files are stored."); QPushButton *browsePath = new QPushButton("..."); diff --git a/statsview.cpp b/statsview.cpp index bc19e68a..81b8707a 100644 --- a/statsview.cpp +++ b/statsview.cpp @@ -1,5 +1,6 @@ #include "statsview.h" #include "ui_statsview.h" +#include "settingsfacade.h" #include #include "wftstats.h" #include "surfacemanager.h" @@ -173,8 +174,7 @@ void statsView::on_checkBox_2_toggled(bool checked) void statsView::on_saveImg_clicked() { - QSettings settings; - QString path = settings.value("projectPath").toString(); + QString path = SettingsFacade::instance().appStore().load().projectPath; QFile fn(path); QString csvName = path + "/stats.pdf"; QString name = QFileInfo(csvName).absoluteFilePath() + "/stats.png"; @@ -226,8 +226,7 @@ QString statsView::title(const QString &dir){ void statsView::on_SaveCSV_clicked() { - QSettings settings; - QString path = settings.value("projectPath").toString(); + QString path = SettingsFacade::instance().appStore().load().projectPath; QFile fn(path); QFileInfo info(fn.fileName()); QString csvName = path + "/stats.csv"; @@ -293,8 +292,7 @@ void statsView::on_SaveCSV_clicked() void statsView::on_savePdf_clicked() { - QSettings settings; - QString path = settings.value("projectPath").toString(); + QString path = SettingsFacade::instance().appStore().load().projectPath; QFile fn(path); QFileInfo info(fn.fileName()); QString csvName = path + "/stats.pdf"; diff --git a/surfacemanager.cpp b/surfacemanager.cpp index 228f2e35..74922ba0 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -17,6 +17,7 @@ ****************************************************************************/ #include "surfacemanager.h" #include "spdlog/spdlog.h" +#include "settingsfacade.h" #include #include #include @@ -3404,7 +3405,7 @@ bool QPointFLessThan(QPointF p1, QPointF p2){ void SurfaceManager::tiltAnalysis(){ QSettings set; - QString path = set.value("mirrorConfigFile").toString(); + QString path = SettingsFacade::instance().appStore().load().mirrorConfigFile; QFile fn(path); QFileInfo info(fn.fileName()); QString dd = info.dir().absolutePath(); diff --git a/unwraperrorsview.cpp b/unwraperrorsview.cpp index 2eea6f8b..908dd266 100644 --- a/unwraperrorsview.cpp +++ b/unwraperrorsview.cpp @@ -1,5 +1,6 @@ #include "unwraperrorsview.h" #include "ui_unwraperrorsview.h" +#include "settingsfacade.h" #include #include #include @@ -71,7 +72,7 @@ unwrapErrorsView::~unwrapErrorsView() void unwrapErrorsView::on_save_clicked() { QSettings set; - QString path = set.value("mirrorConfigFile").toString(); + QString path = SettingsFacade::instance().appStore().load().mirrorConfigFile; QFile fn(path); QFileInfo info(fn.fileName()); QString dd = info.dir().absolutePath(); From abcc92794d83a7e21c0b9b43259ee8c7767cb0eb Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 11:07:55 +0200 Subject: [PATCH 06/20] all access to public members done through accesor. TODO remove members --- averagewavefrontfilesdlg.cpp | 2 +- dftarea.cpp | 4 +-- foucaultview.cpp | 24 ++++++------- igramarea.cpp | 2 +- mainwindow.cpp | 8 ++--- metricsdisplay.cpp | 4 +-- mirrordlg.cpp | 4 +-- mirrordlg.h | 6 ++++ nullvariationdlg.cpp | 8 ++--- percentcorrectiondlg.cpp | 4 +-- profileplot.cpp | 6 ++-- reportdlg.cpp | 2 +- simigramdlg.cpp | 6 ++-- simulationsview.cpp | 6 ++-- standastigwizard.cpp | 2 +- statsview.cpp | 8 ++--- surfacemanager.cpp | 70 ++++++++++++++++++------------------ wftstats.cpp | 14 ++++---- zernikeprocess.cpp | 40 ++++++++++----------- 19 files changed, 113 insertions(+), 107 deletions(-) diff --git a/averagewavefrontfilesdlg.cpp b/averagewavefrontfilesdlg.cpp index 7fc615f0..4b7b6f5d 100644 --- a/averagewavefrontfilesdlg.cpp +++ b/averagewavefrontfilesdlg.cpp @@ -66,7 +66,7 @@ void averageWaveFrontFilesDlg::on_process_clicked() sm->generateSurfacefromWavefront(wf); cv::Scalar mean,std; cv::meanStdDev(wf->workData,mean,std,wf->workMask); - double stdVal = std.val[0]* md->lambda/outputLambda; + double stdVal = std.val[0]* md->currentSettings().lambda/outputLambda; if (stdVal > filterRMS){ QFileInfo info(name); QString item = QString("%1 RMS:%2").arg(info.baseName()).arg(stdVal, 0, 'f'); diff --git a/dftarea.cpp b/dftarea.cpp index fa7d9962..34b68b33 100644 --- a/dftarea.cpp +++ b/dftarea.cpp @@ -1032,8 +1032,8 @@ void DFTArea::makeSurface(){ mirrorDlg *md = mirrorDlg::get_Instance(); - if (md->fringeSpacing != 1.){ - result *= md->fringeSpacing; + if (md->currentSettings().fringeSpacing != 1.){ + result *= md->currentSettings().fringeSpacing; } if (md->isEllipse()) { diff --git a/foucaultview.cpp b/foucaultview.cpp index 93c8f3c9..8529394a 100644 --- a/foucaultview.cpp +++ b/foucaultview.cpp @@ -203,7 +203,7 @@ void foucaultView::drawGridOverlay(QImage &img) { int maxPixelRadius = w / 2; mirrorDlg *md = mirrorDlg::get_Instance(); - double mirrorRadiusMM = md->diameter / 2.0; + double mirrorRadiusMM = md->currentSettings().diameter / 2.0; // 3. Determine physics-to-pixel scale double stepSizeMM = 0; @@ -298,8 +298,8 @@ void foucaultView::setSurface(wavefront *wf){ double offset = set.value("foucault roc offset", 0.).toDouble(); m_wf = wf; mirrorDlg *md = mirrorDlg::get_Instance(); - double rad = md->diameter/2.; - double FL = md->roc/2.; + double rad = md->currentSettings().diameter/2.; + double FL = md->currentSettings().roc/2.; double mul = (ui->useMM->isChecked()) ? 1. : 1/25.4; m_sag = mul * (rad * rad) /( 4 * FL); m_sag = round(100 * m_sag)/100.; @@ -362,9 +362,9 @@ QImage foucaultView::generateOpticalTestImage(OpticalTestType type, wavefront* w double coc_offset_mm = s.rocOffset * unitMultiplyer; // Physics geometry - double r2 = (md->diameter / 2.0) * (md->diameter / 2.0); - double b = md->roc + coc_offset_mm; - double pv = (sqrt(r2 + (md->roc * md->roc)) - (sqrt(r2 + b * b) - coc_offset_mm)) / (md->lambda * 1.E-6); + double r2 = (md->currentSettings().diameter / 2.0) * (md->currentSettings().diameter / 2.0); + double b = md->currentSettings().roc + coc_offset_mm; + double pv = (sqrt(r2 + (md->currentSettings().roc * md->currentSettings().roc)) - (sqrt(r2 + b * b) - coc_offset_mm)) / (md->currentSettings().lambda * 1.E-6); double z3 = pv / moving_constant; double effectiveZ3 = (type == OpticalTestType::Ronchi) ? (s.ronchiX * z3) : z3; @@ -377,20 +377,20 @@ QImage foucaultView::generateOpticalTestImage(OpticalTestType type, wavefront* w SimulationsView *sv = SimulationsView::getInstance(0); sv->setSurface(wf); - bool oldDoNull = md->doNull; + bool oldDoNull = md->currentSettings().doNull; if (bAutoCollimate == false) - md->doNull = false; // this is normal foucault/ronchi so we *don't* subtract the null (autcoCollimate ronchi or foucault mode will typically subtract the null) + md->m_draft.doNull = false; // this is normal foucault/ronchi so we *don't* subtract the null (autcoCollimate ronchi or foucault mode will typically subtract the null) cv::Mat surf_fft = sv->computeStarTest(s.heightMultiply * sv->nulledSurface(effectiveZ3), size, actualPad, true); wf->InputZerns = originalZerns; // Restore state immediately - md->doNull = oldDoNull; + md->m_draft.doNull = oldDoNull; // 3. Mask Generation cv::Mat mask = cv::Mat::zeros(size, size, CV_64FC1); cv::Mat sourceSlit = cv::Mat::zeros(size, size, CV_64FC1); int hx = (size - 1) / 2 + s.lateralOffset; - double pixwidth = s.outputLambda * 1.E-6 * (0.5 * md->roc / md->diameter) * 2. / (25.4 * actualPad); + double pixwidth = s.outputLambda * 1.E-6 * (0.5 * md->currentSettings().roc / md->currentSettings().diameter) * 2. / (25.4 * actualPad); if (type == OpticalTestType::Ronchi) { double lpi_val = s.lpi * (s.useMM ? 25.4 : 1.0); @@ -954,8 +954,8 @@ void foucaultView::on_RonchiX_valueChanged(double arg1) void foucaultView::on_pushButton_clicked() { mirrorDlg *md = mirrorDlg::get_Instance(); - double rad = md->diameter/2.; - double FL = md->roc/2.; + double rad = md->currentSettings().diameter/2.; + double FL = md->currentSettings().roc/2.; double mul = (ui->useMM->isChecked()) ? 1. : 1/25.4; m_sag = mul * (rad * rad) /( 4 * FL); m_sag = round(100 * m_sag)/100.; diff --git a/igramarea.cpp b/igramarea.cpp index a58cf5d6..871eea48 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -883,7 +883,7 @@ void IgramArea::useAnnulusforCenterOutine(){ if (m_current_boundry == CenterOutline) { mirrorDlg *md = mirrorDlg::get_Instance(); - double rad = m_outside.m_radius * md->m_annularObsPercent; + double rad = m_outside.m_radius * md->currentSettings().annulusPercent; double cx = m_outside.m_center.x(); double cy = m_outside.m_center.y(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 363b13f2..a597f97b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -592,16 +592,16 @@ void MainWindow::updateMetrics(wavefront& wf){ metrics->setZernTitle(ztitle); double z8 = zernTablemodel->values[8]; double BestSC; - if (m_mirrorDlg->doNull && wf.useSANull){ + if (m_mirrorDlg->currentSettings().doNull && wf.useSANull){ BestSC = z8/m_mirrorDlg->z8; } else { - BestSC = m_mirrorDlg->cc +z8/m_mirrorDlg->z8; + BestSC = m_mirrorDlg->currentSettings().cc +z8/m_mirrorDlg->z8; } metrics->setOutputLambda(outputLambda); - metrics->setWavePerFringe(m_mirrorDlg->fringeSpacing, m_mirrorDlg->lambda); - if (m_mirrorDlg->doNull) + metrics->setWavePerFringe(m_mirrorDlg->currentSettings().fringeSpacing, m_mirrorDlg->currentSettings().lambda); + if (m_mirrorDlg->currentSettings().doNull) metrics->mCC->setText(QString("%1").arg(BestSC, 6 ,'f', 3)); else { metrics->mCC->setText("NA"); diff --git a/metricsdisplay.cpp b/metricsdisplay.cpp index 772b3fcf..493c57c2 100644 --- a/metricsdisplay.cpp +++ b/metricsdisplay.cpp @@ -58,8 +58,8 @@ void metricsDisplay::setWavePerFringe(double val, double lambda){ ui->wavesPerFringe->setText(QString("Waves Per Fringe: %1").arg(val, 2, 'f', 1)); ui->lambda->setText(QString("Igram laser wavelength: %1 nm").arg(lambda, 6, 'f', 2)); mirrorDlg *md = mirrorDlg::get_Instance(); - QString donull = (md->doNull) ? (QString("SANull: %1").arg(md->z8 * md->cc, 6, 'f', 4)) : ""; - ui->desiredConicLb->setText(QString("Desired Conic: %1 ").arg( md->cc, 6, 'f', 2) + donull); + QString donull = (md->currentSettings().doNull) ? (QString("SANull: %1").arg(md->currentSettings().z8 * md->currentSettings().cc, 6, 'f', 4)) : ""; + ui->desiredConicLb->setText(QString("Desired Conic: %1 ").arg( md->currentSettings().cc, 6, 'f', 2) + donull); if (md->isEllipse()){ ui->desiredConicLb->setText(""); ui->zernTitle->setText("Zernike Values not computed for Flats"); diff --git a/mirrordlg.cpp b/mirrordlg.cpp index bd7684b5..620bef09 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -137,7 +137,7 @@ double mirrorDlg::getMinorAxis(){ } bool mirrorDlg::isEllipse(){ - return m_outlineShape == ELLIPSE; + return m_draft.outlineShape == ELLIPSE; } void mirrorDlg::saveJson(const QString &fileName){ QJsonObject jDoc, jMirror,jIgram, jEllipse, jAnnulus; @@ -449,7 +449,7 @@ void mirrorDlg::on_ReadBtn_clicked() loadFile(fileName); } QString mirrorDlg::getProjectPath(){ - return m_projectPath; + return m_draft.projectPath; } void mirrorDlg::on_diameter_textChanged(const QString &arg1) { diff --git a/mirrordlg.h b/mirrordlg.h index 64130d11..16fd8fca 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -74,6 +74,12 @@ class mirrorDlg : public QDialog void setMinorAxis(double val); bool m_aperatureReductionEnabled; void setObsPercent(double obs); + + /** @brief Access current mirror settings (read-only snapshot). + * Returns the draft which is the canonical storage for all mirror config. + * All member variables are kept in sync with this for backward compatibility. */ + const MirrorSettings& currentSettings() const { return m_draft; } + private slots: void on_ReadBtn_clicked(); diff --git a/nullvariationdlg.cpp b/nullvariationdlg.cpp index a0612b0f..da231276 100644 --- a/nullvariationdlg.cpp +++ b/nullvariationdlg.cpp @@ -26,8 +26,8 @@ nullVariationDlg::nullVariationDlg(QWidget *parent) : ui->roc->blockSignals(true); ui->diameter->blockSignals(true); - ui->diameter->setText(QString::number(md->diameter)); - ui->roc->setText(QString::number(md->roc)); + ui->diameter->setText(QString::number(md->currentSettings().diameter)); + ui->roc->setText(QString::number(md->currentSettings().roc)); ui->roc->blockSignals(false); ui->diameter->blockSignals(false); @@ -151,7 +151,7 @@ void nullVariationDlg::calculate() double roc = ui->roc->text().toDouble() * mul; mirrorDlg *md = mirrorDlg::get_Instance(); - double lambda = md->lambda; + double lambda = md->currentSettings().lambda; double center = 1.5 * pow(diam,4) * 1000000. /(384. * lambda * pow(roc,3)); //qDebug() << center/1.5; @@ -190,7 +190,7 @@ void nullVariationDlg::on_ComputeSim_clicked() double roc = ui->roc->text().toDouble() * mul; mirrorDlg *md = mirrorDlg::get_Instance(); - double lambda = md->lambda; + double lambda = md->currentSettings().lambda; double center = 1.5 * pow(diam,4) * 1000000. /(384. * lambda * pow(roc,3)); std::default_random_engine generator(time(0)); std::default_random_engine g2(time(0) + 1000); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 8ace9092..898b6247 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -354,7 +354,7 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ ActualZoneKnife << 0.0; mirrorDlg *md = mirrorDlg::get_Instance(); - double nullval = md->z8 * md->cc; // null value was computed at the igram wavevlength + double nullval = md->currentSettings().z8 * md->currentSettings().cc; // null value was computed at the igram wavevlength nullval *= m_lambda_nm/m_outputLambda; // only data from the profile needs the null but it's data is at the output wavelength; // process each zone center @@ -400,7 +400,7 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ void percentCorrectionDlg::plotProfile(){ mirrorDlg *md = mirrorDlg::get_Instance(); - double nullval = md->z8 * md->cc; + double nullval = md->currentSettings().z8 * md->currentSettings().cc; for (int i = 0; i < surfs.length(); ++ i) { QwtPlotCurve *Curve = new QwtPlotCurve(); diff --git a/profileplot.cpp b/profileplot.cpp index 87096ce8..2073a854 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -526,7 +526,7 @@ void ProfilePlot::make_correction_graph(){ QColor penColor = Settings2::m_profile->getColor(i); // give the plot routine new zernike values for each curve. mirrorDlg *md = mirrorDlg::get_Instance(); - surfs << new surfaceData( md->lambda, penColor, theZerns ,name); + surfs << new surfaceData( md->currentSettings().lambda, penColor, theZerns ,name); } QPolygonF avg = createAverageProfile(1., wfs->at(list[0]),true); @@ -1170,11 +1170,11 @@ void ProfilePlot::CreateWaveFrontFromAverage(){ //create a matrix from the avgRadius profile. mirrorDlg *md = mirrorDlg::get_Instance(); // first add the null back into it. - if (md->doNull){ + if (md->currentSettings().doNull){ for (unsigned int i = 0; i < avgRadius.size(); ++i) { double R2 = (double(i))/(avgRadius.size() -1); R2 *= R2; - avgRadius[i] += md->z8 * md->cc * (1. + R2 * (-6 + 6. * R2));; + avgRadius[i] += md->currentSettings().z8 * md->currentSettings().cc * (1. + R2 * (-6 + 6. * R2));; } } cv::Mat result = createInterpolatedCircularSurface(avgRadius); diff --git a/reportdlg.cpp b/reportdlg.cpp index ad5fda56..cd76deab 100644 --- a/reportdlg.cpp +++ b/reportdlg.cpp @@ -9,7 +9,7 @@ ReportDlg::ReportDlg(QPrinter *p, QWidget *parent) : ui(new Ui::ReportDlg) { ui->setupUi(this); - ui->title->setText( mirrorDlg::get_Instance()->m_name); + ui->title->setText(mirrorDlg::get_Instance()->currentSettings().mirrorName); QSettings set; contourWidth = set.value("ReprotContourWidth", 1.).toDouble(); ui->contourWidth->setValue(contourWidth); diff --git a/simigramdlg.cpp b/simigramdlg.cpp index ac3567e2..d128754a 100644 --- a/simigramdlg.cpp +++ b/simigramdlg.cpp @@ -186,7 +186,7 @@ simIgramDlg::simIgramDlg(QWidget *parent) : zernikes[2] = ytilt; size = s.value("simSize", 601).toDouble(); ui->sizeSB->setValue(size); - if (mirrorDlg::get_Instance()->cc == 0.){ + if (mirrorDlg::get_Instance()->currentSettings().cc == 0.){ ui->correctionPb->setChecked(false); } @@ -325,8 +325,8 @@ void simIgramDlg::on_editArbitrary_clicked() { UserDrawnProfileDlg * dlg = UserDrawnProfileDlg::get_instance(); mirrorDlg* md = mirrorDlg::get_Instance(); - if (md->diameter>0) - dlg->setDiameter(md->diameter); + if (md->currentSettings().diameter>0) + dlg->setDiameter(md->currentSettings().diameter); dlg->setModal(true); dlg->exec(); if (dlg->bOkPressed == false) diff --git a/simulationsview.cpp b/simulationsview.cpp index 12fff464..ee49e826 100644 --- a/simulationsview.cpp +++ b/simulationsview.cpp @@ -117,7 +117,7 @@ void SimulationsView::initMTFPlot(){ grid->enableXMin(true); grid->setPen( Qt::gray, 0.0, Qt::DotLine ); grid->attach( ui->MTF); - m_arcSecScaleDraw = new arcSecScaleDraw(mirrorDlg::get_Instance()->diameter); + m_arcSecScaleDraw = new arcSecScaleDraw(mirrorDlg::get_Instance()->currentSettings().diameter); ui->MTF->setAxisScaleDraw(ui->MTF->xBottom, m_arcSecScaleDraw); QwtPlotLegendItem *customLegend = new QwtPlotLegendItem(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) @@ -221,7 +221,7 @@ cv::Mat SimulationsView::nulledSurface(double defocus){ CropGaussianBlur(nulled_surface, nulled_surface, blurRad, m_wf->m_outside, m_wf->m_inside); } - nulled_surface *= M2PI * md->lambda/outputLambda; + nulled_surface *= M2PI * md->currentSettings().lambda/outputLambda; return nulled_surface; } @@ -663,7 +663,7 @@ void SimulationsView::on_MakePB_clicked() // remove obstructions cv::Mat noObstruction = savedMask.clone(); mirrorDlg *md = mirrorDlg::get_Instance(); - double r = md->obs * (2. * m_wf->m_outside.m_radius)/md->diameter; + double r = md->currentSettings().obstruction * (2. * m_wf->m_outside.m_radius)/md->currentSettings().diameter; if (r > 0){ circle(noObstruction,Point(noObstruction.cols/2,noObstruction.cols/2),r, Scalar(255),-1); diff --git a/standastigwizard.cpp b/standastigwizard.cpp index e3395b6b..874ef690 100644 --- a/standastigwizard.cpp +++ b/standastigwizard.cpp @@ -192,7 +192,7 @@ define_input::define_input(QWidget *parent) browsePb = new QPushButton("Add average Wavefront file to List"); QString pdfNameStr = set.value("stand pdf file", "stand.pdf").toString(); connect(browsePb, &QAbstractButton::pressed, this, &define_input::browse); - AstigReportTitle = mirrorDlg::get_Instance()->m_name; + AstigReportTitle = mirrorDlg::get_Instance()->currentSettings().mirrorName; AstigReportPdfName = mirrorDlg::get_Instance()->getProjectPath() + "/" + pdfNameStr; title = new QLineEdit(AstigReportTitle); pdfName = new QPushButton(AstigReportPdfName); diff --git a/statsview.cpp b/statsview.cpp index 81b8707a..cf161d32 100644 --- a/statsview.cpp +++ b/statsview.cpp @@ -269,9 +269,9 @@ void statsView::on_SaveCSV_clicked() double v = wf->InputZerns[ndx]; // apply software Null if needed - if (ndx == 8 and md->doNull) - v -= md->z8 * md->cc; - double Sigma = computeRMS(ndx,v) * md->lambda/outputLambda; + if (ndx == 8 and md->currentSettings().doNull) + v -= md->currentSettings().z8 * md->currentSettings().cc; + double Sigma = computeRMS(ndx,v) * md->currentSettings().lambda/outputLambda; if (ndx == 8) { spherical << QPointF(row,Sigma); @@ -279,7 +279,7 @@ void statsView::on_SaveCSV_clicked() sphericaRunningAvg << QPointF(row,sperAvg/(i+1)); } - mZerns.at(row,ndx) = Sigma * md->lambda/outputLambda; + mZerns.at(row,ndx) = Sigma * md->currentSettings().lambda/outputLambda; } diff --git a/surfacemanager.cpp b/surfacemanager.cpp index 74922ba0..6c4fd68c 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -396,7 +396,7 @@ void SurfaceManager::generateSurfacefromWavefront(wavefront * wf){ QGuiApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); autoInvertDlg dlg_ai; dlg_ai.setMainLabel("Your wavefront may be inverted. What do you want to do?"); - dlg_ai.enableConic(md->cc != 0); + dlg_ai.enableConic(md->currentSettings().cc != 0); dlg_ai.exec(); QGuiApplication::restoreOverrideCursor(); md->updateAutoInvertStatus(); @@ -404,7 +404,7 @@ void SurfaceManager::generateSurfacefromWavefront(wavefront * wf){ bool reverse = false; if (m_inverseMode == invCONIC) { - if (md->cc != 0.0 && md->cc * wf->InputZerns[8] < 0.) + if (md->currentSettings().cc != 0.0 && md->currentSettings().cc * wf->InputZerns[8] < 0.) reverse = true; } else if (m_inverseMode == invINSIDE) { @@ -500,8 +500,8 @@ cv::Mat SurfaceManager::computeWaveFrontFromZernikes(int wx, int wy, std::vector } else { if (en[z]){ - if (z == 8 && md->doNull) - S1 += md->z8 * zpolar.zernike(z); + if (z == 8 && md->currentSettings().doNull) + S1 += md->currentSettings().z8 * zpolar.zernike(z); S1 += zerns[z] * zpolar.zernike(z); } @@ -800,7 +800,7 @@ void SurfaceManager::useDemoWaveFront(){ if (rho <= 1.) { - double S1 = md->z8 * -.9 * zpolar.zernike(8) + .02* zpolar.zernike(9); + double S1 = md->currentSettings().z8 * -.9 * zpolar.zernike(8) + .02* zpolar.zernike(9); result.at(j,i) = S1; } @@ -856,7 +856,7 @@ void SurfaceManager::surfaceSmoothGBValue(double value){ m_gbValue = value; mirrorDlg *md = mirrorDlg::get_Instance(); - m_surfaceTools->setBlurText(QString("%1 mm").arg( .01 * value * md->diameter, 6, 'f', 2)); + m_surfaceTools->setBlurText(QString("%1 mm").arg( .01 * value * md->currentSettings().diameter, 6, 'f', 2)); if (m_wavefronts.size() == 0) return; @@ -878,7 +878,7 @@ void SurfaceManager::surfaceSmoothGBEnabled(bool b){ rad = m_wavefronts[m_currentNdx]->m_outside.m_radius-1; mirrorDlg *md = ((MainWindow*)parent())->m_mirrorDlg; - double mmPerPixel = md->diameter/(2 * rad); + double mmPerPixel = md->currentSettings().diameter/(2 * rad); m_surfaceTools->setBlurText(QString("%1 mm").arg(m_gbValue* mmPerPixel, 6, 'f', 2)); if (m_wavefronts.size() == 0) return; @@ -890,16 +890,16 @@ void SurfaceManager::computeMetrics(wavefront *wf){ mirrorDlg *md = mirrorDlg::get_Instance(); cv::Scalar mean,std; cv::meanStdDev(wf->workData,mean,std,wf->workMask); - wf->mean = mean.val[0] * md->lambda/outputLambda; - wf->std = std.val[0]* md->lambda/outputLambda; + wf->mean = mean.val[0] * md->currentSettings().lambda/outputLambda; + wf->std = std.val[0]* md->currentSettings().lambda/outputLambda; double mmin; double mmax; minMaxIdx(wf->workData, &mmin,&mmax); - wf->min = mmin * md->lambda/outputLambda; - wf->max = mmax * md->lambda/outputLambda; + wf->min = mmin * md->currentSettings().lambda/outputLambda; + wf->max = mmax * md->currentSettings().lambda/outputLambda; ((MainWindow*)(parent()))->zernTablemodel->setValues(wf->InputZerns, !wf->useSANull); @@ -1118,9 +1118,9 @@ void SurfaceManager::createSurfaceFromPhaseMap(cv::Mat phase, CircleOutline outs wf->m_inside = center; wf->data = phase; mirrorDlg *md = mirrorDlg::get_Instance(); - wf->diameter = md->diameter; - wf->lambda = md->lambda; - wf->roc = md->roc; + wf->diameter = md->currentSettings().diameter; + wf->lambda = md->currentSettings().lambda; + wf->roc = md->currentSettings().roc; wf->dirtyZerns = true; wf->wasSmoothed = false; wf->regions = polyArea; @@ -1137,9 +1137,9 @@ void SurfaceManager::createSurfaceFromPhaseMap(cv::Mat phase, CircleOutline outs wavefront * SurfaceManager::readWaveFront(const QString &fileName){ mirrorDlg *md = mirrorDlg::get_Instance(); double xm,ym,radm; - double roc = md->roc, - lambda = md->lambda, - diam = md->diameter; + double roc = md->currentSettings().roc, + lambda = md->currentSettings().lambda, + diam = md->currentSettings().diameter; double xo, yo, rado; wavefront *wf = new wavefront(); @@ -1326,11 +1326,11 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ wf->m_inside = CircleOutline(QPointF(xo,yo), rado); - if (lambda != md->lambda){ + if (lambda != md->currentSettings().lambda){ if (lambdResp == ASK){ QString message("The interferogram wavelength ("); message += QString("%1").arg( lambda, 6, 'f', 3) + - ") Of the wavefront does not match the config value of " + QString("%1\n").arg(md->lambda, 6, 'f', 3) + + ") Of the wavefront does not match the config value of " + QString("%1\n").arg(md->currentSettings().lambda, 6, 'f', 3) + "Do you want to make the config match?"; @@ -1352,11 +1352,11 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ } } - if (roundl(diam * 10) != roundl(md->diameter* 10)) + if (roundl(diam * 10) != roundl(md->currentSettings().diameter* 10)) { QString message("The mirror diameter ("); message += QString("%1").arg(diam, 6, 'f', 3) + - ") Of the wavefront does not match the config value of " + QString("%1\n").arg(md->diameter, 6, 'f', 3) + + ") Of the wavefront does not match the config value of " + QString("%1\n").arg(md->currentSettings().diameter, 6, 'f', 3) + "Do you want to make the config match?"; if (diamResp == ASK){ int resp = QMessageBox(QMessageBox::Information,"config", message,QMessageBox::Yes|QMessageBox::No | @@ -1375,16 +1375,16 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ emit diameterChanged(diam); } else { - diam = md->diameter; + diam = md->currentSettings().diameter; } } - if (roundl(roc * 10.) != roundl(md->roc * 10.)) + if (roundl(roc * 10.) != roundl(md->currentSettings().roc * 10.)) { QString message("The mirror roc ("); message += QString("%1").arg(roc, 6, 'f', 3) + - ") Of the wavefront does not match the config value of " + QString("%1\n").arg(md->roc, 6, 'f', 3) + + ") Of the wavefront does not match the config value of " + QString("%1\n").arg(md->currentSettings().roc, 6, 'f', 3) + "Do you want to make the config match?"; //qDebug() << message; if (rocResp == ASK){ @@ -1404,7 +1404,7 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ emit rocChanged(roc); } else { - roc = md->roc; + roc = md->currentSettings().roc; } } @@ -3009,9 +3009,9 @@ void SurfaceManager::report(){ + QDate::currentDate().toString() + " " +QTime::currentTime().toString()+"
DFTFringe Version:"+APP_VERSION+""); - QString Diameter = (md->isEllipse()) ? " Horizontal Axis: " : " Diameter: " +QString().number(md->diameter,'f',1) ; - QString ROC = (md->isEllipse()) ? "Vertical Axis: " + QString().number(md->m_verticalAxis) : "ROC: " + QString().number(md->roc,'f',1); - QString FNumber = (md->isEllipse()) ? "" : "Fnumber: " + QString().number(md->FNumber,'f',1); + QString Diameter = (md->isEllipse()) ? " Horizontal Axis: " : " Diameter: " +QString().number(md->currentSettings().diameter,'f',1) ; + QString ROC = (md->isEllipse()) ? "Vertical Axis: " + QString().number(md->currentSettings().ellipseMinorAxis) : "ROC: " + QString().number(md->currentSettings().roc,'f',1); + QString FNumber = (md->isEllipse()) ? "" : "Fnumber: " + QString().number(md->currentSettings().roc/(2.0*md->currentSettings().diameter),'f',1); QString BFC = (md->isEllipse()) ? " Flat" : "Best Fit CC: " +metrics->mCC->text(); QString html = "

" "" @@ -3019,9 +3019,9 @@ void SurfaceManager::report(){ "" - "" - "" + "" + "" "
" + Diameter + " mm" + ROC + " mm
RMS: " + QString().number(wf->std,'f',3) + QString(" waves at %1 nmStrehl: ").arg(outputLambda, 6, 'f', 1) + metrics->mStrehl->text() + "" + BFC + "
" + ((md->isEllipse()) ? "":"Desired Conic: " + QString::number(md->cc)) + "" + - ((md->doNull) ? QString("SANull: %1").arg(md->z8 * md->cc, 6, 'f', 4) : "No software Null") + "Waves per fringe: " + QString::number(md->fringeSpacing) + "
Interferogram Wave length: "+ QString::number(md->lambda) + "nm
" + ((md->isEllipse()) ? "":"Desired Conic: " + QString::number(md->currentSettings().cc)) + "" + + ((md->currentSettings().doNull) ? QString("SANull: %1").arg(md->currentSettings().z8 * md->currentSettings().cc, 6, 'f', 4) : "No software Null") + "Waves per fringe: " + QString::number(md->currentSettings().fringeSpacing) + "
Interferogram Wave length: "+ QString::number(md->currentSettings().lambda) + "nm

"; // zerenike values @@ -3029,8 +3029,8 @@ void SurfaceManager::report(){ if (!md->isEllipse()){ zerns = "


" "" "" "" + ((md->currentSettings().doNull) ? QString("SANull: %1").arg(md->getZ8() * md->currentSettings().cc, 6, 'f', 4) : "No software Null") + "" "" "

" + - ((!md->m_useAnnular) ? QString("Zernike Values at interferogram wavelength") : - QString("Annular Zernike Values %1\% center hole").arg(100 * md->m_annularObsPercent, 6,'f',2))+ + ((!md->currentSettings().useAnnulus) ? QString("Zernike Values at interferogram wavelength") : + QString("Annular Zernike Values %1\% center hole").arg(100 * md->currentSettings().annulusPercent, 6,'f',2))+ "

"; zerns.append(""); @@ -3042,8 +3042,8 @@ void SurfaceManager::report(){ val = m_surfaceTools->m_defocus; enabled = true; } - if ( i == 8 && md->doNull){ - val -= md->z8 * md->cc; + if ( i == 8 && md->currentSettings().doNull){ + val -= md->currentSettings().z8 * md->currentSettings().cc; } diff --git a/wftstats.cpp b/wftstats.cpp index 3b4c876e..e728860d 100644 --- a/wftstats.cpp +++ b/wftstats.cpp @@ -139,10 +139,10 @@ void wftStats::computeZernStats( int ndx){ for (int i = 0; i < c.rows; ++i){ int row = (i + ndx) % c.rows; - double v = computeRMS(ndx,c.at(row)) * outputLambda/md->lambda; + double v = computeRMS(ndx,c.at(row)) * outputLambda/md->currentSettings().lambda; if (isPair){ cv::Mat c2 = m_Zerns.col(zern+1); - double v2 = computeRMS(ndx,c2.at(row)) * outputLambda/md->lambda; + double v2 = computeRMS(ndx,c2.at(row)) * outputLambda/md->currentSettings().lambda; double s = sqrt(v * v + v2 * v2); v = s; zname += " "; @@ -214,9 +214,9 @@ void wftStats::computeWftStats( QVector wavefronts, int ndx){ double v = wf->InputZerns[ndx]; // apply software Null if needed - if (ndx == 8 and md->doNull) - v -= md->z8 * md->cc; - double Sigma = computeRMS(ndx,v) * outputLambda/md->lambda; + if (ndx == 8 and md->currentSettings().doNull) + v -= md->currentSettings().z8 * md->currentSettings().cc; + double Sigma = computeRMS(ndx,v) * outputLambda/md->currentSettings().lambda; if (ndx == 8) { spherical << QPointF(row,Sigma); @@ -294,9 +294,9 @@ void wftStats::computeWftRunningAvg( QVector wavefronts, int ndx){ cv::Mat avg = sum/(j+1); cv::Scalar mean,std; cv::meanStdDev(resized,mean,std,mask); - double stdi = std.val[0]* md->lambda/outputLambda; + double stdi = std.val[0]* md->currentSettings().lambda/outputLambda; cv::meanStdDev(avg,mean,std,mask); - avgPoints << QPointF(j,std.val[0] * md->lambda/outputLambda); + avgPoints << QPointF(j,std.val[0] * md->currentSettings().lambda/outputLambda); wftPoints << QPointF(j,stdi); trueNdx << i; } diff --git a/zernikeprocess.cpp b/zernikeprocess.cpp index d6ea4a52..e8bf66a6 100644 --- a/zernikeprocess.cpp +++ b/zernikeprocess.cpp @@ -381,7 +381,7 @@ void zernikeProcess::unwrap_to_zernikes(wavefront &wf, int zterms){ // if annular zernikes needed then do this instead of all the other stuff below this. mirrorDlg *md = mirrorDlg::get_Instance(); - if (md->m_useAnnular) { + if (md->currentSettings().useAnnulus) { initGrid(wf, 12); ZernFitWavefront(wf); @@ -491,12 +491,12 @@ cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, cv::Mat unwrapped = wf.data.clone(); - double scz8 = md->z8 * md->cc; + double scz8 = md->currentSettings().z8 * md->currentSettings().cc; mirrorDlg *md = mirrorDlg::get_Instance(); - if (!md->doNull || !wf.useSANull){ + if (!md->currentSettings().doNull || !wf.useSANull){ scz8 = 0.; } double midx = wf.m_outside.m_center.rx(); @@ -524,7 +524,7 @@ cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, // make a list of points on the surface containing their rho and theta values as well as their // row column indexes in the matix that contanis the wave front. // annular wave fronts already have this made elsewhere. - if (!md->m_useAnnular){ + if (!md->currentSettings().useAnnulus){ m_rhoTheta = rhotheta(nx ,wf.m_outside.m_radius, midx,midy, &wf); if (m_lastusedAnnulus) m_needsInit=true; @@ -541,7 +541,7 @@ cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, rho = m_rhoTheta.row(0)(i); theta = m_rhoTheta.row(1)(i); - if (!md->m_useAnnular){ + if (!md->currentSettings().useAnnulus){ zpolar = new zernikePolar(rho,theta, Z_TERMS); } @@ -550,8 +550,8 @@ cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, if (last_term > 7) { - if (md->doNull && enables[8]){ - if (!md->m_useAnnular) + if (md->currentSettings().doNull && enables[8]){ + if (!md->currentSettings().useAnnulus) nz -= scz8 * zpolar->zernike(8); else { nz -= scz8 * m_zerns(i, 8); @@ -562,7 +562,7 @@ cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, for (int z = start_term; z < Z_TERMS; ++z) { if ((z == 3) && doDefocus){ - if (!md->m_useAnnular) { + if (!md->currentSettings().useAnnulus) { nz += defocus * zpolar->zernike(z); nz -= zerns[z] * zpolar->zernike(z); } @@ -572,7 +572,7 @@ cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, } } else if (!enables[z]){ - if (!md->m_useAnnular) { + if (!md->currentSettings().useAnnulus) { nz -= zerns[z] * zpolar->zernike(z); } else { @@ -581,7 +581,7 @@ cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, } } - if (!md->m_useAnnular){ + if (!md->currentSettings().useAnnulus){ delete zpolar; } @@ -597,7 +597,7 @@ void zernikeProcess::fillVoid(wavefront &wf){ double ux,uy; double rho,theta; mirrorDlg *md = mirrorDlg::get_Instance(); - bool useannular = md->m_useAnnular; + bool useannular = md->currentSettings().useAnnulus; if (wf.regions.size() > 0){ int x = wf.regions[0][0].x; @@ -667,7 +667,7 @@ void zernikeProcess::fillVoid(wavefront &wf){ arma::rowvec r(rhov),t(thetav); // now that we have the points in rho and theta get the zernike terms at each of those points - arma::mat zerns = zapm( r.as_col(), t.as_col(), md->m_annularObsPercent, 12); + arma::mat zerns = zapm( r.as_col(), t.as_col(), md->currentSettings().annulusPercent, 12); // compute the surface at each point by using the zernike poly at each point. for (arma::uword i = 0; i < r.size(); ++i){ double S1 = 0.0; @@ -748,7 +748,7 @@ void zernikeProcess::fillVoid(wavefront &wf){ arma::rowvec r(rhov),t(thetav); // now that we have the points in rho and theta get the zernike terms at each of those points - arma::mat zerns = zapm( r.as_col(), t.as_col(), md->m_annularObsPercent, 12); + arma::mat zerns = zapm( r.as_col(), t.as_col(), md->currentSettings().annulusPercent, 12); // compute the surface at each point by using the zernike poly at each point. for (arma::uword i = 0; i < r.size(); ++i){ double S1 = 0.0; @@ -875,7 +875,7 @@ cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ mirrorDlg *md = mirrorDlg::get_Instance(); double r,g,b; - spectral_color(r,g,b, md->lambda); + spectral_color(r,g,b, md->currentSettings().lambda); if (doColor) { result = cv::Vec4f(0.,125. * .5 * g, 125 * r, 125. * b); } @@ -914,9 +914,9 @@ cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ for (unsigned int z = 0; z < m_zerns.n_cols; ++z){ double val = dlg.zernikes[z]; if (z == 8){ - val = (dlg.doCorrection && md->doNull) ? md->cc * md->z8 * val * .01 : val; + val = (dlg.doCorrection && md->currentSettings().doNull) ? md->currentSettings().cc * md->currentSettings().z8 * val * .01 : val; } - S1 += val * m_zerns(i,z)/((doColor) ? md->fringeSpacing: 1.); + S1 += val * m_zerns(i,z)/((doColor) ? md->currentSettings().fringeSpacing: 1.); int x = m_col[i]; int y = m_row[i]; @@ -948,8 +948,8 @@ arma::mat zernikeProcess::rhotheta( int width, double radius, double cx, double bool useMask = false; double centerR = 0.0; mirrorDlg *md = mirrorDlg::get_Instance(); - if (md->m_useAnnular){ - centerR = md->m_annularObsPercent; + if (md->currentSettings().useAnnulus){ + centerR = md->currentSettings().annulusPercent; } if (wf != 0){ useMask = true; @@ -1079,8 +1079,8 @@ void zernikeProcess::initGrid(int width, double radius, double cx, double cy, in double obsPercent = 0.; bool shouldUseAnnulus = false; mirrorDlg *md = mirrorDlg::get_Instance(); - if (md->m_useAnnular){ - obsPercent = md->m_annularObsPercent; + if (md->currentSettings().useAnnulus){ + obsPercent = md->currentSettings().annulusPercent; shouldUseAnnulus = true; } From 13e191e14a1c95ddae375a50789dbd55bb09631b Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 11:11:39 +0200 Subject: [PATCH 07/20] fix build --- foucaultview.cpp | 11 ++++------- metricsdisplay.cpp | 2 +- mirrordlg.cpp | 31 +++++++++++++++++++------------ percentcorrectiondlg.cpp | 6 ++++-- profileplot.cpp | 2 +- simulationsview.cpp | 6 ++++-- simulationsview.h | 2 +- statsview.cpp | 2 +- surfacemanager.cpp | 8 ++++---- wftstats.cpp | 2 +- zernikeprocess.cpp | 10 +++++----- zernikeprocess.h | 2 +- 12 files changed, 46 insertions(+), 38 deletions(-) diff --git a/foucaultview.cpp b/foucaultview.cpp index 8529394a..4e2d7641 100644 --- a/foucaultview.cpp +++ b/foucaultview.cpp @@ -377,14 +377,11 @@ QImage foucaultView::generateOpticalTestImage(OpticalTestType type, wavefront* w SimulationsView *sv = SimulationsView::getInstance(0); sv->setSurface(wf); - bool oldDoNull = md->currentSettings().doNull; - if (bAutoCollimate == false) - md->m_draft.doNull = false; // this is normal foucault/ronchi so we *don't* subtract the null (autcoCollimate ronchi or foucault mode will typically subtract the null) + // For normal Foucault/Ronchi mode (not autocollimation), disable null correction + // Autocollimation mode applies null if configured; normal mode does not + bool applyNull = bAutoCollimate && md->currentSettings().doNull; - cv::Mat surf_fft = sv->computeStarTest(s.heightMultiply * sv->nulledSurface(effectiveZ3), size, actualPad, true); - - wf->InputZerns = originalZerns; // Restore state immediately - md->m_draft.doNull = oldDoNull; + cv::Mat surf_fft = sv->computeStarTest(s.heightMultiply * sv->nulledSurface(effectiveZ3, applyNull), size, actualPad, true); // 3. Mask Generation cv::Mat mask = cv::Mat::zeros(size, size, CV_64FC1); diff --git a/metricsdisplay.cpp b/metricsdisplay.cpp index 493c57c2..178d8fb7 100644 --- a/metricsdisplay.cpp +++ b/metricsdisplay.cpp @@ -58,7 +58,7 @@ void metricsDisplay::setWavePerFringe(double val, double lambda){ ui->wavesPerFringe->setText(QString("Waves Per Fringe: %1").arg(val, 2, 'f', 1)); ui->lambda->setText(QString("Igram laser wavelength: %1 nm").arg(lambda, 6, 'f', 2)); mirrorDlg *md = mirrorDlg::get_Instance(); - QString donull = (md->currentSettings().doNull) ? (QString("SANull: %1").arg(md->currentSettings().z8 * md->currentSettings().cc, 6, 'f', 4)) : ""; + QString donull = (md->currentSettings().doNull) ? (QString("SANull: %1").arg(md->z8 * md->currentSettings().cc, 6, 'f', 4)) : ""; ui->desiredConicLb->setText(QString("Desired Conic: %1 ").arg( md->currentSettings().cc, 6, 'f', 2) + donull); if (md->isEllipse()){ ui->desiredConicLb->setText(""); diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 620bef09..9f8cd585 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -100,7 +100,10 @@ void mirrorDlg::loadDraftFromSettings() m_verticalAxis = m_draft.ellipseMinorAxis; aperatureReduction = m_draft.apertureReduction; m_aperatureReductionEnabled = m_draft.apertureReductionEnabled; - m_projectPath = m_draft.projectPath; + + // Load application-level settings separately (projectPath, mirrorConfigFile, lastPath) + ApplicationSettings appSettings = SettingsFacade::instance().appStore().load(); + m_projectPath = appSettings.projectPath; } void mirrorDlg::showEvent(QShowEvent *event) @@ -179,7 +182,7 @@ void mirrorDlg::saveJson(const QString &fileName){ } void mirrorDlg:: on_saveBtn_clicked() { - QString path = m_draft.mirrorConfigFile; + QString path = m_projectPath; // Use current project path for file dialog default QString extensionTypes("config file (*.json)"); QString fileName = QFileDialog::getSaveFileName(this, tr("Save config file"), path, @@ -197,10 +200,12 @@ void mirrorDlg:: on_saveBtn_clicked() saveJson(fileName); QFileInfo info(fileName); - // Update draft with new file path, then persist via facade - m_draft.mirrorConfigFile = fileName; - m_draft.projectPath = info.absolutePath(); - m_projectPath = m_draft.projectPath; + // Update application settings with new file path + ApplicationSettings appSettings = SettingsFacade::instance().appStore().load(); + appSettings.mirrorConfigFile = fileName; + appSettings.projectPath = info.absolutePath(); + SettingsFacade::instance().appStore().save(appSettings); + m_projectPath = appSettings.projectPath; } void mirrorDlg::loadFile(QString & fileName){ @@ -210,15 +215,18 @@ void mirrorDlg::loadFile(QString & fileName){ m_outlineShape = CIRCLE; QFileInfo info(fileName); - // Only persist non-mirror-settings to QSettings (lastPath) + // Persist UI convenience path to QSettings QSettings settings; settings.setValue("lastPath", info.absolutePath()); emit newPath(info.absolutePath()); - // Update draft with new file path and project path via facade - m_draft.projectPath = info.absolutePath(); - m_draft.mirrorConfigFile = fileName; + // Update application settings with new file path and mirror config file via facade + ApplicationSettings appSettings = SettingsFacade::instance().appStore().load(); + appSettings.projectPath = info.absolutePath(); + appSettings.mirrorConfigFile = fileName; + SettingsFacade::instance().appStore().save(appSettings); + m_projectPath = appSettings.projectPath; if (fileName.endsWith(".json")){ @@ -449,7 +457,7 @@ void mirrorDlg::on_ReadBtn_clicked() loadFile(fileName); } QString mirrorDlg::getProjectPath(){ - return m_draft.projectPath; + return m_projectPath; // Already synced from application settings in loadDraftFromSettings() } void mirrorDlg::on_diameter_textChanged(const QString &arg1) { @@ -643,7 +651,6 @@ void mirrorDlg::on_buttonBox_accepted() m_draft.ellipseMinorAxis = m_verticalAxis; m_draft.apertureReductionEnabled = m_aperatureReductionEnabled; m_draft.apertureReduction = aperatureReduction; - m_draft.projectPath = m_projectPath; // Persist draft to QSettings via facade (single atomic save) SettingsFacade::instance().mirrorStore().save(m_draft); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 898b6247..4ae01bbf 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -98,6 +98,7 @@ void percentCorrectionDlg::saveSettings(){ * fixme figure that out. */ QList percentCorrectionDlg::generateZoneCenters(double radius, int number_of_zones, bool makeNew){ + QSettings set; QList zoneCenters; if (!makeNew) { // read last used zones @@ -354,7 +355,7 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ ActualZoneKnife << 0.0; mirrorDlg *md = mirrorDlg::get_Instance(); - double nullval = md->currentSettings().z8 * md->currentSettings().cc; // null value was computed at the igram wavevlength + double nullval = md->z8 * md->currentSettings().cc; // null value was computed at the igram wavevlength nullval *= m_lambda_nm/m_outputLambda; // only data from the profile needs the null but it's data is at the output wavelength; // process each zone center @@ -400,7 +401,7 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ void percentCorrectionDlg::plotProfile(){ mirrorDlg *md = mirrorDlg::get_Instance(); - double nullval = md->currentSettings().z8 * md->currentSettings().cc; + double nullval = md->z8 * md->currentSettings().cc; for (int i = 0; i < surfs.length(); ++ i) { QwtPlotCurve *Curve = new QwtPlotCurve(); @@ -753,6 +754,7 @@ void percentCorrectionDlg::on_loadZones_clicked() void percentCorrectionDlg::on_saveZones_clicked() { + QSettings set; QString path = SettingsFacade::instance().appStore().load().projectPath; QString extensionTypes(tr( "zone file (*.zones)")); QString fileName = QFileDialog::getSaveFileName(0, diff --git a/profileplot.cpp b/profileplot.cpp index 2073a854..38a3582d 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -1174,7 +1174,7 @@ void ProfilePlot::CreateWaveFrontFromAverage(){ for (unsigned int i = 0; i < avgRadius.size(); ++i) { double R2 = (double(i))/(avgRadius.size() -1); R2 *= R2; - avgRadius[i] += md->currentSettings().z8 * md->currentSettings().cc * (1. + R2 * (-6 + 6. * R2));; + avgRadius[i] += md->z8 * md->currentSettings().cc * (1. + R2 * (-6 + 6. * R2));; } } cv::Mat result = createInterpolatedCircularSurface(avgRadius); diff --git a/simulationsview.cpp b/simulationsview.cpp index ee49e826..71a4a36a 100644 --- a/simulationsview.cpp +++ b/simulationsview.cpp @@ -191,7 +191,7 @@ SimulationsView *SimulationsView::getInstance(QWidget *parent){ -cv::Mat SimulationsView::nulledSurface(double defocus){ +cv::Mat SimulationsView::nulledSurface(double defocus, bool applyNull){ cv::Mat out; mirrorDlg *md = mirrorDlg::get_Instance(); @@ -210,7 +210,9 @@ cv::Mat SimulationsView::nulledSurface(double defocus){ // save the user selected defocus enable to be restored after this. bool saved_defocus_enable = zernEnables[3]; zernEnables[3] = false; - cv::Mat nulled_surface = zp.null_unwrapped( *(m_Instance->m_wf), newZerns, zernEnables); + + // Pass the applyNull flag to control whether null correction is applied + cv::Mat nulled_surface = zp.null_unwrapped( *(m_Instance->m_wf), newZerns, zernEnables, 0, Z_TERMS, applyNull); zernEnables[3] = saved_defocus_enable; if (GB_enabled){ diff --git a/simulationsview.h b/simulationsview.h index 59a68808..9c107a75 100644 --- a/simulationsview.h +++ b/simulationsview.h @@ -51,7 +51,7 @@ class SimulationsView : public QWidget void compute(); bool needs_drawing; bool needs_drawing_3D; - cv::Mat nulledSurface(double defocus); + cv::Mat nulledSurface(double defocus, bool applyNull = true); cv::Mat m_PSF; private: bool alias; diff --git a/statsview.cpp b/statsview.cpp index cf161d32..c7008c94 100644 --- a/statsview.cpp +++ b/statsview.cpp @@ -270,7 +270,7 @@ void statsView::on_SaveCSV_clicked() // apply software Null if needed if (ndx == 8 and md->currentSettings().doNull) - v -= md->currentSettings().z8 * md->currentSettings().cc; + v -= md->z8 * md->currentSettings().cc; double Sigma = computeRMS(ndx,v) * md->currentSettings().lambda/outputLambda; if (ndx == 8) { diff --git a/surfacemanager.cpp b/surfacemanager.cpp index 6c4fd68c..f2963e58 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -501,7 +501,7 @@ cv::Mat SurfaceManager::computeWaveFrontFromZernikes(int wx, int wy, std::vector else { if (en[z]){ if (z == 8 && md->currentSettings().doNull) - S1 += md->currentSettings().z8 * zpolar.zernike(z); + S1 += md->z8 * zpolar.zernike(z); S1 += zerns[z] * zpolar.zernike(z); } @@ -800,7 +800,7 @@ void SurfaceManager::useDemoWaveFront(){ if (rho <= 1.) { - double S1 = md->currentSettings().z8 * -.9 * zpolar.zernike(8) + .02* zpolar.zernike(9); + double S1 = md->z8 * -.9 * zpolar.zernike(8) + .02* zpolar.zernike(9); result.at(j,i) = S1; } @@ -3020,7 +3020,7 @@ void SurfaceManager::report(){ QString(" waves at %1 nm" "" + ((md->currentSettings().doNull) ? QString("SANull: %1").arg(md->z8 * md->currentSettings().cc, 6, 'f', 4) : "No software Null") + "" "" "
Term
WyantRMS
Strehl: ").arg(outputLambda, 6, 'f', 1) + metrics->mStrehl->text() + "" + BFC + "
" + ((md->isEllipse()) ? "":"Desired Conic: " + QString::number(md->currentSettings().cc)) + "" + - ((md->currentSettings().doNull) ? QString("SANull: %1").arg(md->currentSettings().z8 * md->currentSettings().cc, 6, 'f', 4) : "No software Null") + "Waves per fringe: " + QString::number(md->currentSettings().fringeSpacing) + "
Interferogram Wave length: "+ QString::number(md->currentSettings().lambda) + "nm

"; @@ -3043,7 +3043,7 @@ void SurfaceManager::report(){ enabled = true; } if ( i == 8 && md->currentSettings().doNull){ - val -= md->currentSettings().z8 * md->currentSettings().cc; + val -= md->z8 * md->currentSettings().cc; } diff --git a/wftstats.cpp b/wftstats.cpp index e728860d..4b37fefd 100644 --- a/wftstats.cpp +++ b/wftstats.cpp @@ -215,7 +215,7 @@ void wftStats::computeWftStats( QVector wavefronts, int ndx){ // apply software Null if needed if (ndx == 8 and md->currentSettings().doNull) - v -= md->currentSettings().z8 * md->currentSettings().cc; + v -= md->z8 * md->currentSettings().cc; double Sigma = computeRMS(ndx,v) * outputLambda/md->currentSettings().lambda; if (ndx == 8) { diff --git a/zernikeprocess.cpp b/zernikeprocess.cpp index e8bf66a6..d2394420 100644 --- a/zernikeprocess.cpp +++ b/zernikeprocess.cpp @@ -484,19 +484,19 @@ void zernikeProcess::unwrap_to_zernikes(wavefront &wf, int zterms){ } cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, std::vector enables, - int start_term, int last_term) + int start_term, int last_term, bool applyNull) { int nx = wf.data.cols; cv::Mat unwrapped = wf.data.clone(); - double scz8 = md->currentSettings().z8 * md->currentSettings().cc; - mirrorDlg *md = mirrorDlg::get_Instance(); + + double scz8 = md->z8 * md->currentSettings().cc; - if (!md->currentSettings().doNull || !wf.useSANull){ + if (!applyNull || !md->currentSettings().doNull || !wf.useSANull){ scz8 = 0.; } double midx = wf.m_outside.m_center.rx(); @@ -914,7 +914,7 @@ cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ for (unsigned int z = 0; z < m_zerns.n_cols; ++z){ double val = dlg.zernikes[z]; if (z == 8){ - val = (dlg.doCorrection && md->currentSettings().doNull) ? md->currentSettings().cc * md->currentSettings().z8 * val * .01 : val; + val = (dlg.doCorrection && md->currentSettings().doNull) ? md->currentSettings().cc * md->z8 * val * .01 : val; } S1 += val * m_zerns(i,z)/((doColor) ? md->currentSettings().fringeSpacing: 1.); diff --git a/zernikeprocess.h b/zernikeprocess.h index f01d570f..f7fd3183 100644 --- a/zernikeprocess.h +++ b/zernikeprocess.h @@ -55,7 +55,7 @@ class zernikeProcess : public QObject explicit zernikeProcess(QObject *parent = 0); static zernikeProcess *get_Instance(); void unwrap_to_zernikes(wavefront &wf, int zterms = Z_TERMS); - cv::Mat null_unwrapped(wavefront&wf, std::vector zerns, std::vector enables,int start_term =0, int last_term = Z_TERMS); + cv::Mat null_unwrapped(wavefront&wf, std::vector zerns, std::vector enables, int start_term = 0, int last_term = Z_TERMS, bool applyNull = true); std::vector ZernFitWavefront( wavefront &wf); void initGrid(wavefront &wf, int maxOrder); void initGrid(int width, double radius, double cx, double cy, int maxOrder, double inside = 0); From 419d4ec2370c96cbdb4319c082cb2b32e06b0712 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 14:18:20 +0200 Subject: [PATCH 08/20] ensure programmatically mirror dialog is only one to be able to modify mirror settings --- bathastigdlg.cpp | 6 ++--- dftarea.cpp | 16 ++++++------ igramarea.cpp | 20 +++++++-------- mainwindow.cpp | 4 +-- mirrordlg.cpp | 14 ++++++++++- mirrordlg.h | 53 ++++++++++++++++++++++++---------------- percentcorrectiondlg.cpp | 8 +++--- profileplot.cpp | 8 +++--- settingsfacade.cpp | 5 ++++ settingsfacade.h | 14 +++++++++++ settingsstores.h | 5 ++-- surfacemanager.cpp | 18 ++++++++------ zernikedlg.cpp | 4 +-- 13 files changed, 110 insertions(+), 65 deletions(-) diff --git a/bathastigdlg.cpp b/bathastigdlg.cpp index c8aaba0e..d5162f5b 100644 --- a/bathastigdlg.cpp +++ b/bathastigdlg.cpp @@ -8,9 +8,9 @@ bathAstigDlg::bathAstigDlg(QWidget *parent) : { ui->setupUi(this); mirrorDlg &md = *mirrorDlg::get_Instance(); - ui->diamSb->setValue(md.diameter); - ui->rocsb->setValue(md.roc); - ui->lambdaSb->setValue(md.lambda); + ui->diamSb->setValue(md.currentSettings().diameter); + ui->rocsb->setValue(md.currentSettings().roc); + ui->lambdaSb->setValue(md.currentSettings().lambda); ui->sepSb->setValue(5.); compute(); } diff --git a/dftarea.cpp b/dftarea.cpp index 34b68b33..831c0465 100644 --- a/dftarea.cpp +++ b/dftarea.cpp @@ -40,7 +40,7 @@ cv::Mat makeMask(const CircleOutline &outside, const CircleOutline ¢er, con double rady = radm; mirrorDlg &md = *mirrorDlg::get_Instance(); if (md.isEllipse()) - rady = radm * md.m_verticalAxis/md.diameter; + rady = radm * md.currentSettings().ellipseMinorAxis/md.currentSettings().diameter; double rado = center.m_radius; double cx = outside.m_center.x(); double cy = outside.m_center.y(); @@ -151,14 +151,14 @@ DFTArea::DFTArea(QWidget *mparent, IgramArea *ip, DFTTools * tools, vortexDebug grid->attach(test); QPolygonF points; mirrorDlg &md = *mirrorDlg::get_Instance(); - double roc = md.roc; - double diam = md.diameter; + double roc = md.currentSettings().roc; + double diam = md.currentSettings().diameter; double r3 = roc * roc * roc; double d4 = diam * diam * diam * diam; for (double i = 0; i < .03; i += .0001){ - double z1 = -i * 384. * r3 * md.lambda * 1.E-6/(d4); + double z1 = -i * 384. * r3 * md.currentSettings().lambda * 1.E-6/(d4); points << QPointF( -i, z1 ); @@ -251,9 +251,9 @@ cv::Mat DFTArea::grayComplexMatfromImage(QImage &img){ double centerY = igramArea->m_outside.m_center.y(); mirrorDlg &md = *mirrorDlg::get_Instance(); - double pixelsPermm =(igramArea->m_outside.m_radius/(md.diameter/2.)); - double reduction = md.aperatureReduction * pixelsPermm; - if (md.m_aperatureReductionEnabled == false) + double pixelsPermm =(igramArea->m_outside.m_radius/(md.currentSettings().diameter/2.)); + double reduction = md.currentSettings().apertureReduction * pixelsPermm; + if (md.currentSettings().apertureReductionEnabled == false) reduction = 0; double rad = igramArea->m_outside.m_radius - reduction; @@ -262,7 +262,7 @@ cv::Mat DFTArea::grayComplexMatfromImage(QImage &img){ double rady = rad; if (md.isEllipse()){ - rady = rady * md.m_verticalAxis/ md.diameter; + rady = rady * md.currentSettings().ellipseMinorAxis / md.currentSettings().diameter; } double left = centerX - rad; diff --git a/igramarea.cpp b/igramarea.cpp index 871eea48..b7b7cc68 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -151,9 +151,9 @@ IgramArea::IgramArea(QWidget *parent, void *mw) void IgramArea::computeEdgeRadius(){ // compute mask inner edge in pixels mirrorDlg &md = *mirrorDlg::get_Instance(); - double pixelsPermm =(m_outside.m_radius/(md.diameter/2.)); - m_edgeMaskWidth = md.aperatureReduction * pixelsPermm; - if (md.m_aperatureReductionEnabled == false) + double pixelsPermm =(m_outside.m_radius/(md.currentSettings().diameter/2.)); + m_edgeMaskWidth = md.currentSettings().apertureReduction * pixelsPermm; + if (md.currentSettings().apertureReductionEnabled == false) m_edgeMaskWidth = 0; } @@ -1545,7 +1545,7 @@ void IgramArea::mouseMoveEvent(QMouseEvent *event) int majorRad = fabs((m_OutterP2.x() - m_OutterP1.x()))/2.; double e = (double)minorRad/majorRad; mirrorDlg &md = *mirrorDlg::get_Instance(); - md.m_verticalAxis = md.diameter * e; + md.setVerticalAxis(md.currentSettings().diameter * e); drawBoundary(); return; } @@ -1624,8 +1624,8 @@ void IgramArea::mouseReleaseEvent(QMouseEvent *event) setCursor(Qt::ArrowCursor); if (event->button() == Qt::LeftButton && verticalTracking) { mirrorDlg &md = *mirrorDlg::get_Instance(); - double e = md.m_verticalAxis/ md.diameter; - md.setMinorAxis( e * md.diameter); + double e = md.currentSettings().ellipseMinorAxis / md.currentSettings().diameter; + md.setMinorAxis( e * md.currentSettings().diameter); } @@ -1705,7 +1705,7 @@ void IgramArea::drawBoundary() mirrorDlg &md = *mirrorDlg::get_Instance(); if ((md.isEllipse())){ - s2 = md.m_verticalAxis/ md.diameter; + s2 = md.currentSettings().ellipseMinorAxis / md.currentSettings().diameter; } if (m_searching_outside){ QColor c(Qt::cyan); @@ -1719,7 +1719,7 @@ void IgramArea::drawBoundary() painter.setBrush(Qt::NoBrush); } outside.draw(painter,1.,s2); - if ( md.m_aperatureReductionEnabled && md.m_clearAperature != md.diameter){ + if ( md.currentSettings().apertureReductionEnabled && md.currentSettings().apertureReduction != md.currentSettings().diameter){ painter.setPen(QPen(edgePenColor, edgePenWidth, Qt::DotLine)); computeEdgeRadius(); painter.drawEllipse(outside.m_center, @@ -1927,7 +1927,7 @@ void IgramArea::paintEvent(QPaintEvent *event) mirrorDlg &md = *mirrorDlg::get_Instance(); double e = 1.; if (md.isEllipse()){ - e = md.m_verticalAxis/md.diameter; + e = md.currentSettings().ellipseMinorAxis / md.currentSettings().diameter; } @@ -2022,7 +2022,7 @@ void IgramArea::crop() { mirrorDlg &md = *mirrorDlg::get_Instance(); if (md.isEllipse()){ - double e = md.m_verticalAxis/md.diameter; + double e = md.currentSettings().ellipseMinorAxis/md.currentSettings().diameter; rady = radx * e; top = fmax(0,cy - rady); bottom = igramColor.height() - (rady + cy); diff --git a/mainwindow.cpp b/mainwindow.cpp index a597f97b..372c83d0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -586,8 +586,8 @@ void MainWindow::updateMetrics(wavefront& wf){ double Strehl = pow(e, -st); metrics->mStrehl->setText(QString("%1").arg(Strehl, 6, 'f', 3)); QString ztitle("Zernike Values"); - if (m_mirrorDlg->m_useAnnular){ - ztitle = QString("Annular Zernike values %1% center hole").arg(100 * m_mirrorDlg->m_annularObsPercent, 6, 'f',1); + if (m_mirrorDlg->currentSettings().useAnnulus){ + ztitle = QString("Annular Zernike values %1% center hole").arg(100 * m_mirrorDlg->currentSettings().annulusPercent, 6, 'f',1); } metrics->setZernTitle(ztitle); double z8 = zernTablemodel->values[8]; diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 9f8cd585..2a14cd90 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -653,7 +653,8 @@ void mirrorDlg::on_buttonBox_accepted() m_draft.apertureReduction = aperatureReduction; // Persist draft to QSettings via facade (single atomic save) - SettingsFacade::instance().mirrorStore().save(m_draft); + // Note: Only mirrordlg can call this (via friend declaration) - enforces single source of truth + SettingsFacade::instance().saveMirrorSettings(m_draft); if (m_obsChanged) emit obstructionChanged(); @@ -708,6 +709,17 @@ void mirrorDlg::setMinorAxis(double val){ //on_minorAxisEdit_textChanged( QString::number(val)); } +void mirrorDlg::setVerticalAxis(double val){ + m_verticalAxis = val; + m_draft.ellipseMinorAxis = val; +} + +void mirrorDlg::setOutlineShape(outlineShape shape){ + m_outlineShape = shape; + m_draft.outlineShape = (int)shape; + ui->ellipseShape->setChecked(shape == ELLIPSE); +} + void mirrorDlg::on_ellipseShape_clicked(bool checked) { if (checked) m_outlineShape = ELLIPSE; diff --git a/mirrordlg.h b/mirrordlg.h index 16fd8fca..4fc1efa3 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -37,49 +37,60 @@ class mirrorDlg : public QDialog mirrorDlg(const mirrorDlg&) = delete; mirrorDlg& operator=(const mirrorDlg&) = delete; + // File and configuration operations void loadFile(QString & fileName); void updateZ8(); void updateAutoInvertStatus(); - QString m_name; + // Computed/derived values (read-only, not from settings) bool mm; - double diameter; - double roc; double FNumber; - double obs; // obstruction - double cc; - bool doNull; double z8; - double lambda; - double fringeSpacing; - bool flipv; - bool fliph; - bool m_useAnnular; - bool m_connectAnnulusToObs; - double m_annularObsPercent; // a value from 0 to 1 (not 0 to 100) - double m_clearAperature; - double aperatureReduction; static QString m_projectPath; + + // State flags + bool m_obsChanged; + bool m_majorHorizontal; + + // Methods for configuration access/modification void on_roc_Changed(const double newVal); void on_diameter_Changed(const double diam); bool shouldFlipH(); static QString getProjectPath(); - bool m_obsChanged; void newLambda(const QString &v); double getMinorAxis(); - bool m_majorHorizontal; - double m_verticalAxis; - outlineShape m_outlineShape; bool isEllipse(); void setMinorAxis(double val); - bool m_aperatureReductionEnabled; + void setVerticalAxis(double val); + void setOutlineShape(outlineShape shape); void setObsPercent(double obs); /** @brief Access current mirror settings (read-only snapshot). * Returns the draft which is the canonical storage for all mirror config. - * All member variables are kept in sync with this for backward compatibility. */ + * All internal member variables are kept in sync with this. */ const MirrorSettings& currentSettings() const { return m_draft; } +private: + // Configuration members (access via currentSettings() or setters) + QString m_name; + double diameter; + double roc; + double obs; // obstruction + double cc; + bool doNull; + double lambda; + double fringeSpacing; + bool flipv; + bool fliph; + bool m_useAnnular; + bool m_connectAnnulusToObs; + double m_annularObsPercent; // a value from 0 to 1 (not 0 to 100) + double m_clearAperature; + double aperatureReduction; + bool m_aperatureReductionEnabled; + double m_verticalAxis; + outlineShape m_outlineShape; + private slots: void on_ReadBtn_clicked(); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 4ae01bbf..fa205094 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -31,7 +31,7 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : mirrorDlg &md = *mirrorDlg::get_Instance(); - m_radius = md.m_clearAperature/2.; + m_radius = md.currentSettings().apertureReduction/2.; QSettings set; ui->minvalue->blockSignals(true); ui->maxvalue->blockSignals(true); @@ -639,12 +639,12 @@ void percentCorrectionDlg::setData( QVector< surfaceData *> data) { mirrorDlg &md = *mirrorDlg::get_Instance(); - m_roc = md.roc; - m_lambda_nm = md.lambda; + m_roc = md.currentSettings().roc; + m_lambda_nm = md.currentSettings().lambda; QSettings set; m_outputLambda = set.value("outputLambda").toDouble(); - m_radius = md.m_clearAperature/2.; + m_radius = md.currentSettings().apertureReduction/2.; surfs = data; ui->percentTable->setRowCount(data.length()); diff --git a/profileplot.cpp b/profileplot.cpp index 38a3582d..853ffe5c 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -427,8 +427,8 @@ QPolygonF ProfilePlot::createProfile(double units, const wavefront *wf, bool all // 1. Setup constants double steps = 1.0 / wf->m_outside.m_radius; double offset = allowOffset ? y_offset : 0.0; - double radius = md.m_clearAperature / 2.0; - double obs_radius = md.obs / 2.0; + double radius = md.currentSettings().apertureReduction / 2.0; + double obs_radius = md.currentSettings().obstruction / 2.0; if (m_displayInches) { obs_radius /= 25.4; @@ -443,12 +443,12 @@ QPolygonF ProfilePlot::createProfile(double units, const wavefront *wf, bool all if (m_displayPercent) { radx = 100.0 * radx / radius; - obs_radius = 100.0 * (md.obs / 2.0) / radius; + obs_radius = 100.0 * (md.currentSettings().obstruction / 2.0) / radius; } double e = 1.0; if (md.isEllipse()) { - e = md.m_verticalAxis / md.diameter; + e = md.currentSettings().ellipseMinorAxis / md.currentSettings().diameter; } // Calculate matrix coordinates diff --git a/settingsfacade.cpp b/settingsfacade.cpp index f3b887d1..5a65fcac 100644 --- a/settingsfacade.cpp +++ b/settingsfacade.cpp @@ -45,3 +45,8 @@ const ApplicationSettingsStore &SettingsFacade::appStore() const { return m_appStore; } + +void SettingsFacade::saveMirrorSettings(const MirrorSettings &settings) +{ + m_mirrorStore.save(settings); +} diff --git a/settingsfacade.h b/settingsfacade.h index f9ae4085..15e9693b 100644 --- a/settingsfacade.h +++ b/settingsfacade.h @@ -3,14 +3,21 @@ #include "settingsstores.h" +// Forward declaration for friend access +class mirrorDlg; + /** * @brief Thin entry point that delegates to domain-specific settings stores. * * This class intentionally stays small; domain behavior belongs in internal * stores such as MirrorSettingsStore or ContourSettingsStore. + * + * Access control: saveMirrorSettings() is restricted to mirrordlg (via friend) + * to ensure mirror configuration is saved only from the dialog's OK button. */ class SettingsFacade { + friend class mirrorDlg; // Only mirrordlg can call saveMirrorSettings() public: static SettingsFacade &instance(); @@ -30,6 +37,13 @@ class SettingsFacade const ApplicationSettingsStore &appStore() const; private: + friend class mirrorDlg; // Allow mirrordlg to call restricted save + + /** @brief Restricted save for mirror settings (mirrordlg only via friend). + * Ensures single source of truth: only the mirror dialog's OK button can persist changes. + * Nobody will be able to save mirror settings directly elsewhere in the code. */ + void saveMirrorSettings(const MirrorSettings &settings); + SettingsFacade() = default; // Enforce singleton // Only facade owns these diff --git a/settingsstores.h b/settingsstores.h index 12c26b88..bf719cc7 100644 --- a/settingsstores.h +++ b/settingsstores.h @@ -16,12 +16,13 @@ struct MirrorSettings { class MirrorSettingsStore { private: - friend class SettingsFacade; // Only facade can construct + friend class SettingsFacade; // Only facade can construct and call save() MirrorSettingsStore() = default; + void save(const MirrorSettings &value) const; + public: MirrorSettings load() const; - void save(const MirrorSettings &value) const; }; diff --git a/surfacemanager.cpp b/surfacemanager.cpp index f2963e58..bb4f06fc 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -647,7 +647,7 @@ void SurfaceManager::makeMask(wavefront *wf, bool useInsideCircle){ mirrorDlg &md = *mirrorDlg::get_Instance(); double rx = radm; double rx2 = rx * rx; - double ry = rx * md.m_verticalAxis/md.diameter; + double ry = rx * md.currentSettings().ellipseMinorAxis / md.currentSettings().diameter; double ry2 = ry * ry; if (!mirrorDlg::get_Instance()->isEllipse()){ uchar v = 0xff; @@ -718,7 +718,7 @@ void SurfaceManager::makeMask(wavefront *wf, bool useInsideCircle){ // add central obstruction (not to be confused with a hole in the mirror - this comes from mirror configuration) - double r = md.obs * (2. * radm)/md.diameter; + double r = md.currentSettings().obstruction * (2. * radm)/md.currentSettings().diameter; r/= 2.; if (r > 0){ @@ -941,9 +941,9 @@ void SurfaceManager::computeZerns() mirrorDlg &md = *mirrorDlg::get_Instance(); foreach(int ndx , doThese){ wavefront &wf = *m_wavefronts[ndx]; - wf.diameter = md.diameter; - wf.roc = md.roc; - wf.lambda = md.lambda; + wf.diameter = md.currentSettings().diameter; + wf.roc = md.currentSettings().roc; + wf.lambda = md.currentSettings().lambda; } m_waveFrontTimer->start(500); @@ -997,7 +997,7 @@ void SurfaceManager::writeWavefront(const QString &fname, wavefront *wf, bool sa } mirrorDlg &md = *mirrorDlg::get_Instance(); if (md.isEllipse()){ - file << "ellipse_vertical_axis " << md.m_verticalAxis; + file << "ellipse_vertical_axis " << md.currentSettings().ellipseMinorAxis; } } @@ -1305,8 +1305,10 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ continue; } if (l.startsWith("ellipse_vertical_axis")){ - md->m_outlineShape = ELLIPSE; - iss >> dummy >> md->m_verticalAxis; + md->setOutlineShape(ELLIPSE); + double vertAxis; + iss >> dummy >> vertAxis; + md->setVerticalAxis(vertAxis); } if (l.startsWith("Do Not use null") || l.startsWith("nulled") ){ wf->useSANull = false; diff --git a/zernikedlg.cpp b/zernikedlg.cpp index b95416b4..78acb1d1 100644 --- a/zernikedlg.cpp +++ b/zernikedlg.cpp @@ -119,8 +119,8 @@ QVariant ZernTableModel::data(const QModelIndex &index, int role) const } mirrorDlg &md = *mirrorDlg::get_Instance(); - if (index.row() == 8 && md.doNull && !m_nulled){ - double val = values[8] - md.z8 * md.cc; + if (index.row() == 8 && md.currentSettings().doNull && !m_nulled){ + double val = values[8] - md.z8 * md.currentSettings().cc; return QString("%1 %2").arg(val, 6, 'f', 3).arg( computeRMS(8, val), 6, 'f', 3); } From 6629b254a9a7e1b622a4b3b491fa86ad0b7a2305 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 15:28:31 +0200 Subject: [PATCH 09/20] fix the draft/current settings way of working --- mirrordlg.cpp | 348 ++++++++++++++++++++++---------------------------- mirrordlg.h | 43 ++----- 2 files changed, 170 insertions(+), 221 deletions(-) diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 2a14cd90..a613906d 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -43,11 +43,9 @@ mirrorDlg::mirrorDlg(QWidget *parent) : QDialog(parent), mm(true),m_obsChanged(false),ui(new Ui::mirrorDlg) { - m_useAnnular = false; - m_connectAnnulusToObs = false; ui->setupUi(this); - // Initialize defaults only; loadDraftFromSettings() called in showEvent() populates UI + // Initialize defaults only; loadDraftFromSettings() populates m_current and m_draft FNumber = 0.0; ui->FNumber->blockSignals(true); ui->roc->blockSignals(true); @@ -69,6 +67,9 @@ mirrorDlg::mirrorDlg(QWidget *parent) : ui->minorAxisEdit->blockSignals(false); m_aperatureReductionValueChanged = false; + + // Initialize settings from persistent storage (in case dialog used without showEvent) + loadDraftFromSettings(); } mirrorDlg::~mirrorDlg() @@ -79,27 +80,11 @@ mirrorDlg::~mirrorDlg() void mirrorDlg::loadDraftFromSettings() { - // Load mirror settings from persistent storage via facade into working draft. - // This ensures every dialog open/show starts with the last-saved state. - m_draft = SettingsFacade::instance().mirrorStore().load(); - - // Sync public member variables with draft for backward compatibility. - m_name = m_draft.mirrorName; - diameter = m_draft.diameter; - roc = m_draft.roc; - obs = m_draft.obstruction; - cc = m_draft.cc; - lambda = m_draft.lambda; - fringeSpacing = m_draft.fringeSpacing; - fliph = m_draft.flipH; - doNull = m_draft.doNull; - m_useAnnular = m_draft.useAnnulus; - m_annularObsPercent = m_draft.annulusPercent; - m_connectAnnulusToObs = m_draft.annulusToObstruction; - m_outlineShape = (outlineShape)m_draft.outlineShape; - m_verticalAxis = m_draft.ellipseMinorAxis; - aperatureReduction = m_draft.apertureReduction; - m_aperatureReductionEnabled = m_draft.apertureReductionEnabled; + // Load mirror settings from persistent storage via facade into BOTH copies. + // m_current: persistent copy (source of truth for external code) + // m_draft: working copy for dialog edits (discarded on Cancel) + m_current = SettingsFacade::instance().mirrorStore().load(); + m_draft = m_current; // Load application-level settings separately (projectPath, mirrorConfigFile, lastPath) ApplicationSettings appSettings = SettingsFacade::instance().appStore().load(); @@ -112,22 +97,22 @@ void mirrorDlg::showEvent(QShowEvent *event) // This ensures Cancel always reverts to the last-saved state. loadDraftFromSettings(); - // Sync UI with reloaded draft values + // Sync UI with reloaded draft (working copy) values ui->name->setText(m_draft.mirrorName); - ui->diameter->setText(QString("%1").arg(diameter, 6, 'f', 2)); - ui->roc->setText(QString("%1").arg(roc, 6, 'f', 2)); - ui->obs->setText(QString("%1").arg(obs, 6, 'f', 2)); - ui->lambda->setText(QString("%1").arg(lambda, 6, 'f', 1)); - ui->cc->setText(QString("%1").arg(cc, 6, 'f', 2)); + ui->diameter->setText(QString("%1").arg(m_draft.diameter, 6, 'f', 2)); + ui->roc->setText(QString("%1").arg(m_draft.roc, 6, 'f', 2)); + ui->obs->setText(QString("%1").arg(m_draft.obstruction, 6, 'f', 2)); + ui->lambda->setText(QString("%1").arg(m_draft.lambda, 6, 'f', 1)); + ui->cc->setText(QString("%1").arg(m_draft.cc, 6, 'f', 2)); ui->flipH->setChecked(m_draft.flipH); ui->nullCB->setChecked(m_draft.doNull); - ui->fringeSpacingEdit->setText(QString("%1").arg(fringeSpacing, 6, 'f', 3)); - ui->ellipseShape->setChecked(m_outlineShape == ELLIPSE); - ui->minorAxisEdit->setText(QString::number(m_verticalAxis)); - ui->ReducApp->setChecked(m_aperatureReductionEnabled); - ui->reduceValue->setValue(aperatureReduction); - ui->useAnnulus->setChecked(m_useAnnular); - ui->annulusPercent->setValue(m_annularObsPercent * 100); + ui->fringeSpacingEdit->setText(QString("%1").arg(m_draft.fringeSpacing, 6, 'f', 3)); + ui->ellipseShape->setChecked((outlineShape)m_draft.outlineShape == ELLIPSE); + ui->minorAxisEdit->setText(QString::number(m_draft.ellipseMinorAxis)); + ui->ReducApp->setChecked(m_draft.apertureReductionEnabled); + ui->reduceValue->setValue(m_draft.apertureReduction); + ui->useAnnulus->setChecked(m_draft.useAnnulus); + ui->annulusPercent->setValue(m_draft.annulusPercent * 100); QDialog::showEvent(event); } @@ -140,30 +125,29 @@ double mirrorDlg::getMinorAxis(){ } bool mirrorDlg::isEllipse(){ - return m_draft.outlineShape == ELLIPSE; + return (outlineShape)m_draft.outlineShape == ELLIPSE; } void mirrorDlg::saveJson(const QString &fileName){ QJsonObject jDoc, jMirror,jIgram, jEllipse, jAnnulus; - jDoc["name"] = m_name; + jDoc["name"] = m_draft.mirrorName; jDoc["show units in mm"] = mm; - jDoc["useNull"] = doNull; - jIgram["wavelength"] = lambda; - jIgram["fringe spacing"] = fringeSpacing; - jMirror["diameter"] = diameter; - jMirror["obs diameter"] = obs; - jMirror["roc"] = roc; - jMirror["desired conic"] = cc; - jMirror["edgeMaskon"] = m_aperatureReductionEnabled; - jMirror["edge mask value"] = aperatureReduction; - jIgram["wavelength"] = lambda; + jDoc["useNull"] = m_draft.doNull; + jIgram["wavelength"] = m_draft.lambda; + jIgram["fringe spacing"] = m_draft.fringeSpacing; + jMirror["diameter"] = m_draft.diameter; + jMirror["obs diameter"] = m_draft.obstruction; + jMirror["roc"] = m_draft.roc; + jMirror["desired conic"] = m_draft.cc; + jMirror["edgeMaskon"] = m_draft.apertureReductionEnabled; + jMirror["edge mask value"] = m_draft.apertureReduction; + jIgram["wavelength"] = m_draft.lambda; jIgram["null value"] = z8; - jIgram["flip horizontal"] = fliph; - jIgram["flip vert"] = flipv; - jIgram["fringe spacing"] = fringeSpacing; - jEllipse["is ellipse"] = m_outlineShape; - jEllipse["ellipse vert axis"] = m_verticalAxis; - jAnnulus["use annular Zernike values"] = m_useAnnular; - jAnnulus["obs percentage"] = m_annularObsPercent; + jIgram["flip horizontal"] = m_draft.flipH; + jIgram["fringe spacing"] = m_draft.fringeSpacing; + jEllipse["is ellipse"] = m_draft.outlineShape; + jEllipse["ellipse vert axis"] = m_draft.ellipseMinorAxis; + jAnnulus["use annular Zernike values"] = m_draft.useAnnulus; + jAnnulus["obs percentage"] = m_draft.annulusPercent; jDoc["mirror"] = jMirror; jDoc["igram"] = jIgram; jDoc["ellipse"] = jEllipse; @@ -212,7 +196,7 @@ void mirrorDlg::loadFile(QString & fileName){ // clear ellipse in case this is an old config that does not have it. ui->ellipseShape->setChecked(false); - m_outlineShape = CIRCLE; + m_draft.outlineShape = (int)CIRCLE; QFileInfo info(fileName); // Persist UI convenience path to QSettings @@ -247,56 +231,55 @@ void mirrorDlg::loadFile(QString & fileName){ // set diameter early - before setting roc and annulus percentage QJsonObject mirror = loadDoc["mirror"].toObject(); - diameter = QJsonValue(mirror["diameter"]).toDouble(); + m_draft.diameter = QJsonValue(mirror["diameter"]).toDouble(); ui->diameter->blockSignals(true); - ui->diameter->setText(QString("%1").arg(diameter, 6, 'f', 2)); + ui->diameter->setText(QString("%1").arg(m_draft.diameter, 6, 'f', 2)); ui->diameter->blockSignals(false); ui->nullCB->setChecked( QJsonValue(loadDoc["useNull"]).toBool()); - obs = QJsonValue(mirror["obs diameter"]).toDouble(); - roc = QJsonValue(mirror["roc"]).toDouble(); - cc = QJsonValue(mirror["desired conic"]).toDouble(); - m_aperatureReductionEnabled = QJsonValue(mirror["edgeMaskon"]).toBool(); - aperatureReduction=QJsonValue( mirror["edge mask value"]).toDouble(); + m_draft.obstruction = QJsonValue(mirror["obs diameter"]).toDouble(); + m_draft.roc = QJsonValue(mirror["roc"]).toDouble(); + m_draft.cc = QJsonValue(mirror["desired conic"]).toDouble(); + m_draft.apertureReductionEnabled = QJsonValue(mirror["edgeMaskon"]).toBool(); + m_draft.apertureReduction = QJsonValue( mirror["edge mask value"]).toDouble(); QJsonObject Igram = loadDoc["igram"].toObject(); - lambda = QJsonValue(Igram["wavelength"]).toDouble(); + m_draft.lambda = QJsonValue(Igram["wavelength"]).toDouble(); z8 = QJsonValue(Igram["null value"]).toDouble(); - fliph = QJsonValue(Igram["flip horizontal"]).toBool(); - flipv = QJsonValue(Igram["flip vert"]).toBool(); - fringeSpacing = QJsonValue(Igram["fringe spacing"]).toDouble(); + m_draft.flipH = QJsonValue(Igram["flip horizontal"]).toBool(); + m_draft.fringeSpacing = QJsonValue(Igram["fringe spacing"]).toDouble(); QJsonObject Ellipse = loadDoc["ellipse"].toObject(); - m_outlineShape = (outlineShape)QJsonValue(Ellipse["is ellipse"]).toInt(); - m_verticalAxis = QJsonValue(Ellipse["ellipse vert axis"]).toDouble(); + m_draft.outlineShape = QJsonValue(Ellipse["is ellipse"]).toInt(); + m_draft.ellipseMinorAxis = QJsonValue(Ellipse["ellipse vert axis"]).toDouble(); QJsonObject Annulus = loadDoc["Annulus"].toObject(); - m_useAnnular = QJsonValue(Annulus["use annular Zernike values"]).toBool(); - m_annularObsPercent = QJsonValue(Annulus["obs percentage"]).toDouble(); - ui->useAnnulus->setChecked(m_useAnnular); - ui->annulusPercent->setValue(m_annularObsPercent * 100); - on_annulusPercent_valueChanged(m_annularObsPercent * 100); - enableAnnular(m_useAnnular); + m_draft.useAnnulus = QJsonValue(Annulus["use annular Zernike values"]).toBool(); + m_draft.annulusPercent = QJsonValue(Annulus["obs percentage"]).toDouble(); + ui->useAnnulus->setChecked(m_draft.useAnnulus); + ui->annulusPercent->setValue(m_draft.annulusPercent * 100); + on_annulusPercent_valueChanged(m_draft.annulusPercent * 100); + enableAnnular(m_draft.useAnnulus); ui->fringeSpacingEdit->blockSignals(true); - ui->fringeSpacingEdit->setText(QString("%1").arg(fringeSpacing, 3, 'f', 1)); + ui->fringeSpacingEdit->setText(QString("%1").arg(m_draft.fringeSpacing, 3, 'f', 1)); ui->fringeSpacingEdit->blockSignals(false); - ui->obs->setText(QString().number(obs)); + ui->obs->setText(QString().number(m_draft.obstruction)); ui->roc->blockSignals(true); - ui->roc->setText(QString("%1").arg(roc, 6, 'f', 2)); + ui->roc->setText(QString("%1").arg(m_draft.roc, 6, 'f', 2)); ui->roc->blockSignals(false); - ui->cc->setText(QString().number(cc)); + ui->cc->setText(QString().number(m_draft.cc)); ui->z8->setText(QString().number(z8)); - ui->ellipseShape->setChecked(m_outlineShape == ELLIPSE); + ui->ellipseShape->setChecked((outlineShape)m_draft.outlineShape == ELLIPSE); - ui->minorAxisEdit->setText(QString::number(m_verticalAxis)); + ui->minorAxisEdit->setText(QString::number(m_draft.ellipseMinorAxis)); - FNumber = roc/(2. * diameter); + FNumber = m_draft.roc/(2. * m_draft.diameter); ui->FNumber->blockSignals(true); ui->FNumber->setText(QString("%1").arg(FNumber, 6, 'f', 2)); ui->FNumber->blockSignals(false); @@ -344,29 +327,29 @@ void mirrorDlg::loadFile(QString & fileName){ } ui->name->setText(name); - m_name = name; + m_draft.mirrorName = name; // donull file.read(buf,4); bool *bp = (bool *)buf; ui->nullCB->setChecked(*bp); - doNull = *bp; + m_draft.doNull = *bp; //fringe Spacing file.read(buf,8); double *dp = (double*)buf; - fringeSpacing = *dp; + m_draft.fringeSpacing = *dp; ui->fringeSpacingEdit->blockSignals(true); ui->fringeSpacingEdit->setText(QString("%1").arg(*dp, 3, 'f', 1)); ui->fringeSpacingEdit->blockSignals(false); //read diameter file.read(buf,8); - diameter = *dp; + m_draft.diameter = *dp; //Lambda file.read(buf,8); - lambda = *dp; + m_draft.lambda = *dp; ui->lambda->setText(QString().number(*dp)); //Units mm @@ -376,11 +359,11 @@ void mirrorDlg::loadFile(QString & fileName){ //obsruction file.read(buf,4 * 9); - obs = *(dp++); - ui->obs->setText(QString().number(obs)); + m_draft.obstruction = *(dp++); + ui->obs->setText(QString().number(m_draft.obstruction)); //ROC - roc = *(dp++); + m_draft.roc = *(dp++); //Diameter if (!mm){ @@ -388,15 +371,15 @@ void mirrorDlg::loadFile(QString & fileName){ //roc *= 25.4; } ui->diameter->blockSignals(true); - ui->diameter->setText(QString("%1").arg(diameter, 6, 'f', 2)); + ui->diameter->setText(QString("%1").arg(m_draft.diameter, 6, 'f', 2)); ui->diameter->blockSignals(false); ui->roc->blockSignals(true); - ui->roc->setText(QString("%1").arg(roc, 6, 'f', 2)); + ui->roc->setText(QString("%1").arg(m_draft.roc, 6, 'f', 2)); ui->roc->blockSignals(false); //conic - cc = *(dp++); - ui->cc->setText(QString().number(cc)); + m_draft.cc = *(dp++); + ui->cc->setText(QString().number(m_draft.cc)); //z8 z8 = *(dp++); @@ -414,27 +397,27 @@ void mirrorDlg::loadFile(QString & fileName){ //flips if (!file.eof()){ file.read(buf,4); // 1234 read right here - fliph = *(bool*)buf; + m_draft.flipH = *(bool*)buf; file.read(buf,4); - flipv = *(bool*)buf; + // Skip vertical flip - not stored in MirrorSettings struct and not used } // ellipse if (file.tellg() > 0){ // read outlineShape file.read(buf,4); - m_outlineShape = *(outlineShape*)buf; - ui->ellipseShape->setChecked(m_outlineShape == ELLIPSE); + m_draft.outlineShape = (int)*(outlineShape*)buf; + ui->ellipseShape->setChecked((outlineShape)m_draft.outlineShape == ELLIPSE); } // vertical axis if (file.tellg() > 0){ file.read(buf,8); - m_verticalAxis = *(double*)buf; - ui->minorAxisEdit->setText(QString::number(m_verticalAxis)); + m_draft.ellipseMinorAxis = *(double*)buf; + ui->minorAxisEdit->setText(QString::number(m_draft.ellipseMinorAxis)); } - FNumber = roc/(2. * diameter); + FNumber = m_draft.roc/(2. * m_draft.diameter); ui->FNumber->blockSignals(true); ui->FNumber->setText(QString("%1").arg(FNumber, 6, 'f', 2)); ui->FNumber->blockSignals(false); @@ -463,19 +446,19 @@ QString mirrorDlg::getProjectPath(){ void mirrorDlg::on_diameter_textChanged(const QString &arg1) { double diam = arg1.toDouble() * ((mm) ? 1.: 25.4); - if (m_outlineShape == ELLIPSE){ - double e = m_verticalAxis/diameter; - m_verticalAxis = e * diam; - ui->minorAxisEdit->setText(QString().number(m_verticalAxis)); + if ((outlineShape)m_draft.outlineShape == ELLIPSE){ + double e = m_draft.ellipseMinorAxis/m_draft.diameter; + m_draft.ellipseMinorAxis = e * diam; + ui->minorAxisEdit->setText(QString().number(m_draft.ellipseMinorAxis)); } - diameter = diam; - FNumber = roc/(2. * diameter); + m_draft.diameter = diam; + FNumber = m_draft.roc/(2. * m_draft.diameter); ui->FNumber->blockSignals(true); ui->FNumber->setText(QString("%1").arg(FNumber, 6, 'f', 2)); ui->FNumber->blockSignals(false); updateZ8(); - if (m_useAnnular){ - on_annulusPercent_valueChanged(m_annularObsPercent * 100); + if (m_draft.useAnnulus){ + on_annulusPercent_valueChanged(m_draft.annulusPercent * 100); } } @@ -483,17 +466,17 @@ void mirrorDlg::on_diameter_textChanged(const QString &arg1) { //Used when the just loading wavfront is different void mirrorDlg::on_diameter_Changed(const double diam) { - if (m_outlineShape == ELLIPSE){ - double e = m_verticalAxis/diameter; - m_verticalAxis = e * diam; - ui->minorAxisEdit->setText(QString().number(m_verticalAxis)); + if ((outlineShape)m_draft.outlineShape == ELLIPSE){ + double e = m_draft.ellipseMinorAxis/m_draft.diameter; + m_draft.ellipseMinorAxis = e * diam; + ui->minorAxisEdit->setText(QString().number(m_draft.ellipseMinorAxis)); } - diameter = diam ; - FNumber = roc/(2. * diameter); + m_draft.diameter = diam ; + FNumber = m_draft.roc/(2. * m_draft.diameter); ui->FNumber->blockSignals(true); const QSignalBlocker blocker(ui->diameter); ui->FNumber->setText(QString("%1").arg(FNumber *( (mm) ? 1.: 25.4), 6, 'f', 2)); - ui->diameter->setText(QString("%1").arg(diameter * ((mm) ? 1.: 25.4), 6, 'f', 2)); + ui->diameter->setText(QString("%1").arg(m_draft.diameter * ((mm) ? 1.: 25.4), 6, 'f', 2)); ui->FNumber->blockSignals(false); ui->diameter->blockSignals(false); @@ -504,8 +487,8 @@ void mirrorDlg::on_diameter_Changed(const double diam) void mirrorDlg::on_roc_textChanged(const QString &arg1) { - roc = arg1.toDouble() * ((mm) ? 1: 25.4); - FNumber = roc /(2. * diameter); + m_draft.roc = arg1.toDouble() * ((mm) ? 1: 25.4); + FNumber = m_draft.roc /(2. * m_draft.diameter); ui->FNumber->blockSignals(true); ui->FNumber->setText(QString("%1").arg(FNumber, 6, 'f', 2)); ui->FNumber->blockSignals(false); @@ -515,33 +498,33 @@ void mirrorDlg::on_roc_textChanged(const QString &arg1) /* used when the just loading wavefront is different */ void mirrorDlg::on_roc_Changed(const double newVal) { - roc = newVal; + m_draft.roc = newVal; - FNumber = roc /(2. * diameter); + FNumber = m_draft.roc /(2. * m_draft.diameter); ui->FNumber->blockSignals(true); ui->FNumber->setText(QString("%1").arg(FNumber * ((mm) ? 1.: 25.4), 6, 'f', 2)); ui->FNumber->blockSignals(false); ui->roc->blockSignals(true); - ui->roc->setText(QString("%1").arg(roc * ((mm) ? 1.: 25.4), 6, 'f', 2)); + ui->roc->setText(QString("%1").arg(m_draft.roc * ((mm) ? 1.: 25.4), 6, 'f', 2)); ui->roc->blockSignals(false); updateZ8(); } void mirrorDlg::updateZ8(){ //Z = d^6 / (16 * R^5) - double aperature = (ui->ReducApp->isChecked()) ? diameter- aperatureReduction*2. : diameter; + double aperature = (ui->ReducApp->isChecked()) ? m_draft.diameter - m_draft.apertureReduction*2. : m_draft.diameter; z8 = (pow(aperature,4) * 1000000.) / - (384. * pow(roc, 3) * lambda); + (384. * pow(m_draft.roc, 3) * m_draft.lambda); - if (m_useAnnular){ - double f = (1 - (m_annularObsPercent * m_annularObsPercent)); + if (m_draft.useAnnulus){ + double f = (1 - (m_draft.annulusPercent * m_draft.annulusPercent)); f *= f; z8 *= f; } ui->z8->blockSignals(true); - ui->z8->setText(QString().number(z8 * cc)); + ui->z8->setText(QString().number(z8 * m_draft.cc)); ui->z8->blockSignals(false); } @@ -550,18 +533,18 @@ void mirrorDlg::on_FNumber_textChanged(const QString &arg1) { FNumber = arg1.toDouble(); - roc = FNumber *(2 * diameter); + m_draft.roc = FNumber *(2 * m_draft.diameter); ui->roc->blockSignals(true); - ui->roc->setText(QString().number(roc * ((mm) ? 1.: 1./25.4))); + ui->roc->setText(QString().number(m_draft.roc * ((mm) ? 1.: 1./25.4))); ui->roc->blockSignals(false); updateZ8(); } void mirrorDlg::on_obs_textChanged(const QString &arg1) { - if (arg1.toDouble() != obs) + if (arg1.toDouble() != m_draft.obstruction) m_obsChanged = true; - obs = ((mm) ? 1: 25.4) * arg1.toDouble(); + m_draft.obstruction = ((mm) ? 1: 25.4) * arg1.toDouble(); } void mirrorDlg::newLambda(const QString &v){ @@ -570,16 +553,16 @@ void mirrorDlg::newLambda(const QString &v){ void mirrorDlg::on_lambda_textChanged(const QString &arg1) { - lambda = arg1.toDouble(); + m_draft.lambda = arg1.toDouble(); updateZ8(); } void mirrorDlg::on_nullCB_clicked(bool checked) { - doNull = checked; + m_draft.doNull = checked; ui->FNumber->blockSignals(true); ui->roc->blockSignals(true); - if (!doNull){ + if (!m_draft.doNull){ ui->FNumber->hide(); ui->fnumberLab->hide(); @@ -603,24 +586,22 @@ void mirrorDlg::on_unitsCB_clicked(bool checked) ui->roc->blockSignals(true); ui->diameter->blockSignals(true); - ui->diameter->setText(QString("%1").arg(diameter/div, 6, 'f', 2)); - ui->roc->setText(QString().number(roc/div)); - ui->obs->setText(QString().number(obs/div)); + ui->diameter->setText(QString("%1").arg(m_draft.diameter/div, 6, 'f', 2)); + ui->roc->setText(QString().number(m_draft.roc/div)); + ui->obs->setText(QString().number(m_draft.obstruction/div)); ui->diameter->blockSignals(false); ui->roc->blockSignals(false); ui->minorAxisEdit->blockSignals(true); - ui->minorAxisEdit->setText(QString("%1").arg(m_verticalAxis/div, 6, 'f', 2)); + ui->minorAxisEdit->setText(QString("%1").arg(m_draft.ellipseMinorAxis/div, 6, 'f', 2)); ui->reduceValue->blockSignals(true); ui->annularDiameter->blockSignals(true); - ui->annularDiameter->setValue(diameter * m_annularObsPercent * ((mm)? 1.: 1./25.4)); + ui->annularDiameter->setValue(m_draft.diameter * m_draft.annulusPercent * ((mm)? 1.: 1./25.4)); ui->annularDiameter->blockSignals(false); - // Get aperatureReduction from draft (already loaded from persistent storage) - aperatureReduction = m_draft.apertureReduction; - - ui->reduceValue->setValue(aperatureReduction * ((mm) ? 1. : 1./25.4)); + // Get apertureReduction from draft (already loaded from persistent storage) + ui->reduceValue->setValue(m_draft.apertureReduction * ((mm) ? 1. : 1./25.4)); ui->reduceValue->blockSignals(false); - ui->ClearAp->setText(QString("%1 ").arg(m_clearAperature * ((mm) ? 1: 1./25.4), 6, 'f', 2)); + ui->ClearAp->setText(QString("%1 ").arg(m_draft.apertureReduction * ((mm) ? 1: 1./25.4), 6, 'f', 2)); } void mirrorDlg::on_buttonBox_accepted() @@ -629,32 +610,17 @@ void mirrorDlg::on_buttonBox_accepted() updateZ8(); SurfaceManager * sm = SurfaceManager::get_instance(); - if (sm->m_inverseMode == invCONIC && cc==0) { + if (sm->m_inverseMode == invCONIC && m_draft.cc == 0) { sm->m_inverseMode = invNOTSET; // don't allow inverse mode to be conic if conic constant is zero updateAutoInvertStatus(); } - // Update draft with current UI values - m_draft.mirrorName = ui->name->text(); - m_draft.diameter = diameter; - m_draft.roc = roc; - m_draft.obstruction = obs; - m_draft.cc = cc; - m_draft.lambda = lambda; - m_draft.fringeSpacing = ui->fringeSpacingEdit->text().toDouble(); - m_draft.flipH = ui->flipH->isChecked(); - m_draft.doNull = doNull; - m_draft.useAnnulus = m_useAnnular; - m_draft.annulusPercent = m_annularObsPercent; - m_draft.annulusToObstruction = m_connectAnnulusToObs; - m_draft.outlineShape = (int)m_outlineShape; - m_draft.ellipseMinorAxis = m_verticalAxis; - m_draft.apertureReductionEnabled = m_aperatureReductionEnabled; - m_draft.apertureReduction = aperatureReduction; + // Commit draft edits to persistent copy + m_current = m_draft; - // Persist draft to QSettings via facade (single atomic save) + // Persist persistent copy to QSettings via facade (single atomic save) // Note: Only mirrordlg can call this (via friend declaration) - enforces single source of truth - SettingsFacade::instance().saveMirrorSettings(m_draft); + SettingsFacade::instance().saveMirrorSettings(m_current); if (m_obsChanged) emit obstructionChanged(); @@ -670,18 +636,18 @@ void mirrorDlg::on_buttonBox_accepted() void mirrorDlg::on_cc_textChanged(const QString &arg1) { - cc = arg1.toDouble(); + m_draft.cc = arg1.toDouble(); updateZ8(); } void mirrorDlg::spacingChangeTimeout(){ spacingChangeTimer.stop(); double v = ui->fringeSpacingEdit->text().toDouble(); - if ( v != fringeSpacing){ + if ( v != m_draft.fringeSpacing){ QMessageBox::information(0,"Fringe Spacing Changed", "This change will only be used when Interferograms are analyzed. " "It will not be applied to any existing wavefronts already loaded."); } - fringeSpacing = v; + m_draft.fringeSpacing = v; } @@ -692,7 +658,7 @@ void mirrorDlg::on_fringeSpacingEdit_textChanged(const QString & /*text*/) void mirrorDlg::on_name_editingFinished() { - m_name = ui->name->text(); + m_draft.mirrorName = ui->name->text(); } @@ -700,34 +666,32 @@ void mirrorDlg::on_name_editingFinished() void mirrorDlg::on_minorAxisEdit_textChanged(const QString &arg1) { - m_verticalAxis = arg1.toDouble(); + m_draft.ellipseMinorAxis = arg1.toDouble(); } void mirrorDlg::setMinorAxis(double val){ - m_verticalAxis = val; + m_draft.ellipseMinorAxis = val; ui->minorAxisEdit->setText(QString::number(val)); //on_minorAxisEdit_textChanged( QString::number(val)); } void mirrorDlg::setVerticalAxis(double val){ - m_verticalAxis = val; m_draft.ellipseMinorAxis = val; } void mirrorDlg::setOutlineShape(outlineShape shape){ - m_outlineShape = shape; m_draft.outlineShape = (int)shape; ui->ellipseShape->setChecked(shape == ELLIPSE); } void mirrorDlg::on_ellipseShape_clicked(bool checked) { - if (checked) m_outlineShape = ELLIPSE; - else m_outlineShape = CIRCLE; + if (checked) m_draft.outlineShape = (int)ELLIPSE; + else m_draft.outlineShape = (int)CIRCLE; - if (m_verticalAxis == 0){ - m_verticalAxis = diameter; - ui->minorAxisEdit->setText(QString().number(m_verticalAxis)); + if (m_draft.ellipseMinorAxis == 0){ + m_draft.ellipseMinorAxis = m_draft.diameter; + ui->minorAxisEdit->setText(QString().number(m_draft.ellipseMinorAxis)); } } @@ -740,21 +704,21 @@ void mirrorDlg::on_buttonBox_helpRequested() void mirrorDlg::setclearAp(){ - m_clearAperature = (diameter - aperatureReduction * 2) ; - if (m_aperatureReductionEnabled == false) - m_clearAperature = diameter; - ui->ClearAp->setText(QString("%1 ").arg(m_clearAperature * ((mm) ? 1: 1./25.4), 6, 'f', 2)); + double clearAperature = (m_draft.diameter - m_draft.apertureReduction * 2) ; + if (m_draft.apertureReductionEnabled == false) + clearAperature = m_draft.diameter; + ui->ClearAp->setText(QString("%1 ").arg(clearAperature * ((mm) ? 1: 1./25.4), 6, 'f', 2)); } void mirrorDlg::on_ReducApp_clicked(bool checked) { - m_aperatureReductionEnabled = checked; + m_draft.apertureReductionEnabled = checked; ui->reduceValue->setEnabled(checked); ui->ClearAp->setVisible(checked); ui->clearApLabel->setVisible(checked); updateZ8(); - ui->reduceValue->setValue(aperatureReduction); + ui->reduceValue->setValue(m_draft.apertureReduction); m_aperatureReductionValueChanged = true; setclearAp(); emit aperatureChanged(); @@ -763,7 +727,7 @@ void mirrorDlg::on_ReducApp_clicked(bool checked) void mirrorDlg::on_reduceValue_valueChanged(double arg1) { - aperatureReduction = ((mm) ? 1: 25.4) * arg1; + m_draft.apertureReduction = ((mm) ? 1: 25.4) * arg1; updateZ8(); setclearAp(); @@ -774,12 +738,12 @@ void mirrorDlg::on_reduceValue_valueChanged(double arg1) void mirrorDlg::on_annulusPercent_valueChanged(double arg1) { ui->annularDiameter->blockSignals(true); - m_annularObsPercent = .01 * arg1; - ui->annularDiameter->setValue( m_annularObsPercent * diameter * ( (mm) ? 1.: 1./25.4)); + m_draft.annulusPercent = .01 * arg1; + ui->annularDiameter->setValue( m_draft.annulusPercent * m_draft.diameter * ( (mm) ? 1.: 1./25.4)); ui->annularDiameter->blockSignals(false); - if (m_connectAnnulusToObs){ - ui->obs->setText(QString::number(m_annularObsPercent * diameter * ((mm)? 1.: 1./25.4))); + if (m_draft.annulusToObstruction){ + ui->obs->setText(QString::number(m_draft.annulusPercent * m_draft.diameter * ((mm)? 1.: 1./25.4))); } updateZ8(); } @@ -805,7 +769,7 @@ void mirrorDlg::enableAnnular(bool enable){ void mirrorDlg::on_useAnnulus_clicked(bool checked) { - m_useAnnular = checked; + m_draft.useAnnulus = checked; enableAnnular(checked); updateZ8(); @@ -823,8 +787,8 @@ void mirrorDlg::on_annulusHelp_clicked() void mirrorDlg::on_annularDiameter_valueChanged(double arg1) { - m_annularObsPercent = arg1/diameter; - ui->annulusPercent->setValue(m_annularObsPercent * 100); + m_draft.annulusPercent = arg1/m_draft.diameter; + ui->annulusPercent->setValue(m_draft.annulusPercent * 100); updateZ8(); } @@ -859,7 +823,7 @@ void mirrorDlg::on_btnChangeAutoInvert_clicked() { autoInvertDlg dlg; dlg.setMainLabel("How should DFTFringe choose to auto invert?"); - dlg.enableConic(cc != 0); + dlg.enableConic(m_draft.cc != 0); dlg.exec(); updateAutoInvertStatus(); } diff --git a/mirrordlg.h b/mirrordlg.h index 4fc1efa3..ca0ad9c3 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -32,6 +32,8 @@ class mirrorDlg : public QDialog Q_OBJECT public: + //TODO if we get rid of the singleton design, settings are read from settingsFacade instead here + // check if it makes sense static mirrorDlg *get_Instance(); ~mirrorDlg(); mirrorDlg(const mirrorDlg&) = delete; @@ -65,31 +67,17 @@ class mirrorDlg : public QDialog void setOutlineShape(outlineShape shape); void setObsPercent(double obs); - /** @brief Access current mirror settings (read-only snapshot). - * Returns the draft which is the canonical storage for all mirror config. - * All internal member variables are kept in sync with this. */ - const MirrorSettings& currentSettings() const { return m_draft; } + /** @brief Access current mirror settings. + * Returns the persistent copy - the last saved state. + * External code reads this as source of truth. */ + const MirrorSettings& currentSettings() const { return m_current; } private: - // Configuration members (access via currentSettings() or setters) - QString m_name; - double diameter; - double roc; - double obs; // obstruction - double cc; - bool doNull; - double lambda; - double fringeSpacing; - bool flipv; - bool fliph; - bool m_useAnnular; - bool m_connectAnnulusToObs; - double m_annularObsPercent; // a value from 0 to 1 (not 0 to 100) - double m_clearAperature; - double aperatureReduction; - bool m_aperatureReductionEnabled; - double m_verticalAxis; - outlineShape m_outlineShape; + // Persistent mirror configuration copy (source of truth for external code) + MirrorSettings m_current; + + // Working copy for dialog edits (discarded on Cancel, committed to m_current on OK) + MirrorSettings m_draft; private slots: void on_ReadBtn_clicked(); @@ -141,6 +129,8 @@ private slots: void on_btnChangeAutoInvert_clicked(); signals: + // TODO some of these are not used. + // also notify shoud probably only happen when OK is clicked, not on every change. void diameterChanged(double); void rocChanged(double); void lambdaChanged(double); @@ -152,8 +142,7 @@ private slots: void aperatureChanged(); protected: - /** @brief Reload draft settings before dialog becomes visible. - * Ensures Cancel always reverts to the last-saved state (issue #121). */ + /** @brief Reload settings before dialog becomes visible. */ void showEvent(QShowEvent *event) override; private: @@ -170,10 +159,6 @@ private slots: void saveJson(const QString &fileName); void enableAnnular(bool enable); - /** @brief Working copy of mirror settings during dialog edit. - * All UI modifications update this draft. On OK, it persists via facade. - * On Cancel, it's discarded, leaving member variables unchanged. */ - MirrorSettings m_draft; }; #endif // MIRRORDLG_H From 7813be5579c9c0da0443cca3d817910e143b6c42 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sat, 8 Aug 2026 16:10:40 +0200 Subject: [PATCH 10/20] fix some compile errors and make more things private --- defocusdlg.cpp | 2 +- mainwindow.cpp | 4 +-- metricsdisplay.cpp | 2 +- mirrordlg.cpp | 3 -- mirrordlg.h | 62 +++++++++++++++++++++++----------------- percentcorrectiondlg.cpp | 4 +-- profileplot.cpp | 4 +-- statsview.cpp | 2 +- surfacemanager.cpp | 8 +++--- wftstats.cpp | 2 +- zernikedlg.cpp | 2 +- zernikeprocess.cpp | 4 +-- 12 files changed, 52 insertions(+), 47 deletions(-) diff --git a/defocusdlg.cpp b/defocusdlg.cpp index 0bbd223c..11c35d03 100644 --- a/defocusdlg.cpp +++ b/defocusdlg.cpp @@ -86,7 +86,7 @@ void defocusDlg::on_defocusSlider_valueChanged(int value) ui->defocusVal->setValue(val); ui->defocusVal->blockSignals(false); - double f = mirrorDlg::get_Instance()->FNumber; + double f = mirrorDlg::get_Instance()->getFNumber(); double mm = f * f * 8. * value * .00055; //mmeters m_defocusInmm = mm; qDebug() << "defocus offset" << mm; diff --git a/mainwindow.cpp b/mainwindow.cpp index 372c83d0..3b69a282 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -593,10 +593,10 @@ void MainWindow::updateMetrics(wavefront& wf){ double z8 = zernTablemodel->values[8]; double BestSC; if (m_mirrorDlg->currentSettings().doNull && wf.useSANull){ - BestSC = z8/m_mirrorDlg->z8; + BestSC = z8/m_mirrorDlg->getZ8(); } else { - BestSC = m_mirrorDlg->currentSettings().cc +z8/m_mirrorDlg->z8; + BestSC = m_mirrorDlg->currentSettings().cc +z8/m_mirrorDlg->getZ8(); } metrics->setOutputLambda(outputLambda); diff --git a/metricsdisplay.cpp b/metricsdisplay.cpp index 178d8fb7..0f70bd73 100644 --- a/metricsdisplay.cpp +++ b/metricsdisplay.cpp @@ -58,7 +58,7 @@ void metricsDisplay::setWavePerFringe(double val, double lambda){ ui->wavesPerFringe->setText(QString("Waves Per Fringe: %1").arg(val, 2, 'f', 1)); ui->lambda->setText(QString("Igram laser wavelength: %1 nm").arg(lambda, 6, 'f', 2)); mirrorDlg *md = mirrorDlg::get_Instance(); - QString donull = (md->currentSettings().doNull) ? (QString("SANull: %1").arg(md->z8 * md->currentSettings().cc, 6, 'f', 4)) : ""; + QString donull = (md->currentSettings().doNull) ? (QString("SANull: %1").arg(md->getZ8() * md->currentSettings().cc, 6, 'f', 4)) : ""; ui->desiredConicLb->setText(QString("Desired Conic: %1 ").arg( md->currentSettings().cc, 6, 'f', 2) + donull); if (md->isEllipse()){ ui->desiredConicLb->setText(""); diff --git a/mirrordlg.cpp b/mirrordlg.cpp index a613906d..ad36e877 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -792,9 +792,6 @@ void mirrorDlg::on_annularDiameter_valueChanged(double arg1) updateZ8(); } -void mirrorDlg::setObsPercent(double obs){ - ui->annulusPercent->setValue(obs); -} void mirrorDlg::updateAutoInvertStatus() { diff --git a/mirrordlg.h b/mirrordlg.h index ca0ad9c3..ee8720e1 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -32,40 +32,32 @@ class mirrorDlg : public QDialog Q_OBJECT public: - //TODO if we get rid of the singleton design, settings are read from settingsFacade instead here + // TODO if we get rid of the singleton design, settings could be read from settingsFacade instead here // check if it makes sense static mirrorDlg *get_Instance(); ~mirrorDlg(); mirrorDlg(const mirrorDlg&) = delete; mirrorDlg& operator=(const mirrorDlg&) = delete; - // File and configuration operations - void loadFile(QString & fileName); - void updateZ8(); + // TODO this group must be investigatedto validate they are OK + // we cannot change settings/configuration from both outside and inside the dialog. We need to have a single source of truth for settings/configuration. void updateAutoInvertStatus(); - - // Computed/derived values (read-only, not from settings) - bool mm; - double FNumber; - double z8; - static QString m_projectPath; - - // State flags - bool m_obsChanged; - bool m_majorHorizontal; - - // Methods for configuration access/modification + void newLambda(const QString &v); + void setMinorAxis(double val); + void setVerticalAxis(double val); + void setOutlineShape(outlineShape shape); void on_roc_Changed(const double newVal); void on_diameter_Changed(const double diam); - bool shouldFlipH(); + + + // Computed/derived value accessors (read-only) + double getFNumber() const { return FNumber; } + double getZ8() const { return z8; } static QString getProjectPath(); - void newLambda(const QString &v); double getMinorAxis(); bool isEllipse(); - void setMinorAxis(double val); - void setVerticalAxis(double val); - void setOutlineShape(outlineShape shape); - void setObsPercent(double obs); + bool shouldFlipH(); + /** @brief Access current mirror settings. * Returns the persistent copy - the last saved state. @@ -73,11 +65,7 @@ class mirrorDlg : public QDialog const MirrorSettings& currentSettings() const { return m_current; } private: - // Persistent mirror configuration copy (source of truth for external code) - MirrorSettings m_current; - - // Working copy for dialog edits (discarded on Cancel, committed to m_current on OK) - MirrorSettings m_draft; + private slots: void on_ReadBtn_clicked(); @@ -154,10 +142,30 @@ private slots: void loadDraftFromSettings(); Ui::mirrorDlg *ui; + + // State flags bool m_aperatureReductionValueChanged; + bool m_obsChanged; + QTimer spacingChangeTimer; + + // Persistent mirror configuration copy (source of truth for external code) + MirrorSettings m_current; + + // Working copy for dialog edits (discarded on Cancel, committed to m_current on OK) + MirrorSettings m_draft; + + // Computed/derived values (read-only, not from settings) + //TODO actually mm is not saved in settings. should probably be saved as it's a user preference. I need to check what happens when user enters values in mm or inch and reopens DFTFringe + bool mm; // Unit display flag: true = mm, false = other units + double FNumber; // Computed f-number (focal length / diameter) + double z8; // Z8 Zernike coefficient or null reference value + static QString m_projectPath; // Current project directory path + void saveJson(const QString &fileName); void enableAnnular(bool enable); + void updateZ8(); + void loadFile(QString & fileName); }; diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index fa205094..31da9def 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -355,7 +355,7 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ ActualZoneKnife << 0.0; mirrorDlg *md = mirrorDlg::get_Instance(); - double nullval = md->z8 * md->currentSettings().cc; // null value was computed at the igram wavevlength + double nullval = md->getZ8() * md->currentSettings().cc; // null value was computed at the igram wavevlength nullval *= m_lambda_nm/m_outputLambda; // only data from the profile needs the null but it's data is at the output wavelength; // process each zone center @@ -401,7 +401,7 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ void percentCorrectionDlg::plotProfile(){ mirrorDlg *md = mirrorDlg::get_Instance(); - double nullval = md->z8 * md->currentSettings().cc; + double nullval = md->getZ8() * md->currentSettings().cc; for (int i = 0; i < surfs.length(); ++ i) { QwtPlotCurve *Curve = new QwtPlotCurve(); diff --git a/profileplot.cpp b/profileplot.cpp index 853ffe5c..d5ea053d 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -406,7 +406,7 @@ QPolygonF ProfilePlot::createAverageProfile(double /*umnits*/, wavefront * /*wf* // double rho = avg[i].x() / md.diameter/2.; // double rho2 = rho * rho; // double y = avg[i].y(); -// y += md.z8 * md.cc * (1. + rho2 * (-6 + 6. * rho2)); +// y += md.getZ8() * md.cc * (1. + rho2 * (-6 + 6. * rho2)); // avg2 << QPointF(avg[i].x(),y); // } // avg = avg2; @@ -1174,7 +1174,7 @@ void ProfilePlot::CreateWaveFrontFromAverage(){ for (unsigned int i = 0; i < avgRadius.size(); ++i) { double R2 = (double(i))/(avgRadius.size() -1); R2 *= R2; - avgRadius[i] += md->z8 * md->currentSettings().cc * (1. + R2 * (-6 + 6. * R2));; + avgRadius[i] += md->getZ8() * md->currentSettings().cc * (1. + R2 * (-6 + 6. * R2));; } } cv::Mat result = createInterpolatedCircularSurface(avgRadius); diff --git a/statsview.cpp b/statsview.cpp index c7008c94..830d036d 100644 --- a/statsview.cpp +++ b/statsview.cpp @@ -270,7 +270,7 @@ void statsView::on_SaveCSV_clicked() // apply software Null if needed if (ndx == 8 and md->currentSettings().doNull) - v -= md->z8 * md->currentSettings().cc; + v -= md->getZ8() * md->currentSettings().cc; double Sigma = computeRMS(ndx,v) * md->currentSettings().lambda/outputLambda; if (ndx == 8) { diff --git a/surfacemanager.cpp b/surfacemanager.cpp index bb4f06fc..058e8958 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -501,7 +501,7 @@ cv::Mat SurfaceManager::computeWaveFrontFromZernikes(int wx, int wy, std::vector else { if (en[z]){ if (z == 8 && md->currentSettings().doNull) - S1 += md->z8 * zpolar.zernike(z); + S1 += md->getZ8() * zpolar.zernike(z); S1 += zerns[z] * zpolar.zernike(z); } @@ -800,7 +800,7 @@ void SurfaceManager::useDemoWaveFront(){ if (rho <= 1.) { - double S1 = md->z8 * -.9 * zpolar.zernike(8) + .02* zpolar.zernike(9); + double S1 = md->getZ8() * -.9 * zpolar.zernike(8) + .02* zpolar.zernike(9); result.at(j,i) = S1; } @@ -3022,7 +3022,7 @@ void SurfaceManager::report(){ QString(" waves at %1 nm
Strehl: ").arg(outputLambda, 6, 'f', 1) + metrics->mStrehl->text() + "" + BFC + "
" + ((md->isEllipse()) ? "":"Desired Conic: " + QString::number(md->currentSettings().cc)) + "" + - ((md->currentSettings().doNull) ? QString("SANull: %1").arg(md->z8 * md->currentSettings().cc, 6, 'f', 4) : "No software Null") + "Waves per fringe: " + QString::number(md->currentSettings().fringeSpacing) + "
Interferogram Wave length: "+ QString::number(md->currentSettings().lambda) + "nm

"; @@ -3045,7 +3045,7 @@ void SurfaceManager::report(){ enabled = true; } if ( i == 8 && md->currentSettings().doNull){ - val -= md->z8 * md->currentSettings().cc; + val -= md->getZ8() * md->currentSettings().cc; } diff --git a/wftstats.cpp b/wftstats.cpp index 4b37fefd..f1106625 100644 --- a/wftstats.cpp +++ b/wftstats.cpp @@ -215,7 +215,7 @@ void wftStats::computeWftStats( QVector wavefronts, int ndx){ // apply software Null if needed if (ndx == 8 and md->currentSettings().doNull) - v -= md->z8 * md->currentSettings().cc; + v -= md->getZ8() * md->currentSettings().cc; double Sigma = computeRMS(ndx,v) * outputLambda/md->currentSettings().lambda; if (ndx == 8) { diff --git a/zernikedlg.cpp b/zernikedlg.cpp index 78acb1d1..4533089d 100644 --- a/zernikedlg.cpp +++ b/zernikedlg.cpp @@ -120,7 +120,7 @@ QVariant ZernTableModel::data(const QModelIndex &index, int role) const mirrorDlg &md = *mirrorDlg::get_Instance(); if (index.row() == 8 && md.currentSettings().doNull && !m_nulled){ - double val = values[8] - md.z8 * md.currentSettings().cc; + double val = values[8] - md.getZ8() * md.currentSettings().cc; return QString("%1 %2").arg(val, 6, 'f', 3).arg( computeRMS(8, val), 6, 'f', 3); } diff --git a/zernikeprocess.cpp b/zernikeprocess.cpp index d2394420..49a7535a 100644 --- a/zernikeprocess.cpp +++ b/zernikeprocess.cpp @@ -493,7 +493,7 @@ cv::Mat zernikeProcess::null_unwrapped(wavefront&wf, std::vector zerns, mirrorDlg *md = mirrorDlg::get_Instance(); - double scz8 = md->z8 * md->currentSettings().cc; + double scz8 = md->getZ8() * md->currentSettings().cc; if (!applyNull || !md->currentSettings().doNull || !wf.useSANull){ @@ -914,7 +914,7 @@ cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ for (unsigned int z = 0; z < m_zerns.n_cols; ++z){ double val = dlg.zernikes[z]; if (z == 8){ - val = (dlg.doCorrection && md->currentSettings().doNull) ? md->currentSettings().cc * md->z8 * val * .01 : val; + val = (dlg.doCorrection && md->currentSettings().doNull) ? md->currentSettings().cc * md->getZ8() * val * .01 : val; } S1 += val * m_zerns(i,z)/((doColor) ? md->currentSettings().fringeSpacing: 1.); From 31ca070a1860f3e40ff6e65ef7e1fe0cf801dde5 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 9 Aug 2026 08:22:07 +0200 Subject: [PATCH 11/20] delete unused signals --- mirrordlg.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mirrordlg.h b/mirrordlg.h index ee8720e1..53b30605 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -117,13 +117,7 @@ private slots: void on_btnChangeAutoInvert_clicked(); signals: - // TODO some of these are not used. - // also notify shoud probably only happen when OK is clicked, not on every change. - void diameterChanged(double); - void rocChanged(double); - void lambdaChanged(double); - void saNullChanged(double); - void CCChanged(double); + // TODO notify shoud probably only happen when OK is clicked, not on every change. void obstructionChanged(); void newPath(QString); void recomputeZerns(); From 59c65af8cec1a379f739833a9b61259098bff216 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 9 Aug 2026 08:26:29 +0200 Subject: [PATCH 12/20] fix compile warning --- mirrordlg.cpp | 4 +++- mirrordlg.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mirrordlg.cpp b/mirrordlg.cpp index ad36e877..8b3f2c54 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -41,7 +41,9 @@ mirrorDlg *mirrorDlg::get_Instance(){ mirrorDlg::mirrorDlg(QWidget *parent) : QDialog(parent), - mm(true),m_obsChanged(false),ui(new Ui::mirrorDlg) + ui(new Ui::mirrorDlg), + m_obsChanged(false), + mm(true) { ui->setupUi(this); diff --git a/mirrordlg.h b/mirrordlg.h index 53b30605..5afcad1b 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -39,7 +39,7 @@ class mirrorDlg : public QDialog mirrorDlg(const mirrorDlg&) = delete; mirrorDlg& operator=(const mirrorDlg&) = delete; - // TODO this group must be investigatedto validate they are OK + // TODO this group must be investigated to validate they are OK // we cannot change settings/configuration from both outside and inside the dialog. We need to have a single source of truth for settings/configuration. void updateAutoInvertStatus(); void newLambda(const QString &v); From 805252fd877b9d6ddf46510ad8af0fef793d0731 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 9 Aug 2026 08:33:15 +0200 Subject: [PATCH 13/20] remove duplicate operation --- mainwindow.cpp | 7 +------ mainwindow.h | 1 - mirrordlg.cpp | 4 +--- mirrordlg.h | 1 - 4 files changed, 2 insertions(+), 11 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 3b69a282..1edb341f 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -274,7 +274,6 @@ MainWindow::MainWindow(QWidget *parent) : } connect(m_surfaceManager, &SurfaceManager::rocChanged,this, &MainWindow::rocChanged); - connect(m_mirrorDlg, &mirrorDlg::newPath,this, &MainWindow::newMirrorDlgPath); progBar = new QProgressBar(this); status1 = new QLabel(); @@ -845,11 +844,7 @@ void MainWindow::on_showIntensity_clicked(bool checked) else m_intensityPlot->close(); } -void MainWindow::newMirrorDlgPath(const QString &path){ - QFileInfo info(path); - QSettings settings; - settings.setValue("lastPath",info.path()); -} + //make a simulated wavefront based on zernike values #define TSIZE 200 void MainWindow::on_actionWavefront_triggered() diff --git a/mainwindow.h b/mainwindow.h index 1f03c955..c9b5f684 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -120,7 +120,6 @@ private slots: void on_shiftDown_clicked(); void on_shiftRight_clicked(); void selectDftTab(); - void newMirrorDlgPath(const QString &path); void on_actionRead_WaveFront_triggered(); void on_actionPreferences_triggered(); diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 8b3f2c54..c2c5bd49 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -204,9 +204,7 @@ void mirrorDlg::loadFile(QString & fileName){ // Persist UI convenience path to QSettings QSettings settings; settings.setValue("lastPath", info.absolutePath()); - - emit newPath(info.absolutePath()); - + // Update application settings with new file path and mirror config file via facade ApplicationSettings appSettings = SettingsFacade::instance().appStore().load(); appSettings.projectPath = info.absolutePath(); diff --git a/mirrordlg.h b/mirrordlg.h index 5afcad1b..742b34f5 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -119,7 +119,6 @@ private slots: signals: // TODO notify shoud probably only happen when OK is clicked, not on every change. void obstructionChanged(); - void newPath(QString); void recomputeZerns(); void aperatureChanged(); From 42a20fcc4498e1031e718d79802700623360273d Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 9 Aug 2026 13:23:49 +0200 Subject: [PATCH 14/20] simplify mirrordlg settings adoption from wft --- mainwindow.cpp | 11 ------- mainwindow.h | 2 -- mirrordlg.cpp | 74 ++++++++++++++++++++++------------------------ mirrordlg.h | 26 ++++++++++------ surfacemanager.cpp | 13 ++++++-- surfacemanager.h | 2 -- 6 files changed, 62 insertions(+), 66 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 1edb341f..50339b1d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -194,7 +194,6 @@ MainWindow::MainWindow(QWidget *parent) : m_ogl->m_surface, metrics); connect(m_contourView, &contourView::showAllContours, m_surfaceManager, &SurfaceManager::showAllContours); connect(m_dftArea, &DFTArea::newWavefront, m_surfaceManager, &SurfaceManager::createSurfaceFromPhaseMap); - connect(m_surfaceManager, &SurfaceManager::diameterChanged,this,&MainWindow::diameterChanged); connect(m_surfaceManager, &SurfaceManager::showTab, ui->tabWidget, &QTabWidget::setCurrentIndex); connect(m_surfTools, &surfaceAnalysisTools::updateSelected, m_surfaceManager, &SurfaceManager::backGroundUpdate); ui->tabWidget->addTab(review, "Results"); @@ -273,7 +272,6 @@ MainWindow::MainWindow(QWidget *parent) : zernEnables[i] = false; } - connect(m_surfaceManager, &SurfaceManager::rocChanged,this, &MainWindow::rocChanged); progBar = new QProgressBar(this); status1 = new QLabel(); @@ -778,15 +776,6 @@ void MainWindow::showMessage(const QString &msg, int id){ } -void MainWindow::diameterChanged(double v){ - m_mirrorDlg->on_diameter_Changed(v); -} -void MainWindow::rocChanged(double v){ - m_mirrorDlg->on_roc_Changed(v); -} - - - void MainWindow::on_SelectOutSideOutline_clicked(bool checked) { m_igramArea->SideOutLineActive( checked); diff --git a/mainwindow.h b/mainwindow.h index c9b5f684..80e95758 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -84,8 +84,6 @@ class MainWindow : public QMainWindow public slots: void enableShiftButtons(bool enable); void showMessage(const QString&, int id); - void diameterChanged(double); - void rocChanged(double); void batchProcess(QStringList fileList); void batchMakeSurfaceReady(); void batchConnections(bool flag); diff --git a/mirrordlg.cpp b/mirrordlg.cpp index c2c5bd49..ae71c5bc 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -428,6 +428,41 @@ void mirrorDlg::loadFile(QString & fileName){ } } } + +void mirrorDlg::adoptWavefrontSettings(double diameter, double roc, double lambda) +{ + if ((outlineShape)m_draft.outlineShape == ELLIPSE && m_draft.diameter != 0.0) { + const double e = m_draft.ellipseMinorAxis / m_draft.diameter; + m_draft.ellipseMinorAxis = e * diameter; + } + + m_draft.diameter = diameter; + m_draft.roc = roc; + m_draft.lambda = lambda; + + FNumber = m_draft.roc / (2. * m_draft.diameter); + + { + const QSignalBlocker blockDiameter(ui->diameter); + const QSignalBlocker blockRoc(ui->roc); + const QSignalBlocker blockLambda(ui->lambda); + const QSignalBlocker blockMinor(ui->minorAxisEdit); + const QSignalBlocker blockFNumber(ui->FNumber); + + ui->diameter->setText(QString("%1").arg(m_draft.diameter * ((mm) ? 1. : 1./25.4), 6, 'f', 2)); + ui->roc->setText(QString("%1").arg(m_draft.roc * ((mm) ? 1. : 1./25.4), 6, 'f', 2)); + ui->lambda->setText(QString("%1").arg(m_draft.lambda, 6, 'f', 1)); + ui->minorAxisEdit->setText(QString::number(m_draft.ellipseMinorAxis)); + ui->FNumber->setText(QString("%1").arg(FNumber, 6, 'f', 2)); + } + + setclearAp(); + updateZ8(); + + m_current = m_draft; + SettingsFacade::instance().saveMirrorSettings(m_current); +} + void mirrorDlg::on_ReadBtn_clicked() { QSettings settings; @@ -463,28 +498,6 @@ void mirrorDlg::on_diameter_textChanged(const QString &arg1) { } -//Used when the just loading wavfront is different -void mirrorDlg::on_diameter_Changed(const double diam) -{ - if ((outlineShape)m_draft.outlineShape == ELLIPSE){ - double e = m_draft.ellipseMinorAxis/m_draft.diameter; - m_draft.ellipseMinorAxis = e * diam; - ui->minorAxisEdit->setText(QString().number(m_draft.ellipseMinorAxis)); - } - m_draft.diameter = diam ; - FNumber = m_draft.roc/(2. * m_draft.diameter); - ui->FNumber->blockSignals(true); - const QSignalBlocker blocker(ui->diameter); - ui->FNumber->setText(QString("%1").arg(FNumber *( (mm) ? 1.: 25.4), 6, 'f', 2)); - ui->diameter->setText(QString("%1").arg(m_draft.diameter * ((mm) ? 1.: 25.4), 6, 'f', 2)); - ui->FNumber->blockSignals(false); - ui->diameter->blockSignals(false); - - setclearAp(); - updateZ8(); - -} - void mirrorDlg::on_roc_textChanged(const QString &arg1) { m_draft.roc = arg1.toDouble() * ((mm) ? 1: 25.4); @@ -495,20 +508,6 @@ void mirrorDlg::on_roc_textChanged(const QString &arg1) updateZ8(); } -/* used when the just loading wavefront is different */ -void mirrorDlg::on_roc_Changed(const double newVal) -{ - m_draft.roc = newVal; - - FNumber = m_draft.roc /(2. * m_draft.diameter); - ui->FNumber->blockSignals(true); - ui->FNumber->setText(QString("%1").arg(FNumber * ((mm) ? 1.: 25.4), 6, 'f', 2)); - ui->FNumber->blockSignals(false); - ui->roc->blockSignals(true); - ui->roc->setText(QString("%1").arg(m_draft.roc * ((mm) ? 1.: 25.4), 6, 'f', 2)); - ui->roc->blockSignals(false); - updateZ8(); -} void mirrorDlg::updateZ8(){ //Z = d^6 / (16 * R^5) @@ -547,9 +546,6 @@ void mirrorDlg::on_obs_textChanged(const QString &arg1) m_draft.obstruction = ((mm) ? 1: 25.4) * arg1.toDouble(); } -void mirrorDlg::newLambda(const QString &v){ - ui->lambda->setText(v); -} void mirrorDlg::on_lambda_textChanged(const QString &arg1) { diff --git a/mirrordlg.h b/mirrordlg.h index 742b34f5..8efb835d 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -39,16 +39,24 @@ class mirrorDlg : public QDialog mirrorDlg(const mirrorDlg&) = delete; mirrorDlg& operator=(const mirrorDlg&) = delete; - // TODO this group must be investigated to validate they are OK - // we cannot change settings/configuration from both outside and inside the dialog. We need to have a single source of truth for settings/configuration. - void updateAutoInvertStatus(); - void newLambda(const QString &v); - void setMinorAxis(double val); + void updateAutoInvertStatus(); //This one makes sense. Not saved + + // ---- file loading ---- + //TODO This one not OK. Edits m_draft.ellipseMinorAxis and wont get saved. + // need to investigate why external code needs to change the minor axis. If it is a user preference, it should be saved in settings. If it is a computed value, it should be computed from other values and not set directly. + void setMinorAxis(double val); + //TODO even worse, same thing but it doesn't update UI text + // on call from a file load but the other ? void setVerticalAxis(double val); + // TODO not OK. Edits m_draft.outlineShape and wont get saved + // from file load void setOutlineShape(outlineShape shape); - void on_roc_Changed(const double newVal); - void on_diameter_Changed(const double diam); + + // Apply loaded wavefront settings to both runtime and persisted mirror settings. + // Intended for a single call after wavefront load mismatch decisions are finalized. + void adoptWavefrontSettings(double diameter, double roc, double lambda); + // Computed/derived value accessors (read-only) double getFNumber() const { return FNumber; } @@ -117,10 +125,9 @@ private slots: void on_btnChangeAutoInvert_clicked(); signals: - // TODO notify shoud probably only happen when OK is clicked, not on every change. void obstructionChanged(); void recomputeZerns(); - void aperatureChanged(); + void aperatureChanged(); // TODO this one only : notify shoud probably only happen when OK is clicked, not on every change. protected: /** @brief Reload settings before dialog becomes visible. */ @@ -143,6 +150,7 @@ private slots: QTimer spacingChangeTimer; // Persistent mirror configuration copy (source of truth for external code) + //TODO check if all UI settings are actually saved in settings MirrorSettings m_current; // Working copy for dialog edits (discarded on Cancel, committed to m_current on OK) diff --git a/surfacemanager.cpp b/surfacemanager.cpp index 058e8958..804172ab 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -1327,6 +1327,8 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ } wf->m_inside = CircleOutline(QPointF(xo,yo), rado); + bool shouldAdoptWavefrontSettings = false; + if (lambda != md->currentSettings().lambda){ if (lambdResp == ASK){ @@ -1350,7 +1352,7 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ } if ( lambdResp == YES || messageResult == QMessageBox::Yes){ - md->newLambda(QString::number(lambda)); + shouldAdoptWavefrontSettings = true; } } @@ -1374,7 +1376,7 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ } } if (diamResp == YES || messageResult == QMessageBox::Yes){ - emit diameterChanged(diam); + shouldAdoptWavefrontSettings = true; } else { diam = md->currentSettings().diameter; @@ -1403,13 +1405,18 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ } } if (rocResp == YES || messageResult == QMessageBox::Yes){ - emit rocChanged(roc); + shouldAdoptWavefrontSettings = true; } else { roc = md->currentSettings().roc; } } + + if (shouldAdoptWavefrontSettings) { + md->adoptWavefrontSettings(diam, roc, lambda); + } + wf->diameter = diam; wf->roc = roc; wf->lambda = lambda; diff --git a/surfacemanager.h b/surfacemanager.h index 39587023..a726fe8a 100644 --- a/surfacemanager.h +++ b/surfacemanager.h @@ -147,8 +147,6 @@ class SurfaceManager : public QObject void deleteWavefront(int); void rotateTheseSig(int, QList); void progress(int); - void diameterChanged(double); - void rocChanged(double); void nameChanged(const QString &, const QString &); void showTab(int); void enableControls(bool); From 3381113f0f64a38827f3596f8d10a3b0800baad5 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 9 Aug 2026 14:40:58 +0200 Subject: [PATCH 15/20] comment settings things that are not yet used --- settingsfacade.cpp | 43 +++++++++++++------------ settingsfacade.h | 21 ++++++------ settingsstores.cpp | 65 ++++++++++++++++++------------------- settingsstores.h | 67 +++++++++++++++++++-------------------- settingsstores_fields.inc | 5 +-- 5 files changed, 102 insertions(+), 99 deletions(-) diff --git a/settingsfacade.cpp b/settingsfacade.cpp index 5a65fcac..52617eb6 100644 --- a/settingsfacade.cpp +++ b/settingsfacade.cpp @@ -16,24 +16,9 @@ const MirrorSettingsStore &SettingsFacade::mirrorStore() const return m_mirrorStore; } -GeneralProcessingSettingsStore &SettingsFacade::generalProcessingStore() -{ - return m_generalProcessingStore; -} - -const GeneralProcessingSettingsStore &SettingsFacade::generalProcessingStore() const -{ - return m_generalProcessingStore; -} - -ContourSettingsStore &SettingsFacade::contourStore() -{ - return m_contourStore; -} - -const ContourSettingsStore &SettingsFacade::contourStore() const +void SettingsFacade::saveMirrorSettings(const MirrorSettings &settings) { - return m_contourStore; + m_mirrorStore.save(settings); } ApplicationSettingsStore &SettingsFacade::appStore() @@ -46,7 +31,23 @@ const ApplicationSettingsStore &SettingsFacade::appStore() const return m_appStore; } -void SettingsFacade::saveMirrorSettings(const MirrorSettings &settings) -{ - m_mirrorStore.save(settings); -} +// examples for future PRs +//GeneralProcessingSettingsStore &SettingsFacade::generalProcessingStore() +//{ +// return m_generalProcessingStore; +//} +// +//const GeneralProcessingSettingsStore &SettingsFacade::generalProcessingStore() const +//{ +// return m_generalProcessingStore; +//} +// +//ContourSettingsStore &SettingsFacade::contourStore() +//{ +// return m_contourStore; +//} +// +//const ContourSettingsStore &SettingsFacade::contourStore() const +//{ +// return m_contourStore; +//} diff --git a/settingsfacade.h b/settingsfacade.h index 15e9693b..83ecd7b1 100644 --- a/settingsfacade.h +++ b/settingsfacade.h @@ -25,17 +25,17 @@ class SettingsFacade MirrorSettingsStore &mirrorStore(); const MirrorSettingsStore &mirrorStore() const; - GeneralProcessingSettingsStore &generalProcessingStore(); - const GeneralProcessingSettingsStore &generalProcessingStore() const; - - ContourSettingsStore &contourStore(); - const ContourSettingsStore &contourStore() const; - - /** @brief Accessor for application-wide path settings (project path, file paths, etc.). */ ApplicationSettingsStore &appStore(); - /** @brief Const accessor for application-wide path settings. */ const ApplicationSettingsStore &appStore() const; + // examples for future PRs + //GeneralProcessingSettingsStore &generalProcessingStore(); + //const GeneralProcessingSettingsStore &generalProcessingStore() const; +// + //ContourSettingsStore &contourStore(); + //const ContourSettingsStore &contourStore() const; + + private: friend class mirrorDlg; // Allow mirrordlg to call restricted save @@ -48,9 +48,10 @@ class SettingsFacade // Only facade owns these MirrorSettingsStore m_mirrorStore; - GeneralProcessingSettingsStore m_generalProcessingStore; - ContourSettingsStore m_contourStore; ApplicationSettingsStore m_appStore; + // examples for future PRs + //GeneralProcessingSettingsStore m_generalProcessingStore; + //ContourSettingsStore m_contourStore; }; #endif // SETTINGSFACADE_H diff --git a/settingsstores.cpp b/settingsstores.cpp index 1829cd91..d2c2c6d5 100644 --- a/settingsstores.cpp +++ b/settingsstores.cpp @@ -24,38 +24,6 @@ void MirrorSettingsStore::save(const MirrorSettings &value) const SETTINGS_STORE_FOR_EACH_MIRROR_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) } -GeneralProcessingSettings GeneralProcessingSettingsStore::load() const -{ - QSettings s; - - GeneralProcessingSettings value{}; - SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS) - - return value; -} - -void GeneralProcessingSettingsStore::save(const GeneralProcessingSettings &value) const -{ - QSettings s; - SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) -} - -ContourSettings ContourSettingsStore::load() const -{ - QSettings s; - - ContourSettings value{}; - SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS) - - return value; -} - -void ContourSettingsStore::save(const ContourSettings &value) const -{ - QSettings s; - SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) -} - ApplicationSettings ApplicationSettingsStore::load() const { QSettings s; @@ -72,5 +40,38 @@ void ApplicationSettingsStore::save(const ApplicationSettings &value) const SETTINGS_STORE_FOR_EACH_APPLICATION_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) } +// examples for future PRs +//GeneralProcessingSettings GeneralProcessingSettingsStore::load() const +//{ +// QSettings s; +// +// GeneralProcessingSettings value{}; +// SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS) +// +// return value; +//} +// +//void GeneralProcessingSettingsStore::save(const GeneralProcessingSettings &value) const +//{ +// QSettings s; +// SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) +//} +// +//ContourSettings ContourSettingsStore::load() const +//{ +// QSettings s; +// +// ContourSettings value{}; +// SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS) +// +// return value; +//} +// +//void ContourSettingsStore::save(const ContourSettings &value) const +//{ +// QSettings s; +// SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS) +//} + #undef SETTINGS_STORE_LOAD_FIELD_FROM_QSETTINGS #undef SETTINGS_STORE_SAVE_FIELD_TO_QSETTINGS diff --git a/settingsstores.h b/settingsstores.h index bf719cc7..ba1a54ea 100644 --- a/settingsstores.h +++ b/settingsstores.h @@ -25,40 +25,6 @@ class MirrorSettingsStore { MirrorSettings load() const; }; - - -struct GeneralProcessingSettings { - SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) -}; - -class GeneralProcessingSettingsStore { -private: - friend class SettingsFacade; - GeneralProcessingSettingsStore() = default; - -public: - GeneralProcessingSettings load() const; - void save(const GeneralProcessingSettings &value) const; -}; - - - -struct ContourSettings { - SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) -}; - -class ContourSettingsStore { -private: - friend class SettingsFacade; - ContourSettingsStore() = default; - -public: - ContourSettings load() const; - void save(const ContourSettings &value) const; -}; - - - struct ApplicationSettings { SETTINGS_STORE_FOR_EACH_APPLICATION_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) }; @@ -73,6 +39,39 @@ class ApplicationSettingsStore { void save(const ApplicationSettings &value) const; }; +// examples for future PRs +//struct GeneralProcessingSettings { +// SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) +//}; +// +//class GeneralProcessingSettingsStore { +//private: +// friend class SettingsFacade; +// GeneralProcessingSettingsStore() = default; +// +//public: +// GeneralProcessingSettings load() const; +// void save(const GeneralProcessingSettings &value) const; +//}; +// +// +// +//struct ContourSettings { +// SETTINGS_STORE_FOR_EACH_CONTOUR_FIELD(SETTINGS_STORE_DECLARE_STRUCT_FIELD) +//}; +// +//class ContourSettingsStore { +//private: +// friend class SettingsFacade; +// ContourSettingsStore() = default; +// +//public: +// ContourSettings load() const; +// void save(const ContourSettings &value) const; +//}; + + + #undef SETTINGS_STORE_DECLARE_STRUCT_FIELD #endif // SETTINGSSTORES_H diff --git a/settingsstores_fields.inc b/settingsstores_fields.inc index 70a84ca8..19c86fe5 100644 --- a/settingsstores_fields.inc +++ b/settingsstores_fields.inc @@ -25,7 +25,8 @@ FIELD(QString, mirrorConfigFile, QString(), "mirrorConfigFile", toString) \ FIELD(QString, lastPath, QString(), "lastPath", toString) -#define SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(FIELD) \ +// examples for futur PRs +/*#define SETTINGS_STORE_FOR_EACH_GENERAL_FIELD(FIELD) \ FIELD(bool, useMakeStarTest, false, "useMakeStarTest", toBool) \ FIELD(int, wavefrontDownSizeValue, 650, "wavefrontDownSizeValue", toInt) \ FIELD(bool, wavefrontShouldDownsize, false, "wavefrontShouldDownsize", toBool) \ @@ -47,4 +48,4 @@ FIELD(int, colorMapIndex, 1, "colorMap ndx", toInt) \ FIELD(QString, contourLineColor, QStringLiteral("grey"), "ContourLineColor", toString) \ FIELD(QString, contourRulerColor, QStringLiteral("grey"), "ContourRulerColor", toString) \ - FIELD(double, contourRulerRadialDeg, 0.0, "contourRulerRadialDeg", toDouble) + FIELD(double, contourRulerRadialDeg, 0.0, "contourRulerRadialDeg", toDouble)*/ From 423fb06e67d21e75d68bbb6d46c9059113b3964c Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 9 Aug 2026 14:41:45 +0200 Subject: [PATCH 16/20] apertureChanged is emit only on accept --- mirrordlg.cpp | 5 ++--- mirrordlg.h | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/mirrordlg.cpp b/mirrordlg.cpp index ae71c5bc..6adb085d 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -619,9 +619,10 @@ void mirrorDlg::on_buttonBox_accepted() SettingsFacade::instance().saveMirrorSettings(m_current); if (m_obsChanged) - emit obstructionChanged(); + emit obstructionChanged(); emit recomputeZerns(); if (m_aperatureReductionValueChanged){ + emit aperatureChanged(); QMessageBox::warning(0, tr("Aperature Reduction value was changed."), tr("Aperature Reduction was changed.\n" "The wave front will not be correct until it is recomputed from the interferogram.")); @@ -717,7 +718,6 @@ void mirrorDlg::on_ReducApp_clicked(bool checked) ui->reduceValue->setValue(m_draft.apertureReduction); m_aperatureReductionValueChanged = true; setclearAp(); - emit aperatureChanged(); } @@ -728,7 +728,6 @@ void mirrorDlg::on_reduceValue_valueChanged(double arg1) setclearAp(); m_aperatureReductionValueChanged = true; - emit aperatureChanged(); } void mirrorDlg::on_annulusPercent_valueChanged(double arg1) diff --git a/mirrordlg.h b/mirrordlg.h index 8efb835d..059e1f11 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -125,9 +125,10 @@ private slots: void on_btnChangeAutoInvert_clicked(); signals: + // Emitted only after OK/accept when committed settings are saved. void obstructionChanged(); void recomputeZerns(); - void aperatureChanged(); // TODO this one only : notify shoud probably only happen when OK is clicked, not on every change. + void aperatureChanged(); protected: /** @brief Reload settings before dialog becomes visible. */ @@ -149,15 +150,14 @@ private slots: QTimer spacingChangeTimer; - // Persistent mirror configuration copy (source of truth for external code) - //TODO check if all UI settings are actually saved in settings + // Persistent mirror configuration copy (source of truth) MirrorSettings m_current; // Working copy for dialog edits (discarded on Cancel, committed to m_current on OK) MirrorSettings m_draft; // Computed/derived values (read-only, not from settings) - //TODO actually mm is not saved in settings. should probably be saved as it's a user preference. I need to check what happens when user enters values in mm or inch and reopens DFTFringe + //TODO actually mm is not saved in settings. should probably be saved as it's a user preference bool mm; // Unit display flag: true = mm, false = other units double FNumber; // Computed f-number (focal length / diameter) double z8; // Z8 Zernike coefficient or null reference value From 1af46664891bee4adca94a7c702528f5236a865b Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Sun, 9 Aug 2026 15:07:44 +0200 Subject: [PATCH 17/20] deduplicate function --- igramarea.cpp | 2 +- mirrordlg.cpp | 4 ---- mirrordlg.h | 3 --- surfacemanager.cpp | 2 +- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/igramarea.cpp b/igramarea.cpp index b7b7cc68..19d5ae51 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -1545,7 +1545,7 @@ void IgramArea::mouseMoveEvent(QMouseEvent *event) int majorRad = fabs((m_OutterP2.x() - m_OutterP1.x()))/2.; double e = (double)minorRad/majorRad; mirrorDlg &md = *mirrorDlg::get_Instance(); - md.setVerticalAxis(md.currentSettings().diameter * e); + md.setMinorAxis(md.currentSettings().diameter * e); drawBoundary(); return; } diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 6adb085d..4987aba5 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -672,10 +672,6 @@ void mirrorDlg::setMinorAxis(double val){ //on_minorAxisEdit_textChanged( QString::number(val)); } -void mirrorDlg::setVerticalAxis(double val){ - m_draft.ellipseMinorAxis = val; -} - void mirrorDlg::setOutlineShape(outlineShape shape){ m_draft.outlineShape = (int)shape; ui->ellipseShape->setChecked(shape == ELLIPSE); diff --git a/mirrordlg.h b/mirrordlg.h index 059e1f11..6edbe88c 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -45,9 +45,6 @@ class mirrorDlg : public QDialog //TODO This one not OK. Edits m_draft.ellipseMinorAxis and wont get saved. // need to investigate why external code needs to change the minor axis. If it is a user preference, it should be saved in settings. If it is a computed value, it should be computed from other values and not set directly. void setMinorAxis(double val); - //TODO even worse, same thing but it doesn't update UI text - // on call from a file load but the other ? - void setVerticalAxis(double val); // TODO not OK. Edits m_draft.outlineShape and wont get saved // from file load void setOutlineShape(outlineShape shape); diff --git a/surfacemanager.cpp b/surfacemanager.cpp index 804172ab..bd832323 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -1308,7 +1308,7 @@ wavefront * SurfaceManager::readWaveFront(const QString &fileName){ md->setOutlineShape(ELLIPSE); double vertAxis; iss >> dummy >> vertAxis; - md->setVerticalAxis(vertAxis); + md->setMinorAxis(vertAxis); } if (l.startsWith("Do Not use null") || l.startsWith("nulled") ){ wf->useSANull = false; From ef52e3341c99d84938b0bbbbde13d352f0912c0c Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Tue, 11 Aug 2026 14:23:17 +0200 Subject: [PATCH 18/20] some comment cleanup --- mirrordlg.h | 12 ++++++------ surfacemanager.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mirrordlg.h b/mirrordlg.h index 6edbe88c..927bbfee 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -32,8 +32,7 @@ class mirrorDlg : public QDialog Q_OBJECT public: - // TODO if we get rid of the singleton design, settings could be read from settingsFacade instead here - // check if it makes sense + // TODO we could get rid of singleton if every file accessed settings though SettingsFacade instead of mirrorDlg::get_Instance()->currentSettings() static mirrorDlg *get_Instance(); ~mirrorDlg(); mirrorDlg(const mirrorDlg&) = delete; @@ -42,11 +41,12 @@ class mirrorDlg : public QDialog void updateAutoInvertStatus(); //This one makes sense. Not saved // ---- file loading ---- - //TODO This one not OK. Edits m_draft.ellipseMinorAxis and wont get saved. - // need to investigate why external code needs to change the minor axis. If it is a user preference, it should be saved in settings. If it is a computed value, it should be computed from other values and not set directly. + //TODO This is still not 100% clean + // One call from loading file shoulb be integgrated to adoptWavefrontSettings + // other calls are outline helpers. Need to be clarified void setMinorAxis(double val); - // TODO not OK. Edits m_draft.outlineShape and wont get saved - // from file load + // TODO to be fixed with #358. + // saving shape shall be asked as it is for ROC, lambda and diameter and be saved using adoptWavefrontSettings void setOutlineShape(outlineShape shape); diff --git a/surfacemanager.cpp b/surfacemanager.cpp index 4c54baeb..490463e7 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -906,7 +906,7 @@ void SurfaceManager::syncGaussianStateForWavefront(wavefront *wf){ m_surfaceTools->setGaussianControls(wf->gbEnabled, wf->gbValue); mirrorDlg *md = mirrorDlg::get_Instance(); - m_surfaceTools->setBlurText(QString("%1 mm").arg(.01 * wf->gbValue * md->diameter, 6, 'f', 2)); + m_surfaceTools->setBlurText(QString("%1 mm").arg(.01 * wf->gbValue * md->currentSettings().diameter, 6, 'f', 2)); } void SurfaceManager::computeMetrics(wavefront *wf){ From 1cfb6773134719cd1d85aeec0975deb8f74fc5ab Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Wed, 12 Aug 2026 07:35:49 +0200 Subject: [PATCH 19/20] fix warning. Square is expected downstream. This is just leftover code --- dftarea.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dftarea.cpp b/dftarea.cpp index 831c0465..f08b2270 100644 --- a/dftarea.cpp +++ b/dftarea.cpp @@ -258,13 +258,6 @@ cv::Mat DFTArea::grayComplexMatfromImage(QImage &img){ double rad = igramArea->m_outside.m_radius - reduction; - - double rady = rad; - - if (md.isEllipse()){ - rady = rady * md.currentSettings().ellipseMinorAxis / md.currentSettings().diameter; - } - double left = centerX - rad; double top = centerY - rad; std::vector bgr_planes; From 836023817e8193118874f49af89eae9fc26528ba Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Wed, 12 Aug 2026 10:25:53 +0200 Subject: [PATCH 20/20] fix some earlier wrong replacements leading to broken profileplot --- igramarea.cpp | 2 +- mirrordlg.cpp | 10 +++++++++- mirrordlg.h | 1 + percentcorrectiondlg.cpp | 4 ++-- profileplot.cpp | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/igramarea.cpp b/igramarea.cpp index 1530426e..1257f200 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -1719,7 +1719,7 @@ void IgramArea::drawBoundary() painter.setBrush(Qt::NoBrush); } outside.draw(painter,1.,s2); - if ( md.currentSettings().apertureReductionEnabled && md.currentSettings().apertureReduction != md.currentSettings().diameter){ + if ( md.currentSettings().apertureReductionEnabled && md.getClearAperture() != md.currentSettings().diameter){ painter.setPen(QPen(edgePenColor, edgePenWidth, Qt::DotLine)); computeEdgeRadius(); painter.drawEllipse(outside.m_center, diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 4987aba5..ebb7598c 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -597,7 +597,7 @@ void mirrorDlg::on_unitsCB_clicked(bool checked) // Get apertureReduction from draft (already loaded from persistent storage) ui->reduceValue->setValue(m_draft.apertureReduction * ((mm) ? 1. : 1./25.4)); ui->reduceValue->blockSignals(false); - ui->ClearAp->setText(QString("%1 ").arg(m_draft.apertureReduction * ((mm) ? 1: 1./25.4), 6, 'f', 2)); + setclearAp(); } void mirrorDlg::on_buttonBox_accepted() @@ -703,6 +703,14 @@ void mirrorDlg::setclearAp(){ ui->ClearAp->setText(QString("%1 ").arg(clearAperature * ((mm) ? 1: 1./25.4), 6, 'f', 2)); } +double mirrorDlg::getClearAperture() const { + double clearAperature = (m_current.diameter - m_current.apertureReduction * 2) ; + if (m_current.apertureReductionEnabled == false){ + clearAperature = m_current.diameter; + } + return clearAperature; +} + void mirrorDlg::on_ReducApp_clicked(bool checked) { m_draft.apertureReductionEnabled = checked; diff --git a/mirrordlg.h b/mirrordlg.h index 927bbfee..9422360a 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -60,6 +60,7 @@ class mirrorDlg : public QDialog double getZ8() const { return z8; } static QString getProjectPath(); double getMinorAxis(); + double getClearAperture() const; bool isEllipse(); bool shouldFlipH(); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 31da9def..6d044c35 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -31,7 +31,7 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : mirrorDlg &md = *mirrorDlg::get_Instance(); - m_radius = md.currentSettings().apertureReduction/2.; + m_radius = md.getClearAperture()/2.; QSettings set; ui->minvalue->blockSignals(true); ui->maxvalue->blockSignals(true); @@ -644,7 +644,7 @@ void percentCorrectionDlg::setData( QVector< surfaceData *> data) { QSettings set; m_outputLambda = set.value("outputLambda").toDouble(); - m_radius = md.currentSettings().apertureReduction/2.; + m_radius = md.getClearAperture()/2.; surfs = data; ui->percentTable->setRowCount(data.length()); diff --git a/profileplot.cpp b/profileplot.cpp index afd3d8a5..2d3c84ff 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -427,7 +427,7 @@ QPolygonF ProfilePlot::createProfile(double units, const wavefront *wf, bool all // 1. Setup constants double steps = 1.0 / wf->m_outside.m_radius; double offset = allowOffset ? y_offset : 0.0; - double radius = md.currentSettings().apertureReduction / 2.0; + double radius = md.getClearAperture() / 2.0; double obs_radius = md.currentSettings().obstruction / 2.0; if (m_displayInches) {