viewer: add/subtract the selected ROI to/from the user mask
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Failing after 3m45s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Failing after 3m44s
Build Packages / build:rpm (rocky8_nocuda) (push) Failing after 3m50s
Build Packages / build:rpm (rocky8_sls9) (push) Failing after 3m45s
Build Packages / build:rpm (rocky8) (push) Failing after 3m46s
Build Packages / build:rpm (rocky9_nocuda) (push) Failing after 4m0s
Build Packages / build:rpm (rocky9_sls9) (push) Failing after 3m56s
Build Packages / build:rpm (ubuntu2204) (push) Failing after 3m5s
Build Packages / build:rpm (ubuntu2404) (push) Failing after 3m7s
Build Packages / build:rpm (rocky9) (push) Failing after 3m12s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Failing after 21s
Build Packages / Generate python client (push) Successful in 31s
Build Packages / XDS test (durin plugin) (push) Successful in 5m53s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m12s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m54s
Build Packages / DIALS test (push) Successful in 8m46s
Build Packages / Unit tests (push) Successful in 48m22s

Restore the ROI-to-mask action on the new list: "Add to mask" and
"Subtract from mask" buttons rasterise the selected ROI into the user
mask (set or clear), through the same UpdateUserMask_i path. The ROI is
evaluated with per-pixel resolution and phi from the geometry, so box,
circle and azimuthal (sector) ROIs all map correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 15:08:59 +02:00
co-authored by Claude Opus 4.8
parent 81b48febcf
commit abc1d1c079
7 changed files with 50 additions and 0 deletions
+31
View File
@@ -584,6 +584,37 @@ void JFJochImageReadingWorker::SetROIDefinition(const ROIDefinition &rois) {
SetROIDefinition_i(rois);
}
void JFJochImageReadingWorker::MaskFromSelectedROI(QString name, bool add) {
QMutexLocker locker(&m);
if (!current_image_ptr)
return;
const auto &exp = current_image_ptr->Dataset().experiment;
const auto rois = exp.ROI().GetROIDefinition();
const std::string n = name.toStdString();
const ROIElement *elem = nullptr;
for (const auto &b : rois.boxes) if (b.GetName() == n) { elem = &b; break; }
if (!elem) for (const auto &c : rois.circles) if (c.GetName() == n) { elem = &c; break; }
if (!elem) for (const auto &a : rois.azimuthal) if (a.GetName() == n) { elem = &a; break; }
if (!elem)
return;
auto user_mask = current_image_ptr->Dataset().pixel_mask.GetUserMask();
auto geom = exp.GetDiffractionGeometry();
const int64_t width = exp.GetXPixelsNum();
const int64_t height = exp.GetYPixelsNum();
for (int64_t y = 0; y < height; y++) {
for (int64_t x = 0; x < width; x++) {
const float res = geom.PxlToRes(x, y);
const float phi = geom.Phi_rad(x, y) * 180.0f / static_cast<float>(PI);
if (elem->CheckROI(x, y, res, phi))
user_mask[x + y * width] = add ? 1 : 0;
}
}
UpdateUserMask_i(user_mask);
}
void JFJochImageReadingWorker::DownloadROIsFromServer() {
QMutexLocker locker(&m);
if (!http_mode)
+1
View File
@@ -166,6 +166,7 @@ public slots:
void SetROIDefinition(const ROIDefinition &rois);
void DownloadROIsFromServer();
void UploadROIsToServer();
void MaskFromSelectedROI(QString name, bool add); // rasterise an ROI into the user mask
void SaveUserMaskTIFF(QString filename);
void LoadUserMaskTIFF(QString filename, bool replace);
+1
View File
@@ -132,6 +132,7 @@ JFJochViewerSidePanel::JFJochViewerSidePanel(QWidget *parent) : QWidget(parent)
connect(roi_list, &JFJochViewerROIList::selectedROIChanged, this, &JFJochViewerSidePanel::selectedROIChanged);
connect(roi_list, &JFJochViewerROIList::downloadROIs, this, &JFJochViewerSidePanel::downloadROIs);
connect(roi_list, &JFJochViewerROIList::uploadROIs, this, &JFJochViewerSidePanel::uploadROIs);
connect(roi_list, &JFJochViewerROIList::maskFromROI, this, &JFJochViewerSidePanel::maskFromROI);
layout->addWidget(new TitleLabel("Data analysis", this));
+1
View File
@@ -35,6 +35,7 @@ signals:
void selectedROIChanged(QString name);
void downloadROIs();
void uploadROIs();
void maskFromROI(QString name, bool add);
void findBeamCenter(const UnitCell &input, bool guess);
void analyze();
+2
View File
@@ -201,6 +201,8 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString
reading_worker, &JFJochImageReadingWorker::DownloadROIsFromServer);
connect(side_panel, &JFJochViewerSidePanel::uploadROIs,
reading_worker, &JFJochImageReadingWorker::UploadROIsToServer);
connect(side_panel, &JFJochViewerSidePanel::maskFromROI,
reading_worker, &JFJochImageReadingWorker::MaskFromSelectedROI);
connect(menuBar, &JFJochViewerMenu::clearUserMaskSelected,
reading_worker, &JFJochImageReadingWorker::ClearUserMask);
+13
View File
@@ -55,6 +55,19 @@ JFJochViewerROIList::JFJochViewerROIList(QWidget *parent) : QWidget(parent) {
}
layout->addLayout(grid);
auto *mask = new QHBoxLayout();
auto *mask_add = new QPushButton("Add to mask", this);
auto *mask_sub = new QPushButton("Subtract from mask", this);
mask->addWidget(mask_add);
mask->addWidget(mask_sub);
layout->addLayout(mask);
connect(mask_add, &QPushButton::clicked, [this] {
if (!SelectedName().isEmpty()) emit maskFromROI(SelectedName(), true);
});
connect(mask_sub, &QPushButton::clicked, [this] {
if (!SelectedName().isEmpty()) emit maskFromROI(SelectedName(), false);
});
result_ = new JFJochViewerROIResult(this);
layout->addWidget(result_);
}
+1
View File
@@ -52,4 +52,5 @@ signals:
void selectedROIChanged(QString name);
void downloadROIs(); // fetch ROIs from the connected broker
void uploadROIs(); // push ROIs to the connected broker
void maskFromROI(QString name, bool add); // add/subtract the selected ROI to/from the user mask
};