Files
Jungfraujoch/viewer/windows/JFJochCalibrationResultWindow.cpp
leonarski_fandClaude Fable 5 33c0124833
Build Packages / Create release (push) Successful in 20s
Build Packages / build:rugnux:aarch64 (cross) (push) Successful in 8m48s
Build Packages / build:rugnux-tgz (x86_64) (push) Successful in 10m2s
Build Packages / build:viewer-tgz:cpu (push) Successful in 11m31s
Build Packages / build:viewer-tgz:cuda (push) Successful in 12m17s
Build Packages / build:windows:nocuda (push) Successful in 17m20s
Build Packages / build:windows:cuda (push) Successful in 19m52s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m50s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 24m30s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m12s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 16m41s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m28s
Build Packages / build:rugnux:windows (push) Successful in 11m4s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 17m26s
Build Packages / Generate python client (push) Successful in 37s
Build Packages / build:rpm (rocky8) (push) Successful in 18m50s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 19m10s
Build Packages / Build documentation (push) Successful in 1m59s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 18m38s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 18m36s
Build Packages / build:rpm (rocky9) (push) Successful in 19m20s
Build Packages / Unit tests (push) Successful in 1h36m23s
viewer: the direct beam reads as x and y rows, like the PONI
One row holding both coordinates sat oddly under a PONI split over two,
so the direct beam gets the same treatment - and with it a real "From
header" column (the header geometry's own direct beam, the file's beam
centre while the header is untilted) and a Change column that says how
far the beam actually moved, where the combined row could only show
dashes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015vRwzF8PLaaa2novAKYorq
2026-09-13 23:08:48 +02:00

106 lines
5.1 KiB
C++

// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "JFJochCalibrationResultWindow.h"
#include <QFrame>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QTableWidget>
#include <QVBoxLayout>
#include "../../common/JFJochMath.h" // PI
namespace {
constexpr double RAD_TO_DEG = 180.0 / PI;
// A big-number "card" for the hero row, as in the merge-statistics window.
QWidget *MakeCard(const QString &value, const QString &caption, QWidget *parent) {
auto *card = new QFrame(parent);
card->setFrameShape(QFrame::StyledPanel);
auto *l = new QVBoxLayout(card);
l->setContentsMargins(12, 8, 12, 8);
l->setSpacing(0);
auto *v = new QLabel(value, card);
QFont f = v->font();
f.setPointSizeF(f.pointSizeF() * 2.2);
f.setBold(true);
v->setFont(f);
v->setStyleSheet("color: #1F3A5F;");
v->setAlignment(Qt::AlignCenter);
auto *c = new QLabel(caption, card);
c->setStyleSheet("color: gray;");
c->setAlignment(Qt::AlignCenter);
l->addWidget(v);
l->addWidget(c);
return card;
}
}
JFJochCalibrationResultWindow::JFJochCalibrationResultWindow(const QString &title,
const CalibrationResult &calibration,
const DiffractionGeometry &header,
const QString &poni_path,
QWidget *parent)
: QWidget(parent, Qt::Window) {
setWindowTitle("Detector calibration — " + title);
setAttribute(Qt::WA_DeleteOnClose);
resize(640, 380);
const DiffractionGeometry &g = calibration.geometry;
const double pxl_mm = g.GetPixelSize_mm();
auto *layout = new QVBoxLayout(this);
auto *hero = new QHBoxLayout();
hero->addWidget(MakeCard(QString::number(calibration.rms_radial_pxl, 'f', 2), "Radial rms [px]", this));
hero->addWidget(MakeCard(QString::number(calibration.beam_sigma_pxl, 'f', 3), "Beam σ [px]", this));
hero->addWidget(MakeCard(QString::number(calibration.ring_points), "Ring points", this));
layout->addLayout(hero);
auto *table = new QTableWidget(7, 4, this);
table->setHorizontalHeaderLabels({"Quantity", "Fitted", "From header", "Change"});
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
table->verticalHeader()->setVisible(false);
table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// The PONI is the point of normal incidence, which is what the .poni file stores; the direct beam
// is where the beam actually lands, which is what every other program calls the beam centre. They
// part company by distance*tan(rot) as soon as the detector is tilted, so show both.
const auto [beam_x, beam_y] = g.GetDirectBeam_pxl();
const auto [header_beam_x, header_beam_y] = header.GetDirectBeam_pxl();
const struct { QString name; double fitted; double header; int digits; } rows[] = {
{"PONI x [px]", g.GetBeamX_pxl(), header.GetBeamX_pxl(), 3},
{"PONI y [px]", g.GetBeamY_pxl(), header.GetBeamY_pxl(), 3},
{"Rot1 [°]", g.GetPoniRot1_rad() * RAD_TO_DEG, header.GetPoniRot1_rad() * RAD_TO_DEG, 4},
{"Rot2 [°]", g.GetPoniRot2_rad() * RAD_TO_DEG, header.GetPoniRot2_rad() * RAD_TO_DEG, 4},
{"Distance [mm]", g.GetDetectorDistance_mm(), header.GetDetectorDistance_mm(), 4},
{"Direct beam x [px]", beam_x, header_beam_x, 3},
{"Direct beam y [px]", beam_y, header_beam_y, 3},
};
for (int i = 0; i < 7; i++) {
const double change = rows[i].fitted - rows[i].header;
table->setItem(i, 0, new QTableWidgetItem(rows[i].name));
table->setItem(i, 1, new QTableWidgetItem(QString::number(rows[i].fitted, 'f', rows[i].digits)));
table->setItem(i, 2, new QTableWidgetItem(QString::number(rows[i].header, 'f', rows[i].digits)));
table->setItem(i, 3, new QTableWidgetItem(
QStringLiteral("%1%2").arg(change >= 0 ? "+" : "").arg(change, 0, 'f', rows[i].digits)));
}
layout->addWidget(table);
auto *note = new QLabel(this);
note->setWordWrap(true);
note->setStyleSheet("color: gray;");
// In mm these are what the .poni file carries, so they are measured pyFAI's way - from the edge of
// the sensor, which puts the centre of pixel i at (i + 0.5) * pixel size - not from the centre of
// the first pixel as the [px] rows above (docs/DETECTOR_GEOMETRY.md).
note->setText(QStringLiteral("PONI x = %1 mm, PONI y = %2 mm.%3")
.arg((g.GetBeamX_pxl() + 0.5) * pxl_mm, 0, 'f', 4)
.arg((g.GetBeamY_pxl() + 0.5) * pxl_mm, 0, 'f', 4)
.arg(poni_path.isEmpty() ? QString() : " Written to " + poni_path));
layout->addWidget(note);
}