v1.0.0-rc.110 (#16)
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 7m46s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 8m45s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 6m56s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 5m58s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 6m59s
Build Packages / build:rpm (rocky8) (push) Successful in 7m33s
Build Packages / Generate python client (push) Successful in 19s
Build Packages / Build documentation (push) Successful in 41s
Build Packages / Create release (push) Has been skipped
Build Packages / build:rpm (rocky9) (push) Successful in 8m45s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 7m51s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 7m12s
Build Packages / Unit tests (push) Successful in 1h8m51s

This is an UNSTABLE release.

* jfjoch_broker: Add auto-contrast option for preview images
* Frontend: Add logo image
* jfjoch_viewer: Add logo image
* jfjoch_viewer: For image chart allow to set min value to zero
* jfjoch_viewer: For resolution estimation plots, visualization uses 1/d^2 as measure
* jfjoch_viewer: Add 3D unit cell visualization (experimental/WIP/not really there)
* Documentation: Add logo image

Reviewed-on: #16
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
This commit was merged in pull request #16.
This commit is contained in:
2025-11-28 12:47:35 +01:00
committed by leonarski_f
parent 05410d7cb3
commit 224cc8b89c
178 changed files with 855 additions and 268 deletions
+150
View File
@@ -0,0 +1,150 @@
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "LatticeVisualizerWidget.h"
#include <QVBoxLayout>
#include <QVector3D>
#include <QQuaternion>
#include <Qt3DExtras/QCylinderMesh>
#include <Qt3DRender/QCamera>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DRender/QPointLight>
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DRender/QRenderSettings>
LatticeVisualizerWidget::LatticeVisualizerWidget(QWidget *parent) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
view = new Qt3DExtras::Qt3DWindow();
view->defaultFrameGraph()->setClearColor(Qt::white);
// Optimize rendering to be on demand (only when scene changes or camera moves)
// This prevents the widget from consuming 100% of a CPU core for a static image
view->renderSettings()->setRenderPolicy(Qt3DRender::QRenderSettings::OnDemand);
QWidget *container = QWidget::createWindowContainer(view, this);
container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(container);
rootEntity = new Qt3DCore::QEntity();
view->setRootEntity(rootEntity);
// Camera setup
Qt3DRender::QCamera *camera = view->camera();
camera->lens()->setOrthographicProjection(-50.0f, 50.0f, -50.0f, 50.0f, -200.0f, 200.0f);
camera->setPosition(QVector3D(0.0f, 0.0f, 50.0f));
camera->setViewCenter(QVector3D(0.0f, 0.0f, 0.0f));
auto *camController = new Qt3DExtras::QOrbitCameraController(rootEntity);
camController->setCamera(camera);
camController->setLinearSpeed(0.0f); // Disable translation to keep the fixed scale view
camController->setLookSpeed(180.0f);
// Light
auto *lightEntity = new Qt3DCore::QEntity(rootEntity);
auto *light = new Qt3DRender::QPointLight(lightEntity);
light->setColor("white");
light->setIntensity(1.0f);
lightEntity->addComponent(light);
// Attach light to camera position or a fixed position?
// Attaching to a transform that follows camera is complex without parenting.
// For simple viz, a fixed light + a light attached to camera usually works best.
// Let's put a simple light at viewer position (approx)
auto *lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(QVector3D(0.0f, 0.0f, 50.0f));
lightEntity->addComponent(lightTransform);
// Create bars with color-blind friendly palette
// Vector a: Vermilion (D55E00)
createBar(0, QColor(213, 94, 0));
// Vector b: Sky Blue (56B4E9)
createBar(1, QColor(86, 180, 233));
// Vector c: Bluish Green (009E73)
createBar(2, QColor(0, 158, 115));
}
void LatticeVisualizerWidget::createBar(int index, const QColor &color) {
bars[index].entity = new Qt3DCore::QEntity(rootEntity);
auto *mesh = new Qt3DExtras::QCylinderMesh();
mesh->setRadius(1.0f); // Base radius, scaled later
mesh->setLength(1.0f); // Base length, scaled later
mesh->setRings(20);
mesh->setSlices(20);
bars[index].transform = new Qt3DCore::QTransform();
bars[index].material = new Qt3DExtras::QPhongMaterial();
bars[index].material->setAmbient(color);
bars[index].material->setDiffuse(color);
bars[index].material->setSpecular(Qt::white);
bars[index].material->setShininess(50.0f);
bars[index].entity->addComponent(mesh);
bars[index].entity->addComponent(bars[index].transform);
bars[index].entity->addComponent(bars[index].material);
}
void LatticeVisualizerWidget::updateBar(int index, float x, float y, float z) {
QVector3D vec(x, y, z);
float length = vec.length();
if (length < 1e-3f) {
bars[index].entity->setEnabled(false);
return;
}
bars[index].entity->setEnabled(true);
// Cylinder is Y-up by default.
QVector3D yAxis(0.0f, 1.0f, 0.0f);
QQuaternion rotation = QQuaternion::rotationTo(yAxis, vec.normalized());
// Center of cylinder is at origin, we need to move it to vec/2
QVector3D translation = vec / 2.0f;
// Scale: X/Z is thickness, Y is length
float thickness = 1.0f; // 40 Angstroms thick
bars[index].transform->setScale3D(QVector3D(thickness, length, thickness));
bars[index].transform->setRotation(rotation);
bars[index].transform->setTranslation(translation);
}
void LatticeVisualizerWidget::setLattice(const float matrix[9]) {
// Assuming row-major:
// a = (matrix[0], matrix[1], matrix[2])
// b = (matrix[3], matrix[4], matrix[5])
// c = (matrix[6], matrix[7], matrix[8])
updateBar(0, matrix[0], matrix[1], matrix[2]);
updateBar(1, matrix[3], matrix[4], matrix[5]);
updateBar(2, matrix[6], matrix[7], matrix[8]);
// Ensure the vertical scale is strictly enforced as requested
Qt3DRender::QCamera *camera = view->camera();
if (camera) {
// Adjust aspect ratio
float aspect = (float)width() / (float)height();
if (std::isnan(aspect) || height() == 0) aspect = 1.0f;
// Height is fixed +/- 200
float h = 200.0f;
float w = h * aspect;
camera->setTop(h);
camera->setBottom(-h);
camera->setLeft(-w);
camera->setRight(w);
}
}
void LatticeVisualizerWidget::loadImage(std::shared_ptr<const JFJochReaderImage> image) {
if (image && image->ImageData().indexing_lattice) {
setLattice(image->ImageData().indexing_lattice->GetVector().data());
} else {
float zero[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
setLattice(zero);
}
}