Files
Jungfraujoch/viewer/JFJochViewerSidePanel.cpp
Filip Leonarski 33aeb64e4c
All checks were successful
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 7m51s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 7m19s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 7m46s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 8m32s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 8m6s
Build Packages / build:rpm (rocky8) (push) Successful in 8m7s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 7m37s
Build Packages / Generate python client (push) Successful in 17s
Build Packages / Create release (push) Has been skipped
Build Packages / Build documentation (push) Successful in 32s
Build Packages / build:rpm (rocky9) (push) Successful in 9m6s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 6m53s
Build Packages / Unit tests (push) Successful in 1h9m39s
v1.0.0-rc.103 (#8)
This is an UNSTABLE release.

* jfjoch_viewer: Minor improvements to the viewer
* jfjoch_broker: Change behavior for modular detectors: coordinates of 0-th pixel can be now arbitrary and detector will be cropped to the smallest rectangle limited by module coordinates

Reviewed-on: #8
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
2025-11-19 09:40:50 +01:00

266 lines
9.7 KiB
C++

// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include <QCheckBox>
#include <QLabel>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QColorDialog>
#include <QComboBox>
#include "JFJochViewerSidePanel.h"
#include "JFJochViewerImageROIStatistics.h"
#include "widgets/TitleLabel.h"
#include "JFJochViewerImageStatistics.h"
#include "../image_analysis/geom_refinement/AssignSpotsToRings.h"
JFJochViewerSidePanel::JFJochViewerSidePanel(QWidget *parent) : QWidget(parent) {
auto layout = new QVBoxLayout(this);
layout->addWidget(new TitleLabel("Image statistics", this));
auto stats = new JFJochViewerImageStatistics(this);
layout->addWidget(stats);
connect(this, &JFJochViewerSidePanel::imageLoaded, stats, &JFJochViewerImageStatistics::loadImage);
layout->addWidget(new TitleLabel("Image features", this));
// Image features...
auto spotToggleCheckBox = new QCheckBox("Show spots", this);
spotToggleCheckBox->setCheckState(Qt::CheckState::Checked);
connect(spotToggleCheckBox, &QCheckBox::toggled, this, &JFJochViewerSidePanel::spotsToggled);
auto highlightIceRingToggleCheckBox = new QCheckBox("Highlight spots on ice rings", this);
highlightIceRingToggleCheckBox->setCheckState(Qt::CheckState::Checked);
connect(highlightIceRingToggleCheckBox, &QCheckBox::toggled, this,&JFJochViewerSidePanel::highlightIceRingsToggled);
auto predictionsToggleCheckBox = new QCheckBox("Show predictions", this);
predictionsToggleCheckBox->setCheckState(Qt::CheckState::Unchecked);
connect(predictionsToggleCheckBox, &QCheckBox::toggled, this,
&JFJochViewerSidePanel::predictionsToggled);
res_rings = new ResolutionRingWidget(this);
connect(res_rings, &ResolutionRingWidget::resRingsSet, [this] (QVector<float> v) {
emit resRingsSet(v);
});
connect(res_rings, &ResolutionRingWidget::ringModeSet, [this] (JFJochDiffractionImage::RingMode mode) {
emit ringModeSet(mode);
});
auto highestPixelsComboBox = new QComboBox(this);
highestPixelsComboBox->addItem("Show 0 highest pixels", 0);
highestPixelsComboBox->addItem("Show 1 highest pixel", 1);
highestPixelsComboBox->addItem("Show 2 highest pixels", 2);
highestPixelsComboBox->addItem("Show 3 highest pixels", 3);
highestPixelsComboBox->addItem("Show 5 highest pixels", 5);
highestPixelsComboBox->addItem("Show 10 highest pixels", 10);
highestPixelsComboBox->setCurrentIndex(0);
connect(highestPixelsComboBox, &QComboBox::currentIndexChanged, this, [this, highestPixelsComboBox](int index) {
int value = highestPixelsComboBox->itemData(index).toInt();
emit showHighestPixels(value);
});
auto saturatedPixelsCheckBox = new QCheckBox("Show saturated pixels", this);
connect(saturatedPixelsCheckBox, &QCheckBox::toggled, this, &JFJochViewerSidePanel::saturatedPixelsToggled);
auto colorSelectButton = new QPushButton("Select feature color", this);
connect(colorSelectButton, &QPushButton::clicked, this, [this]() {
QColor color = QColorDialog::getColor(Qt::magenta, this, "Select Feature Color");
if (color.isValid()) {
emit setFeatureColor(color);
}
});
auto spotColorSelectButton = new QPushButton("Select spot color", this);
connect(spotColorSelectButton, &QPushButton::clicked, this, [this]() {
QColor color = QColorDialog::getColor(Qt::green, this, "Select Spot Color");
if (color.isValid()) {
emit setSpotColor(color);
}
});
auto image_feature_grid = new QGridLayout();
image_feature_grid->addWidget(spotToggleCheckBox, 0, 0);
image_feature_grid->addWidget(highlightIceRingToggleCheckBox, 0, 1);
image_feature_grid->addWidget(predictionsToggleCheckBox, 1, 0);
image_feature_grid->addWidget(saturatedPixelsCheckBox, 2, 0);
image_feature_grid->addWidget(highestPixelsComboBox, 2, 1);
image_feature_grid->addWidget(colorSelectButton, 3, 0);
image_feature_grid->addWidget(spotColorSelectButton, 3, 1);
image_feature_grid->addWidget(res_rings, 4, 0, 1, 2);
layout->addLayout(image_feature_grid);
layout->addWidget(new TitleLabel("Image statistics plot", this));
chart = new JFJochViewerSidePanelChart(this);
layout->addWidget(chart);
connect(this, &JFJochViewerSidePanel::imageLoaded,
chart, &JFJochViewerSidePanelChart::loadImage);
connect(chart, &JFJochViewerSidePanelChart::writeStatusBar,
[&] (QString string, int timeout_ms) {
emit writeStatusBar(string, timeout_ms);
});
layout->addWidget(new TitleLabel("ROI", this));
roi = new JFJochViewerImageROIStatistics(this);
layout->addWidget(roi);
connect(roi, &JFJochViewerImageROIStatistics::ROIBoxConfigured, [this] (QRect box) {
emit ROIBoxConfigured(box);
});
connect(roi, &JFJochViewerImageROIStatistics::ROICircleConfigured, [this] (double x, double y, double radius) {
emit ROICircleConfigured(x, y, radius);
});
connect(roi, &JFJochViewerImageROIStatistics::AddROIToUserMask, [this]() { emit AddROIToUserMask(); });
connect(roi, &JFJochViewerImageROIStatistics::SubtractROIFromUserMask, [this]() { emit SubtractROIFromUserMask(); });
layout->addWidget(new TitleLabel("Data analysis", this));
auto analyzeButton = new QPushButton("Full analysis", this);
connect(analyzeButton, &QPushButton::clicked,[this] {emit analyze();});
layout->addWidget(analyzeButton);
// Calibrant selection combo box
layout->addWidget(new TitleLabel("Powder geometry calibration", this));
calibrantCombo = new QComboBox(this);
updateCalibrantList();
auto findBeamCenterButton = new QPushButton("Guess detector calibration", this);
connect(findBeamCenterButton, &QPushButton::clicked,this, &JFJochViewerSidePanel::findBeamCenterClicked);
auto optimizeBeamCenterButton = new QPushButton("Refine detector calibration", this);
connect(optimizeBeamCenterButton, &QPushButton::clicked,this, &JFJochViewerSidePanel::optimizeBeamCenterClicked);
auto calibrantRingsButton = new QPushButton("Display calibrant rings", this);
connect(calibrantRingsButton, &QPushButton::clicked, this, [this]() {
std::vector<float> rings = CalculateXtalRings(GetCalibrant(), 10);
QVector<float> q_rings;
for (float ring : rings) {
q_rings.append(2 * M_PI / ring);
}
res_rings->setRings(q_rings);
});
// Add preset ice rings button below LaB6 calibration
auto iceRingsButton = new QPushButton("Display ice rings", this);
connect(iceRingsButton, &QPushButton::clicked, this, [this]() {
// Set manual rings and enable display
const QVector<float> ice_rings(ICE_RING_RES_A.begin(), ICE_RING_RES_A.end());
res_rings->setRings(ice_rings);
});
auto refine_row = new QGridLayout();
refine_row->setSpacing(12);
refine_row->addWidget(new QLabel("Calibrant:"),0,0);
refine_row->addWidget(calibrantCombo,0,1);
refine_row->addWidget(findBeamCenterButton,1, 0);
refine_row->addWidget(optimizeBeamCenterButton,1, 1);
refine_row->addWidget(calibrantRingsButton,2, 0);
refine_row->addWidget(iceRingsButton,2, 1);
layout->addLayout(refine_row);
layout->addStretch();
setLayout(layout); // Set the layout to the widget
}
UnitCell JFJochViewerSidePanel::GetCalibrant() const {
UnitCell uc(LAB6_CELL_A, LAB6_CELL_A, LAB6_CELL_A, 90, 90, 90);
switch (calibrantCombo->currentIndex()) {
case 1:
// T. C. Huang , H. Toraya, T. N. Blanton, Y. Wu, J. Appl. Cryst. 26 (1993), 180-184.
uc = UnitCell(5.1769, 4.7218, 58.380, 89.440, 89.634, 75.854);
break;
case 2:
if (sample_cell)
uc = sample_cell.value();
break;
default:
break;
}
return uc;
}
void JFJochViewerSidePanel::updateCalibrantList() {
calibrantCombo->clear();
calibrantCombo->addItem("LaB6");
calibrantCombo->addItem("Silver Behenate");
if (sample_cell)
calibrantCombo->addItem(QString("Current sample (%1 %2 %3 %4 %5 %6)")
.arg(QString::number(sample_cell->a, 'f', 1))
.arg(QString::number(sample_cell->b, 'f', 1))
.arg(QString::number(sample_cell->c, 'f', 1))
.arg(QString::number(sample_cell->alpha, 'f', 1))
.arg(QString::number(sample_cell->beta, 'f', 1))
.arg(QString::number(sample_cell->gamma, 'f', 1)));
calibrantCombo->setCurrentIndex(0);
}
void JFJochViewerSidePanel::optimizeBeamCenterClicked() {
emit findBeamCenter(GetCalibrant(), false);
}
void JFJochViewerSidePanel::findBeamCenterClicked() {
emit findBeamCenter(GetCalibrant(), true);
}
void JFJochViewerSidePanel::spotsToggled(bool input) {
emit showSpots(input);
}
void JFJochViewerSidePanel::predictionsToggled(bool input) {
emit showPredictions(input);
}
void JFJochViewerSidePanel::loadImage(std::shared_ptr<const JFJochReaderImage> image) {
if (image)
sample_cell = image->Dataset().experiment.GetUnitCell();
updateCalibrantList();
emit imageLoaded(image);
}
void JFJochViewerSidePanel::saturatedPixelsToggled(bool input) {
emit showSaturatedPixels(input);
}
void JFJochViewerSidePanel::highlightIceRingsToggled(bool input) {
emit highlightIceRings(input);
}
void JFJochViewerSidePanel::SetROIBox(QRect box) {
roi->SetROIBox(box);
}
void JFJochViewerSidePanel::SetROICircle(double x, double y, double radius) {
roi->SetROICircle(x, y, radius);
}
void JFJochViewerSidePanel::SetROIResult(ROIMessage msg) {
roi->SetROIResult(msg);
}
void JFJochViewerSidePanel::SetRings(QVector<float> v) {
res_rings->setRings(v);
}