Skip to content

Commit eee6ba2

Browse files
committed
added circular grid to ronchi and foucault images
1 parent 2bf27ea commit eee6ba2

File tree

2 files changed

+212
-22
lines changed

2 files changed

+212
-22
lines changed

foucaultview.cpp

Lines changed: 201 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ foucaultView::foucaultView(QWidget *parent, SurfaceManager *sm) :
3333
connect(this, &QWidget::customContextMenuRequested, this,
3434
&foucaultView::showContextMenu);
3535
setContextMenuPolicy(Qt::CustomContextMenu);
36+
37+
// Load Grid Settings with the "ronchiGrid" key
38+
m_gridMode = static_cast<GridMode>(set.value("ronchiGrid/mode", (int)GridMode::None).toInt());
39+
m_gridSpacing = set.value("ronchiGrid/spacing", 10.0).toDouble();
40+
m_gridLineWidth = set.value("ronchiGrid/lineWidth", 1).toInt();
41+
m_showUnitLabels = set.value("ronchiGrid/showLabels", true).toBool();
42+
43+
// Using name() and string check for robust color persistence
44+
m_gridColor = QColor(set.value("ronchiGrid/color", "#00FFFF").toString()); // Default Cyan
45+
m_textColor = QColor(set.value("ronchiGrid/textColor", "#FFFFFF").toString()); // Default White
3646
}
3747

3848

@@ -78,10 +88,176 @@ void foucaultView::showContextMenu(QPoint pos)
7888
connect (showAllRonchi, &QAction::triggered,this, &foucaultView::showSelectedRonchiImages);
7989
myMenu.addAction(showAllRonchi);
8090

91+
QAction *showGrid = new QAction("Show Circular Grid");
92+
connect(showGrid, &QAction::triggered, this, &foucaultView::showGrid);
93+
myMenu.addSeparator();
94+
myMenu.addAction(showGrid);
95+
8196
// Show context menu at handling position
8297
myMenu.exec(globalPos);
8398
}
8499

100+
void foucaultView::showGrid() {
101+
QDialog dlg(this);
102+
dlg.setWindowTitle("Ronchi Grid Settings");
103+
QFormLayout form(&dlg);
104+
105+
// Create UI Elements
106+
QComboBox *unitCombo = new QComboBox(&dlg);
107+
unitCombo->addItems({"None", "Inches", "Millimeters", "Percentage"});
108+
unitCombo->setCurrentIndex((int)m_gridMode);
109+
110+
QDoubleSpinBox *spacingSpin = new QDoubleSpinBox(&dlg);
111+
spacingSpin->setRange(0.01, 1000.0);
112+
spacingSpin->setValue(m_gridSpacing);
113+
114+
QSpinBox *widthSpin = new QSpinBox(&dlg);
115+
widthSpin->setRange(1, 10);
116+
widthSpin->setValue(m_gridLineWidth);
117+
118+
QCheckBox *textToggle = new QCheckBox("Show unit labels", &dlg);
119+
textToggle->setChecked(m_showUnitLabels);
120+
121+
// Color storage (using local temps for the dialog session)
122+
struct State { QColor grid; QColor text; } colors = { m_gridColor, m_textColor };
123+
124+
QPushButton *btnGridCol = new QPushButton("Grid Color");
125+
QPushButton *btnTextCol = new QPushButton("Text Color");
126+
127+
connect(btnGridCol, &QPushButton::clicked, [&]() {
128+
QColor c = QColorDialog::getColor(colors.grid, this);
129+
if (c.isValid()) colors.grid = c;
130+
});
131+
connect(btnTextCol, &QPushButton::clicked, [&]() {
132+
QColor c = QColorDialog::getColor(colors.text, this);
133+
if (c.isValid()) colors.text = c;
134+
});
135+
136+
form.addRow("Grid Units:", unitCombo);
137+
form.addRow("Spacing Value:", spacingSpin);
138+
form.addRow("Line Width (px):", widthSpin);
139+
form.addRow("Labels:", textToggle);
140+
form.addRow("Grid Color:", btnGridCol);
141+
form.addRow("Text Color:", btnTextCol);
142+
143+
// Button Box with Reset
144+
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dlg);
145+
QPushButton *resetBtn = buttonBox.addButton("Reset to Defaults", QDialogButtonBox::ResetRole);
146+
form.addRow(&buttonBox);
147+
148+
// Reset Logic
149+
connect(resetBtn, &QPushButton::clicked, [&]() {
150+
unitCombo->setCurrentIndex(0); // None
151+
spacingSpin->setValue(10.0);
152+
widthSpin->setValue(1);
153+
textToggle->setChecked(true);
154+
colors.grid = Qt::cyan;
155+
colors.text = Qt::white;
156+
});
157+
158+
connect(&buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
159+
connect(&buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);
160+
161+
if (dlg.exec() == QDialog::Accepted) {
162+
m_gridMode = (GridMode)unitCombo->currentIndex();
163+
m_gridSpacing = spacingSpin->value();
164+
m_gridLineWidth = widthSpin->value();
165+
m_showUnitLabels = textToggle->isChecked();
166+
m_gridColor = colors.grid;
167+
m_textColor = colors.text;
168+
169+
// Save to QSettings with "ronchiGrid" prefix
170+
QSettings set;
171+
set.setValue("ronchiGrid/mode", (int)m_gridMode);
172+
set.setValue("ronchiGrid/spacing", m_gridSpacing);
173+
set.setValue("ronchiGrid/lineWidth", m_gridLineWidth);
174+
set.setValue("ronchiGrid/showLabels", m_showUnitLabels);
175+
set.setValue("ronchiGrid/color", m_gridColor.name());
176+
set.setValue("ronchiGrid/textColor", m_textColor.name());
177+
178+
on_makePb_clicked();
179+
}
180+
}
181+
182+
void foucaultView::drawGridOverlay(QImage &img) {
183+
if (m_gridMode == GridMode::None || !m_wf || m_gridSpacing <= 0) return;
184+
185+
QPainter painter(&img);
186+
painter.setRenderHint(QPainter::Antialiasing);
187+
painter.setRenderHint(QPainter::TextAntialiasing);
188+
189+
// 1. Grid Pen (Using your saved settings)
190+
QPen gridPen(m_gridColor, m_gridLineWidth, Qt::DotLine);
191+
painter.setPen(gridPen);
192+
193+
// 2. Dynamic Font Scaling
194+
// Scales between 10pt and 16pt based on image height to stay proportional
195+
int dynamicSize = qBound(10, img.height() / 33, 16);
196+
QFont font("Arial", dynamicSize, QFont::Bold);
197+
painter.setFont(font);
198+
199+
int w = img.width();
200+
int h = img.height();
201+
int centerX = w / 2;
202+
int centerY = h / 2;
203+
int maxPixelRadius = w / 2;
204+
205+
mirrorDlg *md = mirrorDlg::get_Instance();
206+
double mirrorRadiusMM = md->diameter / 2.0;
207+
208+
// 3. Determine physics-to-pixel scale
209+
double stepSizeMM = 0;
210+
if (m_gridMode == GridMode::Millimeters) stepSizeMM = m_gridSpacing;
211+
else if (m_gridMode == GridMode::Inches) stepSizeMM = m_gridSpacing * 25.4;
212+
else if (m_gridMode == GridMode::Percentage) stepSizeMM = (m_gridSpacing / 100.0) * mirrorRadiusMM;
213+
214+
if (stepSizeMM <= 0) return;
215+
216+
// 4. Draw Rings and Labels
217+
for (double currentMM = stepSizeMM; currentMM <= mirrorRadiusMM; currentMM += stepSizeMM) {
218+
int rPx = (int)((currentMM / mirrorRadiusMM) * maxPixelRadius);
219+
220+
painter.setPen(gridPen);
221+
painter.drawEllipse(QPoint(centerX, centerY), rPx, rPx);
222+
223+
if (m_showUnitLabels) {
224+
QString label;
225+
if (m_gridMode == GridMode::Millimeters)
226+
label = QString::number(currentMM, 'f', 1);
227+
else if (m_gridMode == GridMode::Inches)
228+
label = QString::number(currentMM / 25.4, 'f', 2);
229+
else
230+
label = QString::number((currentMM / mirrorRadiusMM) * 100.0, 'f', 0) + "%";
231+
232+
// Determine initial Y position at the top of the ring
233+
int yPos = centerY - rPx;
234+
235+
// EDGE CLIPPING FIX:
236+
// If the label is too close to the top edge (within 30 pixels),
237+
// shift it down so the text box doesn't get cut off.
238+
if (yPos < 30) {
239+
yPos = 30;
240+
}
241+
242+
// Define a wide bounding box for the text
243+
// Centered on X, and centered vertically on our adjusted yPos
244+
QRect textRect(centerX - 60, yPos - 15, 120, 30);
245+
246+
// Draw shadow for legibility (Black offset)
247+
painter.setPen(Qt::black);
248+
painter.drawText(textRect.translated(1, 1), Qt::AlignCenter, label);
249+
250+
// Draw actual colored text from your settings
251+
painter.setPen(m_textColor);
252+
painter.drawText(textRect, Qt::AlignCenter, label);
253+
}
254+
}
255+
256+
// 5. Center Crosshair
257+
painter.setPen(QPen(m_gridColor, 1, Qt::SolidLine));
258+
painter.drawLine(centerX - 12, centerY, centerX + 12, centerY);
259+
painter.drawLine(centerX, centerY - 12, centerX, centerY + 12);
260+
}
85261
void foucaultView::showSelectedRonchiImages(){
86262

87263
surfaceAnalysisTools *saTools = surfaceAnalysisTools::get_Instance();
@@ -312,8 +488,12 @@ void foucaultView::on_makePb_clicked()
312488
if (img.isNull()) return;
313489

314490
QSize s = label->size();
315-
QPixmap pix = QPixmap::fromImage(img.scaledToWidth(s.width()));
491+
QImage displayImg = img.scaled(s, Qt::KeepAspectRatio, Qt::SmoothTransformation);
492+
493+
// Overlay grid
494+
drawGridOverlay(displayImg);
316495

496+
QPixmap pix = QPixmap::fromImage(displayImg);
317497
QPainter painter(&pix);
318498
painter.save();
319499
painter.setPen(QPen(QColor(Qt::white)));
@@ -375,21 +555,19 @@ void foucaultView::generateBatchRonchiImage(const QList<wavefront*>& wavefrontLi
375555

376556
int headerHeight = 70;
377557
int textBuffer = 40;
378-
379558
int cellW = imgDim;
380559
int cellH = imgDim + textBuffer;
381560

382-
// Total Canvas size
383561
QImage canvas(cellW * cols, (cellH * rows) + headerHeight, QImage::Format_RGB32);
384562
canvas.fill(Qt::black);
385563

386564
QPainter painter(&canvas);
387565
painter.setRenderHint(QPainter::Antialiasing);
388566
QApplication::setOverrideCursor(Qt::WaitCursor);
389567

390-
// NEW: Container for individual Ronchi images to be used in comparison
391568
QList<QImage> individualRonchis;
392569
QList<QString> names;
570+
393571
// 5. Draw Simulation Header
394572
painter.setPen(Qt::white);
395573
painter.setFont(QFont("Arial", 12, QFont::Bold));
@@ -410,20 +588,30 @@ void foucaultView::generateBatchRonchiImage(const QList<wavefront*>& wavefrontLi
410588
int row = i / cols;
411589
int col = i % cols;
412590

591+
// Generate the raw Ronchi image
413592
QImage ronchi = generateOpticalTestImage(OpticalTestType::Ronchi, currentWf, s, ui->autocollimation->isChecked());
414593

415594
if (!ronchi.isNull()) {
416-
// Store a copy for the comparison feature
595+
// STORE RAW: Add to list for the Compare Dialog (Prevents crash & artifacting)
417596
individualRonchis.append(ronchi);
418597

598+
// STORE NAME: Essential for the Compare Dialog to avoid out-of-bounds crash
599+
QFileInfo fileInfo(currentWf->name);
600+
QString displayName = fileInfo.baseName();
601+
names.append(displayName);
602+
603+
// GRID OVERLAY: Apply only to a copy for the batch preview canvas
604+
QImage displayCopy = ronchi;
605+
if (m_gridMode != GridMode::None) {
606+
drawGridOverlay(displayCopy);
607+
}
608+
419609
int xPos = col * cellW;
420610
int yPos = headerHeight + (row * cellH);
421611

422-
painter.drawImage(xPos, yPos, ronchi);
612+
painter.drawImage(xPos, yPos, displayCopy);
423613

424-
QFileInfo fileInfo(currentWf->name);
425-
QString displayName = fileInfo.baseName();
426-
names << displayName;
614+
// Draw Label on Canvas
427615
int textWidth = fm.horizontalAdvance(displayName);
428616
int xText = xPos + (cellW - textWidth) / 2;
429617
int yText = yPos + imgDim + (textBuffer / 2) + (fm.ascent() / 2);
@@ -448,14 +636,13 @@ void foucaultView::generateBatchRonchiImage(const QList<wavefront*>& wavefrontLi
448636
QScrollArea *scroll = new QScrollArea(&previewDlg);
449637
scroll->setWidgetResizable(true);
450638
scroll->setAlignment(Qt::AlignCenter);
451-
//scroll->setStyleSheet("background-color: #1a1a1a;");
452639

453640
QLabel *imgLabel = new QLabel();
454641
imgLabel->setAlignment(Qt::AlignCenter);
455642
scroll->setWidget(imgLabel);
456643
layout->addWidget(scroll);
457644

458-
// 8. Zoom Slider Integration
645+
// 8. Zoom Slider
459646
QPixmap previewPixmap = QPixmap::fromImage(canvas);
460647
QHBoxLayout *zoomLayout = new QHBoxLayout();
461648
QSlider *slider = new QSlider(Qt::Horizontal);
@@ -479,13 +666,10 @@ void foucaultView::generateBatchRonchiImage(const QList<wavefront*>& wavefrontLi
479666
connect(slider, &QSlider::valueChanged, updateZoom);
480667
updateZoom(100);
481668

482-
// 9. Navigation and Comparison Buttons
669+
// 9. Buttons
483670
QHBoxLayout *btns = new QHBoxLayout();
484-
485-
// NEW: Comparison button
486671
QPushButton *compareBtn = new QPushButton(tr("Compare Top Two Patterns"));
487672
compareBtn->setIcon(style()->standardIcon(QStyle::SP_BrowserReload));
488-
// Feature only enabled if 2 or more wavefronts were processed
489673
compareBtn->setEnabled(individualRonchis.size() >= 2);
490674

491675
QPushButton *saveBtn = new QPushButton(tr("Save Grid Image"));
@@ -497,23 +681,18 @@ void foucaultView::generateBatchRonchiImage(const QList<wavefront*>& wavefrontLi
497681
btns->addWidget(cancelBtn);
498682
layout->addLayout(btns);
499683

500-
// Connect the comparison trigger
684+
// Comparison Trigger (Uses captured lists)
501685
connect(compareBtn, &QPushButton::clicked, &previewDlg, [=, &previewDlg]() {
502-
// [=] copies individualRonchis and names so they stay
503-
// valid even after generateBatchRonchiImage() returns.
504-
if (individualRonchis.size() >= 2) {
686+
if (individualRonchis.size() >= 2 && names.size() >= 2) {
505687
RonchiCompareDialog compDlg(individualRonchis[0], names[0],
506688
individualRonchis[1], names[1], &previewDlg);
507689
compDlg.exec();
508690
}
509691
});
510692

511-
512693
connect(saveBtn, &QPushButton::clicked, &previewDlg, &QDialog::accept);
513694
connect(cancelBtn, &QPushButton::clicked, &previewDlg, &QDialog::reject);
514695

515-
516-
// 10. Execute Dialog and Save Grid
517696
if (previewDlg.exec() == QDialog::Accepted) {
518697
QString path = QFileDialog::getSaveFileName(this, tr("Save Ronchi Grid"),
519698
imageDir, tr("Images (*.png *.jpg)"));

foucaultview.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ enum class OpticalTestType {
1515
Ronchi
1616
};
1717

18+
enum class GridMode { None, Inches, Millimeters, Percentage };
19+
20+
1821
// Parameter container so this can be called without needing the UI pointers
1922
struct OpticalTestSettings {
2023
double rocOffset = 0.0;
@@ -81,6 +84,7 @@ private slots:
8184
void on_SaveImageCB_clicked(bool checked);
8285
void saveRonchiImage();
8386
void saveFoucaultImage();
87+
void showGrid();
8488
void on_overlayProfile_stateChanged(int arg1);
8589
void on_RonchiX_valueChanged(double arg1);
8690
void on_pushButton_clicked();
@@ -99,7 +103,14 @@ private slots:
99103
double m_temp_sag;
100104
wavefront *m_wf;
101105
int lateralOffset;
106+
GridMode m_gridMode = GridMode::None;
107+
double m_gridSpacing = 10.0; // Default spacing value
108+
int m_gridLineWidth = 1;
109+
bool m_showUnitLabels = true;
110+
QColor m_gridColor = Qt::cyan;
111+
QColor m_textColor = Qt::white;
102112

113+
void drawGridOverlay(QImage &img);
103114
explicit foucaultView(QWidget *parent = 0, SurfaceManager *sm = 0);
104115
cv::Mat compute_star_test(int pupil_size, double defocus, double pad, bool use_OPD);
105116
double getStep();

0 commit comments

Comments
 (0)