From 940b7e34d482b3a5d258d5bd202462427b4ba527 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Mon, 22 Jun 2026 08:30:49 +0200 Subject: [PATCH] viewer: indexing algorithm/refinement radio groups, rotation fix, live job plots Processing settings: - Split the spot/index settings widget into two tabs (Spot finding | Indexing) via TakeSpotFindingPage()/TakeIndexingPage(). - Indexing tab now exposes the indexing algorithm (Auto/FFBIDX/FFT/FFTW/None) and geometry refinement (None/Orientation/Beam center/Pixel refine) as radio groups with short explanations. - Fix: UpdateSpotFindingSettings dropped algorithm + geometry-refinement when copying into indexing_settings (the geom checkbox was a no-op); both now flow into jobs via curr_experiment. Processing jobs window: - Rotation indexing from the job dialog now also sets RotationIndexing(true) on the experiment's IndexingSettings; otherwise IndexAndRefine builds no rotation indexer and the two-pass pre-pass throws. - Status cell shows a QProgressBar with " / ". - Live results: JFJochProcessController::OnImageProcessed accumulates per-image results into a JFJochReaderDataset and emits it throttled (~4 Hz) as liveDataset, forwarded to the dataset-info plots so they update while a job runs. Co-Authored-By: Claude Opus 4.8 --- viewer/JFJochImageReadingWorker.cpp | 2 + viewer/JFJochProcessController.cpp | 55 +++++++++ viewer/JFJochProcessController.h | 13 ++ viewer/JFJochViewerWindow.cpp | 5 +- viewer/JFJochViewerWindow.h | 3 + viewer/windows/JFJochProcessingJobsWindow.cpp | 46 ++++++- viewer/windows/JFJochProcessingJobsWindow.h | 4 + viewer/windows/JFJochSettingsWindow.cpp | 3 +- .../windows/JFJochViewerProcessingWindow.cpp | 113 +++++++++++++----- viewer/windows/JFJochViewerProcessingWindow.h | 17 ++- 10 files changed, 216 insertions(+), 45 deletions(-) diff --git a/viewer/JFJochImageReadingWorker.cpp b/viewer/JFJochImageReadingWorker.cpp index 509fe1c9..7614cfd6 100644 --- a/viewer/JFJochImageReadingWorker.cpp +++ b/viewer/JFJochImageReadingWorker.cpp @@ -557,6 +557,8 @@ void JFJochImageReadingWorker::UpdateSpotFindingSettings(const SpotFindingSettin QMutexLocker locker(&m); spot_finding_settings = settings; + indexing_settings.Algorithm(indexing.GetAlgorithm()); + indexing_settings.GeomRefinementAlgorithm(indexing.GetGeomRefinementAlgorithm()); indexing_settings.Tolerance(indexing.GetTolerance()); indexing_settings.ViableCellMinSpots(indexing.GetViableCellMinSpots()); indexing_settings.IndexIceRings(indexing.GetIndexIceRings()); diff --git a/viewer/JFJochProcessController.cpp b/viewer/JFJochProcessController.cpp index ee3e1bc1..7adc058c 100644 --- a/viewer/JFJochProcessController.cpp +++ b/viewer/JFJochProcessController.cpp @@ -6,8 +6,11 @@ #include +#include + JFJochProcessController::JFJochProcessController(QObject *parent) : QObject(parent) { qRegisterMetaType("ProcessResult"); + qRegisterMetaType>("std::shared_ptr"); } JFJochProcessController::~JFJochProcessController() { @@ -44,6 +47,16 @@ void JFJochProcessController::run_(QString file_path, DiffractionExperiment expe JFJochHDF5Reader reader; reader.ReadFile(file_path.toStdString()); + // Seed the live dataset with the experiment so the chart has geometry context; per-image + // results are filled in by OnImageProcessed as the run progresses. + { + auto base = std::make_shared(); + base->experiment = experiment; + std::lock_guard lock(live_mutex_); + live_dataset_ = std::move(base); + last_live_emit_ = {}; + } + JFJochProcess process(reader, std::move(experiment), std::move(pixel_mask), std::move(config)); active_ = &process; if (cancel_pending_) @@ -71,3 +84,45 @@ void JFJochProcessController::OnProgress(uint64_t done, uint64_t total) { if (done == total || done % step == 0) emit progress(done, total); } + +void JFJochProcessController::OnImageProcessed(const DataMessage &msg) { + std::shared_ptr snapshot; + { + std::lock_guard lock(live_mutex_); + if (!live_dataset_) + return; + + // Place each available per-image result at its ordinal; gaps (images still being processed + // by other threads) read back as NaN. + const int64_t i = msg.number; + auto put = [i](std::vector &v, float val) { + if (static_cast(v.size()) <= i) + v.resize(i + 1, NAN); + v[i] = val; + }; + auto &d = *live_dataset_; + if (msg.spot_count) put(d.spot_count, *msg.spot_count); + if (msg.spot_count_indexed) put(d.spot_count_indexed, *msg.spot_count_indexed); + if (msg.spot_count_low_res) put(d.spot_count_low_res, *msg.spot_count_low_res); + if (msg.spot_count_ice_rings) put(d.spot_count_ice_rings, *msg.spot_count_ice_rings); + if (msg.indexing_result) put(d.indexing_result, *msg.indexing_result ? 1.0f : 0.0f); + if (msg.indexing_lattice_count) put(d.indexing_lattice_count, *msg.indexing_lattice_count); + if (msg.bkg_estimate) put(d.bkg_estimate, *msg.bkg_estimate); + if (msg.resolution_estimate) put(d.resolution_estimate, *msg.resolution_estimate); + if (msg.profile_radius) put(d.profile_radius, *msg.profile_radius); + if (msg.mosaicity_deg) put(d.mosaicity_deg, *msg.mosaicity_deg); + if (msg.b_factor) put(d.b_factor, *msg.b_factor); + if (msg.integrated_reflections) put(d.integrated_reflections, *msg.integrated_reflections); + if (msg.image_scale_factor) put(d.image_scale_factor, *msg.image_scale_factor); + if (msg.image_scale_cc) put(d.image_scale_cc, *msg.image_scale_cc); + if (msg.image_scale_b_factor) put(d.image_scale_b, *msg.image_scale_b_factor); + + // Throttle to ~4 Hz so the GUI plots refresh smoothly without flooding the event queue. + const auto now = std::chrono::steady_clock::now(); + if (now - last_live_emit_ < std::chrono::milliseconds(250)) + return; + last_live_emit_ = now; + snapshot = std::make_shared(d); // immutable copy for the GUI thread + } + emit liveDataset(snapshot); +} diff --git a/viewer/JFJochProcessController.h b/viewer/JFJochProcessController.h index 50e0f16e..ff64ede0 100644 --- a/viewer/JFJochProcessController.h +++ b/viewer/JFJochProcessController.h @@ -7,11 +7,15 @@ #include #include +#include +#include +#include #include #include "../process/JFJochProcess.h" #include "../common/DiffractionExperiment.h" #include "../common/PixelMask.h" +#include "../reader/JFJochReaderDataset.h" Q_DECLARE_METATYPE(ProcessResult) @@ -41,11 +45,14 @@ signals: void progress(quint64 done, quint64 total); void finished(ProcessResult result); void failed(QString error); + // Per-image results accumulated so far, for live dataset-info plots while a job runs (throttled). + void liveDataset(std::shared_ptr dataset); private: // JFJochProcessObserver - called from worker threads, forwarded as queued signals. void OnPhase(const std::string &phase) override; void OnProgress(uint64_t done, uint64_t total) override; + void OnImageProcessed(const DataMessage &msg) override; void run_(QString file_path, DiffractionExperiment experiment, PixelMask pixel_mask, ProcessConfig config); void joinWorker_(); @@ -54,4 +61,10 @@ private: std::atomic active_{nullptr}; std::atomic running_{false}; std::atomic cancel_pending_{false}; + + // Live per-image results, accumulated by OnImageProcessed (worker threads) and emitted as + // immutable copies. live_mutex_ guards both the dataset and the throttle timestamp. + std::mutex live_mutex_; + std::shared_ptr live_dataset_; + std::chrono::steady_clock::time_point last_live_emit_; }; diff --git a/viewer/JFJochViewerWindow.cpp b/viewer/JFJochViewerWindow.cpp index c2948e21..bec373d1 100644 --- a/viewer/JFJochViewerWindow.cpp +++ b/viewer/JFJochViewerWindow.cpp @@ -114,7 +114,7 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString auto azintImageWindow = new JFJoch2DAzintImageWindow(this); auto magnifierWindow = new JFJochMagnifierWindow(this); - auto processingJobsWindow = new JFJochProcessingJobsWindow(reading_worker, this); + processingJobsWindow = new JFJochProcessingJobsWindow(reading_worker, this); menuBar->AddWindowEntry(tableWindow, "Image list"); menuBar->AddWindowEntry(spotWindow, "Spot list"); @@ -434,6 +434,9 @@ void JFJochViewerWindow::NewDatasetInfo() { info, &JFJochViewerDatasetInfo::datasetLoaded); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, info, &JFJochViewerDatasetInfo::imageLoaded); + // Live processing results: refresh the plots while a job runs. + connect(processingJobsWindow, &JFJochProcessingJobsWindow::liveDataset, + info, &JFJochViewerDatasetInfo::datasetLoaded); connect(info, &JFJochViewerDatasetInfo::imageSelected, reading_worker, &JFJochImageReadingWorker::LoadImage); connect(toolBarDisplay, &JFJochViewerToolbarDisplay::colorMapChanged, diff --git a/viewer/JFJochViewerWindow.h b/viewer/JFJochViewerWindow.h index 56011e19..549bc15d 100644 --- a/viewer/JFJochViewerWindow.h +++ b/viewer/JFJochViewerWindow.h @@ -13,6 +13,8 @@ #include "JFJochViewerStatusBar.h" #include "toolbar/JFJochViewerToolbarDisplay.h" +class JFJochProcessingJobsWindow; + class JFJochViewerWindow : public QMainWindow { Q_OBJECT const QString stylesheet = "background-color: rgb(255, 235, 230);"; @@ -25,6 +27,7 @@ private: JFJochImageReadingWorker *reading_worker; JFJochViewerToolbarDisplay *toolBarDisplay; JFJochViewerStatusBar *statusbar; + JFJochProcessingJobsWindow *processingJobsWindow; std::shared_ptr lastDataset; // added std::shared_ptr lastImage; // added diff --git a/viewer/windows/JFJochProcessingJobsWindow.cpp b/viewer/windows/JFJochProcessingJobsWindow.cpp index 800553fe..627a1be1 100644 --- a/viewer/windows/JFJochProcessingJobsWindow.cpp +++ b/viewer/windows/JFJochProcessingJobsWindow.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ JFJochProcessingJobsWindow::JFJochProcessingJobsWindow(JFJochImageReadingWorker connect(controller_, &JFJochProcessController::progress, this, &JFJochProcessingJobsWindow::onProgress); connect(controller_, &JFJochProcessController::finished, this, &JFJochProcessingJobsWindow::onFinished); connect(controller_, &JFJochProcessController::failed, this, &JFJochProcessingJobsWindow::onFailed); + connect(controller_, &JFJochProcessController::liveDataset, this, &JFJochProcessingJobsWindow::liveDataset); auto *toolbar = addToolBar("Jobs"); toolbar->setMovable(false); @@ -165,9 +167,18 @@ void JFJochProcessingJobsWindow::newJob() { const ProcessConfig config = buildConfig(spec, inputs); + // Rotation indexing must be enabled on the indexing settings too (config.rotation_indexing only + // drives the two-pass pre-pass); otherwise IndexAndRefine never builds a rotation indexer. + DiffractionExperiment experiment = inputs.experiment; + if (spec.mode == ProcessMode::FullAnalysis) { + auto idx = experiment.GetIndexingSettings(); + idx.RotationIndexing(spec.rotation); + experiment.ImportIndexingSettings(idx); + } + if (action == 2) { // copy command line const QString cmd = QString::fromStdString( - JFJochProcessCommandLine(config, inputs.experiment, inputs.file.toStdString())); + JFJochProcessCommandLine(config, experiment, inputs.file.toStdString())); QApplication::clipboard()->setText(cmd); QMessageBox::information(this, "Command line", cmd + "\n\n(copied to clipboard)"); return; @@ -190,6 +201,15 @@ void JFJochProcessingJobsWindow::newJob() { table_->setItem(row, COL_INDEX, new QTableWidgetItem("-")); table_->setItem(row, COL_CELL, new QTableWidgetItem("-")); + // A progress bar lives in the Status cell while the job runs; it shows the phase as text until + // image processing starts, then " / " with the bar filling in the background. + running_bar_ = new QProgressBar(table_); + running_bar_->setAlignment(Qt::AlignCenter); + running_bar_->setRange(0, spec.images > 0 ? spec.images : 1); + running_bar_->setValue(0); + running_bar_->setFormat("queued"); + table_->setCellWidget(row, COL_STATUS, running_bar_); + JobInfo info; info.name = name; if (spec.save) @@ -197,7 +217,7 @@ void JFJochProcessingJobsWindow::newJob() { jobs_.push_back(info); running_row_ = row; - controller_->start(inputs.file, inputs.experiment, inputs.pixel_mask, config); + controller_->start(inputs.file, experiment, inputs.pixel_mask, config); emit writeStatusBar("Started processing job " + name); } @@ -229,18 +249,29 @@ void JFJochProcessingJobsWindow::setStatus(int row, const QString &text) { } void JFJochProcessingJobsWindow::onPhase(QString phase) { - if (running_row_ >= 0 && phase != "Processing images") - setStatus(running_row_, phase); + // The "Processing images" phase is shown by onProgress; other phases (first pass, scaling, ...) + // show their name as text over an empty bar. + if (!running_bar_ || phase == "Processing images") + return; + running_bar_->setRange(0, 1); + running_bar_->setValue(0); + running_bar_->setFormat(phase); } void JFJochProcessingJobsWindow::onProgress(quint64 done, quint64 total) { - if (running_row_ >= 0) - setStatus(running_row_, QStringLiteral("running %1%").arg(total ? done * 100 / total : 0)); + if (!running_bar_) + return; + running_bar_->setRange(0, static_cast(total)); + running_bar_->setValue(static_cast(done)); + running_bar_->setFormat("%v / %m"); } void JFJochProcessingJobsWindow::onFinished(ProcessResult result) { const int row = running_row_; running_row_ = -1; + if (row >= 0) + table_->removeCellWidget(row, COL_STATUS); // deletes running_bar_ + running_bar_ = nullptr; if (row < 0 || row >= static_cast(jobs_.size())) return; @@ -265,6 +296,9 @@ void JFJochProcessingJobsWindow::onFinished(ProcessResult result) { void JFJochProcessingJobsWindow::onFailed(QString error) { const int row = running_row_; running_row_ = -1; + if (row >= 0) + table_->removeCellWidget(row, COL_STATUS); // deletes running_bar_ + running_bar_ = nullptr; setStatus(row, "failed"); QMessageBox::warning(this, "Processing failed", error); } diff --git a/viewer/windows/JFJochProcessingJobsWindow.h b/viewer/windows/JFJochProcessingJobsWindow.h index a679c850..8302a743 100644 --- a/viewer/windows/JFJochProcessingJobsWindow.h +++ b/viewer/windows/JFJochProcessingJobsWindow.h @@ -11,6 +11,7 @@ #include "../JFJochImageReadingWorker.h" // ReprocessingInputs class QTableWidget; +class QProgressBar; // Makes processing a first-class GUI activity: a table of processing jobs run on the current // dataset. A job can be run locally (off the GUI thread, via JFJochProcessController) or its @@ -25,6 +26,8 @@ signals: void registerSnapshot(QString name, QString master_path); void activateSnapshot(QString name); void writeStatusBar(QString message, int timeout_ms = 0); + // Live per-image results while a job runs, for the dataset-info plots. + void liveDataset(std::shared_ptr dataset); private slots: void newJob(); @@ -60,6 +63,7 @@ private: JFJochImageReadingWorker *worker_; JFJochProcessController *controller_; QTableWidget *table_; + QProgressBar *running_bar_ = nullptr; // lives in the running row's Status cell int running_row_ = -1; int job_counter_ = 0; std::vector jobs_; diff --git a/viewer/windows/JFJochSettingsWindow.cpp b/viewer/windows/JFJochSettingsWindow.cpp index 51b6ee2d..2f5f2ca0 100644 --- a/viewer/windows/JFJochSettingsWindow.cpp +++ b/viewer/windows/JFJochSettingsWindow.cpp @@ -20,7 +20,8 @@ JFJochSettingsWindow::JFJochSettingsWindow(const SpotFindingSettings &spot, cons m_scaling = new JFJochScalingPanel(scaling, this); auto *tabs = new QTabWidget(this); - tabs->addTab(m_processing->takeCentralWidget(), "Spot finding && indexing"); + tabs->addTab(m_processing->TakeSpotFindingPage(), "Spot finding"); + tabs->addTab(m_processing->TakeIndexingPage(), "Indexing"); tabs->addTab(m_azint->takeCentralWidget(), "Azimuthal"); tabs->addTab(m_bragg, "Bragg integration"); tabs->addTab(m_scaling, "Scaling"); diff --git a/viewer/windows/JFJochViewerProcessingWindow.cpp b/viewer/windows/JFJochViewerProcessingWindow.cpp index adcc8f2e..6df8821c 100644 --- a/viewer/windows/JFJochViewerProcessingWindow.cpp +++ b/viewer/windows/JFJochViewerProcessingWindow.cpp @@ -6,19 +6,44 @@ #include #include #include -#include +#include +#include +#include + +namespace { + struct RadioChoice { const char *label; int value; }; + + // A titled group of mutually-exclusive radio buttons, with an optional explanatory line. + QGroupBox *MakeRadioGroup(const QString &title, const QString &help, + const std::vector &choices, int current, + QButtonGroup *group, QWidget *parent) { + auto *box = new QGroupBox(title, parent); + auto *layout = new QVBoxLayout(box); + if (!help.isEmpty()) { + auto *label = new QLabel(help, box); + label->setWordWrap(true); + layout->addWidget(label); + } + for (const auto &c: choices) { + auto *button = new QRadioButton(c.label, box); + button->setChecked(c.value == current); + group->addButton(button, c.value); + layout->addWidget(button); + } + return box; + } +} JFJochViewerProcessingWindow::JFJochViewerProcessingWindow(const SpotFindingSettings &settings, const IndexingSettings& indexing,QWidget *parent) : JFJochHelperWindow(parent), m_settings(settings), m_indexing(indexing) { setWindowTitle("Image processing settings"); - QWidget *centralWidget = new QWidget(this); - setCentralWidget(centralWidget); + // --- Spot finding page --- + m_spotFindingPage = new QWidget(this); + auto spotLayout = new QVBoxLayout(m_spotFindingPage); - auto mainLayout = new QVBoxLayout(centralWidget); - - auto generalGroup = new QGroupBox("Spot finding", this); + auto generalGroup = new QGroupBox("Spot finding", m_spotFindingPage); auto generalLayout = new QFormLayout(generalGroup); m_enableCheckBox = new QCheckBox("Enable", this); @@ -68,34 +93,58 @@ JFJochViewerProcessingWindow::JFJochViewerProcessingWindow(const SpotFindingSett m_highResSpuriousGapOneOverD->setEnabled(gapFilterEnabled); generalLayout->addRow("Gap threshold in Q-space [A^-1]:", m_highResSpuriousGapOneOverD); - auto processingGroup = new QGroupBox("Other steps", this); - auto processingLayout = new QFormLayout(processingGroup); - m_iceRingWidthQRecipA = new SliderPlusBox(0.0, 0.3, 0.001, 3, this); m_iceRingWidthQRecipA->setValue(m_settings.ice_ring_width_Q_recipA); generalLayout->addRow("Ice ring width in Q-space [A^-1]:", m_iceRingWidthQRecipA); + auto processingGroup = new QGroupBox("Other steps", m_spotFindingPage); + auto processingLayout = new QFormLayout(processingGroup); + m_quickIntegrationCheckBox = new QCheckBox("Enable Bragg Integration", this); m_quickIntegrationCheckBox->setChecked(m_settings.quick_integration); processingLayout->addRow("", m_quickIntegrationCheckBox); - // Indexing group - auto indexingGroup = new QGroupBox("Indexing", this); - auto indexingLayout = new QFormLayout(indexingGroup); + spotLayout->addWidget(generalGroup); + spotLayout->addWidget(processingGroup); + spotLayout->addStretch(); + + // --- Indexing page --- + m_indexingPage = new QWidget(this); + auto indexLayout = new QVBoxLayout(m_indexingPage); m_indexingCheckBox = new QCheckBox("Enable Indexing", this); m_indexingCheckBox->setChecked(m_settings.indexing); - indexingLayout->addRow("", m_indexingCheckBox); + indexLayout->addWidget(m_indexingCheckBox); + + m_indexAlgGroup = new QButtonGroup(this); + indexLayout->addWidget(MakeRadioGroup( + "Indexing algorithm", + "FFBIDX is fast but needs a known cell; FFT/FFTW index de-novo (FFT on GPU, FFTW on CPU). " + "Auto picks the best available.", + {{"Auto", static_cast(IndexingAlgorithmEnum::Auto)}, + {"FFBIDX — GPU, needs known cell", static_cast(IndexingAlgorithmEnum::FFBIDX)}, + {"FFT — GPU, de-novo", static_cast(IndexingAlgorithmEnum::FFT)}, + {"FFTW — CPU, de-novo", static_cast(IndexingAlgorithmEnum::FFTW)}, + {"None — skip indexing", static_cast(IndexingAlgorithmEnum::None)}}, + static_cast(m_indexing.GetAlgorithm()), m_indexAlgGroup, m_indexingPage)); + + m_geomRefGroup = new QButtonGroup(this); + indexLayout->addWidget(MakeRadioGroup( + "Geometry refinement", + "How the geometry is refined once a lattice is found.", + {{"None", static_cast(GeomRefinementAlgorithmEnum::None)}, + {"Orientation only", static_cast(GeomRefinementAlgorithmEnum::OrientationOnly)}, + {"Beam center + lattice", static_cast(GeomRefinementAlgorithmEnum::BeamCenter)}, + {"Pixel refinement (experimental)", static_cast(GeomRefinementAlgorithmEnum::PixelRefine)}}, + static_cast(m_indexing.GetGeomRefinementAlgorithm()), m_geomRefGroup, m_indexingPage)); + + auto indexingGroup = new QGroupBox("Indexing parameters", m_indexingPage); + auto indexingLayout = new QFormLayout(indexingGroup); m_idxIndexIceRings = new QCheckBox("Index ice rings", this); m_idxIndexIceRings->setChecked(m_indexing.GetIndexIceRings()); indexingLayout->addRow("", m_idxIndexIceRings); - m_geomRefinementCheckBox = new QCheckBox("Refine beam center", this); - m_geomRefinementCheckBox->setChecked(m_indexing.GetGeomRefinementAlgorithm() == GeomRefinementAlgorithmEnum::BeamCenter); - indexingLayout->addRow("", m_geomRefinementCheckBox); - - // Indexing settings UI m_idxTolerance = new SliderPlusBox(0.0, 0.5, 0.001, 3, this); m_idxTolerance->setValue(m_indexing.GetTolerance()); indexingLayout->addRow("Indexing tolerance", m_idxTolerance); @@ -108,14 +157,10 @@ JFJochViewerProcessingWindow::JFJochViewerProcessingWindow(const SpotFindingSett m_idxViableCellMinSpots->setValue(static_cast(m_indexing.GetViableCellMinSpots())); indexingLayout->addRow("Viable cell min spots", m_idxViableCellMinSpots); - auto buttonsLayout = new QHBoxLayout(); - buttonsLayout->addStretch(); - - mainLayout->addWidget(generalGroup); - mainLayout->addWidget(indexingGroup); - mainLayout->addWidget(processingGroup); - mainLayout->addLayout(buttonsLayout); + indexLayout->addWidget(indexingGroup); + indexLayout->addStretch(); + // --- Connections --- connect(m_enableCheckBox, &QCheckBox::toggled, [this](bool checked) { m_settings.enable = checked; Update(); @@ -191,6 +236,16 @@ JFJochViewerProcessingWindow::JFJochViewerProcessingWindow(const SpotFindingSett Update(); }); + connect(m_indexAlgGroup, &QButtonGroup::idClicked, [this](int id) { + m_indexing.Algorithm(static_cast(id)); + Update(); + }); + + connect(m_geomRefGroup, &QButtonGroup::idClicked, [this](int id) { + m_indexing.GeomRefinementAlgorithm(static_cast(id)); + Update(); + }); + // Indexing settings signals connect(m_idxTolerance, &SliderPlusBox::valueChanged, [this](double val) { m_indexing.Tolerance(static_cast(val)); @@ -207,14 +262,6 @@ JFJochViewerProcessingWindow::JFJochViewerProcessingWindow(const SpotFindingSett Update(); }); - connect(m_geomRefinementCheckBox, &QCheckBox::toggled, [this](bool checked) { - if (checked) - m_indexing.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::BeamCenter); - else - m_indexing.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::None); - Update(); - }); - connect(m_idxViableCellMinSpots, &SliderPlusBox::valueChanged, [this](double val) { m_indexing.ViableCellMinSpots(static_cast(std::lround(val))); Update(); diff --git a/viewer/windows/JFJochViewerProcessingWindow.h b/viewer/windows/JFJochViewerProcessingWindow.h index df6488de..0049f9fe 100644 --- a/viewer/windows/JFJochViewerProcessingWindow.h +++ b/viewer/windows/JFJochViewerProcessingWindow.h @@ -13,6 +13,10 @@ #include "../widgets/SliderPlusBox.h" #include "../../image_analysis/spot_finding/SpotFindingSettings.h" +class QButtonGroup; + +// Holds the spot finding and indexing controls. The two are exposed as separate pages +// (TakeSpotFindingPage / TakeIndexingPage) so the settings window can show them as two tabs. class JFJochViewerProcessingWindow : public JFJochHelperWindow { Q_OBJECT @@ -31,7 +35,8 @@ class JFJochViewerProcessingWindow : public JFJochHelperWindow { QCheckBox *m_indexingCheckBox; QCheckBox *m_quickIntegrationCheckBox; - QCheckBox *m_geomRefinementCheckBox; + QButtonGroup *m_indexAlgGroup; // indexing algorithm (FFBIDX/FFT/FFTW/Auto/None) + QButtonGroup *m_geomRefGroup; // geometry refinement (None/Orientation/Beam/Pixel) SliderPlusBox *m_idxTolerance; // [0.0 .. 0.5], step 0.001 SliderPlusBox *m_idxUnitCellDistTolerance; // [0.0001 .. 0.2001], step 0.0001 @@ -40,6 +45,9 @@ class JFJochViewerProcessingWindow : public JFJochHelperWindow { SliderPlusBox *m_iceRingWidthQRecipA; + QWidget *m_spotFindingPage; + QWidget *m_indexingPage; + SpotFindingSettings m_settings; IndexingSettings m_indexing; @@ -48,9 +56,10 @@ public: explicit JFJochViewerProcessingWindow(const SpotFindingSettings &settings, const IndexingSettings& indexing, QWidget *parent = nullptr); + // The two pages, for lifting into tabs. Ownership passes to the caller (e.g. a QTabWidget). + QWidget *TakeSpotFindingPage() { return m_spotFindingPage; } + QWidget *TakeIndexingPage() { return m_indexingPage; } + signals: void settingsChanged(const SpotFindingSettings &settings, const IndexingSettings &indexing, int64_t max_spots); }; - - -