Files
HPPA/HPPA/View3D.cpp
tangchao0503 e43d60e264 add:
1、增加显微镜场景:添加显微镜3D模型;
2、设置界面添加确认按钮;

fix:
1、相机看板:(1)帧率*积分时间=999,防止nir崩溃(2)记录帧率和积分时间,下次打开软件后恢复;(3)只能拖动slider改变值,不能点击slider改变值;
2、加入判断,不能多次打开同一个影像;
3、图像控制看板:只能拖动slider改变值,不能点击slider改变值;
2026-04-16 16:43:28 +08:00

390 lines
12 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.

#include "View3D.h"
#include <QHBoxLayout>
#include <QShowEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <Qt3DExtras/QForwardRenderer>
#include <QtMath>
#include <Qt3DRender/QAttribute>
#include <QGeometryRenderer>
View3DBase::View3DBase(const QString& baseModelPath,
const QString& armModelPath,
QWidget* parent)
: QWidget(parent),
m_container(nullptr),
m_baseModelPath(baseModelPath),
m_armModelPath(armModelPath)
{
m_view = new Qt3DExtras::Qt3DWindow();
// 部分 Qt5.9 构建可能需要强转 frame graph,但 defaultFrameGraph() 通常可用
QColor c1("#0D1233");
m_view->defaultFrameGraph()->setClearColor(c1);
m_rootEntity = new Qt3DCore::QEntity();
initScene();
initCamera();
// 自动旋转臂(如果不需要可注释掉 timer/connect)
//connect(&m_timer, &QTimer::timeout, this, [=]() {
// m_angle += 1.0f;
// m_t += 1.0f;
// if (m_angle >= 360.0f) m_angle = 0.0f;
// if (m_armTransform)
// {
// //m_armTransform->setRotationX(m_angle);
// //m_armTransform->setTranslation(QVector3D(m_t, 0, 0));
//
// Qt3DCore::QTransform transform;
// transform.setTranslation(QVector3D(2, 0, 0));
// QMatrix4x4 M = m_armTransform->matrix();
// M = transform.matrix() * M; // 左乘:在世界坐标系叠加
// m_armTransform->setMatrix(M);
// qDebug() << m_armTransform->matrix();
// }
// });
}
void View3DBase::setViewCenter(float x, float y, float z)
{
m_viewCenter.setX(x);
m_viewCenter.setY(y);
m_viewCenter.setZ(z);
}
void View3DBase::setDistance(float distance)
{
m_distance = distance;
}
void View3DBase::initScene()
{
/*auto* lightEntity = new Qt3DCore::QEntity(m_rootEntity);
auto* light = new Qt3DRender::QPointLight(lightEntity);
light->setColor(Qt::white);
light->setIntensity(1.2f);
auto* lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(QVector3D(500, 500, 500));
lightEntity->addComponent(light);
lightEntity->addComponent(lightTransform);*/
// ===== 创建 base 根节点 =====
auto* baseModel = new Qt3DCore::QEntity(m_rootEntity);
auto* baseLoader = new Qt3DRender::QSceneLoader(baseModel);
baseLoader->setSource(QUrl::fromLocalFile(m_baseModelPath));
//connect(baseLoader, &Qt3DRender::QSceneLoader::statusChanged,
// this, &View3DBase::onSceneLoaderStatusChanged);
m_baseTransform = new Qt3DCore::QTransform();
m_baseTransform->setTranslation(QVector3D(0, 0, 0));
baseModel->addComponent(baseLoader);
baseModel->addComponent(m_baseTransform);
connect(baseLoader, &Qt3DRender::QSceneLoader::statusChanged,
this, [=](Qt3DRender::QSceneLoader::Status status) {
if (status == Qt3DRender::QSceneLoader::Ready) {
applyWhiteMaterialRecursive(baseModel);
}
});
// ===== 创建 arm 根节点 =====
auto* armModel = new Qt3DCore::QEntity(m_rootEntity);
auto* armLoader = new Qt3DRender::QSceneLoader(armModel);
armLoader->setSource(QUrl::fromLocalFile(m_armModelPath));
m_armTransform = new Qt3DCore::QTransform();
m_armTransform->setTranslation(QVector3D(0, 0, 0));
armModel->addComponent(armLoader);
armModel->addComponent(m_armTransform);
connect(armLoader, &Qt3DRender::QSceneLoader::statusChanged,
this, [=](Qt3DRender::QSceneLoader::Status status) {
if (status == Qt3DRender::QSceneLoader::Ready) {
applyWhiteMaterialRecursive(armModel);
}
});
// 坐标轴依然挂在 root,不会被移动
//createAxes();
m_view->setRootEntity(m_rootEntity);
qDebug() << m_baseTransform->matrix();
qDebug() << m_armTransform->matrix();
//m_armTransform->setTranslation(QVector3D(2000, 0, 0));
//m_baseTransform->setTranslation(QVector3D(-1000, -1000, -1000));
qDebug() << m_baseTransform->matrix();
qDebug() << m_armTransform->matrix();
}
void View3DBase::applyWhiteMaterialRecursive(Qt3DCore::QEntity* entity)
{
// 如果这个 entity 有 mesh,就给它加白色材质
auto meshes = entity->componentsOfType<Qt3DRender::QGeometryRenderer>();
if (!meshes.isEmpty()) {
auto* mat = new Qt3DExtras::QPhongMaterial(entity);
QColor c1("#cccccc");
mat->setDiffuse(c1);
mat->setAmbient(c1);
mat->setSpecular(c1);
mat->setShininess(50.0f);
entity->addComponent(mat);
}
// 递归处理子节点
const auto children = entity->children();
for (QObject* obj : children) {
auto* childEntity = qobject_cast<Qt3DCore::QEntity*>(obj);
if (childEntity)
applyWhiteMaterialRecursive(childEntity);
}
}
void View3DBase::createAxes()
{
// 参数
float axisLength = 500.0f;
float axisRadius = 50.0f;
// ----- X axis (red) -----
Qt3DCore::QEntity* xAxis = new Qt3DCore::QEntity(m_rootEntity);
auto* xMesh = new Qt3DExtras::QCylinderMesh();
xMesh->setRadius(axisRadius);
xMesh->setLength(axisLength);
xMesh->setRings(16);
xMesh->setSlices(16);
auto* xTrans = new Qt3DCore::QTransform();
// cylinder 默认沿 Y 轴,绕 Z 轴 90 度让其沿 X
xTrans->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), 90.0f));
xTrans->setTranslation(QVector3D(axisLength / 2.0f, 0.0f, 0.0f));
auto* xMat = new Qt3DExtras::QPhongMaterial();
xMat->setDiffuse(QColor(Qt::red));
xAxis->addComponent(xMesh);
xAxis->addComponent(xTrans);
xAxis->addComponent(xMat);
// ----- Y axis (green) -----
Qt3DCore::QEntity* yAxis = new Qt3DCore::QEntity(m_rootEntity);
auto* yMesh = new Qt3DExtras::QCylinderMesh();
yMesh->setRadius(axisRadius);
yMesh->setLength(axisLength*2);
yMesh->setRings(16);
yMesh->setSlices(16);
auto* yTrans = new Qt3DCore::QTransform();
// Y 轴无需旋转(cylinder 默认沿 Y)
yTrans->setTranslation(QVector3D(0.0f, axisLength / 2.0f, 0.0f));
auto* yMat = new Qt3DExtras::QPhongMaterial();
yMat->setDiffuse(QColor(Qt::green));
yAxis->addComponent(yMesh);
yAxis->addComponent(yTrans);
yAxis->addComponent(yMat);
// ----- Z axis (blue) -----
Qt3DCore::QEntity* zAxis = new Qt3DCore::QEntity(m_rootEntity);
auto* zMesh = new Qt3DExtras::QCylinderMesh();
zMesh->setRadius(axisRadius);
zMesh->setLength(axisLength*3);
zMesh->setRings(16);
zMesh->setSlices(16);
auto* zTrans = new Qt3DCore::QTransform();
// 让 cylinder 沿 Z:绕 X 轴 90 度
zTrans->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), 90.0f));
zTrans->setTranslation(QVector3D(0.0f, 0.0f, axisLength / 2.0f));
auto* zMat = new Qt3DExtras::QPhongMaterial();
zMat->setDiffuse(QColor(Qt::blue));
zAxis->addComponent(zMesh);
zAxis->addComponent(zTrans);
zAxis->addComponent(zMat);
}
void View3DBase::initCamera()
{
m_camera = m_view->camera();
// 16:10 假设窗口比例,后续 resize 时相机透视会保持
m_camera->lens()->setPerspectiveProjection(50.0f, 16.0f / 10.0f, 0.1f, 10000.0f);
updateCameraPosition();
}
void View3DBase::updateCameraPosition()
{
float yaw = qDegreesToRadians(m_yawDeg);
float pitch = qDegreesToRadians(m_pitchDeg);
float x = m_distance * qCos(pitch) * qSin(yaw);
float y = m_distance * qSin(pitch);
float z = m_distance * qCos(pitch) * qCos(yaw);
QVector3D camPos = m_viewCenter + QVector3D(x, y, z);
m_camera->setPosition(camPos);
m_camera->setViewCenter(m_viewCenter);
}
void View3DBase::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
if (!m_container) {
m_container = QWidget::createWindowContainer(m_view, this);
m_view->installEventFilter(this);
auto* layout = new QHBoxLayout(this);
layout->addWidget(m_container);
layout->setMargin(0);
setLayout(layout);
// 启动自动旋转 timer(如果你不需要可以注释)
m_timer.start(100);
}
}
bool View3DBase::eventFilter(QObject* obj, QEvent* event)
{
if (obj == m_view)
{
// 鼠标按下
if (event->type() == QEvent::MouseButtonPress) {
auto* e = static_cast<QMouseEvent*>(event);
if (e->button() == Qt::LeftButton) {
m_mouseDragging = true;
m_lastMousePos = e->pos();
}
else if (e->button() == Qt::MiddleButton) {
m_middleDragging = true;
m_lastMousePos = e->pos();
}
}
// 鼠标释放
else if (event->type() == QEvent::MouseButtonRelease) {
auto* e = static_cast<QMouseEvent*>(event);
if (e->button() == Qt::LeftButton) {
m_mouseDragging = false;
}
else if (e->button() == Qt::MiddleButton) {
m_middleDragging = false;
}
}
// 鼠标移动
else if (event->type() == QEvent::MouseMove) {
auto* e = static_cast<QMouseEvent*>(event);
QPoint pos = e->pos();
QPoint delta = pos - m_lastMousePos;
// 左键:orbit(旋转)
if (m_mouseDragging) {
float sensitivity = 0.3f;
m_yawDeg -= delta.x() * sensitivity;
m_pitchDeg += delta.y() * sensitivity;
if (m_pitchDeg > 89.0f) m_pitchDeg = 89.0f;
if (m_pitchDeg < -89.0f) m_pitchDeg = -89.0f;
updateCameraPosition();
}
// 中键:pan(平移 viewCenter)
if (m_middleDragging) {
float speed = 2.0f;
// 根据摄像机方向计算平移方向
QVector3D camPos = m_camera->position();
QVector3D forward = (m_viewCenter - camPos).normalized();
QVector3D up(0, 1, 0);
QVector3D right = QVector3D::crossProduct(forward, up).normalized();
// 世界坐标变化量
QVector3D deltaMove =
-right * (delta.x() * speed) +
up * (delta.y() * speed);
// 将平移应用到两个模型根 Transform
if (m_baseRootTransform)
m_baseRootTransform->setTranslation(
m_baseRootTransform->translation() + deltaMove*-1);
if (m_armRootTransform)
m_armRootTransform->setTranslation(
m_armRootTransform->translation() + deltaMove*-1);
}
m_lastMousePos = pos;
}
// 滚轮缩放
else if (event->type() == QEvent::Wheel) {
auto* e = static_cast<QWheelEvent*>(event);
// Qt5: angleDelta 返回像素值(通常为 120 per notch)
int delta = e->angleDelta().y();
if (delta == 0) delta = e->delta(); // 备选
m_distance -= delta * 2.0f; // 缩放速度
if (m_distance < 2.0f) m_distance = 2.0f;
if (m_distance > 10000.0f) m_distance = 10000.0f;
updateCameraPosition();
}
}
// 让 Qt 继续处理(保持原行为)
return QWidget::eventFilter(obj, event);
}
View3DPlantPhenotype::View3DPlantPhenotype(const QString& baseModelPath, const QString& armModelPath, QWidget* parent)
:View3DBase(baseModelPath, armModelPath, parent)
{
}
void View3DPlantPhenotype::setLoc(std::vector<double> loc)
{
double x = round(loc[0] * 100) / 100;
double y = round(loc[1] * 100) / 100;
m_armTransform->setTranslation(QVector3D(x, y, 0));
}
View3DLinearStage::View3DLinearStage(const QString& baseModelPath, const QString& armModelPath, QWidget* parent)
:View3DBase(baseModelPath, armModelPath, parent)
{
}
void View3DLinearStage::setLoc(std::vector<double> loc)
{
double x = round(loc[0] * 100) / 100;
m_armTransform->setTranslation(QVector3D(x, 0, 0));
}
View3DMicroscopicMotionModel::View3DMicroscopicMotionModel(const QString& baseModelPath, const QString& armModelPath, QWidget* parent)
:View3DBase(baseModelPath, armModelPath, parent)
{
}
void View3DMicroscopicMotionModel::setLoc(std::vector<double> loc)
{
double x = round(loc[0] * 100) / 100;
double y = round(loc[1] * 100) / 100;
m_armTransform->setTranslation(QVector3D(x, y, 0));
}