From 7aa93543caf0cd7c061121d87fb4fdd7748e9081 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Wed, 9 Oct 2024 20:47:13 -0500 Subject: [PATCH 01/25] updated make movie of wave fronts --- mainwindow.cpp | 252 ++++++++++++++++++++++++++++++++++-------------- mainwindow.h | 2 + mainwindow.ui | 5 + oglview.cpp | 2 +- profileplot.cpp | 151 +++++++++++++++++++++++------ 5 files changed, 305 insertions(+), 107 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index b9ca8746..22ee501f 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -48,7 +48,7 @@ #include "colorchannel.h" #include "opencv2/opencv.hpp" #include "spdlog/spdlog.h" - +#include using namespace QtConcurrent; std::vector g_wavefronts; @@ -1108,7 +1108,7 @@ void MainWindow::batchProcess(QStringList fileList){ } QApplication::processEvents(); - QObject().thread()->msleep(1000); + //QObject().thread()->msleep(1000); ui->SelectOutSideOutline->setChecked(true); if (!batchIgramWizard::autoCb->isChecked()){ while (m_inBatch && !m_OutlineDoneInBatch && !m_skipItem) { @@ -1125,7 +1125,7 @@ void MainWindow::batchProcess(QStringList fileList){ m_igramArea->nextStep(); QApplication::processEvents(); - QObject().thread()->msleep(1000); + //QObject().thread()->msleep(1000); m_batchMakeSurfaceReady = false; if (!batchIgramWizard::autoCb->isChecked() && !m_skipItem){ @@ -1610,80 +1610,179 @@ void MainWindow::on_useLastOutline_clicked() void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() { -// QStringList fileNames = SelectWaveFrontFiles(); -// this->setCursor(Qt::WaitCursor); -// QProgressDialog pd(" Loading wavefronts in PRogress.", "Cancel", 0, 100); -// pd.setRange(0, fileNames.size()); -// if (fileNames.length()> 0) -// pd.show(); -// int cnt = 0; -// QSettings set; -// QString lastPath = set.value("lastPath",".").toString(); -// int memThreshold = set.value("lowMemoryThreshold",300).toInt(); -// QImage img = m_ogl->m_gl->grabFrameBuffer(); - -// int width = img.width(); -// int height = img.height(); - -// try { -// QString fileName = QFileDialog::getSaveFileName(0, "Save AVI video as:", lastPath,"*.avi" ); -// if (fileName.length() > 0){ -// if (!(fileName.toUpper().endsWith(".AVI"))) -// fileName.append(".avi"); -// cv::VideoWriter video(fileName.toStdString().c_str(),-1,4,cv::Size(width,height),true); -// if (!video.isOpened()){ -// QString msg = QString("could not open %1 %2x%3 for writing.").arg(fileName).arg( -// width).arg(height); -// QMessageBox::warning(0,"warning", msg); -// return; -// } -// foreach (QString name, fileNames){ -// int mem = showmem("loading"); -// statusBar()->showMessage(QString("memory %1 MB").arg(mem)); -// if (mem< memThreshold + 50){ -// while (m_surfaceManager->m_wavefronts.size() > 1){ -// m_surfaceManager->deleteCurrent(); -// } -// } -// QApplication::processEvents(); - -// if (pd.wasCanceled()) -// break; - - -// pd.setLabelText(name); -// QApplication::processEvents(); -// wavefront *wf = m_surfaceManager->readWaveFront(name); - -// m_surfaceManager->makeMask(wf); -// m_surfaceManager->generateSurfacefromWavefront(wf); -// m_surfaceManager->computeMetrics(wf); - -// pd.setValue(++cnt); - -// m_ogl->m_gl->setSurface(wf); -// delete wf; -// QApplication::processEvents(); - -// QImage img = m_ogl->m_gl->grabFrameBuffer(); -// QPainter painter(&img); -// painter.setPen(Qt::yellow); -// painter.setBrush(Qt::yellow); -// QFileInfo info(name); -// painter.drawText(20,50, info.baseName()); -// cv::Mat frame = cv::Mat(img.height(), img.width(),CV_8UC4, img.bits(), img.bytesPerLine()).clone(); -// cv::Mat resized; -// cv::resize(frame, resized, cv::Size(width,height)); -// video.write(resized); -// } -// } -// } -// catch(std::exception& e) { -// qDebug() << "Exception writing video " << e.what(); -// } + if (QMessageBox::No == QMessageBox::question(0,"---------- 3D wave front Video maker -------------","This will create an 3D image of each wave front file selected and save it as an image.\n" + " So a video app can turn them into a movie. Select Yes if you want to continue.")) + { + return; + } + QStringList fileNames = SelectWaveFrontFiles(); + this->setCursor(Qt::WaitCursor); + QProgressDialog pd(" Loading wavefronts in PRogress.", "Cancel", 0, 100); + pd.setRange(0, fileNames.size()); + if (fileNames.length()> 0) + pd.show(); -// this->setCursor(Qt::ArrowCursor); + //ask which sets to make (asig and/or wavefronts) + bool dowavefront = false; + bool doastig = false; + astigScatterPlot *astigPlot = NULL; + QWidget *astigWindow = NULL; + if (QMessageBox::Yes == QMessageBox::question(0,"3D","Make image of 3D model of each wave front?")) + { + dowavefront = true; + } + + if (QMessageBox::Yes == QMessageBox::question(0,"astig","Make plot of astig for each wave front?")) + { + doastig = true; + astigPlot = new astigScatterPlot; + QVBoxLayout *layout = new QVBoxLayout(); + astigWindow = new QWidget(); + layout->addWidget(astigPlot); + astigWindow->setLayout(layout); + astigWindow->resize(1000,1000); + astigWindow->show(); + + } + if (!doastig and !dowavefront) + return; + int cnt = 0; + QSettings set; + QString lastPath = set.value("lastPath",".").toString(); + int memThreshold = set.value("lowMemoryThreshold",300).toInt(); + QImage img = m_ogl->m_surface->render(1000,1000); + + int width = img.width(); + int height = img.height(); + + try { + + QString dir = QFileDialog::getExistingDirectory(0, "Select directory where images will be saved.", lastPath, + QFileDialog::ShowDirsOnly + | QFileDialog::DontResolveSymlinks); + int framecnt = 0; + if (dir.length() > 0){ + + + foreach (QString name, fileNames){ + + QApplication::processEvents(); + + if (pd.wasCanceled()) + break; + + + pd.setLabelText(name); + QApplication::processEvents(); + wavefront *wf = m_surfaceManager->readWaveFront(name); + + m_surfaceManager->makeMask(wf); + m_surfaceManager->generateSurfacefromWavefront(wf); + m_surfaceManager->computeMetrics(wf); + + pd.setValue(++cnt); + + m_ogl->m_surface->setSurface(wf); + QPointF astig(wf->InputZerns[4], wf->InputZerns[5]); + delete wf; + QApplication::processEvents(); + if (dowavefront){ + QImage img = m_ogl->m_surface->render(1000,1000); + QPainter painter(&img); + painter.setPen(Qt::yellow); + painter.setBrush(Qt::yellow); + QFileInfo info(name); + painter.drawText(20,50, info.baseName()); + cv::Mat frame = cv::Mat(img.height(), img.width(),CV_8UC4, img.bits(), img.bytesPerLine()).clone(); + cv::Mat resized; + cv::resize(frame, resized, cv::Size(width,height)); + // write frame + QString filename = dir + "//" + QString("f%1.jpg").arg(framecnt++,3,10, QChar('0')); + img.save ( filename ); + } + if (doastig){ + + astigPlot->addValue("", astig); + + // write frame + QString filename = dir + "//" + QString("astig%1.jpg").arg(framecnt++,3,10, QChar('0')); + astigWindow->grab().save ( filename ); + qDebug() << filename; + } + } + } + if (QMessageBox::Yes == QMessageBox::question(0,"---------- 3D wave front Video maker -------------","Do you have FFMpeg and want it to make a video from these images?")) + + { + QString cmd = "ffmpeg -framerate 60 -i f%03d.jpg -c:v libx264 -vf format=yuv420p -y output.mp4"; + if (doastig) {cmd.replace("f%03d", "a%03d");} + bool ok = false; + QString text = QInputDialog::getText(this, + "------------------ FFmpeg command to create video from images.----------------", + "-------------------- Command to make 60 fps. Copy to command line app. -----------------", + QLineEdit::Normal, + "ffmpeg -framerate 60 -i f%03d.jpg -c:v libx264 -vf format=yuv420p -y output.mp4", + &ok); + if (ok) { + QDialog *dialog = new QDialog; + dialog->setWindowTitle("Popup Text Edit"); + dialog->resize(1000,1000); + QTextEdit *textEdit = new QTextEdit("ffmpeg output"); + + QPushButton *closeButton = new QPushButton("Close"); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(textEdit); + layout->addWidget(closeButton); + + dialog->setLayout(layout); + + QObject::connect(closeButton, &QPushButton::clicked, dialog, &QDialog::close); + + dialog->show(); + + + QApplication::setOverrideCursor(Qt::WaitCursor); + QProcess *proc = new QProcess; + connect(proc, QOverload::of(&QProcess::finished), + [=](int exitCode, QProcess::ExitStatus exitStatus){ qDebug() << "what" << exitStatus; }); + + proc->setProcessChannelMode(QProcess::MergedChannels); + proc->setWorkingDirectory(dir); + QStringList args = cmd.split(" "); + qDebug() << "args" << args.mid(1); + proc->start("ffmpeg",args.mid(1)); + + + while (!proc->waitForFinished(200)){ + QString q = proc->readAll(); + if (q != "") + textEdit->append(q); + QApplication::processEvents(); + } + + qDebug() << "done" ; + + proc->waitForFinished(); + QString out = proc->readAll() ; + QApplication::restoreOverrideCursor(); + + QString fn = dir + "/" + args[args.length()-1]; + QDesktopServices::openUrl(fn); + + } + } + + } + catch(std::exception& e) { + + qDebug() << "Exception writing video " << e.what(); + } + if (astigWindow != NULL) + delete astigWindow; + this->setCursor(Qt::ArrowCursor); + QApplication::restoreOverrideCursor(); } arma::mat zapm(const arma::vec& rho, const arma::vec& theta, const double& eps, const int& maxorder=12) ; @@ -1840,3 +1939,6 @@ void MainWindow::on_useAnnulust_clicked() m_igramArea->useAnnulusforCenterOutine(); } + + + diff --git a/mainwindow.h b/mainwindow.h index ff293490..01c8c20c 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -268,6 +268,8 @@ private slots: void on_useAnnulust_clicked(); + + private: Ui::MainWindow *ui; diff --git a/mainwindow.ui b/mainwindow.ui index 7e781dc0..61661c99 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -1484,6 +1484,11 @@ em; Arbitrary Wavefront + + + Create Movie of astig fom wavefonts + + diff --git a/oglview.cpp b/oglview.cpp index aa5eaaf3..a894978f 100644 --- a/oglview.cpp +++ b/oglview.cpp @@ -177,7 +177,7 @@ void OGLView::showSelected() // show all selected wavefronts as 3D plots QVector m_wavefronts =SurfaceManager::get_instance()->m_wavefronts; surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); QList list = saTools->SelectedWaveFronts(); - int cols = 4; + int cols = 3; if (list.size() %3 == 0) cols = 3; int rows = ceil((double)list.size()/cols); int columns = cols;//min(m_wavefronts.size(),int(ceil((double)m_wavefronts.size()/rows))); diff --git a/profileplot.cpp b/profileplot.cpp index d2ace222..c8b5ccac 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -16,6 +16,7 @@ ****************************************************************************/ #include "profileplot.h" +#include "simigramdlg.h" #include "ui_profileplot.h" #include #include @@ -45,8 +46,16 @@ #include "mirrordlg.h" #include #include "surfaceanalysistools.h" +#include "surfacemanager.h" +#include "zernikeprocess.h" +#include extern double outputLambda; +#include +#include +#include +#include + #define PITORAD M_PI/180.; double g_angle = 270. * PITORAD; //start at 90 deg (pointing east) double y_offset = 0.; @@ -83,11 +92,9 @@ bool ProfilePlot::eventFilter( QObject *object, QEvent *event ) } ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): - QWidget( parent ), - m_wf(0), m_tools(tools), - m_showSurface(1.), m_showNm(1.), dragging(false), - offsetType("Middle"), - m_defocusValue(0.), ui(new Ui::ProfilePlot) + QWidget( parent ), m_wf(0), m_tools(tools), + m_showSurface(1.),m_showNm(1.),dragging(false), + offsetType("Middle"),ui(new Ui::ProfilePlot), m_defocusValue(0.) { zoomed = false; m_defocus_mode = false; @@ -215,7 +222,6 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): ui->setupUi(this); populate(); } - ProfilePlot::~ProfilePlot(){ delete ui; } @@ -345,16 +351,7 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ double radius = md.m_clearAperature/2.; double obs_radius = md.obs/2.; - // If there is an annulus use it if it is a larger radius than the set obstruction - if (md.m_useAnnular){ - double annularRadius = md.m_annularObsPercent * md.diameter/2.; - if (annularRadius > obs_radius ){ - obs_radius = annularRadius; - } - - - } - +// qDebug() << "Clear" << radius; for (double rad = -1.; rad < 1.; rad += steps){ int dx, dy; double radn = rad * wf->m_outside.m_radius; @@ -376,21 +373,21 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ continue; } - if (wf->workMask.at(dy,dx)){ - double defocus = 0.; + if (wf->workMask.at(dy,dx)){ + double defocus = 0.; - if (m_defocus_mode){ - defocus = (m_defocusValue)* (-1. + 2. * rad * rad); - points << QPointF(radx,(units * (m_defocus_wavefront((int)dy,(int)dx) + defocus ) * - wf->lambda/outputLambda) +y_offset * units); - } - else { + if (m_defocus_mode){ + defocus = (m_defocusValue)* (-1. + 2. * rad * rad); + points << QPointF(radx,(units * (m_defocus_wavefront((int)dy,(int)dx) + defocus ) * + wf->lambda/outputLambda) +y_offset * units); + } + else { - points << QPointF(radx,(units * (wf->workData((int)dy,(int)dx) ) * + points << QPointF(radx,(units * (wf->workData((int)dy,(int)dx) ) * wf->lambda/outputLambda) +y_offset * units); + } } - } - //else points << QPointF(radx,0.0); + //else points << QPointF(radx,0.0); } if (m_showSlopeError){ @@ -427,7 +424,7 @@ void ProfilePlot::populate() compass->setGeometry(QRect(80,80,70,70)); QString tmp("nanometers"); if (m_showNm == 1.) - tmp = QString("waves of %1 nm").arg(outputLambda, 6, 'f', 1); + tmp = QString().sprintf("waves of %6.1lf nm",outputLambda); m_plot->setAxisTitle( m_plot->yLeft, "Error in " + tmp ); m_plot->setAxisTitle( m_plot->xBottom, "Radius mm" ); @@ -445,7 +442,7 @@ void ProfilePlot::populate() if (m_wf->m_outside.m_radius > 0 && settings.value("GBlur", false).toBool()){ double val = .01 * (m_wf->diameter) * smoothing; - QString t = QString("Surface Smoothing diameter %1% of surface diameter %2 mm").arg(smoothing, 6, 'f', 2).arg( val, 6, 'f', 1 ); + QString t = QString().sprintf("Surface Smoothing diameter %6.2lf%% of surface diameter %6.1lf mm", smoothing , val ); QwtText title(t); title.setRenderFlags( Qt::AlignHCenter | Qt::AlignTop ); @@ -538,11 +535,102 @@ void ProfilePlot::populate() QwtPlotCurve *cprofileavg = new QwtPlotCurve( "average"); cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowLine, false ); - cprofileavg->setPen( QPen(Qt::blue,5) ); + cprofileavg->setPen( QPen(Qt::red,3) ); cprofileavg->setSamples( avg); cprofileavg->attach( m_plot ); g_angle = startAngle; - break; + + // calculate and show percentages of correction + + SurfaceManager &sm = *SurfaceManager::get_instance(); + std::vector zernikes; + zernikes = sm.getCurrent()->InputZerns; + double z8 = zernikes[8]; //Z8 of current wavefront + + mirrorDlg &md = *mirrorDlg::get_Instance(); + double radius = md.m_clearAperature/2.; // mirror radius of clear aperture + double roc = md.roc; // ROC of the mirror + double lambda_nm = md.lambda; + // double lambda = lambda_nm * 1e-6; //igram wavelength in mm + double desiredZ8 = md.z8; + // double sphereParabolaDiff = pow(radius, 4) / (8 * pow(roc, 3)); // calculate sphere-parabola difference of the mirror (on surface), from Telescope Making #8, pg 36-, Richard Berry + // double wavesOfCorr = sphereParabolaDiff / lambda; // sphere-parabola difference of the mirror in waves at igram wavelength + + + double BestSC = z8/desiredZ8; // best fit conic of current wavefront + double slope; + // double slope2; + double rho; + double slopedefocused; + double avgdefocus = -3 * z8; // defocus term coefficient needed for avg + double slopeOfAvgDefocus; + double dx = 2.0 / (avg.size() -1.0); + double desiredSlope; + double percentCorr; + // double avgdefocused; // for debugging + + + QPolygonF slp; + QPolygonF slp2; + + double size = avg.size(); + + + for (int i = 2; i < size - 2; ++i){ + rho = avg[i].x() / radius; + // avgdefocused = avg[i].y() + avgdefocus * (2* rho * rho -1) * (lambda_nm/outputLambda); // for debugging + slope = 0.5 * ((avg[i+2].y() - avg[i-2].y()) / (4 * dx) - (avg[(size - i) +2].y() - avg[(size - i) -2].y()) / (4 * dx) ); //slope of average profile avg (smoothed a bit), with artificial Null applied (for output wavelength) + slopeOfAvgDefocus = ( -3 * z8 * 4 * rho + (desiredZ8) * (24 * pow(rho , 3) - 12 * rho)) * (lambda_nm/outputLambda); //slope of the defocus term needed for avg, PLUS the slope of the first spherical term removed by artificial null, converted to output wavelength + /* The profileplot avg is the measured profile minus artificial Null. The above term restores the slope of the original measured surface... + */ + slopedefocused = slope - slopeOfAvgDefocus; //slope of the restored original profile, without artificial null + desiredSlope = (3 * desiredZ8 * 4 * rho + desiredZ8 * (24 * pow(rho , 3) - 12 * rho))* (lambda_nm/outputLambda); // slope of defocused perfect parabola, converted to output wavelength + percentCorr = ( slopedefocused / desiredSlope ) + 2 * (-z8 / desiredZ8); + + + slp << QPointF(avg[i].x(), percentCorr); + // slp2 << QPointF(avg[i].x(), slopedefocused); + } + + //QVector slope; + QwtPlotCurve *slopeCurve = new QwtPlotCurve; + slopeCurve->setSamples(slp); + slopeCurve->setRenderHint( QwtPlotItem::RenderAntialiased ); + slopeCurve->setPen(QPen(QColor("green"),3)); + slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,false ); + slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine,false ); + slopeCurve->setItemAttribute(QwtPlotCurve::Legend,false); + slopeCurve->attach( m_plot); + + QwtPlotCurve *slopeCurve2 = new QwtPlotCurve; + slopeCurve2->setSamples(slp2); + slopeCurve2->setRenderHint( QwtPlotItem::RenderAntialiased ); + slopeCurve2->setPen(QPen(QColor("blue"),3)); + slopeCurve2->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,false ); + slopeCurve2->setLegendAttribute(QwtPlotCurve::LegendShowLine,false ); + slopeCurve2->setItemAttribute(QwtPlotCurve::Legend,false); + slopeCurve2->attach( m_plot); + + + + + std::ofstream myfile; + myfile.open("_Zahlen_for_debug.txt"); + + myfile << "roc = "<< roc << "\n" + << "lambda = "<< lambda_nm << "\n" + << "lambda = "<< outputLambda << "\n" + << "Z8 = "<< z8 << "\n" + << " avgdefocus = "<< avgdefocus << "\n" + << " desiredZ8 = "<< desiredZ8 << "\n" ; + + myfile.close(); + + + + break; + + } case 2:{ // show each wave front @@ -675,6 +763,7 @@ void ProfilePlot::contourPointSelected(const QPointF &pos){ double dely = pos.y() - m_wf->data.cols/2; double angle = atan2(delx,dely); // swaped x and y to rotate by 90 deg. + double angle2 = angle; const double twopi = M_PI * 2.; // force 0 to 360 if (angle < 0) From 4b2e8aa8d32f399e33d91b6d313c11e21ea08e31 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Mon, 14 Oct 2024 00:04:03 -0500 Subject: [PATCH 02/25] added percent correction feature to profile --- DFTFringe_Dale.pro | 3 + mainwindow.cpp | 11 +++- mainwindow.h | 2 + mainwindow.ui | 6 ++ percentcorrectiondlg.cpp | 139 +++++++++++++++++++++++++++++++++++++++ percentcorrectiondlg.h | 42 ++++++++++++ percentcorrectiondlg.ui | 103 +++++++++++++++++++++++++++++ profileplot.cpp | 135 +++++++++++-------------------------- profileplot.h | 9 ++- 9 files changed, 351 insertions(+), 99 deletions(-) create mode 100644 percentcorrectiondlg.cpp create mode 100644 percentcorrectiondlg.h create mode 100644 percentcorrectiondlg.ui diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index 45155013..238195f1 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -42,6 +42,7 @@ SOURCES += main.cpp \ dftarea.cpp \ oglrendered.cpp \ pdfcalibrationdlg.cpp \ + percentcorrectiondlg.cpp \ profileplot.cpp \ psiresizeimagesdlg.cpp \ surface3dcontrolsdlg.cpp \ @@ -159,6 +160,7 @@ HEADERS += mainwindow.h \ dftarea.h \ oglrendered.h \ pdfcalibrationdlg.h \ + percentcorrectiondlg.h \ profileplot.h \ psiresizeimagesdlg.h \ surface3dcontrolsdlg.h \ @@ -276,6 +278,7 @@ FORMS += mainwindow.ui \ edgeplot.ui \ oglrendered.ui \ pdfcalibrationdlg.ui \ + percentcorrectiondlg.ui \ profilearea.ui \ profileplot.ui \ contourtools.ui \ diff --git a/mainwindow.cpp b/mainwindow.cpp index 22ee501f..3d8a0612 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1726,9 +1726,9 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() &ok); if (ok) { QDialog *dialog = new QDialog; - dialog->setWindowTitle("Popup Text Edit"); + dialog->setWindowTitle("ffmpeg output"); dialog->resize(1000,1000); - QTextEdit *textEdit = new QTextEdit("ffmpeg output"); + QTextEdit *textEdit = new QTextEdit(); QPushButton *closeButton = new QPushButton("Close"); @@ -1942,3 +1942,10 @@ void MainWindow::on_useAnnulust_clicked() + +void MainWindow::on_actionShow_percentage_of_correction_triggered() +{ + + +} + diff --git a/mainwindow.h b/mainwindow.h index 01c8c20c..ffbf9a2f 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -270,6 +270,8 @@ private slots: + void on_actionShow_percentage_of_correction_triggered(); + private: Ui::MainWindow *ui; diff --git a/mainwindow.ui b/mainwindow.ui index 61661c99..ea287d18 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -94,6 +94,7 @@ + @@ -1489,6 +1490,11 @@ em; Create Movie of astig fom wavefonts + + + Show percentage of correction + + diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp new file mode 100644 index 00000000..77340a7a --- /dev/null +++ b/percentcorrectiondlg.cpp @@ -0,0 +1,139 @@ +#include "percentcorrectiondlg.h" +#include "ui_percentcorrectiondlg.h" +#include "qwt_plot_grid.h" +#include "qwt_scale_div.h" +#include "qwt_plot_barchart.h" +#include + +percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : + QDialog(parent),m_showZones(false), + ui(new Ui::percentCorrectionDlg) +{ + ui->setupUi(this); + + resize(1000,800); +} +void percentCorrectionDlg::replot(){ + + double min = 1000.; + double max = -1000.; + int smoothrange = .1 * m_size; + QPolygonF slp; + QPolygonF slp2; + QPolygonF smoothed; + double rho; + double dx = 2.0 / (m_avg.size() -1.0); + for (int i = 2; i <= m_size - 2; ++i){ + double rho = m_avg[i].x() / m_radius; + double slope = 0.5 * ((m_avg[i+2].y() - m_avg[i-2].y()) / (4 * dx) - (m_avg[(m_size - i) +2].y() - m_avg[(m_size - i) -2].y()) / (4 * dx) ); //slope of average profile avg (smoothed a bit), with artificial Null applied (for output wavelength) + double slopeOfAvgDefocus = ( -3 * m_z8 * 4 * rho + (m_desiredZ8) * (24 * pow(rho , 3) - 12 * rho)) * (m_lambda_nm/m_outputLambda); //slope of the defocus term needed for avg, PLUS the slope of the first spherical term removed by artificial null, converted to output wavelength + /* The profileplot avg is the measured profile minus artificial Null. The above term restores the slope of the original measured surface... + */ + double slopedefocused = slope - slopeOfAvgDefocus; //slope of the restored original profile, without artificial null + double desiredSlope = (3 * m_desiredZ8 * 4 * rho + m_desiredZ8 * (24 * pow(rho , 3) - 12 * rho))* (m_lambda_nm/m_outputLambda); // slope of defocused perfect parabola, converted to output wavelength + double percentCorr = ( slopedefocused / desiredSlope ) + 2 * (-m_z8 / m_desiredZ8); + + if (rho > .10){ + slp << QPointF(m_avg[i].x(), 100. * (percentCorr)); + } + + } + for (int i = 0; i < slp.size()-smoothrange; i++){ + double smoothavg = 0; + for (int j = i; j < i + smoothrange; ++j){ + smoothavg += slp[j].y(); + + } + smoothed << QPointF(slp[i + smoothrange/2].x(),smoothavg/ (double)smoothrange); + if (smoothed.last().y() < min){ + min = smoothed.last().y(); + } + if (smoothed.last().y() > max){ + max = smoothed.last().y(); + } + } + ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); + QwtPlotGrid *grid = new QwtPlotGrid(); + grid->setZ(1); + + grid->enableXMin(true); + grid->enableYMin(true); + + grid->setPen( Qt::gray, 0, Qt::DotLine ); + grid->setMajorPen( Qt::blue, 2.0,Qt::SolidLine); + grid->setMinorPen(Qt::black, 2.0, Qt::DotLine); + grid->attach( ui->plot); + + + QwtPlotCurve *slopeCurve = new QwtPlotCurve; + slopeCurve->setSamples(slp); + slopeCurve->setRenderHint( QwtPlotItem::RenderAntialiased ); + slopeCurve->setPen(QPen(QColor("green"),3)); + slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,false ); + slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine,false ); + slopeCurve->setItemAttribute(QwtPlotCurve::Legend,false); + slopeCurve->attach( ui->plot); + ui->plot->setAxisTitle( ui->plot->yLeft, "Percent correction" ); + ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); + if (max < 120) + max = 120; + else max += 10.; + if (min > -10) + min = -10; + else min-= 10.; + slopeCurve->setZ(1); + ui->plot->setAxisScale(QwtPlot::yLeft, min, max); + ui->plot->replot(); +} +void percentCorrectionDlg::plot( QPolygonF avg, double radius,double z8, + double desiredZ8, + double lambda_nm, double outputLambda){ + + m_avg = avg; + m_radius = radius; + m_z8 = z8; + m_desiredZ8 = desiredZ8; + m_lambda_nm = lambda_nm; + m_outputLambda = outputLambda; + m_size = avg.size()-1; + replot(); +} + +percentCorrectionDlg::~percentCorrectionDlg() +{ + delete ui; +} + + + + + + + +void percentCorrectionDlg::on_checkBox_clicked(bool checked) +{ + + if (checked){ + setWindowFlags(Qt::WindowStaysOnTopHint); + show(); + } + else + setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); + +} + + +void percentCorrectionDlg::on_zones_valueChanged(int arg1) +{ + m_number_of_zones = arg1; + replot(); + +} + + +void percentCorrectionDlg::on_checkBox_2_clicked(bool checked) +{ + m_showZones = checked; + replot(); +} + diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h new file mode 100644 index 00000000..39ad159f --- /dev/null +++ b/percentcorrectiondlg.h @@ -0,0 +1,42 @@ +#ifndef PERCENTCORRECTIONDLG_H +#define PERCENTCORRECTIONDLG_H + +#include +#include +#include + +namespace Ui { +class percentCorrectionDlg; +} + +class percentCorrectionDlg : public QDialog +{ + Q_OBJECT + int m_number_of_zones = 6; + int m_size; + double m_radius; + double m_z8; + double m_desiredZ8; + double m_lambda_nm; + double m_outputLambda; + bool m_showZones; +public: + explicit percentCorrectionDlg( QWidget *parent = nullptr); + ~percentCorrectionDlg(); + QPolygonF m_avg; + void plot(QPolygonF avg, double radius,double z8, + double desiredZ8, double lambda_nm, double outputlampda); + void replot(); +private slots: + + void on_checkBox_clicked(bool checked); + + void on_zones_valueChanged(int arg1); + + void on_checkBox_2_clicked(bool checked); + +private: + Ui::percentCorrectionDlg *ui; +}; + +#endif // PERCENTCORRECTIONDLG_H diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui new file mode 100644 index 00000000..532eabba --- /dev/null +++ b/percentcorrectiondlg.ui @@ -0,0 +1,103 @@ + + + percentCorrectionDlg + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile. It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. It also ignores any attempt to change the ROC using defocus. Sorry.</p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p></body></html> + + + true + + + + + + + + + + + Always on top + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::NoButton + + + true + + + + + + + + QwtPlot + QWidget +
qwt_plot.h
+ 1 +
+
+ + + + buttonBox + accepted() + percentCorrectionDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + percentCorrectionDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/profileplot.cpp b/profileplot.cpp index c8b5ccac..ffaf08c5 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -55,12 +55,11 @@ extern double outputLambda; #include #include #include - +#include "percentcorrectiondlg.h" #define PITORAD M_PI/180.; double g_angle = 270. * PITORAD; //start at 90 deg (pointing east) double y_offset = 0.; - bool ProfilePlot::eventFilter( QObject *object, QEvent *event ) { if ( event->type() == QEvent::MouseButtonPress ) @@ -96,6 +95,8 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): m_showSurface(1.),m_showNm(1.),dragging(false), offsetType("Middle"),ui(new Ui::ProfilePlot), m_defocusValue(0.) { +qDebug() << "new profilePlot"; + m_pcdlg = new percentCorrectionDlg; zoomed = false; m_defocus_mode = false; m_plot = new QwtPlot(this); @@ -113,6 +114,7 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): connect(ShowAll, SIGNAL(clicked()), this, SLOT(showAll())); l1->addStretch(); showSlopeError = new QCheckBox("Show Slope: "); + showPercentCorrection = new QCheckBox("Show Correction"); slopeLimitSB = new QDoubleSpinBox(); @@ -135,7 +137,8 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): showSlopeError->setChecked(m_showSlopeError); connect(slopeLimitSB, SIGNAL(valueChanged(double)), this, SLOT(slopeLimit(double))); connect(showSlopeError,SIGNAL(clicked(bool)), this, SLOT(showSlope(bool))); - + connect(showPercentCorrection,SIGNAL(clicked(bool)), this, SLOT(showCorrection(bool))); + l1->addWidget(showPercentCorrection); l1->addWidget(showSlopeError); l1->addWidget(slopeLimitSB); l1->addWidget(showNmCB); @@ -224,6 +227,7 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): } ProfilePlot::~ProfilePlot(){ delete ui; + delete m_pcdlg; } void ProfilePlot::showSlope(bool val){ @@ -420,6 +424,7 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ void ProfilePlot::populate() { +qDebug() << "new populate"; m_plot->detachItems(QwtPlotItem::Rtti_PlotItem); compass->setGeometry(QRect(80,80,70,70)); QString tmp("nanometers"); @@ -463,11 +468,8 @@ void ProfilePlot::populate() m_plot->setAxisScaleDiv(QwtPlot::xBottom, sd1); m_plot->detachItems( QwtPlotItem::Rtti_PlotCurve); m_plot->detachItems( QwtPlotItem::Rtti_PlotMarker); - //double b = 10. * ceil((m_wf->workData.cols/2.)/10.)+10; - //m_plot->setAxisScale( QwtPlot::xBottom, -b, b,50); - //m_plot->setAxisScaleDraw(m_plot->xBottom, new RadiusScaleDraw(m_wf->m_outside.m_radius,m_wf->diameter)); + QPolygonF avg; - // Insert new curves switch (type) { case 0:{ // show one QStringList path = wfs->at(0)->name.split("/"); @@ -491,8 +493,7 @@ void ProfilePlot::populate() break; } case 1: { // show 16 diameters - - if (true){ +qDebug() << "case 16"; QString t = "Average of all 16 diameters"; QwtText title(t); title.setRenderFlags( Qt::AlignHCenter | Qt::AlignBottom ); @@ -504,7 +505,7 @@ void ProfilePlot::populate() QwtPlotTextLabel *titleItem = new QwtPlotTextLabel(); titleItem->setText( title ); titleItem->attach( m_plot ); - } + double startAngle = g_angle; QPolygonF sum; @@ -528,110 +529,42 @@ void ProfilePlot::populate() cprofile->setSamples( points); cprofile->attach( m_plot ); } - QPolygonF avg; + foreach(QPointF p, sum){ avg << QPointF(p.x(),p.y()/16); } QwtPlotCurve *cprofileavg = new QwtPlotCurve( "average"); cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowLine, false ); - cprofileavg->setPen( QPen(Qt::red,3) ); + cprofileavg->setPen( QPen(Qt::blue,5) ); cprofileavg->setSamples( avg); cprofileavg->attach( m_plot ); g_angle = startAngle; - // calculate and show percentages of correction - - SurfaceManager &sm = *SurfaceManager::get_instance(); - std::vector zernikes; - zernikes = sm.getCurrent()->InputZerns; - double z8 = zernikes[8]; //Z8 of current wavefront - - mirrorDlg &md = *mirrorDlg::get_Instance(); - double radius = md.m_clearAperature/2.; // mirror radius of clear aperture - double roc = md.roc; // ROC of the mirror - double lambda_nm = md.lambda; - // double lambda = lambda_nm * 1e-6; //igram wavelength in mm - double desiredZ8 = md.z8; - // double sphereParabolaDiff = pow(radius, 4) / (8 * pow(roc, 3)); // calculate sphere-parabola difference of the mirror (on surface), from Telescope Making #8, pg 36-, Richard Berry - // double wavesOfCorr = sphereParabolaDiff / lambda; // sphere-parabola difference of the mirror in waves at igram wavelength + if (m_showCorrection){ + // calculate and show percentages of correction + SurfaceManager &sm = *SurfaceManager::get_instance(); + std::vector zernikes; + zernikes = sm.getCurrent()->InputZerns; + double z8 = zernikes[8]; //Z8 of current wavefront - double BestSC = z8/desiredZ8; // best fit conic of current wavefront - double slope; - // double slope2; - double rho; - double slopedefocused; - double avgdefocus = -3 * z8; // defocus term coefficient needed for avg - double slopeOfAvgDefocus; - double dx = 2.0 / (avg.size() -1.0); - double desiredSlope; - double percentCorr; - // double avgdefocused; // for debugging - - - QPolygonF slp; - QPolygonF slp2; - - double size = avg.size(); - - - for (int i = 2; i < size - 2; ++i){ - rho = avg[i].x() / radius; - // avgdefocused = avg[i].y() + avgdefocus * (2* rho * rho -1) * (lambda_nm/outputLambda); // for debugging - slope = 0.5 * ((avg[i+2].y() - avg[i-2].y()) / (4 * dx) - (avg[(size - i) +2].y() - avg[(size - i) -2].y()) / (4 * dx) ); //slope of average profile avg (smoothed a bit), with artificial Null applied (for output wavelength) - slopeOfAvgDefocus = ( -3 * z8 * 4 * rho + (desiredZ8) * (24 * pow(rho , 3) - 12 * rho)) * (lambda_nm/outputLambda); //slope of the defocus term needed for avg, PLUS the slope of the first spherical term removed by artificial null, converted to output wavelength - /* The profileplot avg is the measured profile minus artificial Null. The above term restores the slope of the original measured surface... - */ - slopedefocused = slope - slopeOfAvgDefocus; //slope of the restored original profile, without artificial null - desiredSlope = (3 * desiredZ8 * 4 * rho + desiredZ8 * (24 * pow(rho , 3) - 12 * rho))* (lambda_nm/outputLambda); // slope of defocused perfect parabola, converted to output wavelength - percentCorr = ( slopedefocused / desiredSlope ) + 2 * (-z8 / desiredZ8); - - - slp << QPointF(avg[i].x(), percentCorr); - // slp2 << QPointF(avg[i].x(), slopedefocused); - } + mirrorDlg &md = *mirrorDlg::get_Instance(); + double radius = md.m_clearAperature/2.; // mirror radius of clear aperture + // ROC of the mirror + double lambda_nm = md.lambda; - //QVector slope; - QwtPlotCurve *slopeCurve = new QwtPlotCurve; - slopeCurve->setSamples(slp); - slopeCurve->setRenderHint( QwtPlotItem::RenderAntialiased ); - slopeCurve->setPen(QPen(QColor("green"),3)); - slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,false ); - slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine,false ); - slopeCurve->setItemAttribute(QwtPlotCurve::Legend,false); - slopeCurve->attach( m_plot); + double desiredZ8 = md.z8; - QwtPlotCurve *slopeCurve2 = new QwtPlotCurve; - slopeCurve2->setSamples(slp2); - slopeCurve2->setRenderHint( QwtPlotItem::RenderAntialiased ); - slopeCurve2->setPen(QPen(QColor("blue"),3)); - slopeCurve2->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,false ); - slopeCurve2->setLegendAttribute(QwtPlotCurve::LegendShowLine,false ); - slopeCurve2->setItemAttribute(QwtPlotCurve::Legend,false); - slopeCurve2->attach( m_plot); + m_pcdlg->show(); + m_pcdlg->plot(avg, radius, + z8,desiredZ8, lambda_nm, outputLambda); + } - std::ofstream myfile; - myfile.open("_Zahlen_for_debug.txt"); - - myfile << "roc = "<< roc << "\n" - << "lambda = "<< lambda_nm << "\n" - << "lambda = "<< outputLambda << "\n" - << "Z8 = "<< z8 << "\n" - << " avgdefocus = "<< avgdefocus << "\n" - << " desiredZ8 = "<< desiredZ8 << "\n" ; - - myfile.close(); - - - - break; - - - + break; } case 2:{ // show each wave front @@ -708,8 +641,12 @@ void ProfilePlot::populate() mX->setXValue(0 ); mX->attach( m_plot ); + } + + + void ProfilePlot::updateGradient() { @@ -778,3 +715,9 @@ void ProfilePlot::contourPointSelected(const QPointF &pos){ compass->blockSignals(false); } +void ProfilePlot::showCorrection(bool show){ + m_showCorrection = show; + Show16->setChecked(show); + show16(); + +} diff --git a/profileplot.h b/profileplot.h index 9a37a9ff..cb1c060d 100644 --- a/profileplot.h +++ b/profileplot.h @@ -30,6 +30,7 @@ #include #include #include +#include "percentcorrectiondlg.h" namespace Ui { class ProfilePlot; } @@ -39,6 +40,8 @@ class ProfilePlot : public QWidget Q_OBJECT public: + percentCorrectionDlg *m_pcdlg; + bool m_showCorrection = false; QwtPlot *m_plot; wavefront* m_wf; ProfilePlot( QWidget *parent = NULL, ContourTools* tools = 0 ); @@ -60,6 +63,7 @@ class ProfilePlot : public QWidget double m_showNm; bool zoomed; bool m_showSlopeError; + double slopeLimitArcSec; void setDefocusValue(double val); void setDefocusWaveFront( cv::Mat_ wf); @@ -82,15 +86,18 @@ public slots: void showSlope(bool); void slopeLimit(double); void contourPointSelected(const QPointF &pos); + void populate(); + void showCorrection(bool); private: - void populate(); + void updateGradient(); bool dragging; QPoint startPos; QString offsetType; QwtCompass *compass; QCheckBox *showSlopeError; + QCheckBox *showPercentCorrection; QDoubleSpinBox *slopeLimitSB; double m_defocusValue; From 0ce3740b271c176e04f2ef62248de1598b2bdcfa Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Mon, 14 Oct 2024 02:50:56 -0500 Subject: [PATCH 03/25] update DFTFringe.pro to add percentcorrectiondlg class --- DFTFringe.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DFTFringe.pro b/DFTFringe.pro index bb981d82..2a5edbe4 100644 --- a/DFTFringe.pro +++ b/DFTFringe.pro @@ -204,6 +204,7 @@ SOURCES += SingleApplication/singleapplication.cpp \ outlineplots.cpp \ outlinestatsdlg.cpp \ pdfcalibrationdlg.cpp \ + percentcorrectiondlg.cpp \ pixelstats.cpp \ plotcolor.cpp \ profileplot.cpp \ @@ -324,6 +325,7 @@ HEADERS += bezier/bezier.h \ outlineplots.h \ outlinestatsdlg.h \ pdfcalibrationdlg.h \ + percentcorrectiondlg.h \ pixelstats.h \ plotcolor.h \ profileplot.h \ From a21649e96a960a226b8250b459a8dad3dc94d635 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Tue, 15 Oct 2024 18:04:36 -0500 Subject: [PATCH 04/25] lenhanced percentage correction. Added save and restore variables to a couple of dialogs --- defocusdlg.cpp | 23 ++++++- defocusdlg.h | 3 + percentcorrectiondlg.cpp | 95 +++++++++++++++++++++------ percentcorrectiondlg.h | 18 +++-- percentcorrectiondlg.ui | 104 +++++++++++++++++++++++++---- profileplot.cpp | 138 +++++++++++++++++++++++---------------- zernikesmoothingdlg.cpp | 12 ++-- zernikesmoothingdlg.ui | 3 + 8 files changed, 292 insertions(+), 104 deletions(-) diff --git a/defocusdlg.cpp b/defocusdlg.cpp index 4c5af6c1..07d50929 100644 --- a/defocusdlg.cpp +++ b/defocusdlg.cpp @@ -1,11 +1,18 @@ #include "defocusdlg.h" #include "ui_defocusdlg.h" #include +#include defocusDlg::defocusDlg(QWidget *parent) : QDialog(parent), ui(new Ui::defocusDlg) { ui->setupUi(this); + QSettings set; + + if (set.contains("defocus dialogGeometry")) { + setGeometry(set.value("defocus dialogGeometry").toRect()); + + } } defocusDlg::~defocusDlg() @@ -20,7 +27,7 @@ void defocusDlg::on_multiplier_valueChanged(int /*arg1*/) { on_defocusSlider_valueChanged(ui->defocusSlider->value()); } -#include + #include "math.h" void defocusDlg::on_defocusVal_valueChanged(double arg1) { @@ -42,6 +49,7 @@ void defocusDlg::on_defocusVal_valueChanged(double arg1) ui->multiplier->setValue(1.); ui->multiplier->blockSignals(false); } + emit defocus(arg1); } @@ -62,7 +70,7 @@ void defocusDlg::on_defocusSlider_valueChanged(int value) double f = mirrorDlg::get_Instance()->FNumber; double mm = f * f * 8. * value * .00055; //mmeters - qDebug() << "mm" << mm; + ui->Focusoffset->setText(QString("%1mm").arg(mm, 6,'f',3)); } @@ -77,3 +85,14 @@ void defocusDlg::on_pushButton_clicked() "

The resulting focal length offset is displayed in mm at the lower right.

"); } +void defocusDlg::moveEvent(QMoveEvent *event) { + QSettings set; + set.setValue("defocus dialogGeometry", geometry()); + QDialog::moveEvent(event); + +} +void defocusDlg::closeEvent(QCloseEvent *event) { + QSettings set; + set.setValue("defocus dialogGeometry", geometry()); + QDialog::closeEvent(event); +} diff --git a/defocusdlg.h b/defocusdlg.h index 5a69edcf..ce08fad8 100644 --- a/defocusdlg.h +++ b/defocusdlg.h @@ -14,6 +14,9 @@ class defocusDlg : public QDialog public: explicit defocusDlg(QWidget *parent = nullptr); ~defocusDlg(); +protected: + void closeEvent(QCloseEvent *event); + void moveEvent(QMoveEvent *event); signals: void defocus(double def); private slots: diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 77340a7a..db55b0ba 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -4,6 +4,9 @@ #include "qwt_scale_div.h" #include "qwt_plot_barchart.h" #include +#include "qwt_plot_marker.h" +#include +#include "surfaceanalysistools.h" percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : QDialog(parent),m_showZones(false), @@ -12,8 +15,23 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : ui->setupUi(this); resize(1000,800); + QSettings set; + ui->minvalue->blockSignals(true); + ui->maxvalue->blockSignals(true); + ui->minvalue->setValue(set.value("percent_correction_min",-10).toDouble()); + ui->maxvalue->setValue(set.value("percent_correction_max", 120).toDouble()); + ui->minvalue->blockSignals(false); + ui->maxvalue->blockSignals(false); + + m_number_of_zones = set.value("percent number of zones", 5).toInt(); + ui->numberOfZones->blockSignals(true); + ui->numberOfZones->setValue(m_number_of_zones); + ui->numberOfZones->blockSignals(false); + if (set.contains("percent_Correction_dialogGeometry")) { + setGeometry(set.value("percent_Correction_dialogGeometry").toRect()); + } } -void percentCorrectionDlg::replot(){ +void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ double min = 1000.; double max = -1000.; @@ -21,12 +39,21 @@ void percentCorrectionDlg::replot(){ QPolygonF slp; QPolygonF slp2; QPolygonF smoothed; - double rho; + surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); + double exc_pct = 100. * pow(16.75,2.)/pow(m_radius,2.); + QList zoneCenter; + for (int i = 0; i <= m_number_of_zones; ++i){ + zoneCenter << m_radius * sqrt((1. -.01 * exc_pct) * i/m_number_of_zones + .01 * exc_pct); + } +qDebug() << "zones" << zoneCenter; double dx = 2.0 / (m_avg.size() -1.0); for (int i = 2; i <= m_size - 2; ++i){ double rho = m_avg[i].x() / m_radius; double slope = 0.5 * ((m_avg[i+2].y() - m_avg[i-2].y()) / (4 * dx) - (m_avg[(m_size - i) +2].y() - m_avg[(m_size - i) -2].y()) / (4 * dx) ); //slope of average profile avg (smoothed a bit), with artificial Null applied (for output wavelength) double slopeOfAvgDefocus = ( -3 * m_z8 * 4 * rho + (m_desiredZ8) * (24 * pow(rho , 3) - 12 * rho)) * (m_lambda_nm/m_outputLambda); //slope of the defocus term needed for avg, PLUS the slope of the first spherical term removed by artificial null, converted to output wavelength + if (saTools->m_useDefocus){ + slopeOfAvgDefocus -= saTools->m_defocus * (-1. + 2. * pow(rho,2) ); + } /* The profileplot avg is the measured profile minus artificial Null. The above term restores the slope of the original measured surface... */ double slopedefocused = slope - slopeOfAvgDefocus; //slope of the restored original profile, without artificial null @@ -52,8 +79,20 @@ void percentCorrectionDlg::replot(){ max = smoothed.last().y(); } } - ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); + if (!addToPlot) + ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); + for (int i = 0; i < zoneCenter.size()-1; ++i) { + double centerv = (zoneCenter[i] + zoneCenter[i+1])/2.; + QwtPlotMarker *marker = new QwtPlotMarker(); + marker->setLineStyle(QwtPlotMarker::VLine); // Set the line style to vertical + marker->setLabel(QString().number(i+1)); + marker->setLinePen(Qt::red,2,Qt::DashLine); + marker->setLabelAlignment(Qt::AlignLeft); + marker->setXValue(centerv); // Set the x-coordinate for the line + marker->attach(ui->plot); // + } QwtPlotGrid *grid = new QwtPlotGrid(); + grid->setZ(1); grid->enableXMin(true); @@ -68,26 +107,21 @@ void percentCorrectionDlg::replot(){ QwtPlotCurve *slopeCurve = new QwtPlotCurve; slopeCurve->setSamples(slp); slopeCurve->setRenderHint( QwtPlotItem::RenderAntialiased ); - slopeCurve->setPen(QPen(QColor("green"),3)); + slopeCurve->setPen(QPen(penColor,3)); slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,false ); slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine,false ); slopeCurve->setItemAttribute(QwtPlotCurve::Legend,false); slopeCurve->attach( ui->plot); ui->plot->setAxisTitle( ui->plot->yLeft, "Percent correction" ); ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); - if (max < 120) - max = 120; - else max += 10.; - if (min > -10) - min = -10; - else min-= 10.; slopeCurve->setZ(1); - ui->plot->setAxisScale(QwtPlot::yLeft, min, max); + ui->plot->setAxisScale(QwtPlot::yLeft, ui->minvalue->value(), ui->maxvalue->value()); ui->plot->replot(); } void percentCorrectionDlg::plot( QPolygonF avg, double radius,double z8, double desiredZ8, - double lambda_nm, double outputLambda){ + double lambda_nm, double outputLambda, + QColor penColor, bool addToPlot){ m_avg = avg; m_radius = radius; @@ -96,7 +130,7 @@ void percentCorrectionDlg::plot( QPolygonF avg, double radius,double z8, m_lambda_nm = lambda_nm; m_outputLambda = outputLambda; m_size = avg.size()-1; - replot(); + replot(penColor, addToPlot); } percentCorrectionDlg::~percentCorrectionDlg() @@ -122,18 +156,37 @@ void percentCorrectionDlg::on_checkBox_clicked(bool checked) } - -void percentCorrectionDlg::on_zones_valueChanged(int arg1) +void percentCorrectionDlg::on_minvalue_valueChanged(double arg1) { - m_number_of_zones = arg1; - replot(); - + QSettings set; + set.setValue("percent_correction_min",arg1); + emit percent_plot_changed(); } -void percentCorrectionDlg::on_checkBox_2_clicked(bool checked) +void percentCorrectionDlg::on_maxvalue_valueChanged(double arg1) { - m_showZones = checked; - replot(); + QSettings set; + set.setValue("percent_correction_max", arg1); + emit percent_plot_changed(); +} + +void percentCorrectionDlg::closeEvent(QCloseEvent *event) { + QSettings set; + set.setValue("percent_Correction_dialogGeometry", geometry()); + QDialog::closeEvent(event); +} +void percentCorrectionDlg::moveEvent(QMoveEvent *event) { + QSettings set; + set.setValue("percent_Correction_dialogGeometry", geometry()); + QDialog::moveEvent(event); +} +void percentCorrectionDlg::on_numberOfZones_valueChanged(int arg1) +{ + m_number_of_zones = arg1; + QSettings set; + set.setValue("percent number of zones", arg1); + emit percent_plot_changed(); + } diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h index 39ad159f..e9af5a23 100644 --- a/percentcorrectiondlg.h +++ b/percentcorrectiondlg.h @@ -12,7 +12,7 @@ class percentCorrectionDlg; class percentCorrectionDlg : public QDialog { Q_OBJECT - int m_number_of_zones = 6; + int m_number_of_zones = 5; int m_size; double m_radius; double m_z8; @@ -20,20 +20,28 @@ class percentCorrectionDlg : public QDialog double m_lambda_nm; double m_outputLambda; bool m_showZones; +signals: + void percent_plot_changed(); +protected: + void closeEvent(QCloseEvent *event); + void moveEvent(QMoveEvent *event); public: explicit percentCorrectionDlg( QWidget *parent = nullptr); ~percentCorrectionDlg(); QPolygonF m_avg; void plot(QPolygonF avg, double radius,double z8, - double desiredZ8, double lambda_nm, double outputlampda); - void replot(); + double desiredZ8, double lambda_nm, double outputlampda, + QColor penColor, bool addToPlot = false); + void replot(QColor penColor = Qt::blue, bool addToPlot = false); private slots: void on_checkBox_clicked(bool checked); - void on_zones_valueChanged(int arg1); + void on_minvalue_valueChanged(double arg1); - void on_checkBox_2_clicked(bool checked); + void on_maxvalue_valueChanged(double arg1); + + void on_numberOfZones_valueChanged(int arg1); private: Ui::percentCorrectionDlg *ui; diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index 532eabba..c5428c39 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -6,18 +6,24 @@ 0 0 - 400 + 412 300 - Dialog + percent correction + + false + + + <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile.</p><p>It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. </p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p></body></html> + - <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile. It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. It also ignores any attempt to change the ROC using defocus. Sorry.</p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p></body></html> + <html><head/><body><p>Help</p><p><br/></p></body></html> true @@ -27,20 +33,92 @@ - - - - - Always on top - - - - + + + Always on top + + + + + + + percen min: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + -500.000000000000000 + + + 500.000000000000000 + + + 10.000000000000000 + + + -10.000000000000000 + + + + + + + percent max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + -500.000000000000000 + + + 500.000000000000000 + + + 10.000000000000000 + + + 120.000000000000000 + + + + + + + Zones: + + + + + + + 0 + + + 20 + + + 5 + + - + + + + + diff --git a/profileplot.cpp b/profileplot.cpp index ffaf08c5..23e24e2e 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -49,6 +49,7 @@ #include "surfacemanager.h" #include "zernikeprocess.h" #include +#include "plotcolor.h" extern double outputLambda; #include @@ -95,8 +96,9 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): m_showSurface(1.),m_showNm(1.),dragging(false), offsetType("Middle"),ui(new Ui::ProfilePlot), m_defocusValue(0.) { -qDebug() << "new profilePlot"; + m_pcdlg = new percentCorrectionDlg; + QObject::connect(m_pcdlg, SIGNAL(percent_plot_changed()), this, SLOT(populate())); zoomed = false; m_defocus_mode = false; m_plot = new QwtPlot(this); @@ -355,7 +357,6 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ double radius = md.m_clearAperature/2.; double obs_radius = md.obs/2.; -// qDebug() << "Clear" << radius; for (double rad = -1.; rad < 1.; rad += steps){ int dx, dy; double radn = rad * wf->m_outside.m_radius; @@ -394,7 +395,7 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ //else points << QPointF(radx,0.0); } - if (m_showSlopeError){ + if (m_showSlopeError && ((type==1 && !m_showCorrection) || (type == 0) || (type == 2))){ double arcsecLimit = (slopeLimitArcSec/3600) * M_PI/180; double xDel = points[0].x() - points[1].x(); double hDelLimit =m_showNm * m_showSurface * ((outputLambda/m_wf->lambda)*fabs(xDel * tan(arcsecLimit)) /(outputLambda * 1.e-6)); @@ -424,7 +425,7 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ void ProfilePlot::populate() { -qDebug() << "new populate"; + m_plot->detachItems(QwtPlotItem::Rtti_PlotItem); compass->setGeometry(QRect(80,80,70,70)); QString tmp("nanometers"); @@ -468,7 +469,7 @@ qDebug() << "new populate"; m_plot->setAxisScaleDiv(QwtPlot::xBottom, sd1); m_plot->detachItems( QwtPlotItem::Rtti_PlotCurve); m_plot->detachItems( QwtPlotItem::Rtti_PlotMarker); - QPolygonF avg; + switch (type) { case 0:{ // show one @@ -493,7 +494,15 @@ qDebug() << "new populate"; break; } case 1: { // show 16 diameters -qDebug() << "case 16"; + + surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); + QList list = saTools->SelectedWaveFronts(); + bool firstPlot = true; + QColor penColor = QColor("blue"); + + for (int indx = 0; indx < list.size(); ++indx){ + if (indx > 0) penColor = QColor(plotColors[indx % 10]); + QPolygonF avg; QString t = "Average of all 16 diameters"; QwtText title(t); title.setRenderFlags( Qt::AlignHCenter | Qt::AlignBottom ); @@ -506,61 +515,76 @@ qDebug() << "case 16"; titleItem->setText( title ); titleItem->attach( m_plot ); - double startAngle = g_angle; - QPolygonF sum; - - for (int i = 0; i < 16; ++i){ - QPolygonF points; - g_angle = startAngle + i * M_PI/ 16; + double startAngle = g_angle; + QPolygonF sum; + + for (int i = 0; i < 16; ++i){ + QPolygonF points; + g_angle = startAngle + i * M_PI/ 16; + + QwtPlotCurve *cprofile = new QwtPlotCurve( ); + cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); + cprofile->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); + cprofile->setPen( Qt::black ); + + points = createProfile( m_showNm * m_showSurface,wfs->at(list[indx])); + if (i == 0) { + sum = points; + } + else { + for(int j = 0; j < fmin(sum.length(),points.length());++j){ + sum[j].ry() += points[j].y(); + } + } + if (!m_showCorrection){ + cprofile->setSamples( points); + cprofile->attach( m_plot ); + } + } - QwtPlotCurve *cprofile = new QwtPlotCurve( ); - cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); - cprofile->setLegendAttribute( QwtPlotCurve::LegendShowLine, false ); - cprofile->setPen( Qt::black ); - points = createProfile( m_showNm * m_showSurface,m_wf); - if (i == 0) { - sum = points; + // plot the average profile + foreach(QPointF p, sum){ + avg << QPointF(p.x(),p.y()/16); } - else { - for(int j = 0; j < fmin(sum.length(),points.length());++j){ - sum[j].ry() += points[j].y(); - } + QString name("average"); + if (m_showCorrection){ + QStringList path = wfs->at(list[indx])->name.split("/"); + name = path.last().replace(".wft",""); } - cprofile->setSamples( points); - cprofile->attach( m_plot ); - } - - foreach(QPointF p, sum){ - avg << QPointF(p.x(),p.y()/16); - } - QwtPlotCurve *cprofileavg = new QwtPlotCurve( "average"); - cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); - cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowLine, false ); - cprofileavg->setPen( QPen(Qt::blue,5) ); - cprofileavg->setSamples( avg); - cprofileavg->attach( m_plot ); - g_angle = startAngle; - - if (m_showCorrection){ - // calculate and show percentages of correction - - SurfaceManager &sm = *SurfaceManager::get_instance(); - std::vector zernikes; - zernikes = sm.getCurrent()->InputZerns; - double z8 = zernikes[8]; //Z8 of current wavefront - - mirrorDlg &md = *mirrorDlg::get_Instance(); - double radius = md.m_clearAperature/2.; // mirror radius of clear aperture - // ROC of the mirror - double lambda_nm = md.lambda; - - double desiredZ8 = md.z8; - - m_pcdlg->show(); - m_pcdlg->plot(avg, radius, - z8,desiredZ8, lambda_nm, outputLambda); + QwtPlotCurve *cprofileavg = new QwtPlotCurve( name); + cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); + cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); + cprofileavg->setLegendIconSize(QSize(50,20)); + cprofileavg->setPen( QPen(penColor,5) ); + cprofileavg->setSamples( avg); + cprofileavg->attach( m_plot ); + g_angle = startAngle; + + if (m_showCorrection){ + // calculate and show percentages of correction + m_plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); + + m_plot->setStyleSheet(" font: 12pt \"Deja Vu\";"); + SurfaceManager &sm = *SurfaceManager::get_instance(); + std::vector zernikes; + zernikes = sm.getCurrent()->InputZerns; + double z8 = zernikes[8]; //Z8 of current wavefront + + mirrorDlg &md = *mirrorDlg::get_Instance(); + double radius = md.m_clearAperature/2.; // mirror radius of clear aperture + // ROC of the mirror + double lambda_nm = md.lambda; + + double desiredZ8 = md.z8; + + m_pcdlg->show(); + m_pcdlg->raise(); + m_pcdlg->plot(avg, radius, + z8,desiredZ8, lambda_nm, outputLambda,penColor, !firstPlot); + } + firstPlot = false; } @@ -585,7 +609,7 @@ qDebug() << "case 16"; int width = Settings2::m_profile->lineWidth(); if (name == m_wf->name.split("/").last().replace(".wft","")) width = Settings2::m_profile->selectedWidth(); - + cprofile->setLegendIconSize(QSize(50,20)); cprofile->setPen(QPen(Settings2::m_profile->getColor(i),width)); cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); cprofile->setSamples( createProfile( m_showNm * m_showSurface,wfs->at(list[i]))); diff --git a/zernikesmoothingdlg.cpp b/zernikesmoothingdlg.cpp index 9bba9d0f..55c0e14e 100644 --- a/zernikesmoothingdlg.cpp +++ b/zernikesmoothingdlg.cpp @@ -20,7 +20,8 @@ ZernikeSmoothingDlg::ZernikeSmoothingDlg(wavefront &wf, QWidget *parent) : std::vector val(m_noOfTerms,0.); ui->zernView->setModel(tableModel); QSettings set; - m_maxOrder = set.value("Zern maxOrder", 12).toInt(); + + m_maxOrder = set.value("Zern maxOrder", 22).toInt(); ui->maxOrder->setValue(m_maxOrder); ui->termCnt->setText(QString("%1 Terms").arg(m_noOfTerms)); connect(&m_timer, SIGNAL(timeout()), this, SLOT(intiZernTable())); @@ -52,10 +53,12 @@ void ZernikeSmoothingDlg::on_maxOrder_valueChanged(int arg1) { if (arg1 % 2 != 0) ++arg1; + QSettings set; + set.setValue("Zern maxOrder",arg1); + ui->maxOrder->setValue( arg1); m_maxOrder = arg1; - m_zp->setMaxOrder(arg1); m_noOfTerms = m_zp->getNumberOfTerms(); ui->termCnt->setText(QString("%1 Terms").arg(m_noOfTerms)); @@ -66,6 +69,7 @@ void ZernikeSmoothingDlg::on_maxOrder_valueChanged(int arg1) m_timer.setSingleShot(true); m_timer.start(1000); + } cv::Mat makeSurfaceFromZerns(int width, zernikeProcess &zp, std::vector theZerns){ int wx = width; @@ -95,10 +99,6 @@ void ZernikeSmoothingDlg::on_createWaveFront_clicked() m_wf = *p_wf; if (!ui->useCurrentZernySet->isChecked()){ theZerns = m_zp->ZernFitWavefront(m_wf); - qDebug() << "the zerns"; - for (int z = 0; z < 8; ++z){ - qDebug() << z << theZerns[z]; - } } tableModel->setValues(&theZerns); diff --git a/zernikesmoothingdlg.ui b/zernikesmoothingdlg.ui index ced903bd..d79a76f0 100644 --- a/zernikesmoothingdlg.ui +++ b/zernikesmoothingdlg.ui @@ -65,6 +65,9 @@ p, li { white-space: pre-wrap; } 2 + + 22 + From 614cdb424c99cc123d70f63d0c4a7ae3d6126877 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Tue, 15 Oct 2024 19:27:31 -0500 Subject: [PATCH 05/25] removed short cut from view menu to percentage --- DFTFringe_Dale.pro | 2 +- mainwindow.cpp | 8 -------- mainwindow.h | 4 ---- mainwindow.ui | 1 - 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index 238195f1..a5cbe6e0 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -411,7 +411,7 @@ RC_FILE = DFTFringe.rc QMAKE_CXXFLAGS += -std=c++11 # The application version -VERSION = 6.2 +VERSION = Dale7.3.3 # Define the preprocessor macro to get the application version in our application. DEFINES += APP_VERSION=\\\"$$VERSION\\\" diff --git a/mainwindow.cpp b/mainwindow.cpp index 3d8a0612..17cadc9d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1941,11 +1941,3 @@ void MainWindow::on_useAnnulust_clicked() - - -void MainWindow::on_actionShow_percentage_of_correction_triggered() -{ - - -} - diff --git a/mainwindow.h b/mainwindow.h index ffbf9a2f..ff293490 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -268,10 +268,6 @@ private slots: void on_useAnnulust_clicked(); - - - void on_actionShow_percentage_of_correction_triggered(); - private: Ui::MainWindow *ui; diff --git a/mainwindow.ui b/mainwindow.ui index ea287d18..b9936ffa 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -94,7 +94,6 @@ - From 4b9a3f12f49918570a89dfdae51e5acbd5ef075c Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Mon, 21 Oct 2024 03:59:51 -0500 Subject: [PATCH 06/25] reworked actual and expected. Have working percentage --- defocusdlg.cpp | 32 ++++++++--- defocusdlg.h | 1 + percentcorrectiondlg.cpp | 115 ++++++++++++++++++++++++--------------- percentcorrectiondlg.h | 3 +- percentcorrectiondlg.ui | 5 +- profileplot.cpp | 8 ++- surfaceanalysistools.h | 1 + surfacemanager.cpp | 2 +- 8 files changed, 112 insertions(+), 55 deletions(-) diff --git a/defocusdlg.cpp b/defocusdlg.cpp index 07d50929..d2b09095 100644 --- a/defocusdlg.cpp +++ b/defocusdlg.cpp @@ -23,31 +23,38 @@ defocusDlg::~defocusDlg() -void defocusDlg::on_multiplier_valueChanged(int /*arg1*/) +void defocusDlg::on_multiplier_valueChanged(int arg1) { - on_defocusSlider_valueChanged(ui->defocusSlider->value()); + double s = ui->defocusSlider->value()/100.; + ui->defocusVal->blockSignals(true); + ui->defocusVal->setValue( arg1 * s); + ui->defocusVal->blockSignals(false); + emit defocus(arg1 * s); } #include "math.h" void defocusDlg::on_defocusVal_valueChanged(double arg1) { - if (fabs(arg1) > 1) { + if (ui->multiplier->value() * ui->defocusSlider->value()/100. != arg1) { int mul = fabs(arg1/.5); double slid = arg1/mul; ui->multiplier->blockSignals(true); + ui->spinValue->blockSignals(true); ui->spinValue->setValue(slid); - - ui->multiplier->blockSignals(false); ui->multiplier->setValue(mul); + ui->multiplier->blockSignals(false); + ui->spinValue->blockSignals(false); + } else { - + ui->spinValue->blockSignals(true); ui->spinValue->setValue(arg1); ui->multiplier->blockSignals(true); ui->multiplier->setValue(1.); ui->multiplier->blockSignals(false); + ui->spinValue->blockSignals(false); } emit defocus(arg1); @@ -56,7 +63,14 @@ void defocusDlg::on_defocusVal_valueChanged(double arg1) void defocusDlg::on_spinValue_valueChanged(double arg1) { + ui->defocusSlider->blockSignals(true); ui->defocusSlider->setValue(arg1 * 100); + double val = ui->multiplier->value() * arg1; + ui->defocusVal->blockSignals(true); + ui->defocusVal->setValue(val); + ui->defocusVal->blockSignals(false); + ui->defocusSlider->blockSignals(false); + emit defocus(val); } #include "mirrordlg.h" void defocusDlg::on_defocusSlider_valueChanged(int value) @@ -66,12 +80,16 @@ void defocusDlg::on_defocusSlider_valueChanged(int value) ui->spinValue->setValue(val); ui->spinValue->blockSignals(false); val *= ui->multiplier->value(); + ui->defocusVal->blockSignals(true); + val *= ui->multiplier->value(); ui->defocusVal->setValue(val); + ui->defocusVal->blockSignals(false); double f = mirrorDlg::get_Instance()->FNumber; double mm = f * f * 8. * value * .00055; //mmeters - + m_defocusInmm = mm; ui->Focusoffset->setText(QString("%1mm").arg(mm, 6,'f',3)); + emit defocus(val); } diff --git a/defocusdlg.h b/defocusdlg.h index ce08fad8..e68a8b11 100644 --- a/defocusdlg.h +++ b/defocusdlg.h @@ -10,6 +10,7 @@ class defocusDlg; class defocusDlg : public QDialog { Q_OBJECT + double m_defocusInmm; public: explicit defocusDlg(QWidget *parent = nullptr); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index db55b0ba..60960ff9 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -7,7 +7,8 @@ #include "qwt_plot_marker.h" #include #include "surfaceanalysistools.h" - +#include "mirrordlg.h" +#include percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : QDialog(parent),m_showZones(false), ui(new Ui::percentCorrectionDlg) @@ -15,6 +16,7 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : ui->setupUi(this); resize(1000,800); + setWindowFlags(Qt::WindowStaysOnTopHint); QSettings set; ui->minvalue->blockSignals(true); ui->maxvalue->blockSignals(true); @@ -32,53 +34,58 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : } } void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ + auto z8null =[] (double rho, double z8) { + return z8 * (6 * pow(rho, 4) - 6 * pow(rho, 2 + 1));}; double min = 1000.; double max = -1000.; int smoothrange = .1 * m_size; - QPolygonF slp; - QPolygonF slp2; - QPolygonF smoothed; + + QPolygonF expectedslope; + QPolygonF actualslope; + QPolygonF percentplot; surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); double exc_pct = 100. * pow(16.75,2.)/pow(m_radius,2.); QList zoneCenter; for (int i = 0; i <= m_number_of_zones; ++i){ zoneCenter << m_radius * sqrt((1. -.01 * exc_pct) * i/m_number_of_zones + .01 * exc_pct); } -qDebug() << "zones" << zoneCenter; + + double DesiredZ8 = m_desiredZ8; + + if (saTools->m_useDefocus){ // if defocus compute new SA null Desired Z8 + double fnumber = mirrorDlg::get_Instance()->FNumber; + double rocDel = fnumber * fnumber * 8. * saTools->m_defocus * .055; //mmeters + double newRoc = m_roc + rocDel; + DesiredZ8 = (pow(m_radius * 2.,4) * 1000000.) / + (384. * pow(newRoc, 3) * m_lambda_nm); + } + + double size = m_avg.size(); double dx = 2.0 / (m_avg.size() -1.0); + double sag = m_roc - sqrt( pow(m_roc,2)- pow((m_radius * 2.),2)/4.); for (int i = 2; i <= m_size - 2; ++i){ - double rho = m_avg[i].x() / m_radius; - double slope = 0.5 * ((m_avg[i+2].y() - m_avg[i-2].y()) / (4 * dx) - (m_avg[(m_size - i) +2].y() - m_avg[(m_size - i) -2].y()) / (4 * dx) ); //slope of average profile avg (smoothed a bit), with artificial Null applied (for output wavelength) - double slopeOfAvgDefocus = ( -3 * m_z8 * 4 * rho + (m_desiredZ8) * (24 * pow(rho , 3) - 12 * rho)) * (m_lambda_nm/m_outputLambda); //slope of the defocus term needed for avg, PLUS the slope of the first spherical term removed by artificial null, converted to output wavelength - if (saTools->m_useDefocus){ - slopeOfAvgDefocus -= saTools->m_defocus * (-1. + 2. * pow(rho,2) ); - } - /* The profileplot avg is the measured profile minus artificial Null. The above term restores the slope of the original measured surface... - */ - double slopedefocused = slope - slopeOfAvgDefocus; //slope of the restored original profile, without artificial null - double desiredSlope = (3 * m_desiredZ8 * 4 * rho + m_desiredZ8 * (24 * pow(rho , 3) - 12 * rho))* (m_lambda_nm/m_outputLambda); // slope of defocused perfect parabola, converted to output wavelength - double percentCorr = ( slopedefocused / desiredSlope ) + 2 * (-m_z8 / m_desiredZ8); - - if (rho > .10){ - slp << QPointF(m_avg[i].x(), 100. * (percentCorr)); - } + double rho1 = m_avg[i+2].x() / m_radius; + double rho2 = m_avg[i-2].x() /m_radius; + if (rho1 > .10){ - } - for (int i = 0; i < slp.size()-smoothrange; i++){ - double smoothavg = 0; - for (int j = i; j < i + smoothrange; ++j){ - smoothavg += slp[j].y(); + // make expected slope + double parabExpectedSlope = -sag * (pow(rho2,2) - pow(rho1,2))/dx; + + // make actual slope buy adding the error to the expected + double error1 = .0001 * m_avg[i-2].y() * m_lambda_nm * (m_lambda_nm/m_outputLambda); + double error2 = .0001 * m_avg[i+2].y() * m_lambda_nm * (m_lambda_nm/m_outputLambda); + + double parabActualSlope = -sag * ((pow( rho2,2) + error2) - (pow(rho1,2) + error1))/dx; + actualslope << QPointF(m_avg[i].x(), parabActualSlope ); + expectedslope << QPointF( m_avg[i].x(),parabExpectedSlope); + double percent = 100. - 100. * fabs( parabExpectedSlope -parabActualSlope)/((parabExpectedSlope + parabActualSlope)/2.) ; + percentplot << QPointF(m_avg[i].x(),percent); } - smoothed << QPointF(slp[i + smoothrange/2].x(),smoothavg/ (double)smoothrange); - if (smoothed.last().y() < min){ - min = smoothed.last().y(); - } - if (smoothed.last().y() > max){ - max = smoothed.last().y(); - } + } + if (!addToPlot) ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); for (int i = 0; i < zoneCenter.size()-1; ++i) { @@ -99,32 +106,52 @@ qDebug() << "zones" << zoneCenter; grid->enableYMin(true); grid->setPen( Qt::gray, 0, Qt::DotLine ); - grid->setMajorPen( Qt::blue, 2.0,Qt::SolidLine); - grid->setMinorPen(Qt::black, 2.0, Qt::DotLine); + grid->setMajorPen( Qt::blue, 2.0,Qt::DotLine); + grid->setMinorPen(Qt::black, 1.0, Qt::DotLine); grid->attach( ui->plot); + QwtPlotCurve *slopeCurve8 = new QwtPlotCurve("expected slope"); + slopeCurve8->setSamples(expectedslope); + slopeCurve8->attach(ui->plot); + slopeCurve8->setPen(Qt::green,5); + slopeCurve8->setZ(0); + slopeCurve8->setLegendIconSize(QSize(50,20)); + + QwtPlotCurve *slopeCurve9 = new QwtPlotCurve("actual slope"); + slopeCurve9->setSamples(actualslope); + slopeCurve9->attach(ui->plot); + slopeCurve9->setPen(Qt::red,5); + slopeCurve9->setZ(0); + slopeCurve9->setLegendIconSize(QSize(50,20)); + + QwtPlotCurve *slopeCurve5 = new QwtPlotCurve("percent"); + slopeCurve5->setSamples(percentplot); + slopeCurve5->attach(ui->plot); + slopeCurve5->setPen(penColor,5, Qt::DotLine); + slopeCurve5->setZ(5); + slopeCurve5->setLegendIconSize(QSize(50,20)); + + ui->plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); + QwtPlotCurve *slopeCurve3 = new QwtPlotCurve("Actual"); + + slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,true ); + slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowLine,true ); + slopeCurve3->setItemAttribute(QwtPlotCurve::Legend,true); - QwtPlotCurve *slopeCurve = new QwtPlotCurve; - slopeCurve->setSamples(slp); - slopeCurve->setRenderHint( QwtPlotItem::RenderAntialiased ); - slopeCurve->setPen(QPen(penColor,3)); - slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,false ); - slopeCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine,false ); - slopeCurve->setItemAttribute(QwtPlotCurve::Legend,false); - slopeCurve->attach( ui->plot); ui->plot->setAxisTitle( ui->plot->yLeft, "Percent correction" ); ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); - slopeCurve->setZ(1); + slopeCurve3->setZ(1); ui->plot->setAxisScale(QwtPlot::yLeft, ui->minvalue->value(), ui->maxvalue->value()); ui->plot->replot(); } -void percentCorrectionDlg::plot( QPolygonF avg, double radius,double z8, +void percentCorrectionDlg::plot( QPolygonF avg, double radius,double roc, double z8, double desiredZ8, double lambda_nm, double outputLambda, QColor penColor, bool addToPlot){ m_avg = avg; m_radius = radius; + m_roc = roc; m_z8 = z8; m_desiredZ8 = desiredZ8; m_lambda_nm = lambda_nm; diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h index e9af5a23..fdd68112 100644 --- a/percentcorrectiondlg.h +++ b/percentcorrectiondlg.h @@ -20,6 +20,7 @@ class percentCorrectionDlg : public QDialog double m_lambda_nm; double m_outputLambda; bool m_showZones; + double m_roc; signals: void percent_plot_changed(); protected: @@ -29,7 +30,7 @@ class percentCorrectionDlg : public QDialog explicit percentCorrectionDlg( QWidget *parent = nullptr); ~percentCorrectionDlg(); QPolygonF m_avg; - void plot(QPolygonF avg, double radius,double z8, + void plot(QPolygonF avg, double radius,double roc, double z8, double desiredZ8, double lambda_nm, double outputlampda, QColor penColor, bool addToPlot = false); void replot(QColor penColor = Qt::blue, bool addToPlot = false); diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index c5428c39..6c11649d 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -37,12 +37,15 @@ Always on top + + true + - percen min: + percent min: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter diff --git a/profileplot.cpp b/profileplot.cpp index 23e24e2e..72dcb880 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -263,6 +263,8 @@ void ProfilePlot::showSurface(bool flag){ void ProfilePlot::showOne(){ type = 0; + showPercentCorrection->setChecked(false); + m_pcdlg->close(); populate(); m_plot->replot(); } @@ -273,6 +275,8 @@ void ProfilePlot::show16(){ } void ProfilePlot::showAll(){ type = 2; + showPercentCorrection->setChecked(false); + m_pcdlg->close(); populate(); m_plot->replot(); } @@ -579,7 +583,7 @@ void ProfilePlot::populate() m_pcdlg->show(); m_pcdlg->raise(); - m_pcdlg->plot(avg, radius, + m_pcdlg->plot(avg, radius, md.roc, z8,desiredZ8, lambda_nm, outputLambda,penColor, !firstPlot); @@ -742,6 +746,8 @@ void ProfilePlot::contourPointSelected(const QPointF &pos){ void ProfilePlot::showCorrection(bool show){ m_showCorrection = show; Show16->setChecked(show); + if (!show) + m_pcdlg->close(); show16(); } diff --git a/surfaceanalysistools.h b/surfaceanalysistools.h index fa8f4033..8b823c81 100644 --- a/surfaceanalysistools.h +++ b/surfaceanalysistools.h @@ -46,6 +46,7 @@ class surfaceAnalysisTools : public QDockWidget QList SelectedWaveFronts(); bool m_useDefocus; double m_defocus; + double m_defocusInmm; void setBlurText(QString txt); void nameChanged(int, QString); void select(int item); diff --git a/surfacemanager.cpp b/surfacemanager.cpp index ca76cf8e..a9e640e2 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -865,7 +865,7 @@ void SurfaceManager::computeMetrics(wavefront *wf){ } void SurfaceManager::defocusSetup(){ wavefront *wf = m_wavefronts[m_currentNdx]; - qDebug() << "wave" << wf->workData.rows; + m_profilePlot->setDefocusWaveFront(wf->workData); } From 5fb2bec9e32037a8611d634819ad72b6fd2767c4 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Mon, 11 Nov 2024 02:18:07 -0600 Subject: [PATCH 07/25] corrected 16 diameter but. Work in progress on percent correction. Working better and added knife plot. May not be completely accurate yet. More testing in progress. but this save current state. --- defocusdlg.cpp | 2 + percentcorrectiondlg.cpp | 422 +++++++++++++++++++++++++++++++-------- percentcorrectiondlg.h | 13 +- percentcorrectiondlg.ui | 135 +++++++++++-- profileplot.cpp | 37 ++-- 5 files changed, 485 insertions(+), 124 deletions(-) diff --git a/defocusdlg.cpp b/defocusdlg.cpp index d2b09095..0bbd223c 100644 --- a/defocusdlg.cpp +++ b/defocusdlg.cpp @@ -73,6 +73,7 @@ void defocusDlg::on_spinValue_valueChanged(double arg1) emit defocus(val); } #include "mirrordlg.h" +#include void defocusDlg::on_defocusSlider_valueChanged(int value) { double val = value/100.; @@ -88,6 +89,7 @@ void defocusDlg::on_defocusSlider_valueChanged(int value) double f = mirrorDlg::get_Instance()->FNumber; double mm = f * f * 8. * value * .00055; //mmeters m_defocusInmm = mm; + qDebug() << "defocus offset" << mm; ui->Focusoffset->setText(QString("%1mm").arg(mm, 6,'f',3)); emit defocus(val); } diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 60960ff9..443abe78 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -9,6 +9,9 @@ #include "surfaceanalysistools.h" #include "mirrordlg.h" #include +#include +#include "surfacemanager.h" + percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : QDialog(parent),m_showZones(false), ui(new Ui::percentCorrectionDlg) @@ -16,7 +19,7 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : ui->setupUi(this); resize(1000,800); - setWindowFlags(Qt::WindowStaysOnTopHint); + //setWindowFlags(Qt::WindowStaysOnTopHint); QSettings set; ui->minvalue->blockSignals(true); ui->maxvalue->blockSignals(true); @@ -33,71 +36,268 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : setGeometry(set.value("percent_Correction_dialogGeometry").toRect()); } } +// .0000018 +double g_laserLambda = 550.; +double getZernSurface( double RoC, double MirrorRad, double Zernikes[], double radius){ + + double num1 = radius / MirrorRad; + if (num1 > 1.0) + num1 = 1.0; + double num2 = num1 * num1; + double num3 = num2 * num2; + double num4 = num3 * num2; + double num5 = num3 * num3; + double num6 = num5 * num2; + + double num7 = 0.0 + Zernikes[8] * (1.0 - 6.0 * num2 + 6.0 * num3) + Zernikes[15] * (1.0 + 12.0 * num2 - 30.0 * num3 + 20.0 * num4) + Zernikes[24] * (1.0 - 20.0 * num2 + 90.0 * num3 - 140.0 * num4 + 70.0 * num5) + Zernikes[35] * (1.0 + 30.0 * num2 - 210.0 * num3 + 560.0 * num4 - 630.0 * num5 + 252.0 * num6); + double surf = RoC - sqrt(pow(RoC, 2.0) - pow(radius, 2.0)) + num7 * g_laserLambda * 1.E-6/2.; + qDebug() << "z8" << Zernikes[8] << "num7" << num7 << "surf" << surf; + return surf; +} + +double getSlope(double RoC, double radius, double Zernikes[], double x){ + double num1 = x / 100.0; + double surface1 = getZernSurface(RoC, radius, Zernikes, x - num1); + double surface2 = getZernSurface(RoC, radius, Zernikes, x + num1); + //double slope = -(1.0 / (2.0 * num1)) * (surface1 - surface2); + double slope = -(1.0 / (2.0 * num1)) * (surface1 - surface2); +//qDebug() << "x" << x << "slope" << slope; + return slope; +} +double GetActualKE(double RoC, double MirrorRad, double Zernikes[], double Z_Radius) +{ + double slope = getSlope(RoC, MirrorRad, Zernikes, Z_Radius); + double surface = getZernSurface(RoC, MirrorRad, Zernikes, Z_Radius); + //qDebug() << "x" << Z_Radius << "slope" << slope << "surface" << surface << "roc" << RoC; + double actualKe = Z_Radius / slope + surface - RoC; + //qDebug() << "actualKnife" << actualKe; + return actualKe; +} +// 5.3 = x/slope + 5.3 - roc x/slope = roc slope = x/roc +double getIdealKE(double RoC, double Z_Radius) +{ + return pow(Z_Radius, 2.0) / (2.0 * RoC); +} +/* + * paraby(x) = spherey(x) + profile(x) + ? + * + * + */ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ - auto z8null =[] (double rho, double z8) { - return z8 * (6 * pow(rho, 4) - 6 * pow(rho, 2 + 1));}; - double min = 1000.; - double max = -1000.; - int smoothrange = .1 * m_size; + int smoothrange = .1 * m_size; + m_z8 = 0.; QPolygonF expectedslope; QPolygonF actualslope; QPolygonF percentplot; - surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); + QPolygonF franzPrecentPlot; + QPolygonF actualSurface; + QPolygonF idealSurface; + QPolygonF correction; + + QPolygonF data; + SurfaceManager &sm = *SurfaceManager::get_instance(); + std::vector zernikes; + + auto getSphereY = [] (double roc, double x){ + return roc - sqrt(pow(roc,2) - pow(x,2)); + }; + auto getNull = [] (double roc, double radius, double x, double c8, double wavelength){ + double r = x/radius; + qDebug() << "x" << x << "roc"<< roc << "rho" << r; + return wavelength * 1.E-5 * .5 * c8 * (6. * pow(r,4) - 6. * pow(r,2) +1); + }; + auto getConicY = [] (double roc, double conic, double x){ + double y = pow(x,2)/(roc + (sqrt(pow(roc,2) - ((conic + 1) * pow(x,2))))); + return y; + }; + auto average = [] (QPolygonF data, int width, int ndx){ + int cnt = 0; + double sum = 0.; + for (int i = ndx - width; i <= ndx + width; ++i){ + sum += data[i].y(); + ++cnt; + } + return sum/cnt; + }; + + double roc = m_roc + m_roc_offset; + ui->roc->setValue( roc); + zernikes = sm.getCurrent()->InputZerns; + + double wavelength =1e-6 * m_outputLambda; // surface error + int smoothsize = 1 ; + + double C8 = mirrorDlg::get_Instance()->z8; + double conic = mirrorDlg::get_Instance()->cc; + qDebug() << "c8" << C8; + // smooth and convert to surface error. + double min = 999999.; + for (int i = 0; i < m_avg.size(); ++i){ + min = fmin(min, m_avg[i].y()); + } + for (int i = m_avg.size()/2; i < m_avg.size(); ++i){ + //save error y in mm on surface + data << QPointF(m_avg[i ].x(), (m_avg[i].y() - min) * .5E-6 * m_outputLambda); + + + } + + double exc_pct = 100. * pow(16.75,2.)/pow(m_radius,2.); QList zoneCenter; - for (int i = 0; i <= m_number_of_zones; ++i){ - zoneCenter << m_radius * sqrt((1. -.01 * exc_pct) * i/m_number_of_zones + .01 * exc_pct); + QList zoneedge; + QList indexOfZoneCenter; + // crete the zones and the zone centers for later indications + for (int i = 0; i < m_number_of_zones+1; ++i){ + zoneedge << m_radius * sqrt((1. -.01 * exc_pct) * i/m_number_of_zones + .01 * exc_pct); + // find the x entry in the surface that is closest to the zone value } + double lastzone = 0.; + for (int i = 0; i < m_number_of_zones; ++i){ + int ndx = 0; + double zoneCenterv = (lastzone + zoneedge[i])/2.; + lastzone = zoneedge[i]; + for (; ndx < data.size(); ++ ndx){ + double d = data[ndx].x(); + if (d >= zoneCenterv) + break; + } + zoneCenter << zoneCenterv; - double DesiredZ8 = m_desiredZ8; + indexOfZoneCenter << ndx; - if (saTools->m_useDefocus){ // if defocus compute new SA null Desired Z8 - double fnumber = mirrorDlg::get_Instance()->FNumber; - double rocDel = fnumber * fnumber * 8. * saTools->m_defocus * .055; //mmeters - double newRoc = m_roc + rocDel; - DesiredZ8 = (pow(m_radius * 2.,4) * 1000000.) / - (384. * pow(newRoc, 3) * m_lambda_nm); } - double size = m_avg.size(); - double dx = 2.0 / (m_avg.size() -1.0); - double sag = m_roc - sqrt( pow(m_roc,2)- pow((m_radius * 2.),2)/4.); - for (int i = 2; i <= m_size - 2; ++i){ - double rho1 = m_avg[i+2].x() / m_radius; - double rho2 = m_avg[i-2].x() /m_radius; - if (rho1 > .10){ - // make expected slope - double parabExpectedSlope = -sag * (pow(rho2,2) - pow(rho1,2))/dx; - // make actual slope buy adding the error to the expected - double error1 = .0001 * m_avg[i-2].y() * m_lambda_nm * (m_lambda_nm/m_outputLambda); - double error2 = .0001 * m_avg[i+2].y() * m_lambda_nm * (m_lambda_nm/m_outputLambda); + // start at the mirrors middle - double parabActualSlope = -sag * ((pow( rho2,2) + error2) - (pow(rho1,2) + error1))/dx; - actualslope << QPointF(m_avg[i].x(), parabActualSlope ); - expectedslope << QPointF( m_avg[i].x(),parabExpectedSlope); - double percent = 100. - 100. * fabs( parabExpectedSlope -parabActualSlope)/((parabExpectedSlope + parabActualSlope)/2.) ; - percentplot << QPointF(m_avg[i].x(),percent); + QVector IdealzoneKnife; + QVector ActualZoneKnife; + QVector idealDelta; + QVector actualDelta; - } + int zone = 0; + IdealzoneKnife << 0.; + ActualZoneKnife << 0.0; + + + // process each zone center + + // process ideal knife + int ndx = 1; + // while ( ndx < indexOfZoneCenter.length()){ + // IdealzoneKnife << getIdealKE(roc, data[zoneCenter[ndx]].x()) - firstIdeal; + // idealDelta << IdealzoneKnife[ndx] - IdealzoneKnife[ndx-1]; + + + // // process actual knife + + + + // ActualZoneKnife << GetActualKE(roc, m_radius, zernikes.data(), data[zoneCenter[ndx]].x()) - firstAct; + // actualDelta << ActualZoneKnife[ndx] - ActualZoneKnife[ndx-1]; + // double corr = 100 * (actualDelta.last() - idealDelta.last()); + // correction << QPointF(data[zoneCenter[ndx]].x(), corr); + // ++ndx; + // qDebug() << "correction" << correction.last(); + // } + QVector idealknives; + QVector actualknives; + idealknives << 0.; + actualknives << 0; + int del = ui->del->value(); + int avgwidth = ui->avgwidth->value(); + for (int zone = 0; zone < zoneCenter.length(); ++zone){ + + int ndx = indexOfZoneCenter[zone]; + + double x1 = data[ndx-del].x(); + double idealy1 = getConicY(roc, conic, x1); + double y1 = idealy1 + average(data, avgwidth, ndx-del); + + double x = data[ndx].x(); + double idealy = getConicY(roc, conic, x); + double y = average(data, avgwidth, ndx) + idealy; + + double x2 = data[ndx+del].x(); + double idealy2 = getConicY(roc, conic, x2); + qDebug() << "get idealy2" << roc << idealy; + double y2 = average(data, avgwidth, ndx+del) + idealy2; + + + // x^2/(2*roc) dx = 4 * x/(2*roc) = 2 * x/roc + double idealSlope = (idealy2 - idealy1)/(x2-x1) + .0000000001; + double normIdealSlope = -1./idealSlope; + double actualslope = (y2 - y1)/(x2 - x1) + .00000000001; + double normactualslope = -1./actualslope; + + double actualknife = y - x * normactualslope - roc; + double idealknife = idealy - x * normIdealSlope - roc; + + double idealDelta = idealknife - idealknives.last(); + double actualDelta = actualknife - actualknives.last(); + idealknives << idealknife; + actualknives << actualknife; + + // plot knives + + idealSurface << QPointF(x, idealknife); + actualSurface << QPointF(x, actualknife); + qDebug() << "x" << x <<"ideal knife" << idealknife << "idealDeltal" << idealDelta << "actualDelta" << actualDelta; + + + + double correction = 100. * (actualDelta)/(idealDelta); + qDebug() <<"corr" << correction; + if (zone > 0) + percentplot << QPointF( x, correction); + //qDebug() << "percent" << percentplot; } +qDebug() << "roc" << roc; if (!addToPlot) ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); - for (int i = 0; i < zoneCenter.size()-1; ++i) { - double centerv = (zoneCenter[i] + zoneCenter[i+1])/2.; + // draw markers + for (int i = 0; i < zoneCenter.size(); ++i) { + double center= zoneCenter[i]; QwtPlotMarker *marker = new QwtPlotMarker(); marker->setLineStyle(QwtPlotMarker::VLine); // Set the line style to vertical - marker->setLabel(QString().number(i+1)); marker->setLinePen(Qt::red,2,Qt::DashLine); marker->setLabelAlignment(Qt::AlignLeft); - marker->setXValue(centerv); // Set the x-coordinate for the line - marker->attach(ui->plot); // + marker->setXValue(center); + marker->setYValue(-5); + marker->attach(ui->plot); + + QwtPlotMarker *label = new QwtPlotMarker(); + label->setLineStyle(QwtPlotMarker::NoLine); // Set the line style to vertical + label->setLabel(QString().number(center,'f',1)); + label->setLabelAlignment(Qt::AlignLeft); + label->setXValue(center); + label->setYValue(-5); + label->attach(ui->plot); + // draw zone number + QwtPlotMarker *marker2 = new QwtPlotMarker(); + marker2->setLineStyle(QwtPlotMarker::NoLine); + marker2->setLabel(QString().number(i)); + marker2->setLabelAlignment(Qt::AlignLeft); + marker2->setYValue(.5); + marker2->setXValue(center); + marker2->attach(ui->plot); } +// for (int i = 0; i < zoneedge.size(); ++i) { +// double center= zoneedge[i]; +// QwtPlotMarker *marker = new QwtPlotMarker(); +// marker->setLineStyle(QwtPlotMarker::VLine); // Set the line style to vertical +// marker->setLabel(QString().number(i+1) + " " + QString().number(center)); +// marker->setLinePen(Qt::blue,3); +// marker->setLabelAlignment(Qt::AlignHCenter); +// marker->setXValue(center); // Set the x-coordinate for the line +// marker*/->attach(ui->plot); // +// } QwtPlotGrid *grid = new QwtPlotGrid(); grid->setZ(1); @@ -110,40 +310,51 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ grid->setMinorPen(Qt::black, 1.0, Qt::DotLine); grid->attach( ui->plot); - QwtPlotCurve *slopeCurve8 = new QwtPlotCurve("expected slope"); - slopeCurve8->setSamples(expectedslope); - slopeCurve8->attach(ui->plot); - slopeCurve8->setPen(Qt::green,5); - slopeCurve8->setZ(0); - slopeCurve8->setLegendIconSize(QSize(50,20)); - - QwtPlotCurve *slopeCurve9 = new QwtPlotCurve("actual slope"); - slopeCurve9->setSamples(actualslope); - slopeCurve9->attach(ui->plot); - slopeCurve9->setPen(Qt::red,5); - slopeCurve9->setZ(0); - slopeCurve9->setLegendIconSize(QSize(50,20)); - - QwtPlotCurve *slopeCurve5 = new QwtPlotCurve("percent"); - slopeCurve5->setSamples(percentplot); - slopeCurve5->attach(ui->plot); - slopeCurve5->setPen(penColor,5, Qt::DotLine); - slopeCurve5->setZ(5); - slopeCurve5->setLegendIconSize(QSize(50,20)); - - ui->plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); QwtPlotCurve *slopeCurve3 = new QwtPlotCurve("Actual"); - slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,true ); slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowLine,true ); slopeCurve3->setItemAttribute(QwtPlotCurve::Legend,true); + qDebug() << "plot type" << ui->plotType->currentText(); + // if show knives + if (ui->plotType->currentText() == "knife positions") { + QwtPlotCurve *slopeCurve9 = new QwtPlotCurve("actual"); + slopeCurve9->setSamples(actualSurface); + slopeCurve9->attach(ui->plot); + slopeCurve9->setPen(penColor,5); + slopeCurve9->setZ(0); + slopeCurve9->setLegendIconSize(QSize(50,20)); + if (!addToPlot){ + QwtPlotCurve *slopeCurve5 = new QwtPlotCurve("ideal"); + slopeCurve5->setSamples(idealSurface); + slopeCurve5->attach(ui->plot); + slopeCurve5->setPen(Qt::gray,5, Qt::DotLine); + slopeCurve5->setZ(5); + slopeCurve5->setLegendIconSize(QSize(50,20)); + ui->plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); + ui->plot->setAxisAutoScale(QwtPlot::yLeft, true); + + ui->plot->setAxisTitle( ui->plot->yLeft, "knife offset from ROC in mm" ); + ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); - ui->plot->setAxisTitle( ui->plot->yLeft, "Percent correction" ); - ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); - slopeCurve3->setZ(1); - ui->plot->setAxisScale(QwtPlot::yLeft, ui->minvalue->value(), ui->maxvalue->value()); + } + } + else { + QwtPlotCurve *slopeCurve8 = new QwtPlotCurve("correction"); + slopeCurve8->setSamples(percentplot); + slopeCurve8->attach(ui->plot); + slopeCurve8->setPen(penColor,10); + slopeCurve8->setZ(0); + slopeCurve8->setLegendIconSize(QSize(50,20)); + ui->plot->setAxisTitle( ui->plot->yLeft, "Percent correction" ); + ui->plot->setAxisScale(ui->plot->yRight, -10, 20, 1); + ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); + slopeCurve3->setZ(1); + ui->plot->setAxisScale(QwtPlot::yLeft, ui->minvalue->value(), ui->maxvalue->value()); + ui->plot->setAxisScale(QwtPlot::xBottom, 0, m_radius); + } ui->plot->replot(); } + void percentCorrectionDlg::plot( QPolygonF avg, double radius,double roc, double z8, double desiredZ8, double lambda_nm, double outputLambda, @@ -151,10 +362,20 @@ void percentCorrectionDlg::plot( QPolygonF avg, double radius,double roc, double m_avg = avg; m_radius = radius; - m_roc = roc; + surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); + if (saTools->m_useDefocus){ // if defocus compute new SA null Desired Z8 + double fnumber = mirrorDlg::get_Instance()->FNumber; + m_roc_offset = fnumber * fnumber * 8. * saTools->m_defocus * .055; //mmeters + } + else { + m_roc = roc; + } + + + m_z8 = z8; m_desiredZ8 = desiredZ8; - m_lambda_nm = lambda_nm; + g_laserLambda = m_lambda_nm = lambda_nm; m_outputLambda = outputLambda; m_size = avg.size()-1; replot(penColor, addToPlot); @@ -166,23 +387,6 @@ percentCorrectionDlg::~percentCorrectionDlg() } - - - - - -void percentCorrectionDlg::on_checkBox_clicked(bool checked) -{ - - if (checked){ - setWindowFlags(Qt::WindowStaysOnTopHint); - show(); - } - else - setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); - -} - void percentCorrectionDlg::on_minvalue_valueChanged(double arg1) { QSettings set; @@ -217,3 +421,51 @@ void percentCorrectionDlg::on_numberOfZones_valueChanged(int arg1) } + + + + +void percentCorrectionDlg::on_help_clicked() +{ + QToolTip::showText(ui->help->mapToGlobal(QPoint()),ui->help->toolTip(),ui->help); +} + + +void percentCorrectionDlg::on_plotType_currentTextChanged(const QString &arg1) +{ + if (arg1 == "knife positions"){ + ui->maxvalue->setEnabled(false); + ui->minvalue->setEnabled(false); + } + else { + ui->maxvalue->setEnabled(true); + ui->minvalue->setEnabled(true); + } + emit percent_plot_changed(); +} + + + + + +void percentCorrectionDlg::on_testbox_valueChanged(double arg1) +{ + qDebug() << "text box" << arg1; + m_roc_offset = arg1; + + ui->roc->setValue(m_roc + arg1); + replot(); +} + + +void percentCorrectionDlg::on_del_valueChanged(int arg1) +{ + replot(); +} + + +void percentCorrectionDlg::on_avgwidth_valueChanged(int arg1) +{ + replot(); +} + diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h index fdd68112..41284851 100644 --- a/percentcorrectiondlg.h +++ b/percentcorrectiondlg.h @@ -21,6 +21,7 @@ class percentCorrectionDlg : public QDialog double m_outputLambda; bool m_showZones; double m_roc; + double m_roc_offset = 0.; signals: void percent_plot_changed(); protected: @@ -36,14 +37,22 @@ class percentCorrectionDlg : public QDialog void replot(QColor penColor = Qt::blue, bool addToPlot = false); private slots: - void on_checkBox_clicked(bool checked); - void on_minvalue_valueChanged(double arg1); void on_maxvalue_valueChanged(double arg1); void on_numberOfZones_valueChanged(int arg1); + void on_help_clicked(); + + void on_plotType_currentTextChanged(const QString &arg1); + + void on_testbox_valueChanged(double arg1); + + void on_del_valueChanged(int arg1); + + void on_avgwidth_valueChanged(int arg1); + private: Ui::percentCorrectionDlg *ui; }; diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index 6c11649d..8882bad4 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -6,7 +6,7 @@ 0 0 - 412 + 501 300 @@ -15,33 +15,115 @@ - - - false - - - <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile.</p><p>It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. </p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p></body></html> - - - <html><head/><body><p>Help</p><p><br/></p></body></html> - - - true - - - - - + - + + + + percent knife delta + + + + + knife positions + + + + + + - Always on top + ROC - - true + + + + + + 1.000000000000000 + + + 99999.000000000000000 + + + + -9999.000000000000000 + + + 9999.000000000000000 + + + QAbstractSpinBox::AdaptiveDecimalStepType + + + + + + + Delta + + + + + + + 1 + + + 5 + + + + + + + avgw + + + + + + + 1 + + + 2 + + + 3 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile.</p><p>It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. </p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p></body></html> + + + ? + + + + + + + @@ -54,6 +136,9 @@ + + 3 + -500.000000000000000 @@ -80,6 +165,9 @@ + + 3 + -500.000000000000000 @@ -99,6 +187,9 @@ Zones: + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + diff --git a/profileplot.cpp b/profileplot.cpp index 72dcb880..03300e47 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -394,6 +394,7 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ points << QPointF(radx,(units * (wf->workData((int)dy,(int)dx) ) * wf->lambda/outputLambda) +y_offset * units); + } } //else points << QPointF(radx,0.0); @@ -521,7 +522,7 @@ void ProfilePlot::populate() double startAngle = g_angle; QPolygonF sum; - + QMap count; for (int i = 0; i < 16; ++i){ QPolygonF points; g_angle = startAngle + i * M_PI/ 16; @@ -531,24 +532,30 @@ void ProfilePlot::populate() cprofile->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); cprofile->setPen( Qt::black ); - points = createProfile( m_showNm * m_showSurface,wfs->at(list[indx])); - if (i == 0) { - sum = points; - } - else { - for(int j = 0; j < fmin(sum.length(),points.length());++j){ - sum[j].ry() += points[j].y(); - } - } - if (!m_showCorrection){ - cprofile->setSamples( points); - cprofile->attach( m_plot ); + points = createProfile( m_showNm * m_showSurface,wfs->at(list[indx])); + if (i == 0) { + sum = points; + for (int j = 0; j < sum.length(); ++j) + count[j] = 1; + } + else { + for(int j = 0; j < fmin(sum.length(),points.length());++j){ + sum[j].ry() += points[j].y();; + + if (count.contains(j)) count[j] += 1 ; + else count[j] = 1; } } + if (!m_showCorrection){ + cprofile->setSamples( points); + cprofile->attach( m_plot ); + } + } // plot the average profile + int i = 0; foreach(QPointF p, sum){ - avg << QPointF(p.x(),p.y()/16); + avg << QPointF(p.x(),p.y()/(count[i++])); } QString name("average"); if (m_showCorrection){ @@ -584,7 +591,7 @@ void ProfilePlot::populate() m_pcdlg->show(); m_pcdlg->raise(); m_pcdlg->plot(avg, radius, md.roc, - z8,desiredZ8, lambda_nm, outputLambda,penColor, !firstPlot); + md.cc,desiredZ8, lambda_nm, outputLambda,penColor, !firstPlot); } From 446a48d9efb1c08f6cea9f58a0441fe7ff59d191 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Sun, 16 Feb 2025 00:32:06 -0600 Subject: [PATCH 08/25] changed to use only first 4 spherical terms. Work in progress --- DFTFringe_Dale.pro | 2 +- astigstatsdlg.cpp | 4 +- igramarea.cpp | 1 + main.cpp | 8 +- mainwindow.cpp | 14 +- percentcorrectiondlg.cpp | 648 ++++++++++++++++++++++++++++----------- percentcorrectiondlg.h | 59 +++- percentcorrectiondlg.ui | 80 +---- profileplot.cpp | 25 ++ simulationsview.cpp | 2 +- 10 files changed, 592 insertions(+), 251 deletions(-) diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index a5cbe6e0..77dffeb0 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -416,7 +416,7 @@ VERSION = Dale7.3.3 # Define the preprocessor macro to get the application version in our application. DEFINES += APP_VERSION=\\\"$$VERSION\\\" DEFINES += QAPPLICATION_CLASS=QApplication - +DEFINES += DALE_DO_NOT_LOG DISTFILES += \ buildingDFTFringe64.txt \ helptext.txt \ diff --git a/astigstatsdlg.cpp b/astigstatsdlg.cpp index 028a64d6..d5f2931c 100644 --- a/astigstatsdlg.cpp +++ b/astigstatsdlg.cpp @@ -166,8 +166,8 @@ astigStatsDlg::astigStatsDlg(QVector wavefronts, QWidget *parent) : Qt::RightButton ); ui->mPlot->setPalette( Qt::white ); - - ui->bestFitCB->hide(); +qDebug() << "what the heck"; + //ui->bestFitCB->hide(); plot(); } diff --git a/igramarea.cpp b/igramarea.cpp index 28054d03..2cb0fcbf 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -2269,6 +2269,7 @@ void IgramArea::readOutlines(){ return; deleteRegions(); loadOutlineFileOldV6(fileName); + drawBoundary(); } QString IgramArea::makeOutlineName(){ QSettings settings; diff --git a/main.cpp b/main.cpp index 899d146c..e4df488b 100644 --- a/main.cpp +++ b/main.cpp @@ -26,6 +26,7 @@ #include "spdlog/sinks/stdout_color_sinks.h" #include "boost/stacktrace.hpp" + static void my_terminate_handler() { try { spdlog::get("logger")->critical("Unexpected issue. Stacktrace:\n" + boost::stacktrace::to_string((boost::stacktrace::stacktrace()))); @@ -101,7 +102,7 @@ int main(int argc, char *argv[]) spdlog::flush_every(std::chrono::seconds(3)); // Set the logging format - spdlog::get("logger")->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v"); + //spdlog::get("logger")->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v"); // Set logger level settingsDebug::setLogLevel(settingsDebug::getLogLevel()); @@ -118,12 +119,13 @@ int main(int argc, char *argv[]) // from here, any problematic application exit (for example uncatched exceptions) should call my_terminate_handler std::set_terminate(&my_terminate_handler); - +#ifndef DALE_DO_NOT_LOG // override QT message handler because qFatal() and qCritical() would exit cleanly without crashlog qInstallMessageHandler(myQtMessageOutput); // replace with nullptr if you want to use original bahavior for debug purpose // override CV error handler to get crashlog to execute instead of clean exit - cv::redirectError(myCvErrorCallback); // replace with nullptr if you want to use original bahavior for debug purpose + cv::redirectError(myCvErrorCallback); // replace with nullptr if you want to use original bahavior for debug purpose +#endif spdlog::get("logger")->critical("This is a demo stacktrace:\n" + boost::stacktrace::to_string((boost::stacktrace::stacktrace()))); MainWindow *w = new MainWindow; diff --git a/mainwindow.cpp b/mainwindow.cpp index 17cadc9d..4c469488 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -63,6 +63,7 @@ MainWindow::MainWindow(QWidget *parent) : { ui->setupUi(this); ui->useAnnulust->hide(); + spdlog::get("logger")->info("DFTFringe {} started", APP_VERSION); //const QString toolButtonStyle("QToolButton {" @@ -837,7 +838,7 @@ void MainWindow::on_actionSave_interferogram_triggered() void MainWindow::on_actionSave_screen_triggered() { QSettings set; - QString path = set.value("mirrorConfigFile").toString(); + QString path = set.value("saveImagePath").toString(); QFile fn(path); QFileInfo info(fn.fileName()); QString dd = info.dir().absolutePath(); @@ -864,7 +865,7 @@ void MainWindow::on_actionSave_screen_triggered() if (fName.isEmpty()) return; - + set.setValue("saveImagePath", fName); QImage image( this->size(), QImage::Format_ARGB32 ); @@ -875,8 +876,15 @@ void MainWindow::on_actionSave_screen_triggered() this->render( &painter); painter.setPen(QPen(Qt::red,5)); + // want to place the ogl widget back into the main window. + // get the topleft of the ogl but it's parent is not the main window + QPoint ml = this->mapToGlobal(QPoint (0,0)); QRect widgetRect = m_ogl->m_container->geometry(); - widgetRect.moveTopLeft(m_ogl->mapToGlobal(QPoint(0,20))); + QPoint tl = m_ogl->m_container->mapToGlobal(QPoint(0,0)); + QPoint offset = tl-ml; + + + widgetRect.moveTopLeft(offset); painter.drawImage(widgetRect, SurfaceImage); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 443abe78..fc3eca17 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -9,9 +9,231 @@ #include "surfaceanalysistools.h" #include "mirrordlg.h" #include +#include #include #include "surfacemanager.h" +#include +#include + +ZonePicker::ZonePicker( QwtPlot *plot, QList *zones): + QObject( plot ), m_zonelist(zones),m_radius(100.), + d_selectedMarker( NULL ), d_selectedZone(-1) + +{ + QwtPlotCanvas *canvas = qobject_cast( plot->canvas() ); + canvas->installEventFilter( this ); + + // We want the focus, but no focus rect. The + // selected point will be highlighted instead. + + canvas->setFocusPolicy( Qt::StrongFocus ); +#ifndef QT_NO_CURSOR + canvas->setCursor( Qt::PointingHandCursor ); +#endif + canvas->setFocusIndicator( QwtPlotCanvas::ItemFocusIndicator ); + canvas->setFocus(); + canvas->setMouseTracking(true); + +} +void ZonePicker::reset(){ + moving = false; + onazone = false; + d_lastFound = NULL; + +} +QwtPlot *ZonePicker::plot() +{ + return qobject_cast( parent() ); +} + +const QwtPlot *ZonePicker::plot() const +{ + return qobject_cast( parent() ); +} + +bool ZonePicker::event( QEvent *ev ) +{ + if ( ev->type() == QEvent::User ) + { + return true; + } + return QObject::event( ev ); +} + +bool ZonePicker::eventFilter( QObject *object, QEvent *event ) +{ + if ( plot() == NULL || object != plot()->canvas() ) + return false; + + switch( event->type() ) + { + case QEvent::FocusIn: + { + break; + } + case QEvent::FocusOut: + { + break; + } + case QEvent::Paint: + { + QApplication::postEvent( this, new QEvent( QEvent::User ) ); + break; + } + case QEvent::MouseButtonPress: + { + const QMouseEvent *mouseEvent = static_cast( event ); + select( mouseEvent->pos() ); + return true; + } + case QEvent::MouseButtonRelease: + { + moving = false; + //select( mouseEvent->pos() ); + if (d_selectedZone != -1) + emit(zoneMoved(d_selectedZone, d_selectedMarker->xValue())); + return true; + } + case QEvent::MouseMove: + { + const QMouseEvent *mouseEvent = static_cast( event ); + move( mouseEvent->pos() ); + return true; + } + + + default: + break; + } + + return QObject::eventFilter( object, event ); +} + + +// Select the point at a position. If there is no point +// deselect the selected point + +void ZonePicker::select( const QPoint &pos ) +{ + QwtPlotMarker *mark = NULL; + double dist = 10e10; + + double px = pos.x(); + d_selectedMarker = NULL; + if (findItem(pos.x(), 10,QwtPlotItem::Rtti_PlotMarker)){ + d_selectedMarker->setVisible(true); + moving = true; + } + + + +} + +void ZonePicker::edit(bool b){ + m_editing = b; +} + +// Move the selected point +void ZonePicker::move( const QPoint &pos ) +{ + if (m_editing && !moving){ + QwtPlotMarker *found = findItem(pos.x(), 10, QwtPlotItem::Rtti_PlotMarker); + if (found){ + if (!onazone){ + d_lastFound = found; + highlight(d_lastFound, true); + onazone = true; + emit zoneSelected(d_selectedZone); + plot()->replot(); + } + } + else if (onazone){ + // turn off highlight + if (d_lastFound) + highlight(d_lastFound,false); + + plot()->replot(); + onazone = false; + } + return; + } + if ( d_selectedZone == -1) + return; + + double x = plot()->invTransform(d_selectedMarker->xAxis(), pos.x() ); + + if ( (d_selectedZone == m_zonelist->last() && (x >= m_radius * .9)) || + ((d_selectedZone < m_zonelist->length()-1) && x >= (*m_zonelist)[d_selectedZone+1])) + return; + if (d_selectedZone > 1 && x <= (*m_zonelist)[d_selectedZone -1]) + return; + + + d_selectedMarker->setXValue(x); + + d_selectedMarker->setLabel( QString("%1\n%2\%").arg(x, 0, 'f',1).arg(100. * x/m_radius,0,'f',1 )) ; + + emit(zoneMoved(d_selectedZone, d_selectedMarker->xValue())); + + + /* + Enable QwtPlotCanvas::ImmediatePaint, so that the canvas has been + updated before we paint the cursor on it. + */ + QwtPlotCanvas *plotCanvas = + qobject_cast( plot()->canvas() ); + + plotCanvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, true ); + plot()->replot(); + plotCanvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false ); + + +} + +QwtPlotMarker *ZonePicker::findItem(double x, double tolerance, QwtPlotItem::RttiValues type){ + const QwtPlotItemList& itmList = plot()->itemList(); + double px = x; + for ( QwtPlotItemIterator it = itmList.begin(); + it != itmList.end(); ++it ) + { + + if ( ( *it )->rtti() == type ){ + + QwtPlotMarker *m = static_cast( *it ); + if (m->lineStyle() != QwtPlotMarker::VLine) + continue; + const QwtScaleMap xMap = plot()->canvasMap(2); + + const double cx = xMap.transform( m->xValue()); + + double d = px - cx; + + if ( abs(d) < tolerance ){ + + for (int i = 0; i < m_zonelist->length(); ++i){ + double t = m_zonelist->at(i); + if (t == m->xValue()){ + d_selectedZone = i; + d_selectedMarker = m; + return m; + } + } + } + + } + } + return NULL; +} +void ZonePicker::highlight(QwtPlotMarker *m, bool flag){ + + // change pen color if selected. + if (flag) + m->setLinePen(Qt::darkBlue,4,Qt::DashLine); + else + m->setLinePen(Qt::red,2,Qt::DashLine); + +} percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : QDialog(parent),m_showZones(false), ui(new Ui::percentCorrectionDlg) @@ -27,17 +249,92 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : ui->maxvalue->setValue(set.value("percent_correction_max", 120).toDouble()); ui->minvalue->blockSignals(false); ui->maxvalue->blockSignals(false); - + ui->zoneValue->hide(); m_number_of_zones = set.value("percent number of zones", 5).toInt(); + ui->numberOfZones->blockSignals(true); ui->numberOfZones->setValue(m_number_of_zones); ui->numberOfZones->blockSignals(false); if (set.contains("percent_Correction_dialogGeometry")) { setGeometry(set.value("percent_Correction_dialogGeometry").toRect()); } + + zonePicker = new ZonePicker(ui->plot, &zoneCenter); + connect(zonePicker,SIGNAL(zoneMoved(int, double)), this,SLOT(zoneMoved(int, double))); + connect(zonePicker,SIGNAL(zoneSelected(int)),this,SLOT(zoneSelected(int))); } // .0000018 -double g_laserLambda = 550.; +double g_laserLambda = 550.; //fixme should get this from the parent. + +void percentCorrectionDlg::saveSettings(){ + QJsonObject myJsonObject; + myJsonObject["ROC"] = m_roc; + myJsonObject["mirror radius"] = m_radius; + + QJsonArray jzones; + for (const auto &item : zoneCenter) { + jzones.append(item); + } + myJsonObject["zones"] = jzones; + QSettings set; + QJsonDocument jsonDoc(myJsonObject); + set.setValue("correctionZones", jsonDoc.toJson(QJsonDocument::Compact)); + +} +/**************************************************** + * zone data. If none to begin with use 5 zones. + * if last zones then use those. + * if user wants to change let hime but make him press accept + * allow loading and saveing of zones + * allways save current accpeted zones in settings probalby in json format. +*/ +QList generateZoneCenters(double radius, int number_of_zones){ + double exc_pct = 100. * pow(16.75,2.)/pow(radius,2.); + QList zoneCenters; + QList zoneedge; + // create the zones and the zone centers + for (int i = 0; i < number_of_zones+1; ++i){ + zoneedge << radius * sqrt((1. -.01 * exc_pct) * i/number_of_zones + .01 * exc_pct); + } + + double lastzone = 0.; + for (int i = 0; i < number_of_zones; ++i){ + double zoneCenter = (lastzone + zoneedge[i])/2.; + lastzone = zoneedge[i]; + zoneCenters << zoneCenter; + } + return zoneCenters; +} +void percentCorrectionDlg::makeZones(){ + + QSettings set; + if (!set.contains("correctionZones")){ + generateZoneCenters(m_radius, m_number_of_zones); + saveSettings(); + } + else { // read zones from settings + // if mirror is different now than last then make the same number of zones but with new radius values + QString jsonString = set.value("correctionZones").toString(); + + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8(), &jsonError); + QJsonObject jsonData=jsonDoc.object(); + QJsonArray zones = jsonData["zones"].toArray(); + double roc = jsonData["roc"].toDouble(); + zoneCenter.clear(); + for (int i = 0; i < zones.size(); ++i) { + zoneCenter.append(zones[i].toDouble()); + } + // if number of zones has changed then generate new zones. + if ((zones.size() != m_number_of_zones) || (m_radius != jsonData["mirror radius"].toDouble())){ + zoneCenter = generateZoneCenters(m_radius, m_number_of_zones); + saveSettings(); + } + + } + + +} double getZernSurface( double RoC, double MirrorRad, double Zernikes[], double radius){ double num1 = radius / MirrorRad; @@ -50,27 +347,33 @@ double getZernSurface( double RoC, double MirrorRad, double Zernikes[], double r double num6 = num5 * num2; double num7 = 0.0 + Zernikes[8] * (1.0 - 6.0 * num2 + 6.0 * num3) + Zernikes[15] * (1.0 + 12.0 * num2 - 30.0 * num3 + 20.0 * num4) + Zernikes[24] * (1.0 - 20.0 * num2 + 90.0 * num3 - 140.0 * num4 + 70.0 * num5) + Zernikes[35] * (1.0 + 30.0 * num2 - 210.0 * num3 + 560.0 * num4 - 630.0 * num5 + 252.0 * num6); - double surf = RoC - sqrt(pow(RoC, 2.0) - pow(radius, 2.0)) + num7 * g_laserLambda * 1.E-6/2.; - qDebug() << "z8" << Zernikes[8] << "num7" << num7 << "surf" << surf; + double spherey = RoC - sqrt(pow(RoC, 2.0) - pow(radius, 2.0)); + double zerny = num7 * g_laserLambda * .5E-6; + double surf = spherey + zerny; return surf; } - -double getSlope(double RoC, double radius, double Zernikes[], double x){ +// will use zernike values to compute two surface points x+- .01x away from x +// then compute normal slope from that. +double getnormalSlope(double RoC, double radius, double Zernikes[], double x){ double num1 = x / 100.0; double surface1 = getZernSurface(RoC, radius, Zernikes, x - num1); double surface2 = getZernSurface(RoC, radius, Zernikes, x + num1); - //double slope = -(1.0 / (2.0 * num1)) * (surface1 - surface2); - double slope = -(1.0 / (2.0 * num1)) * (surface1 - surface2); -//qDebug() << "x" << x << "slope" << slope; + double slope = (surface2 - surface1)/ (2 * num1); + slope = -1.0 / slope; + return slope; } +// b == knife y value +// y = mx + b +// b = y - mx + double GetActualKE(double RoC, double MirrorRad, double Zernikes[], double Z_Radius) { - double slope = getSlope(RoC, MirrorRad, Zernikes, Z_Radius); + double slope = getnormalSlope(RoC, MirrorRad, Zernikes, Z_Radius); double surface = getZernSurface(RoC, MirrorRad, Zernikes, Z_Radius); - //qDebug() << "x" << Z_Radius << "slope" << slope << "surface" << surface << "roc" << RoC; - double actualKe = Z_Radius / slope + surface - RoC; - //qDebug() << "actualKnife" << actualKe; + + double actualKe = surface - Z_Radius * slope - RoC; + return actualKe; } // 5.3 = x/slope + 5.3 - roc x/slope = roc slope = x/roc @@ -85,7 +388,6 @@ double getIdealKE(double RoC, double Z_Radius) */ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ - int smoothrange = .1 * m_size; m_z8 = 0.; QPolygonF expectedslope; @@ -105,14 +407,17 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ }; auto getNull = [] (double roc, double radius, double x, double c8, double wavelength){ double r = x/radius; - qDebug() << "x" << x << "roc"<< roc << "rho" << r; - return wavelength * 1.E-5 * .5 * c8 * (6. * pow(r,4) - 6. * pow(r,2) +1); + + double val = wavelength * 1.E-5 * .5 * c8 * (6. * pow(r,4) - 6. * pow(r,2) +1); + return val; }; + // return in mm auto getConicY = [] (double roc, double conic, double x){ double y = pow(x,2)/(roc + (sqrt(pow(roc,2) - ((conic + 1) * pow(x,2))))); return y; }; - auto average = [] (QPolygonF data, int width, int ndx){ + auto average = [] (QPolygonF &data, int width, int ndx){ + return data[ndx].y(); int cnt = 0; double sum = 0.; for (int i = ndx - width; i <= ndx + width; ++i){ @@ -121,9 +426,27 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ } return sum/cnt; }; + auto knifeDeltas = [](QPolygonF &knives){ + double last = knives[0].y(); + QPolygonF deltas; + for (int i = 1; i < knives.length(); ++i ){ + deltas << QPointF( knives[i].x(),knives[i].y() - last); + last = knives[i].y(); + } + return deltas; + + }; + auto getZoneCorrection = [] (QPolygonF &ideal, QPolygonF test){ + QPolygonF percent; + for (int i = 0; i < ideal.length(); ++i){ + percent << QPointF( test[i].x(), 100. * test[i].y()/ideal[i].y()); + } + return percent; + }; + double roc = m_roc + m_roc_offset; - ui->roc->setValue( roc); + zernikes = sm.getCurrent()->InputZerns; double wavelength =1e-6 * m_outputLambda; // surface error @@ -131,47 +454,37 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ double C8 = mirrorDlg::get_Instance()->z8; double conic = mirrorDlg::get_Instance()->cc; - qDebug() << "c8" << C8; - // smooth and convert to surface error. - double min = 999999.; - for (int i = 0; i < m_avg.size(); ++i){ - min = fmin(min, m_avg[i].y()); - } - for (int i = m_avg.size()/2; i < m_avg.size(); ++i){ + + // smooth and convert to surface error in mm. +// double min = 999999.; +// for (int i = 0; i < m_avg.size(); ++i){ +// min = fmin(min, m_avg[i].y()); +// } + for (int i = (m_avg.size()-1)/2; i < m_avg.size(); ++i){ //save error y in mm on surface - data << QPointF(m_avg[i ].x(), (m_avg[i].y() - min) * .5E-6 * m_outputLambda); + // Lets try adding the null back into it + // then later on add a sphere to it and see if it matches the zern version + data << QPointF(m_avg[i ].x(), (m_avg[i].y()) * .5E-6 * m_outputLambda ); + } - double exc_pct = 100. * pow(16.75,2.)/pow(m_radius,2.); - QList zoneCenter; - QList zoneedge; - QList indexOfZoneCenter; - // crete the zones and the zone centers for later indications - for (int i = 0; i < m_number_of_zones+1; ++i){ - zoneedge << m_radius * sqrt((1. -.01 * exc_pct) * i/m_number_of_zones + .01 * exc_pct); - // find the x entry in the surface that is closest to the zone value - } - double lastzone = 0.; + // find the x entry in the surface that is closest to the zone value + indexOfZoneCenter.clear(); + for (int i = 0; i < m_number_of_zones; ++i){ int ndx = 0; - double zoneCenterv = (lastzone + zoneedge[i])/2.; - lastzone = zoneedge[i]; for (; ndx < data.size(); ++ ndx){ double d = data[ndx].x(); - if (d >= zoneCenterv) + if (d >= zoneCenter[i]) break; } - zoneCenter << zoneCenterv; - + //zoneCenter << zoneCenter[i]; indexOfZoneCenter << ndx; - } - - // start at the mirrors middle QVector IdealzoneKnife; @@ -186,81 +499,87 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ // process each zone center - // process ideal knife - int ndx = 1; - // while ( ndx < indexOfZoneCenter.length()){ - // IdealzoneKnife << getIdealKE(roc, data[zoneCenter[ndx]].x()) - firstIdeal; - // idealDelta << IdealzoneKnife[ndx] - IdealzoneKnife[ndx-1]; + QPolygonF idealknives; + QPolygonF actualknives; + QPolygonF zernKnives; + QPolygonF zernSurf; - // // process actual knife + double idealoffset = 0.; + double zernOffset = 0.; - // ActualZoneKnife << GetActualKE(roc, m_radius, zernikes.data(), data[zoneCenter[ndx]].x()) - firstAct; - // actualDelta << ActualZoneKnife[ndx] - ActualZoneKnife[ndx-1]; - // double corr = 100 * (actualDelta.last() - idealDelta.last()); - // correction << QPointF(data[zoneCenter[ndx]].x(), corr); - // ++ndx; - // qDebug() << "correction" << correction.last(); - // } - QVector idealknives; - QVector actualknives; - idealknives << 0.; - actualknives << 0; - int del = ui->del->value(); - int avgwidth = ui->avgwidth->value(); for (int zone = 0; zone < zoneCenter.length(); ++zone){ int ndx = indexOfZoneCenter[zone]; - double x1 = data[ndx-del].x(); - double idealy1 = getConicY(roc, conic, x1); - double y1 = idealy1 + average(data, avgwidth, ndx-del); - double x = data[ndx].x(); double idealy = getConicY(roc, conic, x); - double y = average(data, avgwidth, ndx) + idealy; + double y = data[ndx].y() + idealy; + double zernsurf = getZernSurface(roc,m_radius, zernikes.data(), x); - double x2 = data[ndx+del].x(); - double idealy2 = getConicY(roc, conic, x2); - qDebug() << "get idealy2" << roc << idealy; - double y2 = average(data, avgwidth, ndx+del) + idealy2; + zernSurf << QPointF(x, zernsurf); - // x^2/(2*roc) dx = 4 * x/(2*roc) = 2 * x/roc - double idealSlope = (idealy2 - idealy1)/(x2-x1) + .0000000001; - double normIdealSlope = -1./idealSlope; - double actualslope = (y2 - y1)/(x2 - x1) + .00000000001; - double normactualslope = -1./actualslope; + //idealSurface << QPointF(x, normIdealSlope); + double idealknife = getIdealKE(roc, x); + double zernKnife = GetActualKE(roc, m_radius, zernikes.data(), x); - double actualknife = y - x * normactualslope - roc; - double idealknife = idealy - x * normIdealSlope - roc; + if (zone == 0){ + idealoffset = idealknife; + zernOffset = zernKnife; + } + idealknives << QPointF(x,idealknife - idealoffset); + zernKnives << QPointF(x,zernKnife - zernOffset); - double idealDelta = idealknife - idealknives.last(); - double actualDelta = actualknife - actualknives.last(); - idealknives << idealknife; - actualknives << actualknife; // plot knives - idealSurface << QPointF(x, idealknife); - actualSurface << QPointF(x, actualknife); - qDebug() << "x" << x <<"ideal knife" << idealknife << "idealDeltal" << idealDelta << "actualDelta" << actualDelta; + } + QPolygonF idealDeltas = knifeDeltas(idealknives); + QPolygonF zernDeltas = knifeDeltas(zernKnives); + + correction = getZoneCorrection(idealDeltas, zernDeltas); + QPolygonF profileCorrections = getZoneCorrection(idealDeltas, zernDeltas); + + + QPolygonF bars; - double correction = 100. * (actualDelta)/(idealDelta); - qDebug() <<"corr" << correction; - if (zone > 0) - percentplot << QPointF( x, correction); - //qDebug() << "percent" << percentplot; - } -qDebug() << "roc" << roc; if (!addToPlot) ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); + + // draw zone rectangles + if (!ui->editEnable->isChecked()){ + double width; + for(int i = 0; i < profileCorrections.length(); ++i){ + + double y = profileCorrections[i].y(); + + if (i < profileCorrections.length()-1) + width= .80 * (profileCorrections[i+1].x() - profileCorrections[i].x()) ; + + QwtPlotShapeItem *rectangleItem = new QwtPlotShapeItem(); + + rectangleItem->setRect(QRectF(profileCorrections[i].x()-width/2,0,width,y)); + + QPen pen(Qt::black); + pen.setWidth(3); + rectangleItem->setPen(pen); + rectangleItem->setBrush(QBrush(Qt::lightGray)); + rectangleItem->attach(ui->plot); + rectangleItem->setZ(0); + QwtPlotMarker *label = new QwtPlotMarker(); + label->setLineStyle(QwtPlotMarker::NoLine); + label->setLabel(QString("%1\%").arg(y, 0, 'f',1)) ; + label->setValue(profileCorrections[i].x(), y-10); + label->attach(ui->plot); + } + } // draw markers for (int i = 0; i < zoneCenter.size(); ++i) { double center= zoneCenter[i]; @@ -269,35 +588,28 @@ qDebug() << "roc" << roc; marker->setLinePen(Qt::red,2,Qt::DashLine); marker->setLabelAlignment(Qt::AlignLeft); marker->setXValue(center); - marker->setYValue(-5); + if (!ui->editEnable->isChecked()) + marker->setVisible(false); marker->attach(ui->plot); QwtPlotMarker *label = new QwtPlotMarker(); - label->setLineStyle(QwtPlotMarker::NoLine); // Set the line style to vertical - label->setLabel(QString().number(center,'f',1)); - label->setLabelAlignment(Qt::AlignLeft); + label->setLineStyle(QwtPlotMarker::NoLine); + label->setLabel(QString("%1\n%2\%").arg(center, 0, 'f',1).arg(100. * center/m_radius,0,'f',1 )) ; + label->setLabelAlignment(Qt::AlignCenter); label->setXValue(center); - label->setYValue(-5); + label->setYValue(-23); label->attach(ui->plot); + // draw zone number QwtPlotMarker *marker2 = new QwtPlotMarker(); marker2->setLineStyle(QwtPlotMarker::NoLine); - marker2->setLabel(QString().number(i)); - marker2->setLabelAlignment(Qt::AlignLeft); - marker2->setYValue(.5); + marker2->setLabel(QString().number(i+1)); + marker2->setLabelAlignment(Qt::AlignCenter); + marker2->setYValue(-5); marker2->setXValue(center); marker2->attach(ui->plot); } -// for (int i = 0; i < zoneedge.size(); ++i) { -// double center= zoneedge[i]; -// QwtPlotMarker *marker = new QwtPlotMarker(); -// marker->setLineStyle(QwtPlotMarker::VLine); // Set the line style to vertical -// marker->setLabel(QString().number(i+1) + " " + QString().number(center)); -// marker->setLinePen(Qt::blue,3); -// marker->setLabelAlignment(Qt::AlignHCenter); -// marker->setXValue(center); // Set the x-coordinate for the line -// marker*/->attach(ui->plot); // -// } + QwtPlotGrid *grid = new QwtPlotGrid(); grid->setZ(1); @@ -310,56 +622,52 @@ qDebug() << "roc" << roc; grid->setMinorPen(Qt::black, 1.0, Qt::DotLine); grid->attach( ui->plot); - QwtPlotCurve *slopeCurve3 = new QwtPlotCurve("Actual"); - slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,true ); - slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowLine,true ); - slopeCurve3->setItemAttribute(QwtPlotCurve::Legend,true); - qDebug() << "plot type" << ui->plotType->currentText(); - // if show knives - if (ui->plotType->currentText() == "knife positions") { - QwtPlotCurve *slopeCurve9 = new QwtPlotCurve("actual"); - slopeCurve9->setSamples(actualSurface); - slopeCurve9->attach(ui->plot); - slopeCurve9->setPen(penColor,5); - slopeCurve9->setZ(0); - slopeCurve9->setLegendIconSize(QSize(50,20)); - if (!addToPlot){ - QwtPlotCurve *slopeCurve5 = new QwtPlotCurve("ideal"); - slopeCurve5->setSamples(idealSurface); - slopeCurve5->attach(ui->plot); - slopeCurve5->setPen(Qt::gray,5, Qt::DotLine); - slopeCurve5->setZ(5); - slopeCurve5->setLegendIconSize(QSize(50,20)); - ui->plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); - ui->plot->setAxisAutoScale(QwtPlot::yLeft, true); - - ui->plot->setAxisTitle( ui->plot->yLeft, "knife offset from ROC in mm" ); - ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); + ui->plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); + + + QwtPlotCurve *slopeCurve3 = new QwtPlotCurve("zern correction"); + slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,true ); + slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowLine,true ); + slopeCurve3->setItemAttribute(QwtPlotCurve::Legend,true); + slopeCurve3->setSamples(profileCorrections); + slopeCurve3->attach(ui->plot); + slopeCurve3->setPen(Qt::blue,5); + + + - } - } - else { - QwtPlotCurve *slopeCurve8 = new QwtPlotCurve("correction"); - slopeCurve8->setSamples(percentplot); - slopeCurve8->attach(ui->plot); - slopeCurve8->setPen(penColor,10); - slopeCurve8->setZ(0); - slopeCurve8->setLegendIconSize(QSize(50,20)); ui->plot->setAxisTitle( ui->plot->yLeft, "Percent correction" ); ui->plot->setAxisScale(ui->plot->yRight, -10, 20, 1); ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); slopeCurve3->setZ(1); ui->plot->setAxisScale(QwtPlot::yLeft, ui->minvalue->value(), ui->maxvalue->value()); ui->plot->setAxisScale(QwtPlot::xBottom, 0, m_radius); - } + ui->plot->replot(); } +void percentCorrectionDlg::zoneSelected(int ndx){ + m_currentSelectedZone = ndx; + ui->zoneValue->blockSignals(true); + ui->zoneValue->setValue(zoneCenter[ndx]); + ui->zoneValue->blockSignals(false); +} +void percentCorrectionDlg::zoneMoved(int ndx, double value){ + zoneCenter[ndx] = value; + ui->zoneValue->blockSignals(true); + ui->zoneValue->setValue(value); + ui->zoneValue->blockSignals(false); + saveSettings(); + replot(); +} void percentCorrectionDlg::plot( QPolygonF avg, double radius,double roc, double z8, double desiredZ8, double lambda_nm, double outputLambda, QColor penColor, bool addToPlot){ + + + zonePicker->m_radius = radius; m_avg = avg; m_radius = radius; surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); @@ -371,13 +679,15 @@ void percentCorrectionDlg::plot( QPolygonF avg, double radius,double roc, double m_roc = roc; } - - m_z8 = z8; m_desiredZ8 = desiredZ8; g_laserLambda = m_lambda_nm = lambda_nm; m_outputLambda = outputLambda; m_size = avg.size()-1; + + //it is possible that the zones have yet to be set go read them from the settings. + // it will make them if needed. + makeZones(); replot(penColor, addToPlot); } @@ -412,60 +722,54 @@ void percentCorrectionDlg::moveEvent(QMoveEvent *event) { set.setValue("percent_Correction_dialogGeometry", geometry()); QDialog::moveEvent(event); } + void percentCorrectionDlg::on_numberOfZones_valueChanged(int arg1) { m_number_of_zones = arg1; QSettings set; set.setValue("percent number of zones", arg1); - emit percent_plot_changed(); + zonePicker->reset(); + makeZones(); + replot(); } - - - void percentCorrectionDlg::on_help_clicked() { QToolTip::showText(ui->help->mapToGlobal(QPoint()),ui->help->toolTip(),ui->help); } -void percentCorrectionDlg::on_plotType_currentTextChanged(const QString &arg1) -{ - if (arg1 == "knife positions"){ - ui->maxvalue->setEnabled(false); - ui->minvalue->setEnabled(false); - } - else { - ui->maxvalue->setEnabled(true); - ui->minvalue->setEnabled(true); - } - emit percent_plot_changed(); -} - +void percentCorrectionDlg::on_loadZones_clicked() +{ +} -void percentCorrectionDlg::on_testbox_valueChanged(double arg1) +void percentCorrectionDlg::on_saveZones_clicked() { - qDebug() << "text box" << arg1; - m_roc_offset = arg1; - ui->roc->setValue(m_roc + arg1); - replot(); } -void percentCorrectionDlg::on_del_valueChanged(int arg1) +void percentCorrectionDlg::on_editEnable_toggled(bool checked) { + zonePicker->edit(checked); + ui->zoneValue->setEnabled(checked); + if (!checked) + ui->zoneValue->hide(); + else + ui->zoneValue->show(); replot(); } -void percentCorrectionDlg::on_avgwidth_valueChanged(int arg1) +void percentCorrectionDlg::on_zoneValue_valueChanged(double arg1) { + zoneCenter[m_currentSelectedZone] = arg1; replot(); + } diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h index 41284851..ca9c3afb 100644 --- a/percentcorrectiondlg.h +++ b/percentcorrectiondlg.h @@ -4,11 +4,46 @@ #include #include #include +#include namespace Ui { class percentCorrectionDlg; } +class ZonePicker: public QObject +{ + Q_OBJECT + QList *m_zonelist; + bool moving = false; + bool onazone = false; + +public: + bool m_editing = false; + QwtPlotMarker *d_lastFound = NULL; + double m_radius; + ZonePicker( QwtPlot *plot, QList *zones ); + virtual bool eventFilter( QObject *, QEvent * ); + + virtual bool event( QEvent * ); + void edit(bool b); + void reset(); +Q_SIGNALS: + void zoneMoved(int zone, double rad); + void zoneSelected(int ndx); + +private: + QwtPlotMarker *findItem(double x, double tolerance, QwtPlotItem::RttiValues type); + void select( const QPoint & ); + void move( const QPoint & ); + void release(); + void highlight(QwtPlotMarker *m, bool flag); + QwtPlot *plot(); + const QwtPlot *plot() const; + + QwtPlotMarker *d_selectedMarker; + int d_selectedZone; + +}; class percentCorrectionDlg : public QDialog { Q_OBJECT @@ -22,6 +57,11 @@ class percentCorrectionDlg : public QDialog bool m_showZones; double m_roc; double m_roc_offset = 0.; + QList zoneCenter; + QList zoneedge; + QList indexOfZoneCenter; + ZonePicker *zonePicker; + int m_currentSelectedZone = -1; signals: void percent_plot_changed(); protected: @@ -35,6 +75,7 @@ class percentCorrectionDlg : public QDialog double desiredZ8, double lambda_nm, double outputlampda, QColor penColor, bool addToPlot = false); void replot(QColor penColor = Qt::blue, bool addToPlot = false); + private slots: void on_minvalue_valueChanged(double arg1); @@ -45,16 +86,26 @@ private slots: void on_help_clicked(); - void on_plotType_currentTextChanged(const QString &arg1); + void zoneMoved(int ndx, double value); + + void zoneSelected(int ndx); + + void on_loadZones_clicked(); - void on_testbox_valueChanged(double arg1); + void on_saveZones_clicked(); + + void on_editEnable_toggled(bool checked); + + void on_zoneValue_valueChanged(double arg1); - void on_del_valueChanged(int arg1); - void on_avgwidth_valueChanged(int arg1); private: Ui::percentCorrectionDlg *ui; + + void makeZones(); + void saveSettings(); + }; #endif // PERCENTCORRECTIONDLG_H diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index 8882bad4..c343ee93 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -6,7 +6,7 @@ 0 0 - 501 + 505 300 @@ -17,83 +17,33 @@ - - - - percent knife delta - - - - - knife positions - - - - - - + - ROC - - - - - - - 1.000000000000000 - - - 99999.000000000000000 - - - - - - - -9999.000000000000000 - - - 9999.000000000000000 - - - QAbstractSpinBox::AdaptiveDecimalStepType + Load Zone File - + - Delta + Edit Zone centers - - - 1 + + + 2000.000000000000000 - - 5 + + 0.100000000000000 - + - avgw - - - - - - - 1 - - - 2 - - - 3 + Save Zones @@ -137,7 +87,7 @@ - 3 + 5 -500.000000000000000 @@ -166,7 +116,7 @@ - 3 + 5 -500.000000000000000 @@ -198,7 +148,7 @@ 0 - 20 + 1000 5 diff --git a/profileplot.cpp b/profileplot.cpp index 03300e47..d2b8aacb 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -495,7 +495,32 @@ void ProfilePlot::populate() QPolygonF points = createProfile( m_showNm * m_showSurface,m_wf); cprofile->setSamples( points ); + /*if (m_showCorrection){ + // calculate and show percentages of correction + m_plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); + m_plot->setStyleSheet(" font: 12pt \"Deja Vu\";"); + SurfaceManager &sm = *SurfaceManager::get_instance(); + std::vector zernikes; + zernikes = sm.getCurrent()->InputZerns; + double z8 = zernikes[8]; //Z8 of current wavefront + + mirrorDlg &md = *mirrorDlg::get_Instance(); + double radius = md.m_clearAperature/2.; // mirror radius of clear aperture + // ROC of the mirror + double lambda_nm = md.lambda; + + double desiredZ8 = md.z8; + + m_pcdlg->show(); + m_pcdlg->raise(); + bool firstPlot = true; + QColor penColor = QColor("blue"); + m_pcdlg->plot(points, radius, md.roc, + md.cc,desiredZ8, lambda_nm, outputLambda,penColor, !firstPlot); + + + } */ break; } case 1: { // show 16 diameters diff --git a/simulationsview.cpp b/simulationsview.cpp index 5ffac6e5..9237d663 100644 --- a/simulationsview.cpp +++ b/simulationsview.cpp @@ -309,7 +309,7 @@ cv::Mat SimulationsView::computeStarTest(cv::Mat surface, int pupil_size, double } #endif // create star test using pupil_size which is usually smaller than the wavefront being sampled. -cv::Mat SimulationsView::computeStarTest(cv::Mat surface, int pupil_size, double pad , bool returnComplex){ +cv::Mat SimulationsView:: computeStarTest(cv::Mat surface, int pupil_size, double pad , bool returnComplex){ alias = false; cv::Mat out; From 7a4a33c66fabaaedbe864e03ccaebf3d4037054b Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Thu, 27 Feb 2025 00:03:02 -0600 Subject: [PATCH 09/25] reworked percentages to use many spherical terms. Working but want to try changing display to Q3D bar graph. --- mirrordlg.cpp | 2 +- percentcorrectiondlg.cpp | 832 +++++++++++++++++---------------------- percentcorrectiondlg.h | 80 ++-- percentcorrectiondlg.ui | 132 +++++-- profileplot.cpp | 166 +++++--- profileplot.h | 3 +- simigramdlg.cpp | 6 +- zernikeprocess.cpp | 309 +++------------ zernikesmoothingdlg.cpp | 51 ++- zernikesmoothingdlg.h | 5 +- zernikesmoothingdlg.ui | 7 + 11 files changed, 711 insertions(+), 882 deletions(-) diff --git a/mirrordlg.cpp b/mirrordlg.cpp index 8d6d8b63..192d42af 100644 --- a/mirrordlg.cpp +++ b/mirrordlg.cpp @@ -190,7 +190,7 @@ void mirrorDlg:: on_saveBtn_clicked() } QString extensionTypes(tr((m_useAnnular)? "config file (*.json)" : "config file (*.ini *.json)")); QString fileName = QFileDialog::getSaveFileName(0, - tr("Save stats file"), path, + tr("Save config file"), path, extensionTypes); if (fileName.isEmpty()) return; diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index fc3eca17..aa297e46 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -14,226 +14,13 @@ #include "surfacemanager.h" #include #include - - -ZonePicker::ZonePicker( QwtPlot *plot, QList *zones): - QObject( plot ), m_zonelist(zones),m_radius(100.), - d_selectedMarker( NULL ), d_selectedZone(-1) - -{ - QwtPlotCanvas *canvas = qobject_cast( plot->canvas() ); - canvas->installEventFilter( this ); - - // We want the focus, but no focus rect. The - // selected point will be highlighted instead. - - canvas->setFocusPolicy( Qt::StrongFocus ); -#ifndef QT_NO_CURSOR - canvas->setCursor( Qt::PointingHandCursor ); -#endif - canvas->setFocusIndicator( QwtPlotCanvas::ItemFocusIndicator ); - canvas->setFocus(); - canvas->setMouseTracking(true); - -} -void ZonePicker::reset(){ - moving = false; - onazone = false; - d_lastFound = NULL; - -} -QwtPlot *ZonePicker::plot() -{ - return qobject_cast( parent() ); -} - -const QwtPlot *ZonePicker::plot() const -{ - return qobject_cast( parent() ); -} - -bool ZonePicker::event( QEvent *ev ) -{ - if ( ev->type() == QEvent::User ) - { - return true; - } - return QObject::event( ev ); -} - -bool ZonePicker::eventFilter( QObject *object, QEvent *event ) -{ - if ( plot() == NULL || object != plot()->canvas() ) - return false; - - switch( event->type() ) - { - case QEvent::FocusIn: - { - break; - } - case QEvent::FocusOut: - { - break; - } - case QEvent::Paint: - { - QApplication::postEvent( this, new QEvent( QEvent::User ) ); - break; - } - case QEvent::MouseButtonPress: - { - const QMouseEvent *mouseEvent = static_cast( event ); - select( mouseEvent->pos() ); - return true; - } - case QEvent::MouseButtonRelease: - { - moving = false; - //select( mouseEvent->pos() ); - if (d_selectedZone != -1) - emit(zoneMoved(d_selectedZone, d_selectedMarker->xValue())); - return true; - } - case QEvent::MouseMove: - { - const QMouseEvent *mouseEvent = static_cast( event ); - move( mouseEvent->pos() ); - return true; - } - - - default: - break; - } - - return QObject::eventFilter( object, event ); -} - - -// Select the point at a position. If there is no point -// deselect the selected point - -void ZonePicker::select( const QPoint &pos ) -{ - QwtPlotMarker *mark = NULL; - double dist = 10e10; - - double px = pos.x(); - d_selectedMarker = NULL; - if (findItem(pos.x(), 10,QwtPlotItem::Rtti_PlotMarker)){ - d_selectedMarker->setVisible(true); - moving = true; - } - - - -} - -void ZonePicker::edit(bool b){ - m_editing = b; -} - -// Move the selected point -void ZonePicker::move( const QPoint &pos ) -{ - if (m_editing && !moving){ - QwtPlotMarker *found = findItem(pos.x(), 10, QwtPlotItem::Rtti_PlotMarker); - if (found){ - if (!onazone){ - d_lastFound = found; - highlight(d_lastFound, true); - onazone = true; - emit zoneSelected(d_selectedZone); - plot()->replot(); - } - } - else if (onazone){ - // turn off highlight - if (d_lastFound) - highlight(d_lastFound,false); - - plot()->replot(); - onazone = false; - } - return; - } - if ( d_selectedZone == -1) - return; - - double x = plot()->invTransform(d_selectedMarker->xAxis(), pos.x() ); - - if ( (d_selectedZone == m_zonelist->last() && (x >= m_radius * .9)) || - ((d_selectedZone < m_zonelist->length()-1) && x >= (*m_zonelist)[d_selectedZone+1])) - return; - if (d_selectedZone > 1 && x <= (*m_zonelist)[d_selectedZone -1]) - return; - - - d_selectedMarker->setXValue(x); - - d_selectedMarker->setLabel( QString("%1\n%2\%").arg(x, 0, 'f',1).arg(100. * x/m_radius,0,'f',1 )) ; - - emit(zoneMoved(d_selectedZone, d_selectedMarker->xValue())); - - - /* - Enable QwtPlotCanvas::ImmediatePaint, so that the canvas has been - updated before we paint the cursor on it. - */ - QwtPlotCanvas *plotCanvas = - qobject_cast( plot()->canvas() ); - - plotCanvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, true ); - plot()->replot(); - plotCanvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false ); - - -} - -QwtPlotMarker *ZonePicker::findItem(double x, double tolerance, QwtPlotItem::RttiValues type){ - const QwtPlotItemList& itmList = plot()->itemList(); - double px = x; - for ( QwtPlotItemIterator it = itmList.begin(); - it != itmList.end(); ++it ) - { - - if ( ( *it )->rtti() == type ){ - - QwtPlotMarker *m = static_cast( *it ); - if (m->lineStyle() != QwtPlotMarker::VLine) - continue; - const QwtScaleMap xMap = plot()->canvasMap(2); - - const double cx = xMap.transform( m->xValue()); - - double d = px - cx; - - if ( abs(d) < tolerance ){ - - for (int i = 0; i < m_zonelist->length(); ++i){ - double t = m_zonelist->at(i); - if (t == m->xValue()){ - d_selectedZone = i; - d_selectedMarker = m; - return m; - } - } - } - - } - } - return NULL; -} -void ZonePicker::highlight(QwtPlotMarker *m, bool flag){ - - // change pen color if selected. - if (flag) - m->setLinePen(Qt::darkBlue,4,Qt::DashLine); - else - m->setLinePen(Qt::red,2,Qt::DashLine); - -} +#include +#include +#include "zernikeprocess.h" +#include +#include +#include +#include percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : QDialog(parent),m_showZones(false), ui(new Ui::percentCorrectionDlg) @@ -241,7 +28,21 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : ui->setupUi(this); resize(1000,800); + Q3DBars *widgetgraph = new Q3DBars(); + QWidget *container = QWidget::createWindowContainer(widgetgraph); + + QHBoxLayout *hLayout = new QHBoxLayout(ui->bar3D); + + hLayout->addWidget(container, 1); + ui->bar3D->setWindowTitle(" how about this"); //setWindowFlags(Qt::WindowStaysOnTopHint); + + QCheckBox *smoothCheckBox = new QCheckBox(ui->bar3D); + smoothCheckBox->setText(QStringLiteral("Smooth bars")); + smoothCheckBox->setChecked(false); + hLayout->addWidget(smoothCheckBox); + mirrorDlg &md = *mirrorDlg::get_Instance(); + m_radius = md.m_clearAperature/2.; QSettings set; ui->minvalue->blockSignals(true); ui->maxvalue->blockSignals(true); @@ -249,7 +50,8 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : ui->maxvalue->setValue(set.value("percent_correction_max", 120).toDouble()); ui->minvalue->blockSignals(false); ui->maxvalue->blockSignals(false); - ui->zoneValue->hide(); + + m_number_of_zones = set.value("percent number of zones", 5).toInt(); ui->numberOfZones->blockSignals(true); @@ -259,12 +61,10 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : setGeometry(set.value("percent_Correction_dialogGeometry").toRect()); } - zonePicker = new ZonePicker(ui->plot, &zoneCenter); - connect(zonePicker,SIGNAL(zoneMoved(int, double)), this,SLOT(zoneMoved(int, double))); - connect(zonePicker,SIGNAL(zoneSelected(int)),this,SLOT(zoneSelected(int))); + makeZones(); } -// .0000018 -double g_laserLambda = 550.; //fixme should get this from the parent. + +double g_laserLambda = 550.; // a global so a none member function can access it. void percentCorrectionDlg::saveSettings(){ QJsonObject myJsonObject; @@ -273,7 +73,7 @@ void percentCorrectionDlg::saveSettings(){ QJsonArray jzones; for (const auto &item : zoneCenter) { - jzones.append(item); + jzones.append((double)item/m_radius); // zone centers are saved as a percentage. } myJsonObject["zones"] = jzones; QSettings set; @@ -281,10 +81,12 @@ void percentCorrectionDlg::saveSettings(){ set.setValue("correctionZones", jsonDoc.toJson(QJsonDocument::Compact)); } + + + /**************************************************** * zone data. If none to begin with use 5 zones. * if last zones then use those. - * if user wants to change let hime but make him press accept * allow loading and saveing of zones * allways save current accpeted zones in settings probalby in json format. */ @@ -301,62 +103,164 @@ QList generateZoneCenters(double radius, int number_of_zones){ for (int i = 0; i < number_of_zones; ++i){ double zoneCenter = (lastzone + zoneedge[i])/2.; lastzone = zoneedge[i]; - zoneCenters << zoneCenter; + zoneCenters << QString::number(zoneCenter,'f',0).toDouble(); } return zoneCenters; } +void percentCorrectionDlg::updateZoneTable(){ + ui->zoneTable->clearContents(); + ui->zoneTable->setRowCount(zoneCenter.size()); + ui->zoneTable->blockSignals(true); + for (int i = 0; i < zoneCenter.size(); ++i) { + QTableWidgetItem *item = new QTableWidgetItem(QString::number(zoneCenter[i],'f',0)); + ui->zoneTable->setItem(i, 0, item); + item->setTextAlignment(Qt::AlignRight); + } + ui->zoneTable->blockSignals(false); +} +QJsonDocument percentCorrectionDlg::loadZonesFromJson(QString str){ + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(str.toUtf8(), &jsonError); + QJsonObject jsonData=jsonDoc.object(); + QJsonArray zones = jsonData["zones"].toArray(); + + + zoneCenter.clear(); + ui->zoneTable->clearContents(); + ui->zoneTable->setRowCount(zones.size()); + + for (int i = 0; i < zones.size(); ++i) { + double d = zones[i].toDouble()* m_radius; + + zoneCenter.append(QString::number(d,'f',0).toDouble() ); + } + return jsonDoc; +} + +arma::mat percentCorrectionDlg::makeZoneZerns(QList centers){ + std::vector rhovec, thetavec; + + // creaate rowvec or rho and theta. Theta will only be 0. + for (int i = 0; i < centers.length(); ++i){ + + double rho = centers[i]; + rhovec.push_back(rho); + thetavec.push_back(0.); + } + + arma::rowvec rhov(rhovec), thetav(thetavec); + + zernikeProcess zp; + zp.setMaxOrder(m_maxOrder); + + arma::mat theZs = zp.zpmC(rhov, thetav, m_maxOrder); + return theZs; +} + void percentCorrectionDlg::makeZones(){ QSettings set; if (!set.contains("correctionZones")){ generateZoneCenters(m_radius, m_number_of_zones); + saveSettings(); } else { // read zones from settings // if mirror is different now than last then make the same number of zones but with new radius values QString jsonString = set.value("correctionZones").toString(); - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8(), &jsonError); - QJsonObject jsonData=jsonDoc.object(); - QJsonArray zones = jsonData["zones"].toArray(); - double roc = jsonData["roc"].toDouble(); - zoneCenter.clear(); - for (int i = 0; i < zones.size(); ++i) { - zoneCenter.append(zones[i].toDouble()); - } + QJsonDocument doc = loadZonesFromJson(jsonString); // if number of zones has changed then generate new zones. - if ((zones.size() != m_number_of_zones) || (m_radius != jsonData["mirror radius"].toDouble())){ + if ((zoneCenter.size() != m_number_of_zones) || (m_radius != doc.object()["mirror radius"].toDouble())){ zoneCenter = generateZoneCenters(m_radius, m_number_of_zones); saveSettings(); } } + updateZoneTable(); + zoneZerns = makeZoneZerns(zoneCenter); +} +/* + * // creaate rowvec or rho and theta. Theta will only be 0. + std::vector rhovec, thetavec; + + for (double r = 0; r < m_radius; ++r){ + double rho = r/m_radius; + rhovec.push_back(rho); + thetavec.push_back(0.); + } + arma::rowvec rhov(rhovec), thetav(thetavec); + zernikeProcess zp; + arma::mat theZs = zp.zpmC(rhov, thetav, maxorder); -} -double getZernSurface( double RoC, double MirrorRad, double Zernikes[], double radius){ - - double num1 = radius / MirrorRad; - if (num1 > 1.0) - num1 = 1.0; - double num2 = num1 * num1; - double num3 = num2 * num2; - double num4 = num3 * num2; - double num5 = num3 * num3; - double num6 = num5 * num2; - - double num7 = 0.0 + Zernikes[8] * (1.0 - 6.0 * num2 + 6.0 * num3) + Zernikes[15] * (1.0 + 12.0 * num2 - 30.0 * num3 + 20.0 * num4) + Zernikes[24] * (1.0 - 20.0 * num2 + 90.0 * num3 - 140.0 * num4 + 70.0 * num5) + Zernikes[35] * (1.0 + 30.0 * num2 - 210.0 * num3 + 560.0 * num4 - 630.0 * num5 + 252.0 * num6); - double spherey = RoC - sqrt(pow(RoC, 2.0) - pow(radius, 2.0)); - double zerny = num7 * g_laserLambda * .5E-6; + + double rho = rhov(10); + double num1 = rho; + + double num2 = num1 * num1; + double num3 = num2 * num2; + double num4 = num3 * num2; + double num5 = num3 * num3; + double num6 = num5 * num2; + + double z8 = (1.0 - 6.0 * num2 + 6.0 * num3); + double z15 =(-1.0 + 12.0 * num2 - 30.0 * num3 + 20.0 * num4); + double z24 = (1.0 - 20.0 * num2 + 90.0 * num3 - 140.0 * num4 + 70.0 * num5); + + + qDebug() << "rho" << rho << z8 << z15 << z24; + qDebug() << "rho" << rho << "theZs8" << theZs(10,8) << theZs(10,15) << theZs(10,24); +*/ +int maxorder = 18; +double percentCorrectionDlg::getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x){ + + double num1 = x / MirrorRad; + + + + arma::rowvec rhov(1), thetav(1); + rhov[0] = x/m_radius; thetav[0] = 0.; + zernikeProcess zp; + zp.setMaxOrder(m_maxOrder); + + arma::mat theZs = zp.zpmC(rhov, thetav, m_maxOrder); + + + double val = 0; + // for each spherical term + int z = 8; + for(unsigned int j = 6; z < theZs.n_cols; j+=2){ + val += Zernikes[z] * theZs(0,z); + z = j * j /4 + j; + } + +// double num2 = num1 * num1; +// double num3 = num2 * num2; +// double num4 = num3 * num2; +// double num5 = num3 * num3; +// double num6 = num5 * num2; + + +// double num7 = 0.0 + Zernikes[8] * (1.0 - 6.0 * num2 + 6.0 * num3) + +// Zernikes[15] * (-1.0 + 12.0 * num2 - 30.0 * num3 + 20.0 * num4) + +// Zernikes[24] * (1.0 - 20.0 * num2 + 90.0 * num3 - 140.0 * num4 + 70.0 * num5) + +// Zernikes[35] * (-1.0 + 30.0 * num2 - 210.0 * num3 + 560.0 * num4 - 630.0 * num5 + 252.0 * num6); + + +// qDebug() << "rho" << num1 << val << num7; + double spherey = RoC - sqrt(pow(RoC, 2.0) - pow(x, 2.0)); + double zerny = val * m_lambda_nm * .5E-6; double surf = spherey + zerny; return surf; } + // will use zernike values to compute two surface points x+- .01x away from x // then compute normal slope from that. -double getnormalSlope(double RoC, double radius, double Zernikes[], double x){ +double percentCorrectionDlg::getnormalSlope(double RoC, double radius, std::vector Zernikes, double x){ + double num1 = x / 100.0; - double surface1 = getZernSurface(RoC, radius, Zernikes, x - num1); + double surface1 = getZernSurface(RoC, radius, Zernikes, x - num1); // problem with zonendx (the delta is not same as zonendx) double surface2 = getZernSurface(RoC, radius, Zernikes, x + num1); double slope = (surface2 - surface1)/ (2 * num1); slope = -1.0 / slope; @@ -367,12 +271,13 @@ double getnormalSlope(double RoC, double radius, double Zernikes[], double x){ // y = mx + b // b = y - mx -double GetActualKE(double RoC, double MirrorRad, double Zernikes[], double Z_Radius) +double percentCorrectionDlg::GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, double x) { - double slope = getnormalSlope(RoC, MirrorRad, Zernikes, Z_Radius); - double surface = getZernSurface(RoC, MirrorRad, Zernikes, Z_Radius); - double actualKe = surface - Z_Radius * slope - RoC; + double slope = getnormalSlope(RoC, MirrorRad, Zernikes, x); + double surface = getZernSurface(RoC, MirrorRad, Zernikes, x); + + double actualKe = surface - x * slope - RoC; return actualKe; } @@ -381,51 +286,8 @@ double getIdealKE(double RoC, double Z_Radius) { return pow(Z_Radius, 2.0) / (2.0 * RoC); } -/* - * paraby(x) = spherey(x) + profile(x) + ? - * - * - */ -void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ - - int smoothrange = .1 * m_size; - m_z8 = 0.; - QPolygonF expectedslope; - QPolygonF actualslope; - QPolygonF percentplot; - QPolygonF franzPrecentPlot; - QPolygonF actualSurface; - QPolygonF idealSurface; - QPolygonF correction; +QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ - QPolygonF data; - SurfaceManager &sm = *SurfaceManager::get_instance(); - std::vector zernikes; - - auto getSphereY = [] (double roc, double x){ - return roc - sqrt(pow(roc,2) - pow(x,2)); - }; - auto getNull = [] (double roc, double radius, double x, double c8, double wavelength){ - double r = x/radius; - - double val = wavelength * 1.E-5 * .5 * c8 * (6. * pow(r,4) - 6. * pow(r,2) +1); - return val; - }; - // return in mm - auto getConicY = [] (double roc, double conic, double x){ - double y = pow(x,2)/(roc + (sqrt(pow(roc,2) - ((conic + 1) * pow(x,2))))); - return y; - }; - auto average = [] (QPolygonF &data, int width, int ndx){ - return data[ndx].y(); - int cnt = 0; - double sum = 0.; - for (int i = ndx - width; i <= ndx + width; ++i){ - sum += data[i].y(); - ++cnt; - } - return sum/cnt; - }; auto knifeDeltas = [](QPolygonF &knives){ double last = knives[0].y(); QPolygonF deltas; @@ -444,55 +306,13 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ return percent; }; - - double roc = m_roc + m_roc_offset; - - zernikes = sm.getCurrent()->InputZerns; - - double wavelength =1e-6 * m_outputLambda; // surface error - int smoothsize = 1 ; - - double C8 = mirrorDlg::get_Instance()->z8; - double conic = mirrorDlg::get_Instance()->cc; - - // smooth and convert to surface error in mm. -// double min = 999999.; -// for (int i = 0; i < m_avg.size(); ++i){ -// min = fmin(min, m_avg[i].y()); -// } - for (int i = (m_avg.size()-1)/2; i < m_avg.size(); ++i){ - //save error y in mm on surface - // Lets try adding the null back into it - // then later on add a sphere to it and see if it matches the zern version - data << QPointF(m_avg[i ].x(), (m_avg[i].y()) * .5E-6 * m_outputLambda ); - - - - } - - - // find the x entry in the surface that is closest to the zone value - indexOfZoneCenter.clear(); - - for (int i = 0; i < m_number_of_zones; ++i){ - int ndx = 0; - for (; ndx < data.size(); ++ ndx){ - double d = data[ndx].x(); - if (d >= zoneCenter[i]) - break; - } - //zoneCenter << zoneCenter[i]; - indexOfZoneCenter << ndx; - } - + QPolygonF percentage; // start at the mirrors middle QVector IdealzoneKnife; QVector ActualZoneKnife; QVector idealDelta; QVector actualDelta; - - int zone = 0; IdealzoneKnife << 0.; ActualZoneKnife << 0.0; @@ -504,27 +324,20 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ QPolygonF zernKnives; QPolygonF zernSurf; - - - double idealoffset = 0.; double zernOffset = 0.; for (int zone = 0; zone < zoneCenter.length(); ++zone){ - int ndx = indexOfZoneCenter[zone]; - double x = data[ndx].x(); - double idealy = getConicY(roc, conic, x); - double y = data[ndx].y() + idealy; - double zernsurf = getZernSurface(roc,m_radius, zernikes.data(), x); + double x = zoneCenter[zone]; + - zernSurf << QPointF(x, zernsurf); //idealSurface << QPointF(x, normIdealSlope); - double idealknife = getIdealKE(roc, x); - double zernKnife = GetActualKE(roc, m_radius, zernikes.data(), x); + double idealknife = getIdealKE(m_roc, x); + double zernKnife = GetActualKE(m_roc, m_radius, surf->zernvalues, x); if (zone == 0){ idealoffset = idealknife; @@ -541,77 +354,32 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ QPolygonF idealDeltas = knifeDeltas(idealknives); QPolygonF zernDeltas = knifeDeltas(zernKnives); - correction = getZoneCorrection(idealDeltas, zernDeltas); - QPolygonF profileCorrections = getZoneCorrection(idealDeltas, zernDeltas); - - - QPolygonF bars; + QPolygonF correction = getZoneCorrection(idealDeltas, zernDeltas); + return correction; +} +void percentCorrectionDlg::plot(){ + QPolygonF expectedslope; + QPolygonF actualslope; + QPolygonF percentplot; + QPolygonF franzPrecentPlot; + QPolygonF actualSurface; + QPolygonF idealSurface; + QPolygonF correction; - if (!addToPlot) - ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); - - // draw zone rectangles - if (!ui->editEnable->isChecked()){ - double width; - for(int i = 0; i < profileCorrections.length(); ++i){ - - double y = profileCorrections[i].y(); - - if (i < profileCorrections.length()-1) - width= .80 * (profileCorrections[i+1].x() - profileCorrections[i].x()) ; + QPolygonF data; - QwtPlotShapeItem *rectangleItem = new QwtPlotShapeItem(); + std::vector zernikes; - rectangleItem->setRect(QRectF(profileCorrections[i].x()-width/2,0,width,y)); + // first get the zernike poly spherical terms at each zone center. + for (int c = 0; c < zoneCenter.length(); ++c){ - QPen pen(Qt::black); - pen.setWidth(3); - rectangleItem->setPen(pen); - rectangleItem->setBrush(QBrush(Qt::lightGray)); - rectangleItem->attach(ui->plot); - rectangleItem->setZ(0); - QwtPlotMarker *label = new QwtPlotMarker(); - label->setLineStyle(QwtPlotMarker::NoLine); - label->setLabel(QString("%1\%").arg(y, 0, 'f',1)) ; - label->setValue(profileCorrections[i].x(), y-10); - label->attach(ui->plot); - } - } - // draw markers - for (int i = 0; i < zoneCenter.size(); ++i) { - double center= zoneCenter[i]; - QwtPlotMarker *marker = new QwtPlotMarker(); - marker->setLineStyle(QwtPlotMarker::VLine); // Set the line style to vertical - marker->setLinePen(Qt::red,2,Qt::DashLine); - marker->setLabelAlignment(Qt::AlignLeft); - marker->setXValue(center); - if (!ui->editEnable->isChecked()) - marker->setVisible(false); - marker->attach(ui->plot); - - QwtPlotMarker *label = new QwtPlotMarker(); - label->setLineStyle(QwtPlotMarker::NoLine); - label->setLabel(QString("%1\n%2\%").arg(center, 0, 'f',1).arg(100. * center/m_radius,0,'f',1 )) ; - label->setLabelAlignment(Qt::AlignCenter); - label->setXValue(center); - label->setYValue(-23); - label->attach(ui->plot); - - // draw zone number - QwtPlotMarker *marker2 = new QwtPlotMarker(); - marker2->setLineStyle(QwtPlotMarker::NoLine); - marker2->setLabel(QString().number(i+1)); - marker2->setLabelAlignment(Qt::AlignCenter); - marker2->setYValue(-5); - marker2->setXValue(center); - marker2->attach(ui->plot); } + ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); QwtPlotGrid *grid = new QwtPlotGrid(); - grid->setZ(1); grid->enableXMin(true); @@ -622,73 +390,110 @@ void percentCorrectionDlg::replot(QColor penColor, bool addToPlot){ grid->setMinorPen(Qt::black, 1.0, Qt::DotLine); grid->attach( ui->plot); - ui->plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); + // for each surface draw the percent plot + for (int i = 0; i < surfs.length(); ++ i) { + // make percentages + QPolygonF percent = makePercentages( surfs[i]); + QPolygonF bars; - QwtPlotCurve *slopeCurve3 = new QwtPlotCurve("zern correction"); - slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowSymbol,true ); - slopeCurve3->setLegendAttribute(QwtPlotCurve::LegendShowLine,true ); - slopeCurve3->setItemAttribute(QwtPlotCurve::Legend,true); - slopeCurve3->setSamples(profileCorrections); - slopeCurve3->attach(ui->plot); - slopeCurve3->setPen(Qt::blue,5); + if (surfs.length() < 2) { + // draw zone rectangles + if (ui->showBars->isChecked()){ + double width; + for(int i = 0; i < percent.length(); ++i){ + + double y = percent[i].y(); + if (i < percent.length()-1) + width= .80 * (percent[i+1].x() - percent[i].x()) ; + QwtPlotShapeItem *rectangleItem = new QwtPlotShapeItem(); + rectangleItem->setRect(QRectF(percent[i].x() - width/2. ,0,width,y)); + + QPen pen(Qt::black); + pen.setWidth(3); + rectangleItem->setPen(pen); + rectangleItem->setBrush(QBrush(Qt::lightGray)); + rectangleItem->attach(ui->plot); + rectangleItem->setZ(0); + QwtPlotMarker *label = new QwtPlotMarker(); + label->setLineStyle(QwtPlotMarker::NoLine); + label->setLabel(QString("%1\%").arg(y, 0, 'f',1)) ; + label->setValue(percent[i].x(), y-10); + label->attach(ui->plot); + } + } + } + + + + if (surfs.length() == 1) { + // draw markers + for (int i = 0; i < zoneCenter.size(); ++i) { + double center= zoneCenter[i]; + QwtPlotMarker *marker = new QwtPlotMarker(); + marker->setLineStyle(QwtPlotMarker::VLine); // Set the line style to vertical + marker->setLinePen(Qt::red,2,Qt::DashLine); + marker->setLabelAlignment(Qt::AlignLeft); + marker->setXValue(center); + marker->attach(ui->plot); + + QwtPlotMarker *label = new QwtPlotMarker(); + label->setLineStyle(QwtPlotMarker::NoLine); + label->setLabel(QString("%1\n%2\%").arg(center, 0, 'f',1).arg(100. * center/m_radius,0,'f',1 )) ; + label->setLabelAlignment(Qt::AlignCenter); + label->setXValue(center); + label->setYValue(-23); + label->attach(ui->plot); + + // draw zone number + QwtPlotMarker *marker2 = new QwtPlotMarker(); + marker2->setLineStyle(QwtPlotMarker::NoLine); + marker2->setLabel(QString().number(i+1)); + marker2->setLabelAlignment(Qt::AlignCenter); + marker2->setYValue(-5); + marker2->setXValue(center); + marker2->attach(ui->plot); + } + } + + + + QwtPlotCurve *slopeCurve3 = new QwtPlotCurve(); + + slopeCurve3->setSamples(percent); + slopeCurve3->attach(ui->plot); + slopeCurve3->setPen(surfs[i]->penColor,5); ui->plot->setAxisTitle( ui->plot->yLeft, "Percent correction" ); ui->plot->setAxisScale(ui->plot->yRight, -10, 20, 1); - ui->plot->setAxisTitle( ui->plot->xTop, "Radius mm" ); + ui->plot->setAxisTitle( ui->plot->xBottom, "Radius mm" ); slopeCurve3->setZ(1); ui->plot->setAxisScale(QwtPlot::yLeft, ui->minvalue->value(), ui->maxvalue->value()); ui->plot->setAxisScale(QwtPlot::xBottom, 0, m_radius); - - ui->plot->replot(); } -void percentCorrectionDlg::zoneSelected(int ndx){ - m_currentSelectedZone = ndx; - ui->zoneValue->blockSignals(true); - ui->zoneValue->setValue(zoneCenter[ndx]); - ui->zoneValue->blockSignals(false); + ui->plot->replot(); } -void percentCorrectionDlg::zoneMoved(int ndx, double value){ - zoneCenter[ndx] = value; - ui->zoneValue->blockSignals(true); - ui->zoneValue->setValue(value); - ui->zoneValue->blockSignals(false); - saveSettings(); - replot(); -} -void percentCorrectionDlg::plot( QPolygonF avg, double radius,double roc, double z8, - double desiredZ8, - double lambda_nm, double outputLambda, - QColor penColor, bool addToPlot){ +void percentCorrectionDlg::setData( QVector< surfaceData *> data) { - zonePicker->m_radius = radius; - m_avg = avg; - m_radius = radius; - surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); - if (saTools->m_useDefocus){ // if defocus compute new SA null Desired Z8 - double fnumber = mirrorDlg::get_Instance()->FNumber; - m_roc_offset = fnumber * fnumber * 8. * saTools->m_defocus * .055; //mmeters - } - else { - m_roc = roc; - } + mirrorDlg &md = *mirrorDlg::get_Instance(); + m_roc = md.roc; + m_lambda_nm = md.lambda; + m_radius = md.m_clearAperature/2.; + surfs = data; - m_z8 = z8; - m_desiredZ8 = desiredZ8; - g_laserLambda = m_lambda_nm = lambda_nm; - m_outputLambda = outputLambda; - m_size = avg.size()-1; + // create surface samples every 1mm. + // THen change the zone logic to match. //it is possible that the zones have yet to be set go read them from the settings. // it will make them if needed. makeZones(); - replot(penColor, addToPlot); + plot(); } percentCorrectionDlg::~percentCorrectionDlg() @@ -701,7 +506,7 @@ void percentCorrectionDlg::on_minvalue_valueChanged(double arg1) { QSettings set; set.setValue("percent_correction_min",arg1); - emit percent_plot_changed(); + plot(); } @@ -709,7 +514,7 @@ void percentCorrectionDlg::on_maxvalue_valueChanged(double arg1) { QSettings set; set.setValue("percent_correction_max", arg1); - emit percent_plot_changed(); + plot(); } void percentCorrectionDlg::closeEvent(QCloseEvent *event) { @@ -728,9 +533,9 @@ void percentCorrectionDlg::on_numberOfZones_valueChanged(int arg1) m_number_of_zones = arg1; QSettings set; set.setValue("percent number of zones", arg1); - zonePicker->reset(); + makeZones(); - replot(); + plot(); } @@ -744,32 +549,101 @@ void percentCorrectionDlg::on_help_clicked() void percentCorrectionDlg::on_loadZones_clicked() { + QSettings set; + QString path = set.value("projectPath").toString(); + QString extensionTypes(tr( "zone file (*.zones)")); + QString fileName = QFileDialog::getOpenFileName(0, + tr("Read zone file"), path, + extensionTypes); + if (fileName.isEmpty()) + return; + QFile file(fileName); + + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + //qDebug() << "Failed to open file"; + return; + } + + QTextStream in(&file); + QString line = in.readLine(); + + file.close(); + + QJsonDocument doc = loadZonesFromJson(line); + QJsonObject jsonData=doc.object(); + if (jsonData.contains("aborted")) + return; + QJsonArray zones = jsonData["zones"].toArray(); + m_number_of_zones = zones.size(); + ui->numberOfZones->blockSignals(true); + ui->numberOfZones->setValue(m_number_of_zones); + ui->numberOfZones->blockSignals(false); + saveSettings(); + //emit percent_plot_changed(); } void percentCorrectionDlg::on_saveZones_clicked() { + QSettings set; + QString path = set.value("projectPath").toString(); + QString extensionTypes(tr( "zone file (*.zones)")); + QString fileName = QFileDialog::getSaveFileName(0, + tr("Save zone file"), path, + extensionTypes); + if (fileName.isEmpty()) + return; + if (QFileInfo(fileName).suffix().isEmpty()) { fileName.append(".zones"); } + QString jsonString = set.value("correctionZones").toString(); + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qDebug() << " failed to read zones file."; + //return false; // Failed to open file for writing + } + + QTextStream out(&file); + out << jsonString; + file.close(); + set.setValue("projectPath", QFileInfo(fileName).absolutePath()); } -void percentCorrectionDlg::on_editEnable_toggled(bool checked) + + + + +void percentCorrectionDlg::on_zoneTable_itemChanged(QTableWidgetItem *item) { - zonePicker->edit(checked); - ui->zoneValue->setEnabled(checked); - if (!checked) - ui->zoneValue->hide(); - else - ui->zoneValue->show(); - replot(); + qDebug() << "item changed" << item->row() << item->text(); + zoneCenter[item->row()] = item->text().toDouble(); + + saveSettings(); + plot(); } -void percentCorrectionDlg::on_zoneValue_valueChanged(double arg1) + + +void percentCorrectionDlg::on_showBars_clicked(bool checked) { - zoneCenter[m_currentSelectedZone] = arg1; - replot(); + plot(); +} + +void percentCorrectionDlg::on_Generate_clicked() +{ + emit make_percent_correction(m_maxOrder); +} + + +void percentCorrectionDlg::on_maxOrder_valueChanged(int arg1) +{ + m_maxOrder = arg1; + qDebug() << "maxorder" << arg1; + int mmax = arg1/2; + int ncol = (mmax+1)*(mmax+1); + ui->noOfTerms->setText(QString::number(ncol)); } diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h index ca9c3afb..2dc59b23 100644 --- a/percentcorrectiondlg.h +++ b/percentcorrectiondlg.h @@ -5,45 +5,24 @@ #include #include #include +#include +#include namespace Ui { class percentCorrectionDlg; } -class ZonePicker: public QObject -{ - Q_OBJECT - QList *m_zonelist; - bool moving = false; - bool onazone = false; - -public: - bool m_editing = false; - QwtPlotMarker *d_lastFound = NULL; - double m_radius; - ZonePicker( QwtPlot *plot, QList *zones ); - virtual bool eventFilter( QObject *, QEvent * ); - - virtual bool event( QEvent * ); - void edit(bool b); - void reset(); -Q_SIGNALS: - void zoneMoved(int zone, double rad); - void zoneSelected(int ndx); - -private: - QwtPlotMarker *findItem(double x, double tolerance, QwtPlotItem::RttiValues type); - void select( const QPoint & ); - void move( const QPoint & ); - void release(); - void highlight(QwtPlotMarker *m, bool flag); - QwtPlot *plot(); - const QwtPlot *plot() const; +class surfaceData { + public: - QwtPlotMarker *d_selectedMarker; + double igramlambda; + QColor penColor; + // set of zernike values at each zone (rho) + std::vector zernvalues; - int d_selectedZone; + surfaceData( double igramlambda, QColor pen, std::vector zernvalues): igramlambda(igramlambda), + penColor(pen), zernvalues(zernvalues){}; +} ; -}; class percentCorrectionDlg : public QDialog { Q_OBJECT @@ -57,25 +36,34 @@ class percentCorrectionDlg : public QDialog bool m_showZones; double m_roc; double m_roc_offset = 0.; + arma::mat zoneZerns; QList zoneCenter; QList zoneedge; - QList indexOfZoneCenter; - ZonePicker *zonePicker; + + QPolygonF m_avg; + int m_currentprofileIndex = 0; int m_currentSelectedZone = -1; + int m_maxOrder = 12; + QVector surfs; + QPolygonF makePercentages(surfaceData *); + double getnormalSlope(double RoC, double radius, std::vector Zernikes, double x); + double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x); + double GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, double x); signals: void percent_plot_changed(); + void make_percent_correction(int maxOrder); protected: void closeEvent(QCloseEvent *event); void moveEvent(QMoveEvent *event); public: explicit percentCorrectionDlg( QWidget *parent = nullptr); ~percentCorrectionDlg(); - QPolygonF m_avg; - void plot(QPolygonF avg, double radius,double roc, double z8, - double desiredZ8, double lambda_nm, double outputlampda, - QColor penColor, bool addToPlot = false); - void replot(QColor penColor = Qt::blue, bool addToPlot = false); - + std::vector m_zerns; + void setData(QVector< surfaceData *> ); + void plot(); + void updateZoneTable(); + QJsonDocument loadZonesFromJson(QString str); + double GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, int zone); private slots: void on_minvalue_valueChanged(double arg1); @@ -86,19 +74,19 @@ private slots: void on_help_clicked(); - void zoneMoved(int ndx, double value); - - void zoneSelected(int ndx); - void on_loadZones_clicked(); void on_saveZones_clicked(); - void on_editEnable_toggled(bool checked); + void on_zoneTable_itemChanged(QTableWidgetItem *item); + + void on_showBars_clicked(bool checked); - void on_zoneValue_valueChanged(double arg1); + void on_Generate_clicked(); + void on_maxOrder_valueChanged(int arg1); + arma::mat makeZoneZerns(QList centers); private: Ui::percentCorrectionDlg *ui; diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index c343ee93..d5ddb638 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -23,23 +23,6 @@ - - - - Edit Zone centers - - - - - - - 2000.000000000000000 - - - 0.100000000000000 - - - @@ -60,6 +43,50 @@ + + + + Max Order + + + + + + + 10 + + + 100 + + + 2 + + + 12 + + + + + + + Qt::Vertical + + + + + + + Zernike Terms + + + + + + + 35 + + + @@ -132,6 +159,16 @@ + + + + Show bars + + + true + + + @@ -158,11 +195,62 @@ - - - - - + + + + + 5 + + + 1 + + + + + + + + + zone center + + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Generate + + + + diff --git a/profileplot.cpp b/profileplot.cpp index d2b8aacb..d2a6e7af 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -94,11 +94,11 @@ bool ProfilePlot::eventFilter( QObject *object, QEvent *event ) ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): QWidget( parent ), m_wf(0), m_tools(tools), m_showSurface(1.),m_showNm(1.),dragging(false), - offsetType("Middle"),ui(new Ui::ProfilePlot), m_defocusValue(0.) + offsetType("Middle"), m_defocusValue(0.),ui(new Ui::ProfilePlot) { m_pcdlg = new percentCorrectionDlg; - QObject::connect(m_pcdlg, SIGNAL(percent_plot_changed()), this, SLOT(populate())); + QObject::connect(m_pcdlg, SIGNAL(make_percent_correction(int)), this, SLOT(make_correction_graph(int))); zoomed = false; m_defocus_mode = false; m_plot = new QwtPlot(this); @@ -427,7 +427,103 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ } return points; } +// create a smoothed wave front with only spherical terms. +// Use that to get zernike values to send to percent completion feature +// display the profile and then send the zerns to percent completion +// have to decide what is maxOrder + +zernikeProcess *zp = NULL; +int maxOrder = 18; +void ProfilePlot::make_correction_graph( int maxOrder){ + m_showCorrection = true; + + // for each selected wave front + zernikeProcess zp; + zp.setMaxOrder(maxOrder); + + surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); + QList list = saTools->SelectedWaveFronts(); + if (list.length() == 0) + list << 0; + QVector < surfaceData *> surfs; + for (int i = 0; i < list.size(); ++i){ + QStringList path = wfs->at(list[i])->name.split("/"); + QString name = path.last().replace(".wft",""); + + // compute zerns using the new maxorder zern set + zp.initGrid(*wfs->at(list[i]), maxOrder); + std::vector theZerns = zp.ZernFitWavefront(*wfs->at(list[i])); + + // send zernike values to the correction dialog to have it plot correction based on them. + + 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); + } + m_pcdlg->setData(surfs); +} +#ifdef notnow +extern double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double radius); + +QPolygonF ProfilePlot::createZernProfile(wavefront *wf){ + mirrorDlg &md = *mirrorDlg::get_Instance(); + double radius = md.m_clearAperature/2.; // mirror radius of clear aperture + + double RoC = md.roc; + if (zp == NULL) + zp = new zernikeProcess; + zp->initGrid(*wf, maxOrder); + std::vector theZerns; + theZerns = zp->ZernFitWavefront(*wf); + + // make the profl + int wx = wf->data.size[1]; + + int numType = CV_64FC1; + cv::Mat result = cv::Mat::zeros(wx,wx, numType); + + + + // apply the artificial null + theZerns[8] -= md.z8 * md.cc; + // build surface with only spherical terms + for (unsigned long long i = 4; i < zp->m_zerns.n_rows; ++i){ + + double S1 = 0.0; + unsigned int z = 8; + for (unsigned int j = 5; z < theZerns.size(); ++j){ + + double val = theZerns[z]; + S1 += val * zp->m_zerns(i,z); + + z = j * j/4 + j; + } + int x = zp->m_col[i]; + int y = zp->m_row[i]; + if (S1 == 0.0) S1 += .0000001; + result.at(y,x) = S1; + if (y == wx/2.){ + qDebug() << x << y << S1; + } + + } + QPolygonF surf; + int half = result.cols/2; + for (int i = 0; i < result.cols; ++i){ + // map 0 - n to -radius to radius + double x = -radius + 2 * ((double)i/result.cols) * radius; + surf << QPointF(x,result.at(i,half)); + //qDebug() << surf.last(); + } + //m_pcdlg->plot(1, theZerns, radius, md.roc, + //md.cc,md.z8, md.lambda, outputLambda,Qt::black); + return surf; +} + +extern double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double radius); +#endif void ProfilePlot::populate() { @@ -476,7 +572,8 @@ void ProfilePlot::populate() m_plot->detachItems( QwtPlotItem::Rtti_PlotMarker); - switch (type) { + + switch (type) { case 0:{ // show one QStringList path = wfs->at(0)->name.split("/"); QString name; @@ -495,34 +592,10 @@ void ProfilePlot::populate() QPolygonF points = createProfile( m_showNm * m_showSurface,m_wf); cprofile->setSamples( points ); - /*if (m_showCorrection){ - // calculate and show percentages of correction - m_plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); - - m_plot->setStyleSheet(" font: 12pt \"Deja Vu\";"); - SurfaceManager &sm = *SurfaceManager::get_instance(); - std::vector zernikes; - zernikes = sm.getCurrent()->InputZerns; - double z8 = zernikes[8]; //Z8 of current wavefront - - mirrorDlg &md = *mirrorDlg::get_Instance(); - double radius = md.m_clearAperature/2.; // mirror radius of clear aperture - // ROC of the mirror - double lambda_nm = md.lambda; - - double desiredZ8 = md.z8; - - m_pcdlg->show(); - m_pcdlg->raise(); - bool firstPlot = true; - QColor penColor = QColor("blue"); - m_pcdlg->plot(points, radius, md.roc, - md.cc,desiredZ8, lambda_nm, outputLambda,penColor, !firstPlot); - - } */ break; } + case 1: { // show 16 diameters surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); @@ -596,31 +669,6 @@ void ProfilePlot::populate() cprofileavg->attach( m_plot ); g_angle = startAngle; - if (m_showCorrection){ - // calculate and show percentages of correction - m_plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); - - m_plot->setStyleSheet(" font: 12pt \"Deja Vu\";"); - SurfaceManager &sm = *SurfaceManager::get_instance(); - std::vector zernikes; - zernikes = sm.getCurrent()->InputZerns; - double z8 = zernikes[8]; //Z8 of current wavefront - - mirrorDlg &md = *mirrorDlg::get_Instance(); - double radius = md.m_clearAperature/2.; // mirror radius of clear aperture - // ROC of the mirror - double lambda_nm = md.lambda; - - double desiredZ8 = md.z8; - - m_pcdlg->show(); - m_pcdlg->raise(); - m_pcdlg->plot(avg, radius, md.roc, - md.cc,desiredZ8, lambda_nm, outputLambda,penColor, !firstPlot); - - - } - firstPlot = false; } @@ -776,10 +824,14 @@ void ProfilePlot::contourPointSelected(const QPointF &pos){ } void ProfilePlot::showCorrection(bool show){ - m_showCorrection = show; - Show16->setChecked(show); - if (!show) + //m_showCorrection = show; + if (show){ + m_pcdlg->show(); + m_pcdlg->raise(); + + } + else m_pcdlg->close(); - show16(); + } diff --git a/profileplot.h b/profileplot.h index cb1c060d..d1c52b03 100644 --- a/profileplot.h +++ b/profileplot.h @@ -88,7 +88,8 @@ public slots: void contourPointSelected(const QPointF &pos); void populate(); void showCorrection(bool); - + void make_correction_graph(int maxOrder); + //QPolygonF createZernProfile(wavefront *wf); private: void updateGradient(); diff --git a/simigramdlg.cpp b/simigramdlg.cpp index 55bed9a1..fe7ef874 100644 --- a/simigramdlg.cpp +++ b/simigramdlg.cpp @@ -246,13 +246,17 @@ void simIgramDlg::on_buttonBox_accepted() size = ui->sizeSB->value(); s.setValue("simSize", size); } - +extern std::vector zernEnables; void simIgramDlg::on_importPb_clicked() { SurfaceManager &sm = *SurfaceManager::get_instance(); if (sm.m_wavefronts.size() == 0) return; zernikes = sm.getCurrent()->InputZerns; + for (unsigned int z = 0; z < zernikes.size(); ++z){ + if (!zernEnables[z]) + zernikes[z] = 0.; + } tableModel->setValues(&zernikes); ui->correctionPb->setChecked(false); ui->Z8Pb->setChecked(true); diff --git a/zernikeprocess.cpp b/zernikeprocess.cpp index f0a53d10..6acf27ae 100644 --- a/zernikeprocess.cpp +++ b/zernikeprocess.cpp @@ -53,6 +53,8 @@ int Zw[] = { /* n */ // [[Rcpp::export]] + + arma::mat zapm(const arma::vec& rho, const arma::vec& theta, const double& eps, const int& maxorder=12) ; cv::Mat zpmCx(QVector rho, QVector theta, int maxorder) { @@ -1094,6 +1096,7 @@ void spectral_color(double &R,double &G,double &B,double wavelength) cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ + simIgramDlg &dlg = *simIgramDlg::get_instance(); double obs = .01 * dlg.getObs(); int wx = dlg.size + 2 * border; @@ -1106,7 +1109,7 @@ cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ initGrid(wx, rad, (wx-1)/2, (wx-1)/2, m_maxOrder, 0); double spacing = 1.; mirrorDlg *md = mirrorDlg::get_Instance(); - qDebug() << "fringe spacing" << md->fringeSpacing; + double r,g,b; spectral_color(r,g,b, md->lambda); if (doColor) { @@ -1118,7 +1121,6 @@ cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ if (dlg.m_doArbitrary) dlg_arbitrary->prepare(dlg.size); - for (std::size_t i = 0; i < m_rhoTheta.n_cols; ++i) { @@ -1154,6 +1156,8 @@ cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ int x = m_col[i]; int y = m_row[i]; + + if (doColor){ if (rho < obs) @@ -1174,82 +1178,6 @@ cv::Mat zernikeProcess::makeSurfaceFromZerns(int border, bool doColor){ return result; } -#define TSIZE 450 // number of points in zern generator -void ZernikeSmooth(cv::Mat wf, cv::Mat mask) -{ - // given a wavefront generate arbitrary number of zernikes from it. Then create wavefront from the zernikies. - double *m = (double *)(wf.data); - - - int size = wf.cols; - int step = (double)size/200.; // 200 samples across the wavefront - double delta = (double)TSIZE/size; // scale factor from wavefront to zernike generator - - double* tmp = new double[TSIZE * TSIZE]; - memset(tmp, 0,sizeof(double) * TSIZE * TSIZE); - - zern_generator zg(TSIZE); - zg.set_spec(6); - zg.zpoly_list(); - - - - //'calculate LSF matrix elements - - int terms = zg.get_terms_cnt(); - int am_size = terms* terms; - double* Am = new double[am_size]; - double* Bm = new double[terms]; - for (int i = 0; i < am_size; ++i) - { - Am[i] = 0.; - } - for (int i = 0; i < terms; ++i) - Bm[i] = 0; - - //calculate LSF right hand side - for(int y = 0; y < size; y += step) //for each point on the surface - { - for(int x = 0; x < size; x += step) - { - int xx = x* delta; - int yy = y * delta; - if (mask.at(x,y)) - { - int sndx = x + y* size; - - tmp[xx+yy * TSIZE] = m[sndx]; - for (int i = 0; i < terms; ++i) - { - double ipoly = zg.get_zpoly(i,xx,yy); - int dy = i * terms; - for (int j = 0; j < terms; ++j) - { - int ndx = j + dy; - Am[ndx] = Am[ndx] + - ipoly * zg.get_zpoly(j, xx, yy); - } - Bm[i] = Bm[i] + m[sndx] * ipoly; - - } - - } - } - - } - // compute coefficients - gauss_jordan (terms, Am, Bm); - - zg.set_zcoefs(Bm); - - for (int i = 0; i < terms; ++i){ - qDebug() << i << " " << Bm[i]; - } - delete[] Am; - delete[] Bm; - delete[] tmp; -} - arma::mat zernikeProcess::rhotheta( int width, double radius, double cx, double cy, const wavefront *wf){ @@ -1351,6 +1279,7 @@ arma::mat zernikeProcess::zpmC(arma::rowvec rho, arma::rowvec theta, int maxorde nm1mp1 = nm-2; nm2m = (order-2)*(order-2)/4+order-2; zm(i, nm) = 2.*rho[i]*zm(i, nm1mp1) - zm(i, nm2m); + } // now multiply each column by normalizing factor and cos, sin @@ -1433,60 +1362,12 @@ arma::mat zernikeProcess::zapmC(const arma::rowvec& rho, const arma::rowvec& the return annzm; } -void dumpArma(arma::mat mm, QString title = "", QVector colHeading = QVector(0), - QVector RowLable = QVector(0)){ - arma::mat theMat = mm; - QString transposed(" "); - - - QString log; - - QString s; - QTextStream out(&s); - - out << "

" << transposed << title <<" zern matrix size "<< mm.n_rows <<"X" << mm.n_cols << "

"; - - log.append(s); - if (!colHeading.empty()){ - log.append(""); - for (int c = 0; c < colHeading.size(); ++c){ - log.append(""); - } - log.append("\n"); - } - - for (arma::uword row =0; row < theMat.n_rows; ++row){ - if (row > 20) break; - log.append(""); - - for (arma::uword c = 0; c< theMat.n_cols; ++c){ - log.append(QString("").arg(theMat(row,c), 6, 'f', 5)); - } - log.append("\n"); - } - - log.append("
"+colHeading[c] + "
"); - if (!RowLable.empty()){ - - if (row < static_cast(RowLable.size())){ - log.append(QString("%1").arg(RowLable[row])); - } - - } - log.append("%1
"); - QTextEdit *display = new QTextEdit(); - display->resize(2500,1000); - display->insertHtml(log); - - display->show(); - -} void zernikeProcess::initGrid(int width, double radius, double cx, double cy, int maxOrder, double insideRad){ - qDebug() << "initGrid width " << width << radius << cx << cy << maxOrder << insideRad; + // if grid or maxOrder is different then update values. double obsPercent = 0.; bool shouldUseAnnulus = false; @@ -1592,8 +1473,7 @@ std::vector zernikeProcess::ZernFitWavefront(wavefront &wf){ for ( int zi = 0; zi < ztermCnt; ++zi) { double t = m_zerns(i,zi); - //if (zi == 0) - // qDebug() << "z0" << t << "rho:"< zernikeProcess::ZernFitWavefront(wavefront &wf){ wf.InputZerns = std::vector(ztermCnt,0); for (std::size_t z = 0; z < static_cast(X.rows); ++z){ - if (z < wf.InputZerns.size()){ - //qDebug() << z << X(z) << wf.InputZerns[z] << (QString("%1").arg(X(z) - wf.InputZerns[z], 6, 'f', 4)).toDouble(); - } - else { - //qDebug() << z << X(z); - } + wf.InputZerns[z] = X(z); } @@ -1626,148 +1501,54 @@ std::vector zernikeProcess::ZernFitWavefront(wavefront &wf){ X.col(0).copyTo(r); return r; } -void make3DPsf(cv::Mat surface){ - - QWidget *plotWindow = new QWidget; - Q3DSurface *m_PSF_3Dgraph; - m_PSF_3Dgraph = new Q3DSurface(); - QWidget *container = QWidget::createWindowContainer(m_PSF_3Dgraph); - QHBoxLayout *hLayout = new QHBoxLayout(); - QVBoxLayout *vLayout = new QVBoxLayout(); - hLayout->addWidget(container, 1); - hLayout->addLayout(vLayout); - plotWindow->setLayout(hLayout); - - cv::Mat data = surface.clone();//(cv::Rect(start,start,nx/2,nx/2)); - +//debug routine to see what is matrix values. +void dumpArma(arma::mat mm, QString title = "", QVector colHeading = QVector(0), + QVector RowLable = QVector(0)){ + arma::mat theMat = mm; + QString transposed(" "); - double xmin,xmax; - cv::minMaxLoc(data, &xmin,&xmax); - data/=xmax; + QString log; - QSurfaceDataProxy *m_sqrtSinProxy = new QSurfaceDataProxy(); - QSurface3DSeries *m_sqrtSinSeries = new QSurface3DSeries(m_sqrtSinProxy); + QString s; + QTextStream out(&s); - //draw surfaced - { + out << "

" << transposed << title <<" zern matrix size "<< mm.n_rows <<"X" << mm.n_cols << "

"; - int sampleCountX = data.size[1]; - int sampleCountZ = data.size[0]; - int width = sampleCountX; - QSurfaceDataArray *dataArray = new QSurfaceDataArray; - QSurfaceDataArray *dataArray2 = new QSurfaceDataArray; - dataArray->reserve(sampleCountZ); - dataArray2->reserve(sampleCountZ); - for (int i = 0 ; i < sampleCountZ ; i++) { - QSurfaceDataRow *newRow = new QSurfaceDataRow(sampleCountX); - QSurfaceDataRow *backRow = new QSurfaceDataRow(sampleCountX); - float z = -(sampleCountZ/2. - i); - int index = 0; - for (int j = 0; j < sampleCountX; j++) { - float x = -(sampleCountX/2. -j); - - float y = data.at(i,j); - (*newRow)[index].setPosition(QVector3D(x, y, z)); - (*backRow)[index++].setPosition(QVector3D(x, y, width/2)); - } - *dataArray << newRow; - *dataArray2 << backRow; + log.append(s); + if (!colHeading.empty()){ + log.append(""); + for (int c = 0; c < colHeading.size(); ++c){ + log.append(""); } - - QSurfaceDataProxy *m_sqrtSinProxy2 = new QSurfaceDataProxy(); - QSurface3DSeries *m_sqrtSinSeries2 = new QSurface3DSeries(m_sqrtSinProxy2); - - - m_sqrtSinProxy->resetArray(dataArray); - m_sqrtSinSeries->setDrawMode(QSurface3DSeries::DrawSurface); - m_sqrtSinSeries->setFlatShadingEnabled(false); - - m_sqrtSinProxy2->resetArray(dataArray2); - m_sqrtSinSeries2->setDrawMode(QSurface3DSeries::DrawSurfaceAndWireframe); - m_sqrtSinSeries2->setFlatShadingEnabled(false); - - QLinearGradient gr; - gr.setColorAt(0.0, Qt::darkGray); - gr.setColorAt(0.01,Qt::cyan); - gr.setColorAt(0.33, Qt::blue); - gr.setColorAt(0.67, Qt::lightGray); - gr.setColorAt(1.0, Qt::red); - m_PSF_3Dgraph->activeTheme()->setType(Q3DTheme::Theme(3)); - - - - m_PSF_3Dgraph->axisX()->setRange(-width/2, width/2); - m_PSF_3Dgraph->axisZ()->setRange(-width/2, width/2); - - m_PSF_3Dgraph->addSeries(m_sqrtSinSeries); - m_PSF_3Dgraph->addSeries(m_sqrtSinSeries2); - m_PSF_3Dgraph->seriesList().at(0)->setBaseGradient(gr); - m_PSF_3Dgraph->seriesList().at(0)->setColorStyle(Q3DTheme::ColorStyleRangeGradient); - } - plotWindow->show(); -} -#include -#include -#include "zernikesmoothingdlg.h" -using namespace cv; -void debugZernRoutines(wavefront &wf){ - int cols = 4; - for (int i = 0; i < 10; ++i) { - qDebug() << i << i/cols << i%cols; + log.append("\n"); } - return; - - zernikeProcess &zp = *zernikeProcess::get_Instance(); - -// QFile inputFile("C:\\Users\\doeas\\Documents\\t.txt"); -// double xc = 487.; -// double yc = 486.; -// double rad = 463.; -// if (inputFile.open(QIODevice::ReadOnly)) -// { -// QTextStream in(&inputFile); -// int row = 0; -// vector tmpRow; -// vector< vector> data; -// while (!in.atEnd()) -// { -// QString line = in.readLine(); -// QStringList fields = line.simplified().split(" "); -// tmpRow.clear(); -// for (int i = 0; i < fields.size(); ++i){ -// if (fields[i].contains("NA")){ -// tmpRow.push_back(0.0); -// } -// else { -// tmpRow.push_back(fields[i].toDouble()); -// } -// } -// data.push_back(tmpRow); -// } -// inputFile.close(); -// qDebug() << "data" << data.size() << data[10].size(); -// cv::Mat matd(data.size(),data[1].size(), numType,0.); -// for(int i=0; i(i, j) = data.at(i).at(j); -// make3DPsf(matd); -// sm->createSurfaceFromPhaseMap(matd, -// CircleOutline(QPointF(xc,yc),rad), -// CircleOutline(QPointF(0,0),0), -// QString("Mikes wavefront")); + for (arma::uword row =0; row < theMat.n_rows; ++row){ + if (row > 20) break; + log.append(""); + for (arma::uword c = 0; c< theMat.n_cols; ++c){ + log.append(QString("").arg(theMat(row,c), 6, 'f', 5)); + } + log.append("\n"); - for (int terms = 6; terms < 50; terms += 2) { + } - zp.initGrid(wf, terms); - zp.ZernFitWavefront(wf); - qDebug() << "Max Order" << terms << wf.InputZerns[8]/(sqrt(5.)); - } + log.append("
"+colHeading[c] + "
"); + if (!RowLable.empty()){ + if (row < static_cast(RowLable.size())){ + log.append(QString("%1").arg(RowLable[row])); + } + } + log.append("%1
"); + QTextEdit *display = new QTextEdit(); + display->resize(2500,1000); + display->insertHtml(log); + display->show(); - } +} diff --git a/zernikesmoothingdlg.cpp b/zernikesmoothingdlg.cpp index 55c0e14e..08c84ef4 100644 --- a/zernikesmoothingdlg.cpp +++ b/zernikesmoothingdlg.cpp @@ -71,24 +71,49 @@ void ZernikeSmoothingDlg::on_maxOrder_valueChanged(int arg1) } -cv::Mat makeSurfaceFromZerns(int width, zernikeProcess &zp, std::vector theZerns){ + +cv::Mat makeSurfaceFromZerns(int width, zernikeProcess &zp, std::vector theZerns, bool sph = false){ int wx = width; cv::Mat result = cv::Mat::zeros(wx,wx, numType); - - for (unsigned long long i = 0; i < zp.m_zerns.n_rows; ++i){ - double S1 = 0.0; - for (unsigned int z = 0; z < theZerns.size(); ++z){ - double val = theZerns[z]; - S1 += val * zp.m_zerns(i,z); + if (!sph) { + for (unsigned long long i = 0; i < zp.m_zerns.n_rows; ++i){ + double S1 = 0.0; + for (unsigned int z = 0; z < theZerns.size(); ++z){ + double val = theZerns[z]; + S1 += val * zp.m_zerns(i,z); + + //if (rho < .5) S1 = 0.; + } int x = zp.m_col[i]; int y = zp.m_row[i]; - if (S1 == 0.0) S1 += .0000001; - //if (rho < .5) S1 = 0.; result.at(y,x) = S1; } } + else { // use only spherical terms. + unsigned int z = 0; + for (unsigned long long i = 4; i < zp.m_zerns.n_rows; ++i){ + + double S1 = 0.0; + unsigned int z = 8; + for (unsigned int j = 6; z < theZerns.size(); j+=2){ + + double val = theZerns[z]; + S1 += val * zp.m_zerns(i,z); + + z = j * j/4 + j; + } + int x = zp.m_col[i]; + int y = zp.m_row[i]; + if (S1 == 0.0) S1 += .0000001; + result.at(y,x) = S1; + if (y == wx/2.){ + qDebug() << x << y << S1; + } + + } + } return result; } @@ -103,7 +128,7 @@ void ZernikeSmoothingDlg::on_createWaveFront_clicked() tableModel->setValues(&theZerns); - cv::Mat result = makeSurfaceFromZerns(m_wf.data.cols, *m_zp, theZerns); + cv::Mat result = makeSurfaceFromZerns(m_wf.data.cols, *m_zp, theZerns, m_spherical_only); QStringList l = m_wf.name.split("/"); l.back().replace(".wft",""); @@ -123,3 +148,9 @@ void ZernikeSmoothingDlg::on_createWaveFront_clicked() } QApplication::restoreOverrideCursor(); } + +void ZernikeSmoothingDlg::on_sphereOnly_toggled(bool checked) +{ + m_spherical_only = checked; +} + diff --git a/zernikesmoothingdlg.h b/zernikesmoothingdlg.h index 0ab059e4..b1479e61 100644 --- a/zernikesmoothingdlg.h +++ b/zernikesmoothingdlg.h @@ -16,11 +16,14 @@ class ZernikeSmoothingDlg : public QDialog public: explicit ZernikeSmoothingDlg(wavefront &wf, QWidget *parent = nullptr); ~ZernikeSmoothingDlg(); - + bool m_spherical_only = false; private slots: void on_maxOrder_valueChanged(int arg1); void on_createWaveFront_clicked(); void intiZernTable(); + + void on_sphereOnly_toggled(bool checked); + private: Ui::ZernikeSmoothingDlg *ui; int m_maxOrder; diff --git a/zernikesmoothingdlg.ui b/zernikesmoothingdlg.ui index d79a76f0..44ea69d9 100644 --- a/zernikesmoothingdlg.ui +++ b/zernikesmoothingdlg.ui @@ -100,6 +100,13 @@ p, li { white-space: pre-wrap; }
+ + + + Spherical terms only + + + From ffdc4775d4751924c41612644b91d668834abea7 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Wed, 5 Mar 2025 14:37:54 -0600 Subject: [PATCH 10/25] Perhaps done except for cleanup. --- DFTFringe_Dale.pro | 1 + graphmodifier.cpp | 419 +++++++++++++++++++++++++++++++++++++ graphmodifier.h | 113 ++++++++++ percentCorrectionSurface.h | 16 ++ percentcorrectiondlg.cpp | 319 ++++++++++++++++------------ percentcorrectiondlg.h | 45 ++-- percentcorrectiondlg.ui | 64 ++---- profileplot.cpp | 214 +++++++------------ profileplot.h | 2 +- 9 files changed, 866 insertions(+), 327 deletions(-) create mode 100644 graphmodifier.cpp create mode 100644 graphmodifier.h create mode 100644 percentCorrectionSurface.h diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index 77dffeb0..04603eb9 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -160,6 +160,7 @@ HEADERS += mainwindow.h \ dftarea.h \ oglrendered.h \ pdfcalibrationdlg.h \ + percentCorrectionSurface.h \ percentcorrectiondlg.h \ profileplot.h \ psiresizeimagesdlg.h \ diff --git a/graphmodifier.cpp b/graphmodifier.cpp new file mode 100644 index 00000000..05772685 --- /dev/null +++ b/graphmodifier.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Data Visualization module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "graphmodifier.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace QtDataVisualization; + + + +//! [0] +GraphModifier::GraphModifier(Q3DBars *bargraph) + : m_graph(bargraph), + m_xRotation(0.0f), + m_yRotation(0.0f), + m_fontSize(30), + m_segments(4), + m_subSegments(3), + m_minval(0), + m_maxval(120), + //! [1] + m_temperatureAxis(new QValue3DAxis), + m_yearAxis(new QCategory3DAxis), + m_monthAxis(new QCategory3DAxis), + m_primarySeries(new QBar3DSeries), + m_secondarySeries(new QBar3DSeries), + //! [1] + m_barMesh(QAbstract3DSeries::MeshBevelBar), + m_smooth(false) +{ + //! [2] + m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftMedium); + m_graph->activeTheme()->setBackgroundEnabled(false); + m_graph->activeTheme()->setFont(QFont("Times New Roman", m_fontSize)); + m_graph->activeTheme()->setLabelBackgroundEnabled(true); + m_graph->setMultiSeriesUniform(true); + //! [2] + + + + //! [3] + m_temperatureAxis->setTitle("Percent Correction"); + m_temperatureAxis->setSegmentCount(m_segments); + m_temperatureAxis->setSubSegmentCount(m_subSegments); + m_temperatureAxis->setRange(m_minval, m_maxval); + + m_temperatureAxis->setLabelAutoRotation(30.0f); + m_temperatureAxis->setTitleVisible(true); + + m_yearAxis->setTitle("Surface"); + m_yearAxis->setLabelAutoRotation(30.0f); + m_yearAxis->setTitleVisible(true); + m_monthAxis->setTitle("Zone"); + m_monthAxis->setLabelAutoRotation(30.0f); + m_monthAxis->setTitleVisible(true); + + m_graph->setValueAxis(m_temperatureAxis); + m_graph->setRowAxis(m_yearAxis); + m_graph->setColumnAxis(m_monthAxis); + //! [3] + + //! [8] + m_primarySeries->setItemLabelFormat(QStringLiteral("Oulu - @colLabel @rowLabel: @valueLabel")); + m_primarySeries->setMesh(QAbstract3DSeries::MeshBevelBar); + m_primarySeries->setMeshSmooth(false); + + m_secondarySeries->setItemLabelFormat(QStringLiteral("Helsinki - @colLabel @rowLabel: @valueLabel")); + m_secondarySeries->setMesh(QAbstract3DSeries::MeshBevelBar); + m_secondarySeries->setMeshSmooth(false); + m_secondarySeries->setVisible(false); + //! [8] + + //! [4] + m_graph->addSeries(m_primarySeries); + m_graph->addSeries(m_secondarySeries); + //! [4] + + //! [6] + changePresetCamera(); + //! [6] + + //! [9] + //resetData(); + //! [9] + + // Set up property animations for zooming to the selected bar + //! [12] + Q3DCamera *camera = m_graph->scene()->activeCamera(); + m_defaultAngleX = camera->xRotation(); + m_defaultAngleY = camera->yRotation(); + m_defaultZoom = camera->zoomLevel(); + m_defaultTarget = camera->target(); + + m_animationCameraX.setTargetObject(camera); + m_animationCameraY.setTargetObject(camera); + m_animationCameraZoom.setTargetObject(camera); + m_animationCameraTarget.setTargetObject(camera); + + m_animationCameraX.setPropertyName("xRotation"); + m_animationCameraY.setPropertyName("yRotation"); + m_animationCameraZoom.setPropertyName("zoomLevel"); + m_animationCameraTarget.setPropertyName("target"); + + int duration = 1700; + m_animationCameraX.setDuration(duration); + m_animationCameraY.setDuration(duration); + m_animationCameraZoom.setDuration(duration); + m_animationCameraTarget.setDuration(duration); + + // The zoom always first zooms out above the graph and then zooms in + qreal zoomOutFraction = 0.3; + m_animationCameraX.setKeyValueAt(zoomOutFraction, QVariant::fromValue(0.0f)); + m_animationCameraY.setKeyValueAt(zoomOutFraction, QVariant::fromValue(90.0f)); + m_animationCameraZoom.setKeyValueAt(zoomOutFraction, QVariant::fromValue(50.0f)); + m_animationCameraTarget.setKeyValueAt(zoomOutFraction, + QVariant::fromValue(QVector3D(0.0f, 0.0f, 0.0f))); + //! [12] +} +//! [0] + +GraphModifier::~GraphModifier() +{ + delete m_graph; +} + +void GraphModifier::resetData(QList > data, QStringList names) +{ + //! [5] + // Set up data + + + // Create data arrays + QBarDataArray *dataSet = new QBarDataArray; + + + + dataSet->reserve(data.size()); + for (int i = 0; i < data.size(); i++) { + // Create a data row + QBarDataRow *dataRow = new QBarDataRow(data[i].size()); + + for (int s = 0; s < data[i].size(); s++) { + // Add data to the row + (*dataRow)[s].setValue(data[i][s]); + + } + // Add the row to the set + dataSet->append(dataRow); + + } + m_months.clear(); + for (int i = 0; i <= data[0].length(); ++i) { + m_months << QString::number(i+1); + } + // Add data to the data proxy (the data proxy assumes ownership of it) + m_primarySeries->dataProxy()->resetArray(dataSet, names, m_months); + + //! [5] +} + +void GraphModifier::changeRange(int range) +{ + if (range >= m_years.count()) + m_yearAxis->setRange(0, m_years.count() - 1); + else + m_yearAxis->setRange(range, range); +} + +void GraphModifier::changeStyle(int style) +{ + QComboBox *comboBox = qobject_cast(sender()); + if (comboBox) { + m_barMesh = QAbstract3DSeries::Mesh(comboBox->itemData(style).toInt()); + m_primarySeries->setMesh(m_barMesh); + m_secondarySeries->setMesh(m_barMesh); + } +} + +void GraphModifier::changePresetCamera() +{ + m_animationCameraX.stop(); + m_animationCameraY.stop(); + m_animationCameraZoom.stop(); + m_animationCameraTarget.stop(); + + // Restore camera target in case animation has changed it + m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f)); + + //! [10] + static int preset = Q3DCamera::CameraPresetFront; + + m_graph->scene()->activeCamera()->setCameraPreset((Q3DCamera::CameraPreset)preset); + + if (++preset > Q3DCamera::CameraPresetDirectlyBelow) + preset = Q3DCamera::CameraPresetFrontLow; + //! [10] +} + +void GraphModifier::changeTheme(int theme) +{ + Q3DTheme *currentTheme = m_graph->activeTheme(); + currentTheme->setType(Q3DTheme::Theme(theme)); + emit backgroundEnabledChanged(currentTheme->isBackgroundEnabled()); + emit gridEnabledChanged(currentTheme->isGridEnabled()); + emit fontChanged(currentTheme->font()); + emit fontSizeChanged(currentTheme->font().pointSize()); +} + +void GraphModifier::changeLabelBackground() +{ + m_graph->activeTheme()->setLabelBackgroundEnabled(!m_graph->activeTheme()->isLabelBackgroundEnabled()); +} + +void GraphModifier::changeSelectionMode(int selectionMode) +{ + QComboBox *comboBox = qobject_cast(sender()); + if (comboBox) { + int flags = comboBox->itemData(selectionMode).toInt(); + m_graph->setSelectionMode(QAbstract3DGraph::SelectionFlags(flags)); + } +} + +void GraphModifier::changeFont(const QFont &font) +{ + QFont newFont = font; + m_graph->activeTheme()->setFont(newFont); +} + +void GraphModifier::changeFontSize(int fontsize) +{ + m_fontSize = fontsize; + QFont font = m_graph->activeTheme()->font(); + font.setPointSize(m_fontSize); + m_graph->activeTheme()->setFont(font); +} + +void GraphModifier::shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality sq) +{ + int quality = int(sq); + // Updates the UI component to show correct shadow quality + emit shadowQualityChanged(quality); +} + +void GraphModifier::changeLabelRotation(int rotation) +{ + m_temperatureAxis->setLabelAutoRotation(float(rotation)); + m_monthAxis->setLabelAutoRotation(float(rotation)); + m_yearAxis->setLabelAutoRotation(float(rotation)); +} + +void GraphModifier::setAxisTitleVisibility(bool enabled) +{ + m_temperatureAxis->setTitleVisible(enabled); + m_monthAxis->setTitleVisible(enabled); + m_yearAxis->setTitleVisible(enabled); +} + +void GraphModifier::setAxisTitleFixed(bool enabled) +{ + m_temperatureAxis->setTitleFixed(enabled); + m_monthAxis->setTitleFixed(enabled); + m_yearAxis->setTitleFixed(enabled); +} + +//! [11] +void GraphModifier::zoomToSelectedBar() +{ + m_animationCameraX.stop(); + m_animationCameraY.stop(); + m_animationCameraZoom.stop(); + m_animationCameraTarget.stop(); + + Q3DCamera *camera = m_graph->scene()->activeCamera(); + float currentX = camera->xRotation(); + float currentY = camera->yRotation(); + float currentZoom = camera->zoomLevel(); + QVector3D currentTarget = camera->target(); + + m_animationCameraX.setStartValue(QVariant::fromValue(currentX)); + m_animationCameraY.setStartValue(QVariant::fromValue(currentY)); + m_animationCameraZoom.setStartValue(QVariant::fromValue(currentZoom)); + m_animationCameraTarget.setStartValue(QVariant::fromValue(currentTarget)); + + QPoint selectedBar = m_graph->selectedSeries() + ? m_graph->selectedSeries()->selectedBar() + : QBar3DSeries::invalidSelectionPosition(); + + if (selectedBar != QBar3DSeries::invalidSelectionPosition()) { + // Normalize selected bar position within axis range to determine target coordinates + //! [13] + QVector3D endTarget; + float xMin = m_graph->columnAxis()->min(); + float xRange = m_graph->columnAxis()->max() - xMin; + float zMin = m_graph->rowAxis()->min(); + float zRange = m_graph->rowAxis()->max() - zMin; + endTarget.setX((selectedBar.y() - xMin) / xRange * 2.0f - 1.0f); + endTarget.setZ((selectedBar.x() - zMin) / zRange * 2.0f - 1.0f); + //! [13] + + // Rotate the camera so that it always points approximately to the graph center + //! [15] + qreal endAngleX = 90.0 - qRadiansToDegrees(qAtan(qreal(endTarget.z() / endTarget.x()))); + if (endTarget.x() > 0.0f) + endAngleX -= 180.0f; + float barValue = m_graph->selectedSeries()->dataProxy()->itemAt(selectedBar.x(), + selectedBar.y())->value(); + float endAngleY = barValue >= 0.0f ? 30.0f : -30.0f; + if (m_graph->valueAxis()->reversed()) + endAngleY *= -1.0f; + //! [15] + + m_animationCameraX.setEndValue(QVariant::fromValue(float(endAngleX))); + m_animationCameraY.setEndValue(QVariant::fromValue(endAngleY)); + m_animationCameraZoom.setEndValue(QVariant::fromValue(250)); + //! [14] + m_animationCameraTarget.setEndValue(QVariant::fromValue(endTarget)); + //! [14] + } else { + // No selected bar, so return to the default view + m_animationCameraX.setEndValue(QVariant::fromValue(m_defaultAngleX)); + m_animationCameraY.setEndValue(QVariant::fromValue(m_defaultAngleY)); + m_animationCameraZoom.setEndValue(QVariant::fromValue(m_defaultZoom)); + m_animationCameraTarget.setEndValue(QVariant::fromValue(m_defaultTarget)); + } + + m_animationCameraX.start(); + m_animationCameraY.start(); + m_animationCameraZoom.start(); + m_animationCameraTarget.start(); +} +//! [11] + +void GraphModifier::changeShadowQuality(int quality) +{ + QAbstract3DGraph::ShadowQuality sq = QAbstract3DGraph::ShadowQuality(quality); + m_graph->setShadowQuality(sq); + emit shadowQualityChanged(quality); +} + +//! [7] +void GraphModifier::rotateX(int rotation) +{ + m_xRotation = rotation; + m_graph->scene()->activeCamera()->setCameraPosition(m_xRotation, m_yRotation); +} + +void GraphModifier::rotateY(int rotation) +{ + m_yRotation = rotation; + m_graph->scene()->activeCamera()->setCameraPosition(m_xRotation, m_yRotation); +} +//! [7] + +void GraphModifier::setBackgroundEnabled(int enabled) +{ + m_graph->activeTheme()->setBackgroundEnabled(bool(enabled)); +} + +void GraphModifier::setGridEnabled(int enabled) +{ + m_graph->activeTheme()->setGridEnabled(bool(enabled)); +} + +void GraphModifier::setSmoothBars(int smooth) +{ + m_smooth = bool(smooth); + m_primarySeries->setMeshSmooth(m_smooth); + m_secondarySeries->setMeshSmooth(m_smooth); +} + +void GraphModifier::setSeriesVisibility(int enabled) +{ + m_secondarySeries->setVisible(bool(enabled)); +} + +void GraphModifier::setReverseValueAxis(int enabled) +{ + m_graph->valueAxis()->setReversed(enabled); +} + +void GraphModifier::setReflection(bool enabled) +{ + m_graph->setReflection(enabled); +} diff --git a/graphmodifier.h b/graphmodifier.h new file mode 100644 index 00000000..0d9a526f --- /dev/null +++ b/graphmodifier.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Data Visualization module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GRAPHMODIFIER_H +#define GRAPHMODIFIER_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include "percentCorrectionSurface.h" +using namespace QtDataVisualization; + +class GraphModifier : public QObject +{ + Q_OBJECT +public: + explicit GraphModifier(Q3DBars *bargraph); + ~GraphModifier(); + + void resetData(QList >data, QStringList names); + void changePresetCamera(); + void changeLabelBackground(); + void changeFont(const QFont &font); + void changeFontSize(int fontsize); + void rotateX(int rotation); + void rotateY(int rotation); + void setBackgroundEnabled(int enabled); + void setGridEnabled(int enabled); + void setSmoothBars(int smooth); + void setSeriesVisibility(int enabled); + void setReverseValueAxis(int enabled); + void setReflection(bool enabled); + +public Q_SLOTS: + void changeRange(int range); + void changeStyle(int style); + void changeSelectionMode(int selectionMode); + void changeTheme(int theme); + void changeShadowQuality(int quality); + void shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality shadowQuality); + void changeLabelRotation(int rotation); + void setAxisTitleVisibility(bool enabled); + void setAxisTitleFixed(bool enabled); + void zoomToSelectedBar(); + +Q_SIGNALS: + void shadowQualityChanged(int quality); + void backgroundEnabledChanged(bool enabled); + void gridEnabledChanged(bool enabled); + void fontChanged(QFont font); + void fontSizeChanged(int size); + +private: + Q3DBars *m_graph; + float m_xRotation; + float m_yRotation; + int m_fontSize; + int m_segments; + int m_subSegments; + float m_minval; + float m_maxval; + QStringList m_months; + QStringList m_years; + QValue3DAxis *m_temperatureAxis; + QCategory3DAxis *m_yearAxis; + QCategory3DAxis *m_monthAxis; + QBar3DSeries *m_primarySeries; + QBar3DSeries *m_secondarySeries; + QAbstract3DSeries::Mesh m_barMesh; + bool m_smooth; + QPropertyAnimation m_animationCameraX; + QPropertyAnimation m_animationCameraY; + QPropertyAnimation m_animationCameraZoom; + QPropertyAnimation m_animationCameraTarget; + float m_defaultAngleX; + float m_defaultAngleY; + float m_defaultZoom; + QVector3D m_defaultTarget; +}; + +#endif diff --git a/percentCorrectionSurface.h b/percentCorrectionSurface.h new file mode 100644 index 00000000..6b62d489 --- /dev/null +++ b/percentCorrectionSurface.h @@ -0,0 +1,16 @@ +#ifndef PERCENTCORRECTIONSURFACE_H +#include +#define PERCENTCORRECTIONSURFACE_H +class surfaceData { + public: + + double igramlambda; + QColor penColor; + // set of zernike values at each zone (rho) + std::vector zernvalues; + QString m_name; + + surfaceData( double igramlambda, QColor pen, std::vector zernvalues, QString name): igramlambda(igramlambda), + penColor(pen), zernvalues(zernvalues){ m_name = name;}; +} ; +#endif // PERCENTCORRECTIONSURFACE_H diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index aa297e46..206a2e43 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -18,9 +18,8 @@ #include #include "zernikeprocess.h" #include -#include -#include -#include + + percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : QDialog(parent),m_showZones(false), ui(new Ui::percentCorrectionDlg) @@ -28,19 +27,8 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : ui->setupUi(this); resize(1000,800); - Q3DBars *widgetgraph = new Q3DBars(); - QWidget *container = QWidget::createWindowContainer(widgetgraph); - QHBoxLayout *hLayout = new QHBoxLayout(ui->bar3D); - hLayout->addWidget(container, 1); - ui->bar3D->setWindowTitle(" how about this"); - //setWindowFlags(Qt::WindowStaysOnTopHint); - - QCheckBox *smoothCheckBox = new QCheckBox(ui->bar3D); - smoothCheckBox->setText(QStringLiteral("Smooth bars")); - smoothCheckBox->setChecked(false); - hLayout->addWidget(smoothCheckBox); mirrorDlg &md = *mirrorDlg::get_Instance(); m_radius = md.m_clearAperature/2.; QSettings set; @@ -50,8 +38,17 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : ui->maxvalue->setValue(set.value("percent_correction_max", 120).toDouble()); ui->minvalue->blockSignals(false); ui->maxvalue->blockSignals(false); - - + ui->maxOrder->blockSignals(true); + m_maxOrder = set.value("percentMaxOrder",18).toUInt(); + ui->maxOrder->setValue(m_maxOrder); + int mmax = m_maxOrder/2; + int nzerns = (mmax+1)*(mmax+1); + ui->noOfTerms->setText(QString::number(nzerns)); + ui->maxOrder->blockSignals(false); + ui->percentTable->setStyleSheet("background-color: lightgray;"); + QList sizes; + sizes << 500 << 100; + ui->splitter->setSizes(sizes); m_number_of_zones = set.value("percent number of zones", 5).toInt(); ui->numberOfZones->blockSignals(true); @@ -62,8 +59,12 @@ percentCorrectionDlg::percentCorrectionDlg( QWidget *parent) : } makeZones(); + + } + + double g_laserLambda = 550.; // a global so a none member function can access it. void percentCorrectionDlg::saveSettings(){ @@ -79,7 +80,7 @@ void percentCorrectionDlg::saveSettings(){ QSettings set; QJsonDocument jsonDoc(myJsonObject); set.setValue("correctionZones", jsonDoc.toJson(QJsonDocument::Compact)); - + set.setValue("percentMaxOrder",m_maxOrder); } @@ -108,15 +109,32 @@ QList generateZoneCenters(double radius, int number_of_zones){ return zoneCenters; } void percentCorrectionDlg::updateZoneTable(){ - ui->zoneTable->clearContents(); - ui->zoneTable->setRowCount(zoneCenter.size()); - ui->zoneTable->blockSignals(true); + + QStringList vertLabels; + + QStringList hLabels; + + ui->percentTable->clear(); + ui->percentTable->setColumnCount(zoneCenter.size()); + ui->percentTable->setRowCount(2); + ui->percentTable->blockSignals(true); + + for (int i = 0; i < zoneCenter.size(); ++i) { - QTableWidgetItem *item = new QTableWidgetItem(QString::number(zoneCenter[i],'f',0)); - ui->zoneTable->setItem(i, 0, item); - item->setTextAlignment(Qt::AlignRight); + + QTableWidgetItem *item = new QTableWidgetItem(QString("%1mm").arg(zoneCenter[i],0,'f',0)); + item->setTextAlignment(Qt::AlignCenter); + ui->percentTable->setItem(0, i, item); + item->setTextAlignment(Qt::AlignCenter); + vertLabels<< QString().number(i); + hLabels << QString().number(i+1); } - ui->zoneTable->blockSignals(false); + + + ui->percentTable->setHorizontalHeaderLabels(hLabels); + + ui->percentTable->setColumnCount(zoneCenter.size()); + ui->percentTable->blockSignals(false); } QJsonDocument percentCorrectionDlg::loadZonesFromJson(QString str){ QJsonParseError jsonError; @@ -126,8 +144,8 @@ QJsonDocument percentCorrectionDlg::loadZonesFromJson(QString str){ zoneCenter.clear(); - ui->zoneTable->clearContents(); - ui->zoneTable->setRowCount(zones.size()); + ui->percentTable->clearContents(); + ui->percentTable->setColumnCount(zones.size()); for (int i = 0; i < zones.size(); ++i) { double d = zones[i].toDouble()* m_radius; @@ -180,40 +198,9 @@ void percentCorrectionDlg::makeZones(){ updateZoneTable(); zoneZerns = makeZoneZerns(zoneCenter); } -/* - * // creaate rowvec or rho and theta. Theta will only be 0. - std::vector rhovec, thetavec; - - for (double r = 0; r < m_radius; ++r){ - double rho = r/m_radius; - rhovec.push_back(rho); - thetavec.push_back(0.); - } - arma::rowvec rhov(rhovec), thetav(thetavec); - zernikeProcess zp; - - arma::mat theZs = zp.zpmC(rhov, thetav, maxorder); - - - double rho = rhov(10); - double num1 = rho; - - double num2 = num1 * num1; - double num3 = num2 * num2; - double num4 = num3 * num2; - double num5 = num3 * num3; - double num6 = num5 * num2; - - double z8 = (1.0 - 6.0 * num2 + 6.0 * num3); - double z15 =(-1.0 + 12.0 * num2 - 30.0 * num3 + 20.0 * num4); - double z24 = (1.0 - 20.0 * num2 + 90.0 * num3 - 140.0 * num4 + 70.0 * num5); - - qDebug() << "rho" << rho << z8 << z15 << z24; - qDebug() << "rho" << rho << "theZs8" << theZs(10,8) << theZs(10,15) << theZs(10,24); -*/ int maxorder = 18; -double percentCorrectionDlg::getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x){ +double percentCorrectionDlg::getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x, double null = 0.){ double num1 = x / MirrorRad; @@ -231,24 +218,15 @@ double percentCorrectionDlg::getZernSurface( double RoC, double MirrorRad, std:: // for each spherical term int z = 8; for(unsigned int j = 6; z < theZs.n_cols; j+=2){ - val += Zernikes[z] * theZs(0,z); + + if (z == 8) + val += (Zernikes[8]- null) * theZs(0,z); + else + val += Zernikes[z] * theZs(0,z); z = j * j /4 + j; } -// double num2 = num1 * num1; -// double num3 = num2 * num2; -// double num4 = num3 * num2; -// double num5 = num3 * num3; -// double num6 = num5 * num2; - - -// double num7 = 0.0 + Zernikes[8] * (1.0 - 6.0 * num2 + 6.0 * num3) + -// Zernikes[15] * (-1.0 + 12.0 * num2 - 30.0 * num3 + 20.0 * num4) + -// Zernikes[24] * (1.0 - 20.0 * num2 + 90.0 * num3 - 140.0 * num4 + 70.0 * num5) + -// Zernikes[35] * (-1.0 + 30.0 * num2 - 210.0 * num3 + 560.0 * num4 - 630.0 * num5 + 252.0 * num6); - -// qDebug() << "rho" << num1 << val << num7; double spherey = RoC - sqrt(pow(RoC, 2.0) - pow(x, 2.0)); double zerny = val * m_lambda_nm * .5E-6; double surf = spherey + zerny; @@ -257,11 +235,11 @@ double percentCorrectionDlg::getZernSurface( double RoC, double MirrorRad, std:: // will use zernike values to compute two surface points x+- .01x away from x // then compute normal slope from that. -double percentCorrectionDlg::getnormalSlope(double RoC, double radius, std::vector Zernikes, double x){ +double percentCorrectionDlg::getnormalSlope(double RoC, double radius, std::vector Zernikes, double x, double null = 0){ double num1 = x / 100.0; - double surface1 = getZernSurface(RoC, radius, Zernikes, x - num1); // problem with zonendx (the delta is not same as zonendx) - double surface2 = getZernSurface(RoC, radius, Zernikes, x + num1); + double surface1 = getZernSurface(RoC, radius, Zernikes, x - num1, null); // problem with zonendx (the delta is not same as zonendx) + double surface2 = getZernSurface(RoC, radius, Zernikes, x + num1, null); double slope = (surface2 - surface1)/ (2 * num1); slope = -1.0 / slope; @@ -332,9 +310,6 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ double x = zoneCenter[zone]; - - - //idealSurface << QPointF(x, normIdealSlope); double idealknife = getIdealKE(m_roc, x); double zernKnife = GetActualKE(m_roc, m_radius, surf->zernvalues, x); @@ -358,6 +333,36 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ return correction; } + + +void percentCorrectionDlg::plotProfile(){ + + mirrorDlg *md = mirrorDlg::get_Instance(); + double nullval = md->z8 * md->cc; + for (int i = 0; i < surfs.length(); ++ i) { + + QwtPlotCurve *Curve = new QwtPlotCurve(); + QPolygonF profile; + for(double r = -m_radius; r <= m_radius; r += 1. ){ + double y = getZernSurface(m_roc, m_radius, surfs[i]->zernvalues, fabs(r), nullval); + + double sphery = m_roc - sqrt(pow(m_roc, 2.0) - pow(r, 2.0)); + y -= sphery; + y /= m_lambda_nm * .5E-6; + profile << QPointF(r, y); + } + + Curve->setSamples(profile); + Curve->attach(ui->plot); + Curve->setPen(surfs[i]->penColor,5); + Curve->attach(ui->plot); + } + ui->plot->setAxisScale(QwtPlot::xBottom, -m_radius, m_radius); + ui->plot->setAxisAutoScale(QwtPlot::yLeft); + + ui->plot->setAxisTitle( ui->plot->yLeft, "Error in waves at 550 nm" ); + ui->plot->replot(); +} void percentCorrectionDlg::plot(){ @@ -379,6 +384,7 @@ void percentCorrectionDlg::plot(){ } ui->plot->detachItems(QwtPlotItem::Rtti_PlotItem); + QwtPlotGrid *grid = new QwtPlotGrid(); grid->setZ(1); @@ -390,41 +396,71 @@ void percentCorrectionDlg::plot(){ grid->setMinorPen(Qt::black, 1.0, Qt::DotLine); grid->attach( ui->plot); + + if (!ui->correction->isChecked()){ + qDebug() << "doing profile"; + plotProfile(); + return; + } + + ui->percentTable->blockSignals(true); + ui->percentTable->setRowCount(surfs.length() + 1); + QTableWidgetItem *item = new QTableWidgetItem("Zone Center"); + ui->percentTable->setVerticalHeaderItem(0, item); // for each surface draw the percent plot for (int i = 0; i < surfs.length(); ++ i) { // make percentages QPolygonF percent = makePercentages( surfs[i]); + // Create 3D bar data + QVector row; + + for(int j = 0; j < percent.length(); ++j){ + QTableWidgetItem *item = new QTableWidgetItem(QString::number(percent[j].y(),'f',0) + "%"); + item->setTextAlignment(Qt::AlignCenter); + item->setFlags(item->flags() & ~Qt::ItemIsEditable); + ui->percentTable->setItem(i+1,j+1,item); + + row << percent[j].y(); + } + QTableWidgetItem *item = new QTableWidgetItem(surfs[i]->m_name); + item->setForeground(surfs[i]->penColor); + item->setFlags(item->flags() & ~Qt::ItemIsEditable); + + ui->percentTable->setVerticalHeaderItem(i+1, item); + m_seriesName << surfs[i]->m_name; + + QPolygonF bars; - if (surfs.length() < 2) { - // draw zone rectangles - if (ui->showBars->isChecked()){ - double width; - for(int i = 0; i < percent.length(); ++i){ - - double y = percent[i].y(); - - if (i < percent.length()-1) - width= .80 * (percent[i+1].x() - percent[i].x()) ; - - QwtPlotShapeItem *rectangleItem = new QwtPlotShapeItem(); - - rectangleItem->setRect(QRectF(percent[i].x() - width/2. ,0,width,y)); - - QPen pen(Qt::black); - pen.setWidth(3); - rectangleItem->setPen(pen); - rectangleItem->setBrush(QBrush(Qt::lightGray)); - rectangleItem->attach(ui->plot); - rectangleItem->setZ(0); - QwtPlotMarker *label = new QwtPlotMarker(); - label->setLineStyle(QwtPlotMarker::NoLine); - label->setLabel(QString("%1\%").arg(y, 0, 'f',1)) ; - label->setValue(percent[i].x(), y-10); - label->attach(ui->plot); - } + if (surfs.length() < 2) { + // draw zone rectangles + + double width; + for(int i = 0; i < percent.length(); ++i){ + + double y = percent[i].y(); + + if (i < percent.length()-1) + width= .80 * (percent[i+1].x() - percent[i].x()) ; + + QwtPlotShapeItem *rectangleItem = new QwtPlotShapeItem(); + + rectangleItem->setRect(QRectF(percent[i].x() - width/2. ,0,width,y)); + + QPen pen(Qt::black); + pen.setWidth(3); + rectangleItem->setPen(pen); + rectangleItem->setBrush(QBrush(Qt::lightGray)); + rectangleItem->attach(ui->plot); + rectangleItem->setZ(0); + QwtPlotMarker *label = new QwtPlotMarker(); + label->setLineStyle(QwtPlotMarker::NoLine); + label->setLabel(QString("%1\%").arg(y, 0, 'f',1)) ; + label->setValue(percent[i].x(), y-10); + label->attach(ui->plot); } + } @@ -469,31 +505,58 @@ void percentCorrectionDlg::plot(){ ui->plot->setAxisTitle( ui->plot->yLeft, "Percent correction" ); ui->plot->setAxisScale(ui->plot->yRight, -10, 20, 1); - ui->plot->setAxisTitle( ui->plot->xBottom, "Radius mm" ); + ui->plot->setAxisTitle( ui->plot->xBottom, "Mirror Radius mm" ); slopeCurve3->setZ(1); ui->plot->setAxisScale(QwtPlot::yLeft, ui->minvalue->value(), ui->maxvalue->value()); ui->plot->setAxisScale(QwtPlot::xBottom, 0, m_radius); -} + } + ui->percentTable->blockSignals(false); + // Add the series to the graph ui->plot->replot(); } +bool compare(QVector< surfaceData *> data1, QVector< surfaceData *> data2){ + if (data1.length() != data2.length()){ + qDebug() << "different length"; + return false; + } + for (int ndx = 0; ndx < data1.length(); ++ ndx){ + if (data1[ndx]->igramlambda != data2[ndx]->igramlambda || + data1[ndx]->m_name != data2[ndx]->m_name || + data1[ndx]->penColor != data2[ndx]->penColor || + data1[ndx]->zernvalues != data2[ndx]->zernvalues) + + return false; + } + return true; +} void percentCorrectionDlg::setData( QVector< surfaceData *> data) { + bool different = !compare(data,surfs); + qDebug() << "true if different" << different; mirrorDlg &md = *mirrorDlg::get_Instance(); m_roc = md.roc; m_lambda_nm = md.lambda; m_radius = md.m_clearAperature/2.; surfs = data; + ui->percentTable->setRowCount(data.length()); - // create surface samples every 1mm. - // THen change the zone logic to match. + QStringList labels; + labels << "Zone\ncenter"; + foreach(auto t, data){ + labels << t->m_name; + + } + ui->percentTable->setVerticalHeaderLabels(labels); + ui->percentTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); - //it is possible that the zones have yet to be set go read them from the settings. - // it will make them if needed. makeZones(); + plot(); + //if (different) + //emit make_percent_correction(m_maxOrder); } percentCorrectionDlg::~percentCorrectionDlg() @@ -560,7 +623,7 @@ void percentCorrectionDlg::on_loadZones_clicked() QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - //qDebug() << "Failed to open file"; + qDebug() << "Failed to open file"; return; } @@ -612,38 +675,36 @@ void percentCorrectionDlg::on_saveZones_clicked() +void percentCorrectionDlg::on_Generate_clicked() +{ + emit make_percent_correction(); +} -void percentCorrectionDlg::on_zoneTable_itemChanged(QTableWidgetItem *item) +void percentCorrectionDlg::on_maxOrder_valueChanged(int arg1) { - qDebug() << "item changed" << item->row() << item->text(); - zoneCenter[item->row()] = item->text().toDouble(); + m_maxOrder = arg1; + int mmax = arg1/2; + int ncol = (mmax+1)*(mmax+1); + ui->noOfTerms->setText(QString::number(ncol)); saveSettings(); - plot(); } +void percentCorrectionDlg::on_percentTable_itemChanged(QTableWidgetItem *item) +{ + zoneCenter[item->column()] = item->text().toDouble(); -void percentCorrectionDlg::on_showBars_clicked(bool checked) -{ + saveSettings(); plot(); } -void percentCorrectionDlg::on_Generate_clicked() -{ - emit make_percent_correction(m_maxOrder); -} - -void percentCorrectionDlg::on_maxOrder_valueChanged(int arg1) +void percentCorrectionDlg::on_correction_toggled(bool checked) { - m_maxOrder = arg1; - qDebug() << "maxorder" << arg1; - int mmax = arg1/2; - int ncol = (mmax+1)*(mmax+1); - ui->noOfTerms->setText(QString::number(ncol)); + plot(); } diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h index 2dc59b23..9df9adf8 100644 --- a/percentcorrectiondlg.h +++ b/percentcorrectiondlg.h @@ -7,21 +7,18 @@ #include #include #include +#include +#include +#include +#include +#include "graphmodifier.h" +#include "percentCorrectionSurface.h" +using namespace QtDataVisualization; namespace Ui { class percentCorrectionDlg; } -class surfaceData { - public: - double igramlambda; - QColor penColor; - // set of zernike values at each zone (rho) - std::vector zernvalues; - - surfaceData( double igramlambda, QColor pen, std::vector zernvalues): igramlambda(igramlambda), - penColor(pen), zernvalues(zernvalues){}; -} ; class percentCorrectionDlg : public QDialog { @@ -39,19 +36,28 @@ class percentCorrectionDlg : public QDialog arma::mat zoneZerns; QList zoneCenter; QList zoneedge; + QList > m_barData; + QStringList m_seriesName; QPolygonF m_avg; int m_currentprofileIndex = 0; int m_currentSelectedZone = -1; - int m_maxOrder = 12; + QVector surfs; QPolygonF makePercentages(surfaceData *); - double getnormalSlope(double RoC, double radius, std::vector Zernikes, double x); - double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x); + double getnormalSlope(double RoC, double radius, std::vector Zernikes, double x, double null); + double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x, double null); double GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, double x); + void make_3DBarControls(QWidget *widget, QVBoxLayout *vlayout); + Q3DBars *m_barGraph; + GraphModifier *modifier; + QBar3DSeries *m_series; + QBarDataProxy *m_proxy; +public: + int m_maxOrder = 12; signals: void percent_plot_changed(); - void make_percent_correction(int maxOrder); + void make_percent_correction(); protected: void closeEvent(QCloseEvent *event); void moveEvent(QMoveEvent *event); @@ -61,9 +67,14 @@ class percentCorrectionDlg : public QDialog std::vector m_zerns; void setData(QVector< surfaceData *> ); void plot(); + void plotProfile(); + void plotSlope(); void updateZoneTable(); QJsonDocument loadZonesFromJson(QString str); double GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, int zone); +private slots: + void on_percentTable_itemChanged(QTableWidgetItem *item); + private slots: void on_minvalue_valueChanged(double arg1); @@ -78,16 +89,14 @@ private slots: void on_saveZones_clicked(); - void on_zoneTable_itemChanged(QTableWidgetItem *item); - - void on_showBars_clicked(bool checked); - void on_Generate_clicked(); void on_maxOrder_valueChanged(int arg1); arma::mat makeZoneZerns(QList centers); + void on_correction_toggled(bool checked); + private: Ui::percentCorrectionDlg *ui; diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index d5ddb638..2aace84f 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -66,13 +66,6 @@ - - - - Qt::Vertical - - - @@ -160,15 +153,25 @@ - + - Show bars + correction true + + + + surface profile + + + false + + + @@ -195,38 +198,17 @@
- - - - - 5 - - - 1 - - - - - - - - - zone center - - - - - - - - - - - - - - - + + + Qt::Vertical + + + + + + + + diff --git a/profileplot.cpp b/profileplot.cpp index d2a6e7af..317e6a21 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -98,7 +98,7 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): { m_pcdlg = new percentCorrectionDlg; - QObject::connect(m_pcdlg, SIGNAL(make_percent_correction(int)), this, SLOT(make_correction_graph(int))); + QObject::connect(m_pcdlg, SIGNAL(make_percent_correction()), this, SLOT(make_correction_graph())); zoomed = false; m_defocus_mode = false; m_plot = new QwtPlot(this); @@ -433,9 +433,10 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ // have to decide what is maxOrder zernikeProcess *zp = NULL; -int maxOrder = 18; -void ProfilePlot::make_correction_graph( int maxOrder){ + +void ProfilePlot::make_correction_graph(){ m_showCorrection = true; + int maxOrder = m_pcdlg->m_maxOrder; // for each selected wave front zernikeProcess zp; @@ -459,71 +460,12 @@ void ProfilePlot::make_correction_graph( int maxOrder){ 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); + surfs << new surfaceData( md->lambda, penColor, theZerns ,name); } m_pcdlg->setData(surfs); } -#ifdef notnow -extern double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double radius); - -QPolygonF ProfilePlot::createZernProfile(wavefront *wf){ - mirrorDlg &md = *mirrorDlg::get_Instance(); - double radius = md.m_clearAperature/2.; // mirror radius of clear aperture - - double RoC = md.roc; - if (zp == NULL) - zp = new zernikeProcess; - zp->initGrid(*wf, maxOrder); - std::vector theZerns; - theZerns = zp->ZernFitWavefront(*wf); - - // make the profl - int wx = wf->data.size[1]; - - int numType = CV_64FC1; - cv::Mat result = cv::Mat::zeros(wx,wx, numType); - - - - // apply the artificial null - theZerns[8] -= md.z8 * md.cc; - // build surface with only spherical terms - for (unsigned long long i = 4; i < zp->m_zerns.n_rows; ++i){ - - double S1 = 0.0; - unsigned int z = 8; - for (unsigned int j = 5; z < theZerns.size(); ++j){ - - double val = theZerns[z]; - S1 += val * zp->m_zerns(i,z); - - z = j * j/4 + j; - } - int x = zp->m_col[i]; - int y = zp->m_row[i]; - if (S1 == 0.0) S1 += .0000001; - result.at(y,x) = S1; - if (y == wx/2.){ - qDebug() << x << y << S1; - } - - } - QPolygonF surf; - int half = result.cols/2; - for (int i = 0; i < result.cols; ++i){ - // map 0 - n to -radius to radius - double x = -radius + 2 * ((double)i/result.cols) * radius; - surf << QPointF(x,result.at(i,half)); - //qDebug() << surf.last(); - } - //m_pcdlg->plot(1, theZerns, radius, md.roc, - //md.cc,md.z8, md.lambda, outputLambda,Qt::black); - return surf; -} -extern double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double radius); -#endif void ProfilePlot::populate() { @@ -598,81 +540,76 @@ void ProfilePlot::populate() case 1: { // show 16 diameters - surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); - QList list = saTools->SelectedWaveFronts(); - bool firstPlot = true; - QColor penColor = QColor("blue"); - - for (int indx = 0; indx < list.size(); ++indx){ - if (indx > 0) penColor = QColor(plotColors[indx % 10]); - QPolygonF avg; - QString t = "Average of all 16 diameters"; - QwtText title(t); - title.setRenderFlags( Qt::AlignHCenter | Qt::AlignBottom ); - - QFont font; - font.setPointSize(12); - title.setFont( font ); - title.setColor(Qt::blue); - QwtPlotTextLabel *titleItem = new QwtPlotTextLabel(); - titleItem->setText( title ); - titleItem->attach( m_plot ); - - double startAngle = g_angle; - QPolygonF sum; - QMap count; - for (int i = 0; i < 16; ++i){ - QPolygonF points; - g_angle = startAngle + i * M_PI/ 16; - - QwtPlotCurve *cprofile = new QwtPlotCurve( ); - cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); - cprofile->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); - cprofile->setPen( Qt::black ); - - points = createProfile( m_showNm * m_showSurface,wfs->at(list[indx])); - if (i == 0) { - sum = points; - for (int j = 0; j < sum.length(); ++j) - count[j] = 1; - } - else { - for(int j = 0; j < fmin(sum.length(),points.length());++j){ - sum[j].ry() += points[j].y();; - - if (count.contains(j)) count[j] += 1 ; - else count[j] = 1; - } - } - if (!m_showCorrection){ - cprofile->setSamples( points); - cprofile->attach( m_plot ); - } - } - - // plot the average profile - int i = 0; - foreach(QPointF p, sum){ - avg << QPointF(p.x(),p.y()/(count[i++])); - } - QString name("average"); - if (m_showCorrection){ - QStringList path = wfs->at(list[indx])->name.split("/"); - name = path.last().replace(".wft",""); - } - QwtPlotCurve *cprofileavg = new QwtPlotCurve( name); - cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); - cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); - cprofileavg->setLegendIconSize(QSize(50,20)); - cprofileavg->setPen( QPen(penColor,5) ); - cprofileavg->setSamples( avg); - cprofileavg->attach( m_plot ); - g_angle = startAngle; - - } - - - break; + surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); + QList list = saTools->SelectedWaveFronts(); + bool firstPlot = true; + QColor penColor = QColor("blue"); + + for (int indx = 0; indx < list.size(); ++indx){ + if (indx > 0) penColor = QColor(plotColors[indx % 10]); + QPolygonF avg; + QString t = "Average of all 16 diameters"; + QwtText title(t); + title.setRenderFlags( Qt::AlignHCenter | Qt::AlignBottom ); + + QFont font; + font.setPointSize(12); + title.setFont( font ); + title.setColor(Qt::blue); + QwtPlotTextLabel *titleItem = new QwtPlotTextLabel(); + titleItem->setText( title ); + titleItem->attach( m_plot ); + + double startAngle = g_angle; + QPolygonF sum; + + for (int i = 0; i < 16; ++i){ + QPolygonF points; + g_angle = startAngle + i * M_PI/ 16; + + QwtPlotCurve *cprofile = new QwtPlotCurve( ); + cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); + cprofile->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); + cprofile->setPen( Qt::black ); + + points = createProfile( m_showNm * m_showSurface,wfs->at(list[indx])); + if (i == 0) { + sum = points; + } + else { + for(int j = 0; j < fmin(sum.length(),points.length());++j){ + sum[j].ry() += points[j].y(); + } + } + if (!m_showCorrection){ + cprofile->setSamples( points); + cprofile->attach( m_plot ); + } + } + + // plot the average profile + foreach(QPointF p, sum){ + avg << QPointF(p.x(),p.y()/16); + } + QString name("average"); + if (m_showCorrection){ + QStringList path = wfs->at(list[indx])->name.split("/"); + name = path.last().replace(".wft",""); + } + QwtPlotCurve *cprofileavg = new QwtPlotCurve( name); + cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); + cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); + cprofileavg->setLegendIconSize(QSize(50,20)); + cprofileavg->setPen( QPen(penColor,5) ); + cprofileavg->setSamples( avg); + cprofileavg->attach( m_plot ); + g_angle = startAngle; + + + } + + + break; } case 2:{ // show each wave front @@ -828,6 +765,7 @@ void ProfilePlot::showCorrection(bool show){ if (show){ m_pcdlg->show(); m_pcdlg->raise(); + make_correction_graph(); } else diff --git a/profileplot.h b/profileplot.h index d1c52b03..24a6d4db 100644 --- a/profileplot.h +++ b/profileplot.h @@ -88,7 +88,7 @@ public slots: void contourPointSelected(const QPointF &pos); void populate(); void showCorrection(bool); - void make_correction_graph(int maxOrder); + void make_correction_graph(); //QPolygonF createZernProfile(wavefront *wf); private: From 4b8e2fc110965a6f1fba15a991555c35acc4b7bb Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Thu, 20 Mar 2025 15:22:50 -0500 Subject: [PATCH 11/25] profile and zernike based percentages. Profile is not the same but is when input wave length is 550. Added hot keys I and ctrl-o. Limited profile y offset to just one wave from when multiple are selected. Change percent control to a button. --- DFTFringe_Dale.pro | 3 + mainwindow.cpp | 27 ++++ mainwindow.h | 1 + percentcorrectiondlg.cpp | 144 +++++++++++++------- percentcorrectiondlg.h | 17 ++- percentcorrectiondlg.ui | 14 +- profileplot.cpp | 238 ++++++++++++++++++++++------------ profileplot.h | 7 +- settingsGeneral2.h | 16 ++- settingsgeneral2.cpp | 2 + settingsigram.cpp | 14 +- settingsigram.h | 2 + settingsigram.ui | 7 + settingsigramimportconfig.cpp | 52 ++++++++ settingsigramimportconfig.h | 28 ++++ settingsigramimportconfig.ui | 139 ++++++++++++++++++++ 16 files changed, 563 insertions(+), 148 deletions(-) create mode 100644 settingsigramimportconfig.cpp create mode 100644 settingsigramimportconfig.h create mode 100644 settingsigramimportconfig.ui diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index 04603eb9..35e6b779 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -45,6 +45,7 @@ SOURCES += main.cpp \ percentcorrectiondlg.cpp \ profileplot.cpp \ psiresizeimagesdlg.cpp \ + settingsigramimportconfig.cpp \ surface3dcontrolsdlg.cpp \ surfacegraph.cpp \ surfacelightingproxy.cpp \ @@ -164,6 +165,7 @@ HEADERS += mainwindow.h \ percentcorrectiondlg.h \ profileplot.h \ psiresizeimagesdlg.h \ + settingsigramimportconfig.h \ surface3dcontrolsdlg.h \ surfacegraph.h \ surfacelightingproxy.h \ @@ -284,6 +286,7 @@ FORMS += mainwindow.ui \ profileplot.ui \ contourtools.ui \ psiresizeimagesdlg.ui \ + settingsigramimportconfig.ui \ surface3dcontrolsdlg.ui \ surfaceanalysistools.ui \ metricsdisplay.ui \ diff --git a/mainwindow.cpp b/mainwindow.cpp index 4c469488..659d8013 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -200,6 +200,11 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_igramArea, SIGNAL(doDFT()), m_dftArea, SLOT(doDFT())); enableShiftButtons(true); + QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_I), this); + QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(importIgram())); + + QShortcut *shortcut1 = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_O), this); + QObject::connect(shortcut1, SIGNAL(activated()), this, SLOT(importIgram())); connect(m_dftTools,SIGNAL(doDFT()),m_dftArea,SLOT(doDFT())); settingsDlg = Settings2::getInstance(); @@ -261,6 +266,28 @@ MainWindow::MainWindow(QWidget *parent) : openWaveFrontonInit(args); } +void MainWindow::importIgram() { + QSettings set; + + if (set.value("importIgramOpenMostRecent", true).toBool()){ + QString dirPath = set.value("importIgramPath",".").toString(); + QDir dir(dirPath); + QStringList filters; + filters << "*.png" << "*.jpg" << "*.jpeg" << "*.bmp" << "*.gif"; // Add more image formats if needed + + dir.setNameFilters(filters); + dir.setFilter(QDir::Files | QDir::Readable); + QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Time | QDir::Reversed); + + if (fileList.isEmpty()) + return; + + loadFile( fileList.last().filePath()); + } + else on_actionLoad_Interferogram_triggered(); + +} + int showmem(QString t); void MainWindow::openWaveFrontonInit(QStringList args){ QProgressDialog pd(" Loading wavefronts in progress.", "Cancel", 0, 100); diff --git a/mainwindow.h b/mainwindow.h index ff293490..539ac502 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -128,6 +128,7 @@ private slots: void on_saveOutline_clicked(); + void importIgram(); //void on_actionSimulated_interferogram_triggered(); void on_actionPrevious_Wave_front_triggered(); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 206a2e43..c6c2dafc 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -199,47 +199,75 @@ void percentCorrectionDlg::makeZones(){ zoneZerns = makeZoneZerns(zoneCenter); } -int maxorder = 18; -double percentCorrectionDlg::getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x, double null = 0.){ - - double num1 = x / MirrorRad; +// the profile version needs the null removed and is in output lambda (usually 550); +// zernike based does not need the null removed but needs to use laser wave length +double percentCorrectionDlg::getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x, double null = 0., + bool useavg = false){ + + double num1 = x / MirrorRad; + arma::rowvec rhov(1), thetav(1); + rhov[0] = x/m_radius; thetav[0] = 0.; + zernikeProcess zp; + zp.setMaxOrder(m_maxOrder); + + arma::mat theZs = zp.zpmC(rhov, thetav, m_maxOrder); + + double val = 0; + if (useavg) { + + // find x location in profile + val = m_avg[m_avg.length()-1].y(); + for (int i = 0; i < m_avg.length(); ++i){ + if (m_avg[i].x() == x){ + val = m_avg[i].y(); + break; + } + if (m_avg[i].x() > x){ + double dx = m_avg[i].x() - m_avg[i-1].x(); + double dy = m_avg[i].y() - m_avg[i-1].y(); + val = m_avg[i-1].y() + (x - m_avg[i-1].x())*(dy/dx); + break; + } + } + val += (null) * theZs(0,8); + double spherey = RoC - sqrt(pow(RoC, 2.0) - pow(x, 2.0)); + double zerny = val * m_outputLambda * .5E-6; + double surf = spherey + zerny; + return surf; + } + else { - arma::rowvec rhov(1), thetav(1); - rhov[0] = x/m_radius; thetav[0] = 0.; - zernikeProcess zp; - zp.setMaxOrder(m_maxOrder); + // for each spherical term + int z = 8; + for(unsigned int j = 6; z < theZs.n_cols; j+=2){ - arma::mat theZs = zp.zpmC(rhov, thetav, m_maxOrder); + val += Zernikes[z] * theZs(0,z); + z = j * j /4 + j; + } + double spherey = RoC - sqrt(pow(RoC, 2.0) - pow(x, 2.0)); + double zerny = val * m_lambda_nm * .5E-6; + double surf = spherey + zerny; + return surf; + } - double val = 0; - // for each spherical term - int z = 8; - for(unsigned int j = 6; z < theZs.n_cols; j+=2){ - if (z == 8) - val += (Zernikes[8]- null) * theZs(0,z); - else - val += Zernikes[z] * theZs(0,z); - z = j * j /4 + j; - } +} +// profile from profile plot with null removed +void percentCorrectionDlg::setProfile(QPolygonF profile){ + m_avg = profile; - double spherey = RoC - sqrt(pow(RoC, 2.0) - pow(x, 2.0)); - double zerny = val * m_lambda_nm * .5E-6; - double surf = spherey + zerny; - return surf; } - // will use zernike values to compute two surface points x+- .01x away from x // then compute normal slope from that. -double percentCorrectionDlg::getnormalSlope(double RoC, double radius, std::vector Zernikes, double x, double null = 0){ +double percentCorrectionDlg::getnormalSlope(double RoC, double radius, std::vector Zernikes, double x, double null = 0, bool useAvg = false){ double num1 = x / 100.0; - double surface1 = getZernSurface(RoC, radius, Zernikes, x - num1, null); // problem with zonendx (the delta is not same as zonendx) - double surface2 = getZernSurface(RoC, radius, Zernikes, x + num1, null); + double surface1 = getZernSurface(RoC, radius, Zernikes, x - num1, null,useAvg); // problem with zonendx (the delta is not same as zonendx) + double surface2 = getZernSurface(RoC, radius, Zernikes, x + num1, null,useAvg); double slope = (surface2 - surface1)/ (2 * num1); slope = -1.0 / slope; @@ -249,11 +277,11 @@ double percentCorrectionDlg::getnormalSlope(double RoC, double radius, std::vect // y = mx + b // b = y - mx -double percentCorrectionDlg::GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, double x) +double percentCorrectionDlg::GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, double x, double null, bool use_avg) { - double slope = getnormalSlope(RoC, MirrorRad, Zernikes, x); - double surface = getZernSurface(RoC, MirrorRad, Zernikes, x); + double slope = getnormalSlope(RoC, MirrorRad, Zernikes, x, null, use_avg); + double surface = getZernSurface(RoC, MirrorRad, Zernikes, x, null, use_avg); double actualKe = surface - x * slope - RoC; @@ -294,7 +322,8 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ IdealzoneKnife << 0.; ActualZoneKnife << 0.0; - + mirrorDlg *md = mirrorDlg::get_Instance(); + double nullval = md->z8 * md->cc; // process each zone center QPolygonF idealknives; @@ -306,13 +335,14 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ double zernOffset = 0.; for (int zone = 0; zone < zoneCenter.length(); ++zone){ - - double x = zoneCenter[zone]; //idealSurface << QPointF(x, normIdealSlope); double idealknife = getIdealKE(m_roc, x); - double zernKnife = GetActualKE(m_roc, m_radius, surf->zernvalues, x); + + // when using average profile as the profile we need to remove the artificial + // null from the profile thus the nullval being passed. + double zernKnife = GetActualKE(m_roc, m_radius, surf->zernvalues, x, nullval ,ui->useProfile->isChecked()); if (zone == 0){ idealoffset = idealknife; @@ -344,7 +374,7 @@ void percentCorrectionDlg::plotProfile(){ QwtPlotCurve *Curve = new QwtPlotCurve(); QPolygonF profile; for(double r = -m_radius; r <= m_radius; r += 1. ){ - double y = getZernSurface(m_roc, m_radius, surfs[i]->zernvalues, fabs(r), nullval); + double y = getZernSurface(m_roc, m_radius, surfs[i]->zernvalues, fabs(r), nullval, false); double sphery = m_roc - sqrt(pow(m_roc, 2.0) - pow(r, 2.0)); y -= sphery; @@ -354,9 +384,29 @@ void percentCorrectionDlg::plotProfile(){ Curve->setSamples(profile); Curve->attach(ui->plot); - Curve->setPen(surfs[i]->penColor,5); + Curve->setPen(Qt::green,5); Curve->attach(ui->plot); } + QPolygonF profile2; + // now plot the m_avg surface + int i = 0; + for(double r = 0; r < m_avg.length(); r += 1. ){ + + // qDebug() << "r" << r << m_avg[i]; + double y = m_avg[r].y();//getZernSurface(m_roc, m_radius, surfs[i]->zernvalues, fabs(r), true); + + double sphery = m_roc - sqrt(pow(m_roc, 2.0) - pow(r, 2.0)); + //y -= sphery; + //y /= m_lambda_nm * .5E-6; + profile2 << QPointF(m_avg[r].x(), y); + + } + QwtPlotCurve *Curve2 = new QwtPlotCurve(); + Curve2->setSamples(profile2); + Curve2->attach(ui->plot); + Curve2->setPen(Qt::blue,5); + Curve2->attach(ui->plot); + ui->plot->setAxisScale(QwtPlot::xBottom, -m_radius, m_radius); ui->plot->setAxisAutoScale(QwtPlot::yLeft); @@ -364,8 +414,6 @@ void percentCorrectionDlg::plotProfile(){ ui->plot->replot(); } void percentCorrectionDlg::plot(){ - - QPolygonF expectedslope; QPolygonF actualslope; QPolygonF percentplot; @@ -397,11 +445,10 @@ void percentCorrectionDlg::plot(){ grid->attach( ui->plot); - if (!ui->correction->isChecked()){ - qDebug() << "doing profile"; - plotProfile(); - return; - } +// if (!ui->correction->isChecked()){ +// plotProfile(); +// return; +// } ui->percentTable->blockSignals(true); ui->percentTable->setRowCount(surfs.length() + 1); @@ -539,6 +586,9 @@ void percentCorrectionDlg::setData( QVector< surfaceData *> data) { mirrorDlg &md = *mirrorDlg::get_Instance(); m_roc = md.roc; m_lambda_nm = md.lambda; + QSettings set; + m_outputLambda = set.value("outputLambda").toDouble(); + m_radius = md.m_clearAperature/2.; surfs = data; ui->percentTable->setRowCount(data.length()); @@ -703,7 +753,13 @@ void percentCorrectionDlg::on_percentTable_itemChanged(QTableWidgetItem *item) -void percentCorrectionDlg::on_correction_toggled(bool checked) +void percentCorrectionDlg::on_useProfile_clicked(bool checked) +{ + plot(); +} + + +void percentCorrectionDlg::on_useZernikies_clicked(bool checked) { plot(); } diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h index 9df9adf8..a00096a6 100644 --- a/percentcorrectiondlg.h +++ b/percentcorrectiondlg.h @@ -39,14 +39,16 @@ class percentCorrectionDlg : public QDialog QList > m_barData; QStringList m_seriesName; - QPolygonF m_avg; + QPolygonF m_avg; // from profile plot int m_currentprofileIndex = 0; int m_currentSelectedZone = -1; QVector surfs; QPolygonF makePercentages(surfaceData *); - double getnormalSlope(double RoC, double radius, std::vector Zernikes, double x, double null); - double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x, double null); + + double getnormalSlope(double RoC, double radius, std::vector Zernikes, double x, double null, bool use_avg); + double getZernSurface( double RoC, double MirrorRad, std::vector Zernikes, double x, + double null, bool useavg); double GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, double x); void make_3DBarControls(QWidget *widget, QVBoxLayout *vlayout); Q3DBars *m_barGraph; @@ -55,6 +57,7 @@ class percentCorrectionDlg : public QDialog QBarDataProxy *m_proxy; public: int m_maxOrder = 12; + signals: void percent_plot_changed(); void make_percent_correction(); @@ -66,12 +69,14 @@ class percentCorrectionDlg : public QDialog ~percentCorrectionDlg(); std::vector m_zerns; void setData(QVector< surfaceData *> ); + void setProfile(QPolygonF profile); void plot(); void plotProfile(); void plotSlope(); void updateZoneTable(); QJsonDocument loadZonesFromJson(QString str); - double GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, int zone); + double GetActualKE(double RoC, double MirrorRad, std::vector Zernikes, double x, double nulll, bool use_avg); + private slots: void on_percentTable_itemChanged(QTableWidgetItem *item); @@ -95,7 +100,9 @@ private slots: arma::mat makeZoneZerns(QList centers); - void on_correction_toggled(bool checked); + void on_useProfile_clicked(bool checked); + + void on_useZernikies_clicked(bool checked); private: Ui::percentCorrectionDlg *ui; diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index 2aace84f..43e323a9 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -6,7 +6,7 @@ 0 0 - 505 + 528 300 @@ -153,22 +153,22 @@
- + - correction + use profile - true + false - + - surface profile + use zernikes - false + true diff --git a/profileplot.cpp b/profileplot.cpp index 317e6a21..36ca26f1 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -116,7 +116,7 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): connect(ShowAll, SIGNAL(clicked()), this, SLOT(showAll())); l1->addStretch(); showSlopeError = new QCheckBox("Show Slope: "); - showPercentCorrection = new QCheckBox("Show Correction"); + showPercentCorrection = new QPushButton("Show Correction"); slopeLimitSB = new QDoubleSpinBox(); @@ -139,7 +139,7 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): showSlopeError->setChecked(m_showSlopeError); connect(slopeLimitSB, SIGNAL(valueChanged(double)), this, SLOT(slopeLimit(double))); connect(showSlopeError,SIGNAL(clicked(bool)), this, SLOT(showSlope(bool))); - connect(showPercentCorrection,SIGNAL(clicked(bool)), this, SLOT(showCorrection(bool))); + connect(showPercentCorrection,SIGNAL(clicked()), this, SLOT(showCorrection())); l1->addWidget(showPercentCorrection); l1->addWidget(showSlopeError); l1->addWidget(slopeLimitSB); @@ -352,12 +352,74 @@ void ProfilePlot::setDefocusValue(double val){ m_plot->replot(); } } +QPolygonF ProfilePlot::createAverageProfile(double umnits, wavefront *wf, bool removeNull = false){ + surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); + QList list = saTools->SelectedWaveFronts(); + QPolygonF avg; + for (int indx = 0; indx < list.size(); ++indx){ -QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ - QPolygonF points; + double startAngle = g_angle; + QPolygonF sum; + QMap count; + for (int i = 0; i < 720; ++i){ + QPolygonF points; + g_angle = startAngle + i * M_PI/ 720; - double steps = 1./wf->m_outside.m_radius; + QwtPlotCurve *cprofile = new QwtPlotCurve( ); + cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); + cprofile->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); + cprofile->setPen( Qt::black ); + + points = createProfile( m_showNm * m_showSurface,wfs->at(list[indx])); + if (i == 0) { + sum = points; + for (int j = 0; j < sum.length(); ++j) + count[j] = 1; + } + else { + for(int j = 0; j < fmin(sum.length(),points.length());++j){ + sum[j].ry() += points[j].y();; + + if (count.contains(j)) count[j] += 1 ; + else count[j] = 1; + } + } + + } + + // plot the average profile + int i = 0; + foreach(QPointF p, sum){ + if (p.x() < 0) continue; + avg << QPointF(p.x(),p.y()/(count[i++])); + } + + } +// if (removeNull){ +// // Nulled y = (z8 - null)term8(rho) z8 * term8 - null * term8; +// // remove artificial null effect. +// mirrorDlg &md = *mirrorDlg::get_Instance(); +// QPolygonF avg2; +// for (int i = 0; i < avg.length(); ++i){ +// if (avg[i].x() < 0) +// continue; +// 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)); +// avg2 << QPointF(avg[i].x(),y); +// } +// avg = avg2; +// } +qDebug() << "avg" << avg; + return avg; +} +QPolygonF ProfilePlot::createProfile(double units, wavefront *wf, bool allowOffset){ + QPolygonF points; mirrorDlg &md = *mirrorDlg::get_Instance(); + double steps = 1./wf->m_outside.m_radius; + double offset = y_offset; + if (!allowOffset) offset = 0.; double radius = md.m_clearAperature/2.; double obs_radius = md.obs/2.; @@ -388,12 +450,12 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf){ if (m_defocus_mode){ defocus = (m_defocusValue)* (-1. + 2. * rad * rad); points << QPointF(radx,(units * (m_defocus_wavefront((int)dy,(int)dx) + defocus ) * - wf->lambda/outputLambda) +y_offset * units); + wf->lambda/outputLambda) +offset * units); } else { points << QPointF(radx,(units * (wf->workData((int)dy,(int)dx) ) * - wf->lambda/outputLambda) +y_offset * units); + wf->lambda/outputLambda) +offset * units); } } @@ -463,6 +525,8 @@ void ProfilePlot::make_correction_graph(){ surfs << new surfaceData( md->lambda, penColor, theZerns ,name); } + QPolygonF avg = createAverageProfile(1., wfs->at(list[0]),true); + m_pcdlg->setProfile(avg); m_pcdlg->setData(surfs); } @@ -538,79 +602,85 @@ void ProfilePlot::populate() break; } - case 1: { // show 16 diameters + case 1: { // show 16 diameters surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); - QList list = saTools->SelectedWaveFronts(); - bool firstPlot = true; - QColor penColor = QColor("blue"); - - for (int indx = 0; indx < list.size(); ++indx){ - if (indx > 0) penColor = QColor(plotColors[indx % 10]); - QPolygonF avg; - QString t = "Average of all 16 diameters"; - QwtText title(t); - title.setRenderFlags( Qt::AlignHCenter | Qt::AlignBottom ); - - QFont font; - font.setPointSize(12); - title.setFont( font ); - title.setColor(Qt::blue); - QwtPlotTextLabel *titleItem = new QwtPlotTextLabel(); - titleItem->setText( title ); - titleItem->attach( m_plot ); - - double startAngle = g_angle; - QPolygonF sum; - - for (int i = 0; i < 16; ++i){ - QPolygonF points; - g_angle = startAngle + i * M_PI/ 16; - - QwtPlotCurve *cprofile = new QwtPlotCurve( ); - cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); - cprofile->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); - cprofile->setPen( Qt::black ); - - points = createProfile( m_showNm * m_showSurface,wfs->at(list[indx])); - if (i == 0) { - sum = points; - } - else { - for(int j = 0; j < fmin(sum.length(),points.length());++j){ - sum[j].ry() += points[j].y(); - } - } - if (!m_showCorrection){ - cprofile->setSamples( points); - cprofile->attach( m_plot ); - } - } - - // plot the average profile - foreach(QPointF p, sum){ - avg << QPointF(p.x(),p.y()/16); - } - QString name("average"); - if (m_showCorrection){ - QStringList path = wfs->at(list[indx])->name.split("/"); - name = path.last().replace(".wft",""); - } - QwtPlotCurve *cprofileavg = new QwtPlotCurve( name); - cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); - cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); - cprofileavg->setLegendIconSize(QSize(50,20)); - cprofileavg->setPen( QPen(penColor,5) ); - cprofileavg->setSamples( avg); - cprofileavg->attach( m_plot ); - g_angle = startAngle; - - - } - - - break; - } + QList list = saTools->SelectedWaveFronts(); + bool firstPlot = true; + QColor penColor = QColor("blue"); + + for (int indx = 0; indx < list.size(); ++indx){ + if (indx > 0) penColor = QColor(plotColors[indx % 10]); + QPolygonF avg; + QString t = "Average of all 16 diameters"; + QwtText title(t); + title.setRenderFlags( Qt::AlignHCenter | Qt::AlignBottom ); + + QFont font; + font.setPointSize(12); + title.setFont( font ); + title.setColor(Qt::blue); + QwtPlotTextLabel *titleItem = new QwtPlotTextLabel(); + titleItem->setText( title ); + titleItem->attach( m_plot ); + + double startAngle = g_angle; + QPolygonF sum; + QMap count; + for (int i = 0; i < 16; ++i){ + QPolygonF points; + g_angle = startAngle + i * M_PI/ 16; + + QwtPlotCurve *cprofile = new QwtPlotCurve( ); + cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); + cprofile->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); + cprofile->setPen( Qt::black ); + + points = createProfile( m_showNm * m_showSurface,wfs->at(list[indx])); + if (i == 0) { + sum = points; + for (int j = 0; j < sum.length(); ++j) + count[j] = 1; + } + else { + for(int j = 0; j < fmin(sum.length(),points.length());++j){ + sum[j].ry() += points[j].y();; + + if (count.contains(j)) count[j] += 1 ; + else count[j] = 1; + } + } + + cprofile->setSamples( points); + cprofile->attach( m_plot ); + + } + + // plot the average profile + int i = 0; + foreach(QPointF p, sum){ + avg << QPointF(p.x(),p.y()/(count[i++])); + } + QString name("average"); + if (m_showCorrection){ + QStringList path = wfs->at(list[indx])->name.split("/"); + name = path.last().replace(".wft",""); + } + QwtPlotCurve *cprofileavg = new QwtPlotCurve( name); + cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); + cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); + cprofileavg->setLegendIconSize(QSize(50,20)); + cprofileavg->setPen( QPen(penColor,5) ); + cprofileavg->setSamples( avg); + cprofileavg->attach( m_plot ); + g_angle = startAngle; + + + } + + + break; + } case 2:{ // show each wave front m_plot->insertLegend( new QwtLegend() , QwtPlot::BottomLegend); @@ -633,7 +703,7 @@ void ProfilePlot::populate() cprofile->setLegendIconSize(QSize(50,20)); cprofile->setPen(QPen(Settings2::m_profile->getColor(i),width)); cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); - cprofile->setSamples( createProfile( m_showNm * m_showSurface,wfs->at(list[i]))); + cprofile->setSamples( createProfile( m_showNm * m_showSurface,wfs->at(list[i]), i==0)); cprofile->attach( m_plot ); @@ -760,16 +830,12 @@ void ProfilePlot::contourPointSelected(const QPointF &pos){ compass->blockSignals(false); } -void ProfilePlot::showCorrection(bool show){ - //m_showCorrection = show; - if (show){ +void ProfilePlot::showCorrection(){ + + m_pcdlg->show(); m_pcdlg->raise(); make_correction_graph(); - } - else - m_pcdlg->close(); - } diff --git a/profileplot.h b/profileplot.h index 24a6d4db..310af558 100644 --- a/profileplot.h +++ b/profileplot.h @@ -49,7 +49,8 @@ class ProfilePlot : public QWidget QVector *wfs; void setSurface(wavefront * wf); virtual void resizeEvent( QResizeEvent * ); - QPolygonF createProfile(double units, wavefront *wf); + QPolygonF createProfile(double units, wavefront *wf, bool allowOffset = true); + QPolygonF createAverageProfile(double umnits, wavefront *wf, bool removeNull); ContourTools *m_tools; double m_waveRange; virtual bool eventFilter( QObject *, QEvent * ); @@ -87,7 +88,7 @@ public slots: void slopeLimit(double); void contourPointSelected(const QPointF &pos); void populate(); - void showCorrection(bool); + void showCorrection(); void make_correction_graph(); //QPolygonF createZernProfile(wavefront *wf); private: @@ -98,7 +99,7 @@ public slots: QString offsetType; QwtCompass *compass; QCheckBox *showSlopeError; - QCheckBox *showPercentCorrection; + QPushButton *showPercentCorrection; QDoubleSpinBox *slopeLimitSB; double m_defocusValue; diff --git a/settingsGeneral2.h b/settingsGeneral2.h index f35e4184..ad32a54f 100644 --- a/settingsGeneral2.h +++ b/settingsGeneral2.h @@ -25,23 +25,35 @@ class SettingsGeneral2 : public QDialog bool shouldDownsize(){ return m_downsize;} int wavefrontSize(){ return m_waveFrontSize;} double getObs(); + +public slots: + void updateContour(); signals: void outputLambdaChanged(double val); void updateContourPlot(); -public slots: - void updateContour(); + private slots: void on_checkBox_clicked(bool checked); + void on_starTestMakeCb_clicked(bool checked); + void on_showConditionNumbersCb_clicked(bool checked); + void on_wavefrontSizeSb_valueChanged(int arg1); + void on_downSizeCB_clicked(bool checked); + void on_AstigDistGraphWidth_valueChanged(int val); + void on_applyOffsets_clicked(bool checked); + void on_outputLambda_valueChanged(double val); + void on_apply_clicked(); + void on_rulerParms_clicked(); + private: Ui::SettingsGeneral2 *ui; bool m_useSVD; diff --git a/settingsgeneral2.cpp b/settingsgeneral2.cpp index 4c2a18bd..a6c8e7f7 100644 --- a/settingsgeneral2.cpp +++ b/settingsgeneral2.cpp @@ -66,6 +66,8 @@ void SettingsGeneral2::on_rulerParms_clicked(){ } + + void SettingsGeneral2::on_outputLambda_valueChanged(double val){ QSettings set; set.setValue("outputLambda", val); diff --git a/settingsigram.cpp b/settingsigram.cpp index 3280a9b2..7f3d2925 100644 --- a/settingsigram.cpp +++ b/settingsigram.cpp @@ -23,7 +23,7 @@ #include #include #include "spdlog/spdlog.h" - +#include "settingsigramimportconfig.h" static inline QString colorButtonStyleSheet(const QColor &bgColor) { if (bgColor.isValid()) { @@ -271,3 +271,15 @@ void settingsIGram::on_holeY_valueChanged(int arg1) QSettings set; set.setValue("autoholeYOffset", arg1); } + +void settingsIGram::on_importConfig_clicked() +{ + // set the path to igrams that "I key" should look at + // set select most recent + // set just open path + // set open camera stream + + settingsIgramImportConfig dlg; + dlg.exec(); +} + diff --git a/settingsigram.h b/settingsigram.h index 37511ae7..0e5557d8 100644 --- a/settingsigram.h +++ b/settingsigram.h @@ -86,6 +86,8 @@ private slots: void on_holeY_valueChanged(int arg1); + void on_importConfig_clicked(); + private: Ui::settingsIGram *ui; diff --git a/settingsigram.ui b/settingsigram.ui index 189529b1..b82d3114 100644 --- a/settingsigram.ui +++ b/settingsigram.ui @@ -358,6 +358,13 @@ + + + + Import outline configuration (what hot key I does) + + + diff --git a/settingsigramimportconfig.cpp b/settingsigramimportconfig.cpp new file mode 100644 index 00000000..91081f12 --- /dev/null +++ b/settingsigramimportconfig.cpp @@ -0,0 +1,52 @@ +#include "settingsigramimportconfig.h" +#include "ui_settingsigramimportconfig.h" +#include +#include +settingsIgramImportConfig::settingsIgramImportConfig(QWidget *parent) : + QDialog(parent), + ui(new Ui::settingsIgramImportConfig) +{ + ui->setupUi(this); + QSettings set; + ui->importPath->setText(set.value("importIgramPath",".").toString()); + + ui->openPath->setChecked(set.value("importIgramOpenOnly", false).toBool()); + ui->openMostRecent->setChecked(set.value("importIgramOpenMostRecent", true).toBool()); + +} + +settingsIgramImportConfig::~settingsIgramImportConfig() +{ + delete ui; +} + + + + +void settingsIgramImportConfig::on_browse_clicked() +{ + QSettings set; + QString defaultPath = set.value("lastPath",".").toString(); + QString path = set.value("importIgramPath",defaultPath).toString(); + QString directory = QFileDialog::getExistingDirectory( + 0, "Choose directory", "", + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + ui->importPath->setText(directory); + +} + + + +#include + +void settingsIgramImportConfig::on_buttonBox_accepted() +{ + QSettings set; + set.setValue("importIgramPath",ui->importPath->text()); + + + set.setValue("importIgramOpenOnly", ui->openPath->isChecked()); + set.setValue("importIgramOpenMostRecent", ui->openMostRecent->isChecked()); +} + diff --git a/settingsigramimportconfig.h b/settingsigramimportconfig.h new file mode 100644 index 00000000..7ea0cd06 --- /dev/null +++ b/settingsigramimportconfig.h @@ -0,0 +1,28 @@ +#ifndef SETTINGSIGRAMIMPORTCONFIG_H +#define SETTINGSIGRAMIMPORTCONFIG_H + +#include + +namespace Ui { +class settingsIgramImportConfig; +} + +class settingsIgramImportConfig : public QDialog +{ + Q_OBJECT + +public: + explicit settingsIgramImportConfig(QWidget *parent = nullptr); + ~settingsIgramImportConfig(); + +private slots: + + void on_browse_clicked(); + + void on_buttonBox_accepted(); + +private: + Ui::settingsIgramImportConfig *ui; +}; + +#endif // SETTINGSIGRAMIMPORTCONFIG_H diff --git a/settingsigramimportconfig.ui b/settingsigramimportconfig.ui new file mode 100644 index 00000000..59280b00 --- /dev/null +++ b/settingsigramimportconfig.ui @@ -0,0 +1,139 @@ + + + settingsIgramImportConfig + + + + 0 + 0 + 640 + 480 + + + + "I" hot key config + + + + + + Choose what the hot key "I" does when pressed on the main window. + + + + + + + + + Path to igrams to import: + + + + + + + + + + ... + + + + + + + + + + + Just Open Dir + + + + + + + Open most recent igram + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + settingsIgramImportConfig + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + settingsIgramImportConfig + reject() + + + 316 + 260 + + + 286 + 274 + + + + + From 4c1982c3a9b9f3bbff352289e0c09fae306d8b7b Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Sun, 6 Apr 2025 00:57:10 -0500 Subject: [PATCH 12/25] cleaned up percent completion to only use Zernike terms. Added hot key help. Added auto collimation function to ronchi and foucault page. --- DFTFringe_Dale.pro | 3 ++ foucaultview.cpp | 17 +++++++- foucaultview.h | 2 + foucaultview.ui | 89 +++++++++++++++++++--------------------- hotkeysdlg.cpp | 14 +++++++ hotkeysdlg.h | 22 ++++++++++ hotkeysdlg.ui | 71 ++++++++++++++++++++++++++++++++ igramarea.cpp | 2 - mainwindow.cpp | 33 +++++++++++++++ mainwindow.h | 2 + mainwindow.ui | 6 +++ outlinedialog.cpp | 2 +- percentcorrectiondlg.cpp | 16 ++------ percentcorrectiondlg.h | 3 -- percentcorrectiondlg.ui | 20 --------- settingsigram.ui | 4 +- simulationsview.cpp | 4 +- simulationsview.ui | 2 +- 18 files changed, 220 insertions(+), 92 deletions(-) create mode 100644 hotkeysdlg.cpp create mode 100644 hotkeysdlg.h create mode 100644 hotkeysdlg.ui diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index 35e6b779..9812e083 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -33,6 +33,7 @@ SOURCES += main.cpp \ cpoint.cpp \ defocusdlg.cpp \ edgeplot.cpp \ + hotkeysdlg.cpp \ mainwindow.cpp \ igramarea.cpp \ circleoutline.cpp \ @@ -159,6 +160,7 @@ HEADERS += mainwindow.h \ graphicsutilities.h \ dfttools.h \ dftarea.h \ + hotkeysdlg.h \ oglrendered.h \ pdfcalibrationdlg.h \ percentCorrectionSurface.h \ @@ -279,6 +281,7 @@ FORMS += mainwindow.ui \ dfttools.ui \ dftarea.ui \ edgeplot.ui \ + hotkeysdlg.ui \ oglrendered.ui \ pdfcalibrationdlg.ui \ percentcorrectiondlg.ui \ diff --git a/foucaultview.cpp b/foucaultview.cpp index c636f61f..14c96bc4 100644 --- a/foucaultview.cpp +++ b/foucaultview.cpp @@ -197,7 +197,9 @@ void foucaultView::on_makePb_clicked() double z3 = pv / ( moving_constant); bool oldDoNull = md->doNull; - md->doNull = false; + if (!ui->autocollimation->isChecked()){ + md->doNull = false; + } cv::Mat surf_fft; SimulationsView *sv = SimulationsView::getInstance(0); @@ -703,3 +705,16 @@ void foucaultView::on_pushButton_clicked() on_makePb_clicked(); } + + + + +void foucaultView::on_autocollimation_clicked(bool checked) +{ + if (checked) + ui->h2x->setChecked(true); + else + ui->h1x->setChecked(false); + on_makePb_clicked(); +} + diff --git a/foucaultview.h b/foucaultview.h index 591196df..c52afe92 100644 --- a/foucaultview.h +++ b/foucaultview.h @@ -80,6 +80,8 @@ private slots: void on_pushButton_clicked(); + void on_autocollimation_clicked(bool checked); + private: Ui::foucaultView *ui; SurfaceManager *m_sm; diff --git a/foucaultview.ui b/foucaultview.ui index c16a2f8f..9d5c24e4 100644 --- a/foucaultview.ui +++ b/foucaultview.ui @@ -230,53 +230,48 @@ - - - Surface Height - - - - - 10 - 20 - 82 - 17 - - - - 1X - - - true - - - - - - 10 - 40 - 82 - 17 - - - - 2X - - - - - - 10 - 60 - 82 - 17 - - - - 4x - - - + + + + + auto collimation + + + + + + + Surface Height + + + + + + 1X + + + true + + + + + + + 2X + + + + + + + 4x + + + + + + + diff --git a/hotkeysdlg.cpp b/hotkeysdlg.cpp new file mode 100644 index 00000000..a1f45b3c --- /dev/null +++ b/hotkeysdlg.cpp @@ -0,0 +1,14 @@ +#include "hotkeysdlg.h" +#include "ui_hotkeysdlg.h" + +HotKeysDlg::HotKeysDlg(QWidget *parent) : + QDialog(parent), + ui(new Ui::HotKeysDlg) +{ + ui->setupUi(this); +} + +HotKeysDlg::~HotKeysDlg() +{ + delete ui; +} diff --git a/hotkeysdlg.h b/hotkeysdlg.h new file mode 100644 index 00000000..9524cda5 --- /dev/null +++ b/hotkeysdlg.h @@ -0,0 +1,22 @@ +#ifndef HOTKEYSDLG_H +#define HOTKEYSDLG_H + +#include + +namespace Ui { +class HotKeysDlg; +} + +class HotKeysDlg : public QDialog +{ + Q_OBJECT + +public: + explicit HotKeysDlg(QWidget *parent = nullptr); + ~HotKeysDlg(); + +private: + Ui::HotKeysDlg *ui; +}; + +#endif // HOTKEYSDLG_H diff --git a/hotkeysdlg.ui b/hotkeysdlg.ui new file mode 100644 index 00000000..51fa64a9 --- /dev/null +++ b/hotkeysdlg.ui @@ -0,0 +1,71 @@ + + + HotKeysDlg + + + + 0 + 0 + 640 + 480 + + + + -----------------------------Hot keys used in DFtfringe ----------------------------------------- + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + HotKeysDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + HotKeysDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/igramarea.cpp b/igramarea.cpp index 2cb0fcbf..aa546a93 100644 --- a/igramarea.cpp +++ b/igramarea.cpp @@ -119,8 +119,6 @@ IgramArea::IgramArea(QWidget *parent, void *mw) needToConvertBGR = false; QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_Down), this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(shiftDown())); - shortcut = new QShortcut(QKeySequence("d"), this); - QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(shiftDown())); shortcut = new QShortcut(QKeySequence(Qt::Key_Up), this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(shiftUp())); shortcut = new QShortcut(QKeySequence(Qt::Key_Left), this); diff --git a/mainwindow.cpp b/mainwindow.cpp index 659d8013..aac44baf 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1976,3 +1976,36 @@ void MainWindow::on_useAnnulust_clicked() + +void MainWindow::on_actionHot_Keys_triggered() +{ + QString msgtext = + QString("

hot keys (interferogram or results tab>

")+ + "
" + "
i, ctrl-o
" + "
Import interferogram

" + "(see preferences igram settings for path setup)" + "

" + "

outline hot keys

" + "
" + "
h
toggle outline (hide) on or off
" + "
f
zoom to full image
" + "
scroll wheel
zoom image
" + "
ctrl scroll wheel
increase/decrease diameter of outline.
" + "
+/-
expand or contract outline.
" + "
arrow keys
move outline.
" + "
" + + ""; + + QMessageBox msg; + msg.setIconPixmap(QPixmap(":/error.svg")); + msg.setText(msgtext); + msg.setStandardButtons(QMessageBox::Ok); + msg.setDefaultButton(QMessageBox::Ok); + QSpacerItem* horizontalSpacer = new QSpacerItem(800, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + QGridLayout* layout = (QGridLayout*)msg.layout(); + layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount()); + msg.exec(); +} + diff --git a/mainwindow.h b/mainwindow.h index 539ac502..8c698935 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -269,6 +269,8 @@ private slots: void on_useAnnulust_clicked(); + void on_actionHot_Keys_triggered(); + private: Ui::MainWindow *ui; diff --git a/mainwindow.ui b/mainwindow.ui index b9936ffa..29340271 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -135,6 +135,7 @@ Help + @@ -1494,6 +1495,11 @@ em; Show percentage of correction + + + Hot Keys + + diff --git a/outlinedialog.cpp b/outlinedialog.cpp index a5a75356..ba29f37b 100644 --- a/outlinedialog.cpp +++ b/outlinedialog.cpp @@ -44,7 +44,7 @@ outlineDialog::outlineDialog(double x, double y, double rad, QWidget *parent) : hideSearchcontrole(true); QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_Down), this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(shiftDown())); - shortcut = new QShortcut(QKeySequence("d"), this); + shortcut = new QShortcut(QKeySequence(Qt::Key_Up), this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(shiftUp())); shortcut = new QShortcut(QKeySequence(Qt::Key_Left), this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(shiftLeft())); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index c6c2dafc..773cdf3e 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -323,7 +323,8 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ ActualZoneKnife << 0.0; mirrorDlg *md = mirrorDlg::get_Instance(); - double nullval = md->z8 * md->cc; + double nullval = md->z8 * md->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 QPolygonF idealknives; @@ -342,7 +343,7 @@ QPolygonF percentCorrectionDlg::makePercentages(surfaceData *surf){ // when using average profile as the profile we need to remove the artificial // null from the profile thus the nullval being passed. - double zernKnife = GetActualKE(m_roc, m_radius, surf->zernvalues, x, nullval ,ui->useProfile->isChecked()); + double zernKnife = GetActualKE(m_roc, m_radius, surf->zernvalues, x, nullval ,false); if (zone == 0){ idealoffset = idealknife; @@ -564,7 +565,6 @@ void percentCorrectionDlg::plot(){ bool compare(QVector< surfaceData *> data1, QVector< surfaceData *> data2){ if (data1.length() != data2.length()){ - qDebug() << "different length"; return false; } for (int ndx = 0; ndx < data1.length(); ++ ndx){ @@ -712,7 +712,6 @@ void percentCorrectionDlg::on_saveZones_clicked() QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << " failed to read zones file."; - //return false; // Failed to open file for writing } QTextStream out(&file); @@ -753,14 +752,5 @@ void percentCorrectionDlg::on_percentTable_itemChanged(QTableWidgetItem *item) -void percentCorrectionDlg::on_useProfile_clicked(bool checked) -{ - plot(); -} - -void percentCorrectionDlg::on_useZernikies_clicked(bool checked) -{ - plot(); -} diff --git a/percentcorrectiondlg.h b/percentcorrectiondlg.h index a00096a6..7f65a3d7 100644 --- a/percentcorrectiondlg.h +++ b/percentcorrectiondlg.h @@ -100,9 +100,6 @@ private slots: arma::mat makeZoneZerns(QList centers); - void on_useProfile_clicked(bool checked); - - void on_useZernikies_clicked(bool checked); private: Ui::percentCorrectionDlg *ui; diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index 43e323a9..f767774b 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -152,26 +152,6 @@ - - - - use profile - - - false - - - - - - - use zernikes - - - true - - - diff --git a/settingsigram.ui b/settingsigram.ui index b82d3114..90d41eda 100644 --- a/settingsigram.ui +++ b/settingsigram.ui @@ -7,7 +7,7 @@ 0 0 492 - 537 + 563 @@ -361,7 +361,7 @@ - Import outline configuration (what hot key I does) + Import interferogram configuration (what hot key "i" does) diff --git a/simulationsview.cpp b/simulationsview.cpp index 9237d663..6aae6223 100644 --- a/simulationsview.cpp +++ b/simulationsview.cpp @@ -709,8 +709,8 @@ void SimulationsView::on_MakePB_clicked() cv::Mat focused = computeStarTest(nulledSurface(0), fftSize, ui->centerMagnifySB->value()); t = fitStarTest(zoomMat(focused,ui->centerMagnifySB->value()), wid ,gamma/2); - - cv::putText(t,"Focused",cv::Point(20,20),1,1,cv::Scalar(255, 255,255)); + QString focusedtext = QString("Focused magnified by %1x").arg(ui->centerMagnifySB->value()); + cv::putText(t,focusedtext.toStdString().c_str(),cv::Point(20,20),1,1,cv::Scalar(255, 255,255)); QImage focusDisplay ((uchar*)t.data, t.cols, t.rows, t.step, QImage::Format_RGB888); ui->Focused->setPixmap(QPixmap::fromImage(focusDisplay.copy())); diff --git a/simulationsview.ui b/simulationsview.ui index b2a294fd..d933835e 100644 --- a/simulationsview.ui +++ b/simulationsview.ui @@ -145,7 +145,7 @@ - Imaage magnifiction (as with an eyepiece) + Image magnifiction (as with an eyepiece) 1.000000000000000 From e7041aeec610cabd195ef4d72372ea5622fd08d5 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Tue, 8 Apr 2025 02:40:19 -0500 Subject: [PATCH 13/25] Added help for % correction. Added load wave fronts from multiple directories. Added user settable prefixes to wave front movie generation. --- mainwindow.cpp | 60 ++++++++++++++++++++++++++++++++++++++--- mainwindow.h | 2 ++ mainwindow.ui | 6 +++++ percentcorrectiondlg.ui | 2 +- profileplot.cpp | 1 + 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index aac44baf..84a1a8c0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1662,15 +1662,28 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() bool doastig = false; astigScatterPlot *astigPlot = NULL; QWidget *astigWindow = NULL; - + QString waveprefix("f"); + QString astigprefix("astig"); if (QMessageBox::Yes == QMessageBox::question(0,"3D","Make image of 3D model of each wave front?")) { dowavefront = true; + bool ok{}; + QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), + tr("File prefix"), QLineEdit::Normal, + waveprefix, &ok); + if (ok && !text.isEmpty()) + waveprefix = text; } if (QMessageBox::Yes == QMessageBox::question(0,"astig","Make plot of astig for each wave front?")) { doastig = true; + bool ok{}; + QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), + tr("file prefix"), QLineEdit::Normal, + astigprefix, &ok); + if (ok && !text.isEmpty()) + astigprefix = text; astigPlot = new astigScatterPlot; QVBoxLayout *layout = new QVBoxLayout(); astigWindow = new QWidget(); @@ -1733,7 +1746,7 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() cv::Mat resized; cv::resize(frame, resized, cv::Size(width,height)); // write frame - QString filename = dir + "//" + QString("f%1.jpg").arg(framecnt++,3,10, QChar('0')); + QString filename = dir + "//" + QString("%1%2.jpg").arg(waveprefix).arg(framecnt++,3,10, QChar('0')); img.save ( filename ); } if (doastig){ @@ -1741,7 +1754,7 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() astigPlot->addValue("", astig); // write frame - QString filename = dir + "//" + QString("astig%1.jpg").arg(framecnt++,3,10, QChar('0')); + QString filename = dir + "//" + QString("%1%2.jpg").arg(astigprefix).arg(framecnt++,3,10, QChar('0')); astigWindow->grab().save ( filename ); qDebug() << filename; } @@ -2009,3 +2022,44 @@ void MainWindow::on_actionHot_Keys_triggered() msg.exec(); } + +void MainWindow::on_actionLoad_wave_fronts_from_multiple_directories_triggered() +{ + QSettings set; + QString lastPath = set.value("lastPath",".").toString(); + QFileDialog dialog; + QStringList files; + dialog.setFileMode(QFileDialog::Directory); + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + dialog.setDirectory(lastPath); + + QListView *listView = dialog.findChild("listView"); + if (listView) { + listView->setSelectionMode(QAbstractItemView::MultiSelection); + } + + QTreeView *treeView = dialog.findChild(); + if (treeView) { + treeView->setSelectionMode(QAbstractItemView::MultiSelection); + } + + QStringList selectedDirectories; + if (dialog.exec()) { + selectedDirectories = dialog.selectedFiles(); + foreach (QString fn,selectedDirectories){ + QFileDialog dialog(this, "load wave front file", fn, tr("wft(*.wft)")); + dialog.setFileMode(QFileDialog::ExistingFiles); + dialog.setNameFilter(tr("wft (*.wft)")); + + if (dialog.exec()) { + QStringList fileNames = dialog.selectedFiles(); + if (fileNames.size() > 0){ + files << dialog.selectedFiles(); + } + } + } + openWaveFrontonInit(files); + } + +} + diff --git a/mainwindow.h b/mainwindow.h index 8c698935..e8163db4 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -271,6 +271,8 @@ private slots: void on_actionHot_Keys_triggered(); + void on_actionLoad_wave_fronts_from_multiple_directories_triggered(); + private: Ui::MainWindow *ui; diff --git a/mainwindow.ui b/mainwindow.ui index 29340271..237a0278 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -68,6 +68,7 @@ + @@ -1500,6 +1501,11 @@ em; Hot Keys + + + Load wave fronts from multiple directories + + diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index f767774b..cf243ed5 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -83,7 +83,7 @@ - <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile.</p><p>It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. </p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p></body></html> + <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile.</p><p>It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. </p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p><p>It uses the sperical zernike polynomials to derive the profile. If the surface is slightly irregular with zones then using more Zernike terms is more accurate. If the surface is very smooth then you can use fewer Zernike terms. The default value of 22 is a resonalbe number. Use Max Order to change the number of zones.</p><p>This code is a Beta version and tested as best as possible but it may not be correct. Use at your own risk. Best to check with other methods before relying on it to figure a mirror. Use it first on a known mirror to see if it agrees with that.</p><p>You can change the number of zones and the position of the center of a zone. Use the table at the bottom to change the position of the center of a zone. </p><p>You can save or load zone position files.</p></body></html> ? diff --git a/profileplot.cpp b/profileplot.cpp index 36ca26f1..536a4026 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -117,6 +117,7 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): l1->addStretch(); showSlopeError = new QCheckBox("Show Slope: "); showPercentCorrection = new QPushButton("Show Correction"); + showPercentCorrection->setToolTip("Show % correction of zone areas used in the Zambuto method of mirror figuring."); slopeLimitSB = new QDoubleSpinBox(); From cf07f1d2b4dd2a276ca57f1170a7cddd2cd221f9 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Wed, 16 Apr 2025 13:07:07 -0500 Subject: [PATCH 14/25] changed default Foucault ROC to be last value used. Enabled tool tips for menus. Updated some help and tool tips. Added L hot key to open igram directory. --- foucaultview.cpp | 20 ++++++++++++-------- mainwindow.cpp | 20 +++++++++++--------- mainwindow.h | 2 -- mainwindow.ui | 24 +++++++++++++----------- percentcorrectiondlg.ui | 2 +- profileplot.cpp | 2 +- zernikeprocess.cpp | 12 +++++++----- zernikesmoothingdlg.cpp | 7 ++++++- 8 files changed, 51 insertions(+), 38 deletions(-) diff --git a/foucaultview.cpp b/foucaultview.cpp index 14c96bc4..2129a4ac 100644 --- a/foucaultview.cpp +++ b/foucaultview.cpp @@ -101,6 +101,8 @@ void foucaultView::saveFoucaultImage(){ } void foucaultView::setSurface(wavefront *wf){ + QSettings set; + double offset = set.value("foucault roc offset", 0.).toDouble(); m_wf = wf; mirrorDlg *md = mirrorDlg::get_Instance(); double rad = md->diameter/2.; @@ -108,12 +110,8 @@ void foucaultView::setSurface(wavefront *wf){ double mul = (ui->useMM->isChecked()) ? 1. : 1/25.4; m_sag = mul * (rad * rad) /( 4 * FL); m_sag = round(100 * m_sag)/100.; - m_temp_sag = m_sag; - ui->rocOffsetSlider->blockSignals(true); - ui->rocOffsetSlider->setValue((m_sag/2.)/getStep()); - ui->rocOffsetSlider->blockSignals(false); - double step = getStep(); - double offset = (ui->rocOffsetSlider->value()) * step; + m_temp_sag = m_sag; // used to set the zernike slider step size to make it appropriate to a faction of the sagitta. + ui->rocOffsetSb->blockSignals(true); ui->rocOffsetSb->setValue(offset); ui->rocOffsetSb->blockSignals(false); @@ -471,7 +469,9 @@ void foucaultView::on_rocOffsetSb_editingFinished() ui->rocOffsetSlider->blockSignals(true); ui->rocOffsetSlider->setValue(pos); ui->rocOffsetSlider->blockSignals(false); -qDebug() << "slider" << val << step << pos; + QSettings set; + set.setValue("foucault roc offset", val); + m_guiTimer.start(500); } @@ -591,9 +591,11 @@ void foucaultView::on_rocOffsetSlider_valueChanged(int value) double step = getStep(); double offset = (value) * step; + QSettings set; - ui->rocOffsetSb->setValue(offset); + set.setValue("foucault roc offset", offset); + ui->rocOffsetSb->setValue(offset); m_guiTimer.start(1000); } @@ -697,6 +699,8 @@ void foucaultView::on_pushButton_clicked() ui->rocOffsetSlider->blockSignals(false); double step = getStep(); double offset = (ui->rocOffsetSlider->value()) * step; + QSettings set; + set.setValue("foucault roc offset", offset); ui->rocOffsetSb->blockSignals(true); ui->rocOffsetSb->setValue(offset); ui->rocOffsetSb->blockSignals(false); diff --git a/mainwindow.cpp b/mainwindow.cpp index 84a1a8c0..d2e202fa 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -63,7 +63,10 @@ MainWindow::MainWindow(QWidget *parent) : { ui->setupUi(this); ui->useAnnulust->hide(); - + QList acts = ui->menuBar->actions(); + foreach(QAction* a, acts){ + a->menu()->setToolTipsVisible(true); + } spdlog::get("logger")->info("DFTFringe {} started", APP_VERSION); //const QString toolButtonStyle("QToolButton {" @@ -203,6 +206,9 @@ MainWindow::MainWindow(QWidget *parent) : QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_I), this); QObject::connect(shortcut, SIGNAL(activated()), this, SLOT(importIgram())); + QShortcut *shortcutl = new QShortcut(QKeySequence(Qt::Key_L), this); + QObject::connect(shortcutl, SIGNAL(activated()), this, SLOT(on_actionLoad_Interferogram_triggered())); + QShortcut *shortcut1 = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_O), this); QObject::connect(shortcut1, SIGNAL(activated()), this, SLOT(importIgram())); @@ -728,13 +734,6 @@ void MainWindow::on_actionDelete_wave_front_triggered() } - -void MainWindow::on_actionWrite_WaveFront_triggered() -{ - -} - - void MainWindow::on_actionSave_Wavefront_triggered() { m_surfaceManager->SaveWavefronts(false); @@ -1995,10 +1994,13 @@ void MainWindow::on_actionHot_Keys_triggered() QString msgtext = QString("

hot keys (interferogram or results tab>

")+ "
" - "
i, ctrl-o
" + "
I, ctrl-o
" "
Import interferogram

" "(see preferences igram settings for path setup)" "

" + "
L
" + "Open interferogram (manually select interferogram from directory)" + "" "

outline hot keys

" "
" "
h
toggle outline (hide) on or off
" diff --git a/mainwindow.h b/mainwindow.h index e8163db4..b1e64133 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -137,8 +137,6 @@ private slots: void on_actionDelete_wave_front_triggered(); - void on_actionWrite_WaveFront_triggered(); - void on_actionSave_Wavefront_triggered(); void on_SelectOutSideOutline_clicked(bool checked); diff --git a/mainwindow.ui b/mainwindow.ui index 237a0278..fcbb5485 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -1186,17 +1186,12 @@ em; Save WaveFront - Save Selected Wavefront or Wavefronts + <html><head/><body><p>Save Wavefront or Wavefronts that have been selected.</p><p><br/></p></body></html> <html><head/><body><p>Save Selected Wavefront or Wavefronts</p></body></html> - - - Write WaveFront - - Save outline @@ -1226,6 +1221,9 @@ em; Read Wavefront/s + + <html><head/><body><p>Load one or more wave fronts.</p></body></html> + <html><head/><body><p>Read one or more wavefronts</p></body></html> @@ -1283,6 +1281,9 @@ em; Save Wavefront/s + + Save selected wave fronts. + Save all selected wavefronts @@ -1421,6 +1422,9 @@ em; Average wave front files + + Average wave front files seleted from a file folder and not from the selected wave fronts controls. + @@ -1491,11 +1495,6 @@ em; Create Movie of astig fom wavefonts - - - Show percentage of correction - - Hot Keys @@ -1505,6 +1504,9 @@ em; Load wave fronts from multiple directories + + <html><head/><body><p>Select wave fronts from several directories and not just one.</p></body></html> + diff --git a/percentcorrectiondlg.ui b/percentcorrectiondlg.ui index cf243ed5..17245cff 100644 --- a/percentcorrectiondlg.ui +++ b/percentcorrectiondlg.ui @@ -83,7 +83,7 @@ - <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile.</p><p>It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. </p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p><p>It uses the sperical zernike polynomials to derive the profile. If the surface is slightly irregular with zones then using more Zernike terms is more accurate. If the surface is very smooth then you can use fewer Zernike terms. The default value of 22 is a resonalbe number. Use Max Order to change the number of zones.</p><p>This code is a Beta version and tested as best as possible but it may not be correct. Use at your own risk. Best to check with other methods before relying on it to figure a mirror. Use it first on a known mirror to see if it agrees with that.</p><p>You can change the number of zones and the position of the center of a zone. Use the table at the bottom to change the position of the center of a zone. </p><p>You can save or load zone position files.</p></body></html> + <html><head/><body><p>This assumes the surface is a figure of revolution that matches the average profile.</p><p>It computes the slope of the average profile and compares it to the ideal slope for the conic desired. If the slope matches the expected value the percentage will be 100 percent. </p><p>This is only good for desired conics of -1. </p><p>The first 5% radius of the surface is ignored because the desired slope there is 0 to very small which creates invalid data.</p><p>It uses the sperical zernike polynomials to derive the profile. If the surface is slightly irregular with zones then using more Zernike terms is more accurate. If the surface is very smooth then you can use fewer Zernike terms. The default value of 22 is a resonalbe number. Use Max Order to change the number of zones.</p><p>This code is a Beta version and tested as best as possible but it may not be correct. Use at your own risk. Best to check with other methods before relying on it to figure a mirror. Use it first on a known mirror to see if it agrees with that.</p><p>You can change the number of zones and the position of the center of a zone. Use the table at the bottom to change the position of the center of a zone by editing the numbers in the zone center row. Default zone centers are computed the same as Carl Zambuto's spread sheed does.</p><p>You can save or load zone position files.</p></body></html> ? diff --git a/profileplot.cpp b/profileplot.cpp index 536a4026..1b161449 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -517,7 +517,7 @@ void ProfilePlot::make_correction_graph(){ // compute zerns using the new maxorder zern set zp.initGrid(*wfs->at(list[i]), maxOrder); std::vector theZerns = zp.ZernFitWavefront(*wfs->at(list[i])); - + if (theZerns.size() == 0) return; // send zernike values to the correction dialog to have it plot correction based on them. QColor penColor = Settings2::m_profile->getColor(i); diff --git a/zernikeprocess.cpp b/zernikeprocess.cpp index 6acf27ae..ecdba249 100644 --- a/zernikeprocess.cpp +++ b/zernikeprocess.cpp @@ -1205,8 +1205,8 @@ arma::mat zernikeProcess::rhotheta( int width, double radius, double cx, double for (int y = 0; y < rows; ++y){ double uy = (y -cy)/radius; - if (!m_bDontProcessEvents) - QApplication::processEvents(); +// if (!m_bDontProcessEvents) +// QApplication::processEvents(); for (int x = 0; x< rows; ++x){ double ux = (x -cx)/radius; @@ -1464,9 +1464,11 @@ std::vector zernikeProcess::ZernFitWavefront(wavefront &wf){ if (i%5000 == 0) { prg->setValue(i); QApplication::processEvents(); -// if (prg->wasCanceled()){ -// throw 42; -// } + if (prg->wasCanceled()){ + std::vector dummy; + return dummy; // a zero lengh vector signals cancelation. + + } } if ( rho <= 1. && (wf.mask.at( m_row[i], m_col[i]) != 0)){ diff --git a/zernikesmoothingdlg.cpp b/zernikesmoothingdlg.cpp index 08c84ef4..a3ecfddb 100644 --- a/zernikesmoothingdlg.cpp +++ b/zernikesmoothingdlg.cpp @@ -123,7 +123,12 @@ void ZernikeSmoothingDlg::on_createWaveFront_clicked() QApplication::setOverrideCursor(Qt::WaitCursor); m_wf = *p_wf; if (!ui->useCurrentZernySet->isChecked()){ - theZerns = m_zp->ZernFitWavefront(m_wf); + std::vector tzerns = m_zp->ZernFitWavefront(m_wf); + if (tzerns.size() == 0){ + QApplication::restoreOverrideCursor(); + return; + } + theZerns = tzerns; } tableModel->setValues(&theZerns); From 24b50c1fe480ade07c1b2538ec9c782186487ae7 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Wed, 16 Apr 2025 13:18:29 -0500 Subject: [PATCH 15/25] corrected bug where surface error was not set back to 1x when changing back from auto collimation in Foucault view. --- foucaultview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foucaultview.cpp b/foucaultview.cpp index 2129a4ac..07bf0da8 100644 --- a/foucaultview.cpp +++ b/foucaultview.cpp @@ -718,7 +718,7 @@ void foucaultView::on_autocollimation_clicked(bool checked) if (checked) ui->h2x->setChecked(true); else - ui->h1x->setChecked(false); + ui->h1x->setChecked(true); on_makePb_clicked(); } From 4dbe664d3f92123a70cd7b7ad0d0bbfda5a0f8fd Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Sun, 20 Apr 2025 17:04:58 -0500 Subject: [PATCH 16/25] corrected bug in make wave front movie so that frames get numbered corredtly and astig and wave front movies can both be made. --- mainwindow.cpp | 55 ++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index d2e202fa..6030f393 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1673,24 +1673,25 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() if (ok && !text.isEmpty()) waveprefix = text; } - - if (QMessageBox::Yes == QMessageBox::question(0,"astig","Make plot of astig for each wave front?")) - { - doastig = true; - bool ok{}; + if (!dowavefront) { + if (QMessageBox::Yes == QMessageBox::question(0,"astig","Make plot of astig for each wave front?")) + { + doastig = true; + bool ok{}; QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("file prefix"), QLineEdit::Normal, astigprefix, &ok); if (ok && !text.isEmpty()) astigprefix = text; - astigPlot = new astigScatterPlot; - QVBoxLayout *layout = new QVBoxLayout(); - astigWindow = new QWidget(); - layout->addWidget(astigPlot); - astigWindow->setLayout(layout); - astigWindow->resize(1000,1000); - astigWindow->show(); + astigPlot = new astigScatterPlot; + QVBoxLayout *layout = new QVBoxLayout(); + astigWindow = new QWidget(); + layout->addWidget(astigPlot); + astigWindow->setLayout(layout); + astigWindow->resize(1000,1000); + astigWindow->show(); + } } if (!doastig and !dowavefront) return; @@ -1709,6 +1710,7 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); int framecnt = 0; + int astigCnt = 0; if (dir.length() > 0){ @@ -1753,24 +1755,24 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() astigPlot->addValue("", astig); // write frame - QString filename = dir + "//" + QString("%1%2.jpg").arg(astigprefix).arg(framecnt++,3,10, QChar('0')); + QString filename = dir + "//" + QString("%1%2.jpg").arg(astigprefix).arg(astigCnt++,3,10, QChar('0')); astigWindow->grab().save ( filename ); - qDebug() << filename; + } } } if (QMessageBox::Yes == QMessageBox::question(0,"---------- 3D wave front Video maker -------------","Do you have FFMpeg and want it to make a video from these images?")) { - QString cmd = "ffmpeg -framerate 60 -i f%03d.jpg -c:v libx264 -vf format=yuv420p -y output.mp4"; - if (doastig) {cmd.replace("f%03d", "a%03d");} + QString cmd = QString("ffmpeg -framerate 1 -i %1%03d.jpg -c:v libx264 -vf format=yuv420p -y -r 25 %2").arg(dowavefront? waveprefix:astigprefix). \ + arg(dowavefront? "waveFronts.mp4": "astig.mp4"); + bool ok = false; QString text = QInputDialog::getText(this, "------------------ FFmpeg command to create video from images.----------------", - "-------------------- Command to make 60 fps. Copy to command line app. -----------------", + "-------------------- Command to make 2 fps. Copy to command line app. -----------------", QLineEdit::Normal, - "ffmpeg -framerate 60 -i f%03d.jpg -c:v libx264 -vf format=yuv420p -y output.mp4", - &ok); + QString(cmd) ,&ok); if (ok) { QDialog *dialog = new QDialog; dialog->setWindowTitle("ffmpeg output"); @@ -1789,7 +1791,8 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() dialog->show(); - + cmd = textEdit->toPlainText(); + qDebug() << "plain text"<< text; QApplication::setOverrideCursor(Qt::WaitCursor); QProcess *proc = new QProcess; connect(proc, QOverload::of(&QProcess::finished), @@ -1797,17 +1800,17 @@ void MainWindow::on_actionCreate_Movie_of_wavefronts_triggered() proc->setProcessChannelMode(QProcess::MergedChannels); proc->setWorkingDirectory(dir); - QStringList args = cmd.split(" "); + QStringList args = text.split(" "); qDebug() << "args" << args.mid(1); proc->start("ffmpeg",args.mid(1)); while (!proc->waitForFinished(200)){ - QString q = proc->readAll(); - if (q != "") - textEdit->append(q); - QApplication::processEvents(); - } + QString q = proc->readAll(); + if (q != "") + textEdit->append(q); + QApplication::processEvents(); + } qDebug() << "done" ; From 4631671f9e1f11cb60058df294b2d58d1fa77660 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Sun, 20 Apr 2025 21:21:14 -0500 Subject: [PATCH 17/25] Changed test stand removal code to create a better countour plot on page 3 of the report. Added log display to the process wizard window and various QApplication::processevents so the screen updates the displays during the process for better user feedback. --- standastigwizard.cpp | 15 ++++++++++----- standastigwizard.h | 1 + surfacemanager.cpp | 20 ++++++++++++++------ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/standastigwizard.cpp b/standastigwizard.cpp index f57f3d38..6c617378 100644 --- a/standastigwizard.cpp +++ b/standastigwizard.cpp @@ -126,15 +126,17 @@ makeAverages::makeAverages(QWidget *parent) setLayout(layout); } void define_input::pdfNamesPressed(){ - QString fileName = QFileDialog::getSaveFileName((QWidget* )0, "Export PDF", QString(mirrorDlg::get_Instance()->getProjectPath() + - "/stand.pdf"), "*.pdf"); + QSettings set; + QString standReportPath = set.value("stand report path", mirrorDlg::get_Instance()->getProjectPath()).toString(); + QString fileName = QFileDialog::getSaveFileName((QWidget* )0, "Export PDF", standReportPath + "/stand.pdf" , + "*.pdf"); if (fileName.isEmpty()) return; if (QFileInfo(fileName).suffix().isEmpty()) { fileName.append(".pdf"); } AstigReportPdfName = fileName; pdfName->setText(fileName); - QSettings set; - set.setValue("stand pdf file", fileName.split("/").last()); + + set.setValue("stand report path", QFileInfo(fileName).absolutePath()); } void define_input::setBasePath(){ QString baseName = QFileDialog::getExistingDirectory( @@ -250,11 +252,14 @@ define_input::define_input(QWidget *parent) l->addWidget(listDisplay,8,0,10,-1); l->addWidget(new QLabel("Report Title:"),18,0); l->addWidget(title, 18,1); - showWork = new QCheckBox("Show work Files"); + showWork = new QCheckBox("Keep work Files"); l->addWidget(showWork, 18,2); l->addWidget(new QLabel("Pdf File Name:"), 19,0); l->addWidget(pdfName, 19,1,1,-1); l->addWidget(runpb, 20,0,1,7); + m_log = new QTextEdit(); + m_log->append("Ready to add wave fronts to process."); + l->addWidget(m_log,21,0,1,0); setLayout(l); } diff --git a/standastigwizard.h b/standastigwizard.h index 6bc7fc0e..7201e950 100644 --- a/standastigwizard.h +++ b/standastigwizard.h @@ -103,6 +103,7 @@ class define_input : public QWizardPage QRadioButton *CCWRb; QPushButton *runpb; QCheckBox *showWork; + QTextEdit* m_log; //int nextId() const; diff --git a/surfacemanager.cpp b/surfacemanager.cpp index a9e640e2..e01aec01 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -1921,8 +1921,8 @@ textres SurfaceManager::Phase2(QList list, QList inp QTextDocument *doc = editor->document(); textres results; results.Edit = editor; - const int Width = 400 * .9; - const int Height = 300 * .9; + const int Width = 800 * .9; + const int Height = 600 * .9; QImage contour(Width ,Height, QImage::Format_ARGB32 ); QPrinter printer(QPrinter::HighResolution); @@ -1994,6 +1994,7 @@ textres SurfaceManager::Phase2(QList list, QList inp maxYastig = std::max(maxYastig, mirrorY); yastig.at(i,0) = mirrorY; qDebug() << "Mirror astigs " << mirrorX << mirrorY; + QApplication::processEvents(); } Circle fittedcircle1; @@ -2095,7 +2096,7 @@ qDebug() << "circle fit"<< avgRadius << fittedcircle1.r << fittedcircle2.r; "" + QString().number(yval,'f',3) + "" "" + QString().number(mag,'f',3) + "" "" + QString().number((180./ M_PI) * atan2(yval,xval)/2.,'f',1) + ""); - + QApplication::processEvents(); } html.append("MEAN" + QString().number(fittedcircle.a,'f',3) + "" + QString().number(fittedcircle.b,'f',3) + "" + QString().number(sqrt(fittedcircle.a * fittedcircle.a + fittedcircle.b * fittedcircle.b),'f',3) + ""); @@ -2178,6 +2179,7 @@ qDebug() << "circle fit"<< avgRadius << fittedcircle1.r << fittedcircle2.r; cnt = 0; imagesHtml.append(""); } + QApplication::processEvents(); } mirrorAstigRadius /= list.size(); @@ -2446,6 +2448,8 @@ void SurfaceManager::computeStandAstig(define_input *wizPage, QListfname; + wizPage->m_log->append("Loading " + list[i]->fname); + QApplication::processEvents(); loadWavefront(list[i]->fname); wavefront * wf = m_wavefronts[m_currentNdx]; inputs.append(wf); @@ -2461,7 +2465,9 @@ void SurfaceManager::computeStandAstig(define_input *wizPage, QList


" + angle + "

"); // counter rotate it - wizPage->runpb->setText(QString("Counter Rotating ") + list[i]->fname.right(list[i]->fname.size() - list[i]->fname.lastIndexOf("/")-1)); + + wizPage->m_log->setText(QString("Counter Rotating ") + list[i]->fname.right(list[i]->fname.size() - list[i]->fname.lastIndexOf("/")-1)); + QApplication::processEvents(); QList l; l.append(ndx); ndx = m_wavefronts.size(); @@ -2492,7 +2498,8 @@ void SurfaceManager::computeStandAstig(define_input *wizPage, QListsetDocument(doc); //editor->show(); - + wizPage->m_log->append("averaging rotated wave fronts"); + QApplication::processEvents(); // Now average all the rotated ones. QList wlist; for (int i = 0; i < rotated.size(); ++i){ @@ -2539,7 +2546,8 @@ void SurfaceManager::computeStandAstig(define_input *wizPage, QListrunpb->setText("computing stand astigs"); + wizPage->m_log->setText("computing stand astigs"); + QApplication::processEvents(); textres page3res = Phase2(list, inputs, avgNdx); QTabWidget *tabw = new QTabWidget(); tabw->setTabShape(QTabWidget::Triangular); From 8ca70f5380cdea8645f9c0f5687acdb397f300ae Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Fri, 2 May 2025 23:49:59 -0500 Subject: [PATCH 18/25] corrected bugs George pointed out. Added info to revision history --- RevisionHistory.html | 8 ++++++++ foucaultview.cpp | 3 +-- mainwindow.cpp | 2 +- percentcorrectiondlg.cpp | 2 +- profileplot.cpp | 19 ++++++------------- profileplot.h | 1 - 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/RevisionHistory.html b/RevisionHistory.html index b3a2682c..5911a615 100644 --- a/RevisionHistory.html +++ b/RevisionHistory.html @@ -418,3 +418,11 @@
  • Improved saving speed when working on network drives
  • + +
    • Version 7.3.4
    • +
        +
      • Added zonal percent completion graph to profile options
      • +
      • Changed create movie feature to add user provided prefix to each from created.
      • +
      • Added hot keys to import interferogram
      • +
      • Added hot key to help
      • +
      diff --git a/foucaultview.cpp b/foucaultview.cpp index 07bf0da8..0b917774 100644 --- a/foucaultview.cpp +++ b/foucaultview.cpp @@ -697,8 +697,7 @@ void foucaultView::on_pushButton_clicked() ui->rocOffsetSlider->blockSignals(true); ui->rocOffsetSlider->setValue((m_sag/2.)/getStep()); ui->rocOffsetSlider->blockSignals(false); - double step = getStep(); - double offset = (ui->rocOffsetSlider->value()) * step; + double offset = (m_sag/2); QSettings set; set.setValue("foucault roc offset", offset); ui->rocOffsetSb->blockSignals(true); diff --git a/mainwindow.cpp b/mainwindow.cpp index 6030f393..10aae001 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -210,7 +210,7 @@ MainWindow::MainWindow(QWidget *parent) : QObject::connect(shortcutl, SIGNAL(activated()), this, SLOT(on_actionLoad_Interferogram_triggered())); QShortcut *shortcut1 = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_O), this); - QObject::connect(shortcut1, SIGNAL(activated()), this, SLOT(importIgram())); + QObject::connect(shortcut1, SIGNAL(activated()), this, SLOT(on_actionLoad_Interferogram_triggered())); connect(m_dftTools,SIGNAL(doDFT()),m_dftArea,SLOT(doDFT())); settingsDlg = Settings2::getInstance(); diff --git a/percentcorrectiondlg.cpp b/percentcorrectiondlg.cpp index 773cdf3e..6cfce724 100644 --- a/percentcorrectiondlg.cpp +++ b/percentcorrectiondlg.cpp @@ -692,7 +692,7 @@ void percentCorrectionDlg::on_loadZones_clicked() ui->numberOfZones->setValue(m_number_of_zones); ui->numberOfZones->blockSignals(false); saveSettings(); - //emit percent_plot_changed(); + plot(); } diff --git a/profileplot.cpp b/profileplot.cpp index 1b161449..824de9da 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -264,7 +264,6 @@ void ProfilePlot::showSurface(bool flag){ void ProfilePlot::showOne(){ type = 0; - showPercentCorrection->setChecked(false); m_pcdlg->close(); populate(); m_plot->replot(); @@ -276,7 +275,6 @@ void ProfilePlot::show16(){ } void ProfilePlot::showAll(){ type = 2; - showPercentCorrection->setChecked(false); m_pcdlg->close(); populate(); m_plot->replot(); @@ -463,7 +461,7 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf, bool allowOffs //else points << QPointF(radx,0.0); } - if (m_showSlopeError && ((type==1 && !m_showCorrection) || (type == 0) || (type == 2))){ + if (m_showSlopeError && ((type==1) || (type == 0) || (type == 2))){ double arcsecLimit = (slopeLimitArcSec/3600) * M_PI/180; double xDel = points[0].x() - points[1].x(); double hDelLimit =m_showNm * m_showSurface * ((outputLambda/m_wf->lambda)*fabs(xDel * tan(arcsecLimit)) /(outputLambda * 1.e-6)); @@ -498,7 +496,8 @@ QPolygonF ProfilePlot::createProfile(double units, wavefront *wf, bool allowOffs zernikeProcess *zp = NULL; void ProfilePlot::make_correction_graph(){ - m_showCorrection = true; + + int maxOrder = m_pcdlg->m_maxOrder; // for each selected wave front @@ -663,10 +662,7 @@ void ProfilePlot::populate() avg << QPointF(p.x(),p.y()/(count[i++])); } QString name("average"); - if (m_showCorrection){ - QStringList path = wfs->at(list[indx])->name.split("/"); - name = path.last().replace(".wft",""); - } + QwtPlotCurve *cprofileavg = new QwtPlotCurve( name); cprofileavg->setRenderHint( QwtPlotItem::RenderAntialiased ); cprofileavg->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false ); @@ -706,8 +702,6 @@ void ProfilePlot::populate() cprofile->setRenderHint( QwtPlotItem::RenderAntialiased ); cprofile->setSamples( createProfile( m_showNm * m_showSurface,wfs->at(list[i]), i==0)); cprofile->attach( m_plot ); - - } break; @@ -716,8 +710,6 @@ void ProfilePlot::populate() break; } - - // Insert markers // ...a horizontal line at y = 0... @@ -832,7 +824,8 @@ void ProfilePlot::contourPointSelected(const QPointF &pos){ } void ProfilePlot::showCorrection(){ - + if (m_wf == 0) + return; m_pcdlg->show(); m_pcdlg->raise(); diff --git a/profileplot.h b/profileplot.h index 310af558..7ec26e65 100644 --- a/profileplot.h +++ b/profileplot.h @@ -41,7 +41,6 @@ class ProfilePlot : public QWidget public: percentCorrectionDlg *m_pcdlg; - bool m_showCorrection = false; QwtPlot *m_plot; wavefront* m_wf; ProfilePlot( QWidget *parent = NULL, ContourTools* tools = 0 ); From 98b18232bf3f7e09589ad64e50e6502d6dd8f8a6 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Fri, 2 May 2025 23:55:38 -0500 Subject: [PATCH 19/25] updated revision history --- RevisionHistory.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RevisionHistory.html b/RevisionHistory.html index 5911a615..87d26690 100644 --- a/RevisionHistory.html +++ b/RevisionHistory.html @@ -425,4 +425,6 @@
    • Changed create movie feature to add user provided prefix to each from created.
    • Added hot keys to import interferogram
    • Added hot key to help
    • +
    • Added auto collimation setting to Ronchi and Foucault feature
    • +
    • Remembered last ROC offset value in Ronchi and Foucault feature to remember last setting when wave front is changed to a different value
    From 2de1bf029d16182633247627443b280b462256b9 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Wed, 7 May 2025 22:05:16 -0500 Subject: [PATCH 20/25] added show astig polar graph --- DFTFringe_Dale.pro | 3 ++ astigpolargraph.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++++ astigpolargraph.h | 31 ++++++++++++++ astigpolargraph.ui | 97 ++++++++++++++++++++++++++++++++++++++++++ mainwindow.cpp | 11 +++++ mainwindow.h | 2 + mainwindow.ui | 6 +++ reportdlg.ui | 14 +++--- simulationsview.ui | 2 +- 9 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 astigpolargraph.cpp create mode 100644 astigpolargraph.h create mode 100644 astigpolargraph.ui diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index 9812e083..f369b978 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -30,6 +30,7 @@ SOURCES += main.cpp \ annulushelpdlg.cpp \ arbitrarywavefronthelp.cpp \ arbitrarywavwidget.cpp \ + astigpolargraph.cpp \ cpoint.cpp \ defocusdlg.cpp \ edgeplot.cpp \ @@ -151,6 +152,7 @@ HEADERS += mainwindow.h \ annulushelpdlg.h \ arbitrarywavefronthelp.h \ arbitrarywavwidget.h \ + astigpolargraph.h \ cpoint.h \ defocusdlg.h \ edgeplot.h \ @@ -277,6 +279,7 @@ INCLUDEPATH += ./bezier ./SingleApplication FORMS += mainwindow.ui \ annulushelpdlg.ui \ arbitrarywavefronthelp.ui \ + astigpolargraph.ui \ defocusdlg.ui \ dfttools.ui \ dftarea.ui \ diff --git a/astigpolargraph.cpp b/astigpolargraph.cpp new file mode 100644 index 00000000..ce49c900 --- /dev/null +++ b/astigpolargraph.cpp @@ -0,0 +1,101 @@ +#include "astigpolargraph.h" +#include "ui_astigpolargraph.h" +#include "surfacemanager.h" + +void astigPolargraph::makeChart(){ + + + QPolarChart *chart = new QPolarChart(); + + // process each wave front and place astig on the chart + ui->waveFrontTable->setRowCount(m_list.size()); + + QValueAxis *angularAxis = new QValueAxis(); + angularAxis->setTickCount(9); // First and last ticks are co-located on 0/360 angle. + angularAxis->setLabelFormat("%.0f"); + angularAxis->setShadesVisible(true); + angularAxis->setShadesBrush(QBrush(QColor(249, 249, 255))); + chart->addAxis(angularAxis, QPolarChart::PolarOrientationAngular); + + QValueAxis *radialAxis = new QValueAxis(); + radialAxis->setTickCount(5); + radialAxis->setLabelFormat("%.1f"); + chart->addAxis(radialAxis, QPolarChart::PolarOrientationRadial); + double maxAstig = 1.; + + QVector wavefronts =SurfaceManager::get_instance()->m_wavefronts; + + for(int ndx = 0; ndx < m_list.length(); ++ndx){ + wavefront *wf = wavefronts[m_list[ndx]]; + QString name = wf->name; + int slashndx = name.lastIndexOf('/'); + QString shortName = name.mid(name.lastIndexOf('/',slashndx-1)); + QTableWidgetItem *item = new QTableWidgetItem(shortName, 0); + ui->waveFrontTable->setItem(ndx,0,item); + double xastig = wf->InputZerns[4]; + double yastig = wf->InputZerns[5]; + double mag = sqrt(xastig * xastig + yastig * yastig); + if (mag > maxAstig) maxAstig = mag; + + double angle = (atan2(yastig,xastig)/2.) * 180./M_PI; + angle = 90 - angle; + QScatterSeries *series = new QScatterSeries(); + + int lastndx = name.lastIndexOf('/'); + if (lastndx != -1) + name = name.mid(lastndx); + series->setName(name); + series->append(angle,mag); + series->append(angle+180,mag); + chart->addSeries(series); + series->attachAxis(radialAxis); + series->attachAxis(angularAxis); + + QLineSeries *line = new QLineSeries(); + line->append(angle,mag); + line->append(angle+180,mag); + chart->addSeries(line); + line->attachAxis(radialAxis); + line->attachAxis(angularAxis); + chart->legend()->markers(line)[0]->setVisible(false); + + line->setPen(QPen(series->brush(),5)); + + QTableWidgetItem *pv = new QTableWidgetItem(QString().number(mag), 0); + item->setForeground(series->brush()); + ui->waveFrontTable->setItem(ndx, 1, pv); + QTableWidgetItem *anglewidget = new QTableWidgetItem(QString().number(angle,'f',1), 0); + ui->waveFrontTable->setItem(ndx, 2, anglewidget); + } + + chart->setTitle("Magnitude and axis of high edge"); + if (m_list.length() > 4) + chart->legend()->setAlignment(Qt::AlignRight); + else chart->legend()->setAlignment(Qt::AlignBottom); + + maxAstig = ceil(maxAstig); + radialAxis->setRange(0, maxAstig); + angularAxis->setRange(0, 360); + + ui->polarChart->setChart(chart); + + + +} +astigPolargraph::astigPolargraph( QListlist, QWidget *parent) : + QDialog(parent), + ui(new Ui::astigPolargraph), m_list(list) +{ + ui->setupUi(this); + //For some reason the original starter code of makeChart was in this function but it caused a crash. + // I could never figure out why because that code was taken from a working Qt example. When + // moved to inside another function it worked. So there you go. Exact same code with no changes worked there but not here. + makeChart(); + + +} + +astigPolargraph::~astigPolargraph() +{ + delete ui; +} diff --git a/astigpolargraph.h b/astigpolargraph.h new file mode 100644 index 00000000..e8d3dbcb --- /dev/null +++ b/astigpolargraph.h @@ -0,0 +1,31 @@ +#ifndef ASTIGPOLARGRAPH_H +#define ASTIGPOLARGRAPH_H + +#include +#include +#include +#include +#include +#include +#include +#include "wavefront.h" + +namespace Ui { +class astigPolargraph; +} + +class astigPolargraph : public QDialog +{ + Q_OBJECT + +public: + explicit astigPolargraph(QList list,QWidget *parent = nullptr); + ~astigPolargraph(); + +private: + Ui::astigPolargraph *ui; + QList m_list; // list index of selected wave fronts in surface manager's list. + void makeChart(); +}; + +#endif // ASTIGPOLARGRAPH_H diff --git a/astigpolargraph.ui b/astigpolargraph.ui new file mode 100644 index 00000000..646160ea --- /dev/null +++ b/astigpolargraph.ui @@ -0,0 +1,97 @@ + + + astigPolargraph + + + + 0 + 0 + 640 + 480 + + + + Astig polar plot + + + + + + + + + Wave Front + + + + + Ssurface astig PV + + + + + Angle + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + QChartView + QGraphicsView +
    QtCharts
    +
    +
    + + + + buttonBox + accepted() + astigPolargraph + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + astigPolargraph + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
    diff --git a/mainwindow.cpp b/mainwindow.cpp index 10aae001..758e184a 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -2007,6 +2007,7 @@ void MainWindow::on_actionHot_Keys_triggered() "

    outline hot keys

    " "
    " "
    h
    toggle outline (hide) on or off
    " + "
    space bar
    toggle edge zoom on or off
    " "
    f
    zoom to full image
    " "
    scroll wheel
    zoom image
    " "
    ctrl scroll wheel
    increase/decrease diameter of outline.
    " @@ -2068,3 +2069,13 @@ void MainWindow::on_actionLoad_wave_fronts_from_multiple_directories_triggered() } +#include "astigpolargraph.h" +void MainWindow::on_actionastig_in_polar_triggered() +{ + surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance(); + QList list = saTools->SelectedWaveFronts(); + astigPolargraph * graph = new astigPolargraph( list); + graph->resize(2000,1000); + graph->exec(); +} + diff --git a/mainwindow.h b/mainwindow.h index b1e64133..f9a5db32 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -271,6 +271,8 @@ private slots: void on_actionLoad_wave_fronts_from_multiple_directories_triggered(); + void on_actionastig_in_polar_triggered(); + private: Ui::MainWindow *ui; diff --git a/mainwindow.ui b/mainwindow.ui index fcbb5485..3f1218c0 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -94,6 +94,7 @@ + @@ -1508,6 +1509,11 @@ em; <html><head/><body><p>Select wave fronts from several directories and not just one.</p></body></html> + + + Show astig in polar form of selected wave fronts + + diff --git a/reportdlg.ui b/reportdlg.ui index aa23eb2a..983f8382 100644 --- a/reportdlg.ui +++ b/reportdlg.ui @@ -65,7 +65,7 @@ - <html><head/><body><p>If images are cropped on the right size reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> + <html><head/><body><p>If images are cropped on the right side reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> 0.100000000000000 @@ -105,7 +105,7 @@ - <html><head/><body><p>If images are cropped on the right size reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> + <html><head/><body><p>If images are cropped on the right side reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> 0.100000000000000 @@ -146,7 +146,7 @@ - <html><head/><body><p>If images are cropped on the right size reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html>d + <html><head/><body><p>If images are cropped on the right side reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p><p>d</p></body></html> 0.100000000000000 @@ -186,7 +186,7 @@ - <html><head/><body><p>If images are cropped on the right size reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> + <html><head/><body><p>If images are cropped on the right side reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> 0.100000000000000 @@ -230,7 +230,7 @@ - <html><head/><body><p>If images are cropped on the right size reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> + <html><head/><body><p>If images are cropped on the right side reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> 0.100000000000000 @@ -270,7 +270,7 @@ - <html><head/><body><p>If images are cropped on the right size reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> + <html><head/><body><p>If images are cropped on the right side reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> 0.100000000000000 @@ -312,7 +312,7 @@ - <html><head/><body><p>If images are cropped on the right size reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> + <html><head/><body><p>If images are cropped on the right side reduce this number. <br/>If images are too small increase this number.</p><p>Usefull ranges are .8 - 1.1</p></body></html> 0.100000000000000 diff --git a/simulationsview.ui b/simulationsview.ui index d933835e..651b3553 100644 --- a/simulationsview.ui +++ b/simulationsview.ui @@ -145,7 +145,7 @@ - Image magnifiction (as with an eyepiece) + <html><head/><body><p>Image magnification (as with an eyepiece)</p></body></html> 1.000000000000000 From 00b5042da33a5b5c180870cec6725b177f9951df Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Tue, 13 May 2025 02:47:05 -0500 Subject: [PATCH 21/25] corrrected typo on header to polar plot. Changed how selecting a profile can be moved up or down in y value on profile plot. Letting any profile be selected to be moved. --- DFTFringe_Dale.pro | 2 + astigpolargraph.ui | 2 +- profileplot.cpp | 30 +------- profileplot.h | 1 - profileplotpicker.cpp | 169 ++++++++++++++++++++++++++++++++++++++++++ profileplotpicker.h | 36 +++++++++ surfacemanager.cpp | 4 +- 7 files changed, 212 insertions(+), 32 deletions(-) create mode 100644 profileplotpicker.cpp create mode 100644 profileplotpicker.h diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index f369b978..a9402021 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -46,6 +46,7 @@ SOURCES += main.cpp \ pdfcalibrationdlg.cpp \ percentcorrectiondlg.cpp \ profileplot.cpp \ + profileplotpicker.cpp \ psiresizeimagesdlg.cpp \ settingsigramimportconfig.cpp \ surface3dcontrolsdlg.cpp \ @@ -168,6 +169,7 @@ HEADERS += mainwindow.h \ percentCorrectionSurface.h \ percentcorrectiondlg.h \ profileplot.h \ + profileplotpicker.h \ psiresizeimagesdlg.h \ settingsigramimportconfig.h \ surface3dcontrolsdlg.h \ diff --git a/astigpolargraph.ui b/astigpolargraph.ui index 646160ea..b2d16ad1 100644 --- a/astigpolargraph.ui +++ b/astigpolargraph.ui @@ -25,7 +25,7 @@ - Ssurface astig PV + Surface astig PV diff --git a/profileplot.cpp b/profileplot.cpp index 824de9da..2f66e640 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -50,6 +50,7 @@ #include "zernikeprocess.h" #include #include "plotcolor.h" +#include "profileplotpicker.h" extern double outputLambda; #include @@ -61,35 +62,7 @@ extern double outputLambda; double g_angle = 270. * PITORAD; //start at 90 deg (pointing east) double y_offset = 0.; -bool ProfilePlot::eventFilter( QObject *object, QEvent *event ) -{ - if ( event->type() == QEvent::MouseButtonPress ) - { - QMouseEvent *mouseEvent = static_cast( event ); - if (mouseEvent->button() == Qt::RightButton){ - showContextMenu(mouseEvent->pos()); - return false; - } - startPos = mouseEvent->pos(); - dragging = true; - return true; - } - else if (dragging && event->type() == QEvent::MouseMove){ - QMouseEvent *mouseEvent = static_cast( event ); - QPoint p = mouseEvent->pos(); - y_offset = .005 * (startPos.y() - p.y()); - populate(); - m_plot->replot(); - return true; - } - else if (dragging && event->type() == QEvent::MouseButtonRelease){ - dragging = false; - return true; - } - - return QObject::eventFilter( object, event ); -} ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): QWidget( parent ), m_wf(0), m_tools(tools), @@ -102,6 +75,7 @@ ProfilePlot::ProfilePlot(QWidget *parent , ContourTools *tools): zoomed = false; m_defocus_mode = false; m_plot = new QwtPlot(this); + profilePlotPicker *picker = new profilePlotPicker(m_plot); type = 0; QHBoxLayout * l1 = new QHBoxLayout(); QVBoxLayout *v1 = new QVBoxLayout(); diff --git a/profileplot.h b/profileplot.h index 7ec26e65..6cf4a27b 100644 --- a/profileplot.h +++ b/profileplot.h @@ -52,7 +52,6 @@ class ProfilePlot : public QWidget QPolygonF createAverageProfile(double umnits, wavefront *wf, bool removeNull); ContourTools *m_tools; double m_waveRange; - virtual bool eventFilter( QObject *, QEvent * ); QCheckBox *showNmCB; QCheckBox *showSurfaceCB; QRadioButton *OneOnly; diff --git a/profileplotpicker.cpp b/profileplotpicker.cpp new file mode 100644 index 00000000..ccd7b293 --- /dev/null +++ b/profileplotpicker.cpp @@ -0,0 +1,169 @@ +#include "profileplotpicker.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +profilePlotPicker::profilePlotPicker( QwtPlot *plot ): + QObject( plot ), + d_selectedCurve( NULL ), + d_selectedPoint( -1 ) +{ + QwtPlotCanvas *canvas = qobject_cast( plot->canvas() ); + canvas->installEventFilter( this ); + + // We want the focus, but no focus rect. The + canvas->setFocusPolicy( Qt::StrongFocus ); +#ifndef QT_NO_CURSOR + canvas->setCursor( Qt::PointingHandCursor ); +#endif + canvas->setFocusIndicator( QwtPlotCanvas::ItemFocusIndicator ); + canvas->setFocus(); + +} + +QwtPlot *profilePlotPicker::plot() +{ + return qobject_cast( parent() ); +} + +const QwtPlot *profilePlotPicker::plot() const +{ + return qobject_cast( parent() ); +} + +bool profilePlotPicker::event( QEvent *ev ) +{ + if ( ev->type() == QEvent::User ) + { + + return true; + } + return QObject::event( ev ); +} + +bool profilePlotPicker::eventFilter( QObject *object, QEvent *event ) +{ + if ( plot() == NULL || object != plot()->canvas() ) + return false; + + switch( event->type() ) + { + + case QEvent::FocusIn: + { + + break; + } + case QEvent::FocusOut: + { + + break; + } + case QEvent::Paint: + { + QApplication::postEvent( this, new QEvent( QEvent::User ) ); + break; + } + case QEvent::MouseButtonPress: + { + const QMouseEvent *mouseEvent = static_cast( event ); + m_lastMousePos = mouseEvent->pos(); + select( mouseEvent->pos() ); + + return true; + } + case QEvent::MouseMove: + { + + const QMouseEvent *mouseEvent = static_cast( event ); + move( mouseEvent->pos() ); + m_lastMousePos = mouseEvent->pos(); + return true; + } + + default: + break; + } + + return QObject::eventFilter( object, event ); +} + +// Select the point at a position. If there is no point +// deselect the selected point + +void profilePlotPicker::select( const QPoint &pos ) +{ + QwtPlotCurve *curve = NULL; + double dist = 10e10; + int index = -1; + + const QwtPlotItemList& itmList = plot()->itemList(); + for ( QwtPlotItemIterator it = itmList.begin(); + it != itmList.end(); ++it ) + { + if ( ( *it )->rtti() == QwtPlotItem::Rtti_PlotCurve ) + { + QwtPlotCurve *c = static_cast( *it ); + + double d; + int idx = c->closestPoint( pos, &d ); + if ( d < dist ) + { + curve = c; + index = idx; + dist = d; + + } + } + } + + d_selectedCurve = curve; + d_selectedPoint = index; +} + + +// Move the selected point +void profilePlotPicker::move( const QPoint &pos ) +{ + qDebug() << "move pos" << pos; + if ( !d_selectedCurve ) + return; +qDebug() << "Move" << plot()->invTransform(d_selectedCurve->yAxis(), pos.y()); + double last = plot()->invTransform( d_selectedCurve->yAxis(), m_lastMousePos.y() ); + double current = plot()->invTransform( d_selectedCurve->yAxis(), pos.y() ); + double delta = current - last; + + QVector xData( d_selectedCurve->dataSize() ); + QVector yData( d_selectedCurve->dataSize() ); + + for ( int i = 0; + i < static_cast( d_selectedCurve->dataSize() ); i++ ) + { + xData[i] = d_selectedCurve->sample(i).x(); + yData[i] = d_selectedCurve->sample(i).y() + delta; + } + d_selectedCurve->setSamples( xData, yData ); + + /* + Enable QwtPlotCanvas::ImmediatePaint, so that the canvas has been + updated before we paint the cursor on it. + */ + QwtPlotCanvas *plotCanvas = + qobject_cast( plot()->canvas() ); + + plotCanvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, true ); + plot()->replot(); + plotCanvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false ); + + +} + + + + diff --git a/profileplotpicker.h b/profileplotpicker.h new file mode 100644 index 00000000..4c9aa5ef --- /dev/null +++ b/profileplotpicker.h @@ -0,0 +1,36 @@ +#ifndef PROFILEPLOTPICKER_H +#define PROFILEPLOTPICKER_H +#include +#include + + +class QCustomEvent; +class QwtPlot; +class QwtPlotCurve; + +class profilePlotPicker: public QObject +{ + Q_OBJECT + QPoint m_lastMousePos; +public: + profilePlotPicker( QwtPlot *plot ); + virtual bool eventFilter( QObject *, QEvent * ); + + virtual bool event( QEvent * ); + +private: + + void select( const QPoint & ); + void move( const QPoint & ); + void moveBy( int dx, int dy ); + + void release(); + + + QwtPlot *plot(); + const QwtPlot *plot() const; + + QwtPlotCurve *d_selectedCurve; + int d_selectedPoint; +}; +#endif diff --git a/surfacemanager.cpp b/surfacemanager.cpp index e01aec01..bfbf9eb6 100644 --- a/surfacemanager.cpp +++ b/surfacemanager.cpp @@ -1921,8 +1921,8 @@ textres SurfaceManager::Phase2(QList list, QList inp QTextDocument *doc = editor->document(); textres results; results.Edit = editor; - const int Width = 800 * .9; - const int Height = 600 * .9; + const int Width = 800 * .6; + const int Height = 600 * .6; QImage contour(Width ,Height, QImage::Format_ARGB32 ); QPrinter printer(QPrinter::HighResolution); From eb414c650dacdeb9d1cfd150ad7b53b09e0fe366 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Tue, 13 May 2025 02:54:34 -0500 Subject: [PATCH 22/25] updated revision history .html --- RevisionHistory.html | 1 + 1 file changed, 1 insertion(+) diff --git a/RevisionHistory.html b/RevisionHistory.html index 87d26690..02432cc2 100644 --- a/RevisionHistory.html +++ b/RevisionHistory.html @@ -425,6 +425,7 @@
  • Changed create movie feature to add user provided prefix to each from created.
  • Added hot keys to import interferogram
  • Added hot key to help
  • +
  • User can select any profile shown to move it in y direction as an offset. Useful for comparing two work sessions results so that they match at zero height.
  • Added auto collimation setting to Ronchi and Foucault feature
  • Remembered last ROC offset value in Ronchi and Foucault feature to remember last setting when wave front is changed to a different value
  • From 48b45d7d5380bf80ee37a74667f54ebefc241220 Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Tue, 13 May 2025 19:29:28 -0500 Subject: [PATCH 23/25] added wheel event to scale profile and contour plots. Change polar plot headings to be sort enabled. Disabled ability to edit polar plot table entries. --- astigpolargraph.ui | 9 +++++++++ contourtools.h | 4 +++- profileplot.cpp | 7 +++++++ profileplot.h | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/astigpolargraph.ui b/astigpolargraph.ui index b2d16ad1..566f4f73 100644 --- a/astigpolargraph.ui +++ b/astigpolargraph.ui @@ -18,6 +18,15 @@ + + QAbstractItemView::NoEditTriggers + + + false + + + true + Wave Front diff --git a/contourtools.h b/contourtools.h index 668865cd..09dedfd2 100644 --- a/contourtools.h +++ b/contourtools.h @@ -48,9 +48,11 @@ class ContourTools : public QDockWidget void newDisplayErrorRange(double, double); void lineColorChanged(QColor); void fillChanged(int ); +public slots: + void setMinMaxValues(double min,double max); private slots: void updateMinMax(); - void setMinMaxValues(double min,double max); + void setWaveRange(double val); void on_ColorMapCB_activated(int index); diff --git a/profileplot.cpp b/profileplot.cpp index 2f66e640..39ef886e 100644 --- a/profileplot.cpp +++ b/profileplot.cpp @@ -289,7 +289,14 @@ void ProfilePlot::angleChanged(double a){ m_plot->replot(); emit profileAngleChanged(M_2_PI - g_angle +M_PI/4.); } +void ProfilePlot::wheelEvent(QWheelEvent *event) +{ + double factor = 1/1.55; + if( event->angleDelta().y() < 0) factor = 1.5; + + m_tools->setMinMaxValues(m_tools->m_min * factor, m_tools->m_max * factor); +} void ProfilePlot::setSurface(wavefront * wf){ m_wf = wf; diff --git a/profileplot.h b/profileplot.h index 6cf4a27b..f00aacbd 100644 --- a/profileplot.h +++ b/profileplot.h @@ -71,6 +71,7 @@ class ProfilePlot : public QWidget void profileAngleChanged(const double ang); public slots: + void wheelEvent(QWheelEvent *event); void setWavefronts(QVector *wf); void angleChanged(double a); void newDisplayErrorRange(double min, double max); From 4358b490dd748aef7cda094eabaeae478f15f2cd Mon Sep 17 00:00:00 2001 From: Dale Eason Date: Wed, 14 May 2025 00:41:37 -0500 Subject: [PATCH 24/25] update project version number and added more revision history entries. --- DFTFringe_Dale.pro | 2 +- RevisionHistory.html | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index a9402021..b0208d0f 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -423,7 +423,7 @@ RC_FILE = DFTFringe.rc QMAKE_CXXFLAGS += -std=c++11 # The application version -VERSION = Dale7.3.3 +VERSION = Dale7.3.0 # Define the preprocessor macro to get the application version in our application. DEFINES += APP_VERSION=\\\"$$VERSION\\\" diff --git a/RevisionHistory.html b/RevisionHistory.html index 02432cc2..d233c235 100644 --- a/RevisionHistory.html +++ b/RevisionHistory.html @@ -419,13 +419,15 @@ -
    • Version 7.3.4
    • +
      • Version 7.3.0
        • Added zonal percent completion graph to profile options
        • +
        • Added polar plot of the astig of selected wave fronts under View menu.
        • Changed create movie feature to add user provided prefix to each from created.
        • Added hot keys to import interferogram
        • Added hot key to help
        • -
        • User can select any profile shown to move it in y direction as an offset. Useful for comparing two work sessions results so that they match at zero height.
        • +
        • User can move mouse cursor over any profile shown, click and drag it up or down. Useful for comparing two work sessions results so that they match at zero height.
        • +
        • If mouse is over the profile plot the scroll wheel can increase or decrease the y axis range.
        • Added auto collimation setting to Ronchi and Foucault feature
        • Remembered last ROC offset value in Ronchi and Foucault feature to remember last setting when wave front is changed to a different value
        From 5357951ba1042c5e6efd1da78e16621317895920 Mon Sep 17 00:00:00 2001 From: gr5 Date: Wed, 14 May 2025 10:59:23 -0400 Subject: [PATCH 25/25] Fixed project file --- DFTFringe.pro | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/DFTFringe.pro b/DFTFringe.pro index 2a5edbe4..5805fee4 100644 --- a/DFTFringe.pro +++ b/DFTFringe.pro @@ -148,6 +148,7 @@ SOURCES += SingleApplication/singleapplication.cpp \ annulushelpdlg.cpp \ arbitrarywavefronthelp.cpp \ arbitrarywavwidget.cpp \ + astigpolargraph.cpp \ astigscatterplot.cpp \ astigstatsdlg.cpp \ astigzoomer.cpp \ @@ -181,6 +182,7 @@ SOURCES += SingleApplication/singleapplication.cpp \ gplus.cpp \ graphicsutilities.cpp \ helpdlg.cpp \ + hotkeysdlg.cpp \ igramarea.cpp \ igramintensity.cpp \ imagehisto.cpp \ @@ -208,6 +210,7 @@ SOURCES += SingleApplication/singleapplication.cpp \ pixelstats.cpp \ plotcolor.cpp \ profileplot.cpp \ + profileplotpicker.cpp \ psfplot.cpp \ psi_dlg.cpp \ psiphasedisplay.cpp \ @@ -227,6 +230,7 @@ SOURCES += SingleApplication/singleapplication.cpp \ settingsdft.cpp \ settingsGeneral2.cpp \ settingsigram.cpp \ + settingsigramimportconfig.cpp \ settingsprofile.cpp \ showaliasdlg.cpp \ showallcontoursdlg.cpp \ @@ -267,6 +271,7 @@ HEADERS += bezier/bezier.h \ SingleApplication/singleapplication.h \ annulushelpdlg.h \ arbitrarywavefronthelp.h \ + astigpolargraph.h \ arbitrarywavwidget.h \ astigscatterplot.h \ astigstatsdlg.h \ @@ -303,6 +308,7 @@ HEADERS += bezier/bezier.h \ gplus.h \ graphicsutilities.h \ helpdlg.h \ + hotkeysdlg.h \ IgramArea.h \ igramintensity.h \ imagehisto.h \ @@ -326,9 +332,11 @@ HEADERS += bezier/bezier.h \ outlinestatsdlg.h \ pdfcalibrationdlg.h \ percentcorrectiondlg.h \ + percentCorrectionSurface.h \ pixelstats.h \ plotcolor.h \ profileplot.h \ + profileplotpicker.h \ psfplot.h \ psi_dlg.h \ psiphasedisplay.h \ @@ -348,6 +356,7 @@ HEADERS += bezier/bezier.h \ settingsdft.h \ settingsGeneral2.h \ settingsigram.h \ + settingsigramimportconfig.h \ settingsprofile.h \ showaliasdlg.h \ showallcontoursdlg.h \ @@ -386,6 +395,7 @@ HEADERS += bezier/bezier.h \ FORMS += arbitrarywavefronthelp.ui \ annulushelpdlg.ui \ + astigpolargraph.ui \ astigstatsdlg.ui \ averagewavefrontfilesdlg.ui \ batchigramwizard.ui \ @@ -409,6 +419,7 @@ FORMS += arbitrarywavefronthelp.ui \ foucaultview.ui \ generatetargetdlg.ui \ helpdlg.ui \ + hotkeysdlg.ui \ igramintensity.ui \ jitteroutlinedlg.ui \ lensdialog.ui \ @@ -423,6 +434,7 @@ FORMS += arbitrarywavefronthelp.ui \ outlineplots.ui \ outlinestatsdlg.ui \ pdfcalibrationdlg.ui \ + percentcorrectiondlg.ui \ pixelstats.ui \ profilearea.ui \ profileplot.ui \ @@ -443,6 +455,7 @@ FORMS += arbitrarywavefronthelp.ui \ settingsdft.ui \ settingsGeneral2.ui \ settingsigram.ui \ + settingsigramimportconfig.ui \ settingsprofile.ui \ showaliasdlg.ui \ showallcontoursdlg.ui \