From 828f07937b941a40d99cd341fb5460c4c07103a7 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Wed, 12 Aug 2026 16:33:38 +0200 Subject: [PATCH 1/2] annular obstruction is computed based on clearAperture instead diameter to have same logic as in Zernike fit --- mirrordlg.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 95403981..f430bac3 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -30,7 +30,6 @@ #include #include "annulushelpdlg.h" #include "surfacemanager.h" - QString mirrorDlg::m_projectPath = ""; mirrorDlg *mirrorDlg::get_Instance(){ @@ -252,6 +251,7 @@ void mirrorDlg::loadFile(QString & fileName){ cc = QJsonValue(mirror["desired conic"]).toDouble(); m_aperatureReductionEnabled = QJsonValue(mirror["edgeMaskon"]).toBool(); aperatureReduction=QJsonValue( mirror["edge mask value"]).toDouble(); + setclearAp(); QJsonObject Igram = loadDoc["igram"].toObject(); lambda = QJsonValue(Igram["wavelength"]).toDouble(); @@ -466,6 +466,7 @@ void mirrorDlg::on_diameter_textChanged(const QString &arg1) { ui->FNumber->blockSignals(true); ui->FNumber->setText(QString("%1").arg(FNumber, 6, 'f', 2)); ui->FNumber->blockSignals(false); + setclearAp(); updateZ8(); if (m_useAnnular){ on_annulusPercent_valueChanged(m_annularObsPercent * 100); @@ -492,6 +493,9 @@ void mirrorDlg::on_diameter_Changed(const double diam) setclearAp(); updateZ8(); + if (m_useAnnular){ + on_annulusPercent_valueChanged(m_annularObsPercent * 100); + } } @@ -605,7 +609,7 @@ void mirrorDlg::on_unitsCB_clicked(bool checked) ui->minorAxisEdit->setText(QString("%1").arg(m_verticalAxis/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_clearAperature * m_annularObsPercent * ((mm)? 1.: 1./25.4)); ui->annularDiameter->blockSignals(false); QSettings set; aperatureReduction = set.value("config aperatureReduction",0.).toDouble(); @@ -726,6 +730,11 @@ void mirrorDlg::setclearAp(){ if (m_aperatureReductionEnabled == false) m_clearAperature = diameter; ui->ClearAp->setText(QString("%1 ").arg(m_clearAperature * ((mm) ? 1: 1./25.4), 6, 'f', 2)); + if (m_useAnnular) { + ui->annularDiameter->blockSignals(true); + ui->annularDiameter->setValue(m_clearAperature * m_annularObsPercent * ((mm) ? 1. : 1./25.4)); + ui->annularDiameter->blockSignals(false); + } } void mirrorDlg::on_ReducApp_clicked(bool checked) @@ -757,11 +766,11 @@ 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)); + ui->annularDiameter->setValue( m_annularObsPercent * m_clearAperature * ( (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))); + ui->obs->setText(QString::number(m_annularObsPercent * m_clearAperature * ((mm)? 1.: 1./25.4))); } updateZ8(); } @@ -805,7 +814,9 @@ void mirrorDlg::on_annulusHelp_clicked() void mirrorDlg::on_annularDiameter_valueChanged(double arg1) { - m_annularObsPercent = arg1/diameter; + if (m_clearAperature <= 0.) + return; + m_annularObsPercent = arg1/m_clearAperature; ui->annulusPercent->setValue(m_annularObsPercent * 100); updateZ8(); } From 8f8f0efea58d98cd722c1cc31d75418907691624 Mon Sep 17 00:00:00 2001 From: Julien STAUB Date: Wed, 12 Aug 2026 17:26:17 +0200 Subject: [PATCH 2/2] Use full diameter as base for obstruction percent. More logical --- mirrordlg.cpp | 44 +++++++++++++++++++++++++++++++++++++------- mirrordlg.h | 4 +++- zernikeprocess.cpp | 8 ++++---- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/mirrordlg.cpp b/mirrordlg.cpp index f430bac3..f52cb2ba 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -140,6 +140,35 @@ double mirrorDlg::getMinorAxis(){ return ui->minorAxisEdit->text().toDouble(); } +double mirrorDlg::annularObstructionDiameter() const +{ + return m_annularObsPercent * diameter; +} + +double mirrorDlg::annularFitEpsilon() const +{ + if (diameter <= 0.) + return 0.; + + double fitAperture = diameter; + if (m_aperatureReductionEnabled) { + fitAperture = diameter - 2. * aperatureReduction; + } + if (fitAperture <= 0.) { + fitAperture = m_clearAperature; + } + if (fitAperture <= 0.) { + fitAperture = diameter; + } + + double eps = annularObstructionDiameter() / fitAperture; + if (eps < 0.) + eps = 0.; + if (eps >= 1.) + eps = 0.999999; + return eps; +} + bool mirrorDlg::isEllipse(){ return m_outlineShape == ELLIPSE; } @@ -533,7 +562,8 @@ void mirrorDlg::updateZ8(){ if (m_useAnnular){ - double f = (1 - (m_annularObsPercent * m_annularObsPercent)); + double eps = annularFitEpsilon(); + double f = (1 - (eps * eps)); f *= f; z8 *= f; } @@ -609,7 +639,7 @@ void mirrorDlg::on_unitsCB_clicked(bool checked) ui->minorAxisEdit->setText(QString("%1").arg(m_verticalAxis/div, 6, 'f', 2)); ui->reduceValue->blockSignals(true); ui->annularDiameter->blockSignals(true); - ui->annularDiameter->setValue(m_clearAperature * m_annularObsPercent * ((mm)? 1.: 1./25.4)); + ui->annularDiameter->setValue(annularObstructionDiameter() * ((mm)? 1.: 1./25.4)); ui->annularDiameter->blockSignals(false); QSettings set; aperatureReduction = set.value("config aperatureReduction",0.).toDouble(); @@ -732,7 +762,7 @@ void mirrorDlg::setclearAp(){ ui->ClearAp->setText(QString("%1 ").arg(m_clearAperature * ((mm) ? 1: 1./25.4), 6, 'f', 2)); if (m_useAnnular) { ui->annularDiameter->blockSignals(true); - ui->annularDiameter->setValue(m_clearAperature * m_annularObsPercent * ((mm) ? 1. : 1./25.4)); + ui->annularDiameter->setValue(annularObstructionDiameter() * ((mm) ? 1. : 1./25.4)); ui->annularDiameter->blockSignals(false); } } @@ -766,11 +796,11 @@ void mirrorDlg::on_annulusPercent_valueChanged(double arg1) { ui->annularDiameter->blockSignals(true); m_annularObsPercent = .01 * arg1; - ui->annularDiameter->setValue( m_annularObsPercent * m_clearAperature * ( (mm) ? 1.: 1./25.4)); + ui->annularDiameter->setValue( annularObstructionDiameter() * ( (mm) ? 1.: 1./25.4)); ui->annularDiameter->blockSignals(false); if (m_connectAnnulusToObs){ - ui->obs->setText(QString::number(m_annularObsPercent * m_clearAperature * ((mm)? 1.: 1./25.4))); + ui->obs->setText(QString::number(annularObstructionDiameter() * ((mm)? 1.: 1./25.4))); } updateZ8(); } @@ -814,9 +844,9 @@ void mirrorDlg::on_annulusHelp_clicked() void mirrorDlg::on_annularDiameter_valueChanged(double arg1) { - if (m_clearAperature <= 0.) + if (diameter <= 0.) return; - m_annularObsPercent = arg1/m_clearAperature; + m_annularObsPercent = arg1/diameter; ui->annulusPercent->setValue(m_annularObsPercent * 100); updateZ8(); } diff --git a/mirrordlg.h b/mirrordlg.h index a810e1e8..292606a9 100644 --- a/mirrordlg.h +++ b/mirrordlg.h @@ -55,7 +55,7 @@ class mirrorDlg : public QDialog bool fliph; bool m_useAnnular; bool m_connectAnnulusToObs; - double m_annularObsPercent; // a value from 0 to 1 (not 0 to 100) + double m_annularObsPercent; // obstruction ratio vs full mirror diameter, from 0 to 1 double m_clearAperature; double aperatureReduction; static QString m_projectPath; @@ -73,6 +73,8 @@ class mirrorDlg : public QDialog void setMinorAxis(double val); bool m_aperatureReductionEnabled; void setObsPercent(double obs); + double annularObstructionDiameter() const; + double annularFitEpsilon() const; private slots: void on_ReadBtn_clicked(); diff --git a/zernikeprocess.cpp b/zernikeprocess.cpp index d6ea4a52..94372366 100644 --- a/zernikeprocess.cpp +++ b/zernikeprocess.cpp @@ -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->annularFitEpsilon(), 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->annularFitEpsilon(), 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; @@ -949,7 +949,7 @@ arma::mat zernikeProcess::rhotheta( int width, double radius, double cx, double double centerR = 0.0; mirrorDlg *md = mirrorDlg::get_Instance(); if (md->m_useAnnular){ - centerR = md->m_annularObsPercent; + centerR = md->annularFitEpsilon(); } if (wf != 0){ useMask = true; @@ -1080,7 +1080,7 @@ void zernikeProcess::initGrid(int width, double radius, double cx, double cy, in bool shouldUseAnnulus = false; mirrorDlg *md = mirrorDlg::get_Instance(); if (md->m_useAnnular){ - obsPercent = md->m_annularObsPercent; + obsPercent = md->annularFitEpsilon(); shouldUseAnnulus = true; }