// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "JFJochGridScanImage.h" JFJochGridScanImage::JFJochGridScanImage(QWidget *parent) : JFJochImage(parent) {} void JFJochGridScanImage::clear() { W = 0; H = 0; this->settings = std::nullopt; if (scene()) scene()->clear(); CalcROI(); } void JFJochGridScanImage::loadData(const std::vector &data, const GridScanSettings &settings, bool in_one_over_d2) { if (data.empty()) { clear(); return; } this->settings = settings; W = settings.GetGridSizeX_step(); H = settings.GetGridSizeY_step(); image_fp = settings.Rearrange(data, NAN); std::vector indices(image_fp.size()); std::iota(indices.begin(), indices.end(), 0); image_index = settings.Rearrange(indices, -1); one_over_d2 = in_one_over_d2; if (one_over_d2) { for (int i = 0; i < image_fp.size(); i++) if (!std::isnan(image_fp[i])) image_fp[i] = 1.0f / (image_fp[i] * image_fp[i]); } float minv = std::numeric_limits::infinity(); float maxv = -std::numeric_limits::infinity(); for (float v : image_fp) { if (std::isfinite(v)) { if (v < minv) minv = v; if (v > maxv) maxv = v; } } if (!std::isfinite(minv) || !std::isfinite(maxv)) { minv = 0.0f; maxv = 1.0f; } if (!(maxv > minv)) { maxv = minv + 1.0f; } background = minv; foreground = maxv; GeneratePixmap(); Redraw(); CalcROI(); } void JFJochGridScanImage::mouseHover(QMouseEvent *event) { // Map mouse position to image pixel if inside bounds if (W == 0 || H == 0 || image_index.empty()) return; const QPointF pt = mapToScene(event->pos()); // Convert view coordinates to image pixel by truncation int x = static_cast(pt.x()); int y = static_cast(pt.y()); if (x < 0 || x >= W || y < 0 || y >= H) return; int idx = y * W + x; if (idx < 0 || idx >= static_cast(image_index.size())) return; int64_t image_id = image_index[idx]; if (image_id >= 0) { if (event->modifiers() & Qt::ShiftModifier) emit imageSelected(image_id); if (one_over_d2) { if (std::isnan(image_fp[idx])) emit writeStatusBar(QString("Image %1 x %2 y %3 no resolution estimation") .arg(image_id) .arg(x) .arg(y), 6000); else emit writeStatusBar(QString("Image %1 x %2 y %3 d = %4 Å") .arg(image_id) .arg(x) .arg(y) .arg(QString::number(1 / std::sqrt(image_fp[idx]), 'f', 2)), 6000); } else { emit writeStatusBar(QString("Image %1 x %2 y %3 value %4") .arg(image_id) .arg(x) .arg(y) .arg(QString::number(image_fp[idx], 'f', 3)), 6000); } } } void JFJochGridScanImage::loadImage(QMouseEvent *event) { // Map mouse position to image pixel if inside bounds if (W == 0 || H == 0 || image_index.empty()) return; const QPointF pt = mapToScene(event->pos()); // Convert view coordinates to image pixel by truncation int x = static_cast(pt.x()); int y = static_cast(pt.y()); if (x < 0 || x >= W || y < 0 || y >= H) return; int idx = y * W + x; if (idx < 0 || idx >= static_cast(image_index.size())) return; int64_t image_id = image_index[idx]; if (image_id >= 0) emit imageSelected(image_id); } void JFJochGridScanImage::mouseDoubleClickEvent(QMouseEvent *event) { // Map mouse position to image pixel if inside bounds if (W == 0 || H == 0 || image_index.empty()) return; const QPointF pt = mapToScene(event->pos()); // Convert view coordinates to image pixel by truncation int x = static_cast(pt.x()); int y = static_cast(pt.y()); if (x < 0 || x >= W || y < 0 || y >= H) return; int idx = y * W + x; if (idx < 0 || idx >= static_cast(image_index.size())) return; int64_t image_id = image_index[idx]; if (image_id >= 0) emit imageSelected(image_id); JFJochImage::mouseDoubleClickEvent(event); } void JFJochGridScanImage::setImage(int64_t val) { if (settings) { current_image_W = settings->GetElementPosX_step(val); current_image_H = settings->GetElementPosY_step(val); } else { current_image_W = -1; current_image_H = -1; } Redraw(); } void JFJochGridScanImage::addCustomOverlay() { if (current_image_W < 0 || current_image_H < 0 || current_image_W >= W || current_image_H >= H) return; QPen pen(feature_color, 3); pen.setCosmetic(true); auto rect = scene()->addRect(current_image_W, current_image_H, 1, 1, pen); }