Files
Jungfraujoch/viewer/windows/JFJochViewerReciprocalSpaceWindow.h
T
leonarski_fandClaude Opus 5 5782cc0edf Viewer: reciprocal-space view does nothing while its window is closed
The window is a placeholder for future functionality and is closed almost all
of the time, but it extracted the frame's spots and rebuilt and uploaded its
vertex arrays on every image, whether or not anything was on screen.

Guard it in rebuildGL() rather than at each of the eight call sites, so any
future caller inherits the behaviour: while hidden it only records that a
rebuild is owed, and showEvent() pays it. imageLoaded() additionally skips
extracting the frame's spots, which is the other half of the per-frame work.

The OpenGL code path is untouched and still built and exercised the moment the
window is opened.

Note: I could not show a CPU saving for this on the headless test machine --
there, ~74% of the process CPU is Mesa llvmpipe software rasterisation that I
was unable to attribute to any per-frame code path, and it swamps the effect.
The work being skipped is nonetheless unambiguously unnecessary.

Verified in the GUI: after stepping frames with the window closed, opening it
shows the current frame's spots, and it keeps updating while open.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 21:05:21 +02:00

183 lines
6.0 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: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <QMainWindow>
#include <QCheckBox>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QMatrix4x4>
#include <QComboBox>
#include <QMouseEvent>
#include <QWheelEvent>
#include <vector>
#include <memory>
#include <optional>
#include "JFJochHelperWindow.h" // your existing base class
#include "../../common/CrystalLattice.h" // Coord, RotMatrix, etc.
#include "../../common/SpotToSave.h"
#include "../../common/DiffractionGeometry.h"
#include "../../common/GoniometerAxis.h"
// Forward declarations from your codebase
struct JFJochReaderDataset;
class JFJochReaderImage;
struct JFJochReaderSpots;
// ---------------------------------------------------------------------------
// ReciprocalSpaceGLView the actual OpenGL viewport
// ---------------------------------------------------------------------------
class ReciprocalSpaceGLView : public QOpenGLWidget,
protected QOpenGLFunctions_3_3_Core {
Q_OBJECT
public:
explicit ReciprocalSpaceGLView(QWidget *parent = nullptr);
~ReciprocalSpaceGLView() override;
struct Vertex {
float x, y, z;
float r, g, b, a;
float image_x = 0.0f;
float image_y = 0.0f;
float image_number = -1.0f;
float pickable = 0.0f;
};
void resetTarget();
// Called by the outer window whenever data changes.
void setSpots(const std::vector<Vertex> &spots);
void setLines(const std::vector<Vertex> &lines); // axes + cell vectors
signals:
void spotDoubleClicked(QPointF imagePos);
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
void mousePressEvent(QMouseEvent *e) override;
void mouseDoubleClickEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void wheelEvent(QWheelEvent *e) override;
private:
void uploadBuffer(QOpenGLBuffer &vbo, QOpenGLVertexArrayObject &vao,
const std::vector<Vertex> &data);
void setupVAO(QOpenGLVertexArrayObject &vao, QOpenGLBuffer &vbo);
QMatrix4x4 currentViewMatrix() const;
QMatrix4x4 currentMvpMatrix() const;
bool emitNearestSpot(const QPoint &screenPos);
QOpenGLShaderProgram shader_;
bool glReady_ = false;
QOpenGLVertexArrayObject spotsVAO_;
QOpenGLBuffer spotsVBO_;
int spotsCount_ = 0;
std::vector<Vertex> pendingSpots_;
QOpenGLVertexArrayObject linesVAO_;
QOpenGLBuffer linesVBO_;
int linesCount_ = 0;
std::vector<Vertex> pendingLines_;
// Camera state
QMatrix4x4 proj_;
float yaw_ = 0.0f; // degrees
float pitch_ = 20.0f; // degrees
float zoom_ = 80.0f; // distance from camera target
QVector3D target_{0.0f, 0.0f, 0.0f};
QPoint lastMousePos_;
};
// ---------------------------------------------------------------------------
// JFJochViewerReciprocalSpaceWindow the outer QMainWindow
// ---------------------------------------------------------------------------
class JFJochViewerReciprocalSpaceWindow : public JFJochHelperWindow {
Q_OBJECT
public:
explicit JFJochViewerReciprocalSpaceWindow(QWidget *parent = nullptr);
signals:
void loadSpotsRequest(int64_t start_image, int64_t end_image, int64_t stride);
public slots:
void datasetLoaded(std::shared_ptr<const JFJochReaderDataset> dataset);
void imageLoaded(std::shared_ptr<const JFJochReaderImage> image);
void spotsLoaded(std::shared_ptr<const JFJochReaderSpots> spots);
void setSpotColor(QColor color);
void setFeatureColor(QColor color);
void setPredictionColor(QColor color);
private:
struct CurrentSpot {
Coord recip_lab;
Coord recip_crystal;
float image_x = 0.0f;
float image_y = 0.0f;
int64_t image_number = -1;
int32_t h = 0;
int32_t k = 0;
int32_t l = 0;
bool indexed = false;
bool ice_ring = false;
};
struct CurrentReflection {
int32_t h = 0;
int32_t k = 0;
int32_t l = 0;
float image_x = 0.0f;
float image_y = 0.0f;
int64_t image_number = -1;
};
QColor spotColorFor(bool indexed, bool ice_ring) const;
// rebuildGL() is a no-op while the window is closed - it only records that a rebuild is
// owed, and showEvent() pays it. rebuildGLNow() is the actual work.
void rebuildGL(); // rebuilds both spot and line vertex data
void rebuildGLNow();
void showEvent(QShowEvent *event) override;
bool pending_rebuild_ = false;
void loadCurrentImageSpots(std::shared_ptr<const JFJochReaderImage> image);
void addSpot(const SpotToSave &s,
const DiffractionGeometry &geom,
const std::optional<GoniometerAxis> &axis,
int64_t image_number);
// UI
ReciprocalSpaceGLView *glView_ = nullptr;
QCheckBox *crystalFrameCheck = nullptr;
QCheckBox *showCellCheck = nullptr;
QCheckBox *showPredictedCheck = nullptr;
QComboBox *strideCombo = nullptr;
// Data
std::shared_ptr<const JFJochReaderDataset> current_dataset_;
std::shared_ptr<const JFJochReaderImage> current_image_;
std::vector<CurrentSpot> spots_;
std::vector<CurrentReflection> reflections_;
std::optional<CrystalLattice> indexed_lattice_;
std::optional<RotMatrix> current_back_rot_;
bool has_rotation_ = false;
bool full_dataset_mode_ = false;
float scene_scale_ = 100.0f;
// Colors
QColor spot_color = Qt::green;
QColor indexed_color = Qt::magenta; // feature_color in image
QColor prediction_color = Qt::darkRed;
QColor ice_ring_color = Qt::cyan;
};