Files
Jungfraujoch/viewer/windows/JFJochCalibrationResultWindow.cpp
T
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++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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);
}