初步实现2轴的3D模型联动

This commit is contained in:
tangchao0503
2025-12-24 16:59:36 +08:00
parent 36ad438608
commit f999d87da6
9 changed files with 391 additions and 25 deletions

View File

@ -99,7 +99,7 @@ HPPA::HPPA(QWidget* parent)
heightScale = 1; heightScale = 1;
//<2F><><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>ģ<EFBFBD><C4A3> //<2F><><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>ģ<EFBFBD><C4A3>
connect(ui.graphicsView->imager, SIGNAL(leftMouseButtonPressed(int, int)), this, SLOT(onimagerSimulatorMove(int, int))); //connect(ui.graphicsView->imager, SIGNAL(leftMouseButtonPressed(int, int)), this, SLOT(onimagerSimulatorMove(int, int)));
initPanelToolbar(); initPanelToolbar();
setDockNestingEnabled(true); setDockNestingEnabled(true);
@ -125,6 +125,10 @@ HPPA::HPPA(QWidget* parent)
ui.mDockWidgetSimulator->setTile(QString::fromLocal8Bit("3Dģ<EFBFBD><EFBFBD>")); ui.mDockWidgetSimulator->setTile(QString::fromLocal8Bit("3Dģ<EFBFBD><EFBFBD>"));
ui.mDockWidgetSpectrometer->setTile(QString::fromLocal8Bit("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>")); ui.mDockWidgetSpectrometer->setTile(QString::fromLocal8Bit("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>"));
m_view3D_tmp = new View3D("D:\\cpp_project_vs2022\\HPPA\\x64\\Debug\\3DModel\\HPPA_frame.obj", "D:\\cpp_project_vs2022\\HPPA\\x64\\Debug\\3DModel\\HPPA_camera.obj");
ui.mDockWidgetSimulator->setWidget(m_view3D_tmp);
//TOC //TOC
CustomDockWidgetBase* dock_layers = new CustomDockWidgetBase(QString::fromLocal8Bit("layers"), this); CustomDockWidgetBase* dock_layers = new CustomDockWidgetBase(QString::fromLocal8Bit("layers"), this);
dock_layers->setObjectName("mDockLayers"); dock_layers->setObjectName("mDockLayers");
@ -574,6 +578,7 @@ void HPPA::initControlTabwidget()
tmc = new TwoMotorControl(this); tmc = new TwoMotorControl(this);
connect(tmc, SIGNAL(startLineNumSignal(int)), this, SLOT(onCreateTab(int))); connect(tmc, SIGNAL(startLineNumSignal(int)), this, SLOT(onCreateTab(int)));
connect(tmc, SIGNAL(sequenceComplete()), this, SLOT(onsequenceComplete())); connect(tmc, SIGNAL(sequenceComplete()), this, SLOT(onsequenceComplete()));
connect(tmc, SIGNAL(broadcastLocationSignal(std::vector<double>)), m_view3D_tmp, SLOT(setLoc(std::vector<double>)));
tmc->setWindowFlags(Qt::Widget); tmc->setWindowFlags(Qt::Widget);
ui.controlTabWidget->addTab(tmc, QString::fromLocal8Bit("2<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")); ui.controlTabWidget->addTab(tmc, QString::fromLocal8Bit("2<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"));
} }
@ -1144,7 +1149,7 @@ void HPPA::setImagerSimulationPos(double x, double y)
{ {
x = widthScale * x; x = widthScale * x;
y = heightScale * y; y = heightScale * y;
ui.graphicsView->imager->setPos(x, y); //ui.graphicsView->imager->setPos(x, y);
} }
void HPPA::onimagerSimulatorMove(int x, int y) void HPPA::onimagerSimulatorMove(int x, int y)

View File

@ -46,6 +46,8 @@
#include "CustomDockWidgetBase.h" #include "CustomDockWidgetBase.h"
#include "Carousel.h" #include "Carousel.h"
#include "View3D.h"
#define PI 3.1415926 #define PI 3.1415926
QT_CHARTS_USE_NAMESPACE//QChartView ʹ<><CAB9> <20><>Ҫ<EFBFBD>Ӻ꣬ <20><><EFBFBD><EFBFBD><EFBFBD>޷<EFBFBD>ʹ<EFBFBD><CAB9> QT_CHARTS_USE_NAMESPACE//QChartView ʹ<><CAB9> <20><>Ҫ<EFBFBD>Ӻ꣬ <20><><EFBFBD><EFBFBD><EFBFBD>޷<EFBFBD>ʹ<EFBFBD><CAB9>
@ -233,6 +235,8 @@ private:
QPushButton* m_open_rgb_camera_btn; QPushButton* m_open_rgb_camera_btn;
QPushButton* m_close_rgb_camera_btn; QPushButton* m_close_rgb_camera_btn;
View3D* m_view3D_tmp;
public Q_SLOTS: public Q_SLOTS:
void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber); void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber);
void PlotSpectral(int state); void PlotSpectral(int state);

View File

@ -263,22 +263,6 @@ QToolBar QToolButton:hover {
<property name="verticalSpacing"> <property name="verticalSpacing">
<number>0</number> <number>0</number>
</property> </property>
<item row="0" column="0">
<widget class="ImagerPositionSimulation" name="graphicsView">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -813,11 +797,6 @@ QToolBar QToolButton:hover {
<extends>QSlider</extends> <extends>QSlider</extends>
<header>qdoubleslider.h</header> <header>qdoubleslider.h</header>
</customwidget> </customwidget>
<customwidget>
<class>ImagerPositionSimulation</class>
<extends>QGraphicsView</extends>
<header>imagerpositionsimulation.h</header>
</customwidget>
<customwidget> <customwidget>
<class>CustomDockWidgetBase</class> <class>CustomDockWidgetBase</class>
<extends>QDockWidget</extends> <extends>QDockWidget</extends>

View File

@ -32,7 +32,7 @@
</ImportGroup> </ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
<QtInstall>5.13.2_msvc2017_64</QtInstall> <QtInstall>5.13.2_msvc2017_64</QtInstall>
<QtModules>core;network;gui;widgets;serialport;websockets;charts</QtModules> <QtModules>core;network;gui;widgets;serialport;websockets;3dcore;3danimation;3dextras;3dinput;3dlogic;3drender;3dquick;charts</QtModules>
<QtBuildConfig>debug</QtBuildConfig> <QtBuildConfig>debug</QtBuildConfig>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
@ -129,6 +129,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="TwoMotorControl.cpp" /> <ClCompile Include="TwoMotorControl.cpp" />
<ClCompile Include="utility_tc.cpp" /> <ClCompile Include="utility_tc.cpp" />
<ClCompile Include="View3D.cpp" />
<QtRcc Include="HPPA.qrc" /> <QtRcc Include="HPPA.qrc" />
<QtUic Include="about.ui" /> <QtUic Include="about.ui" />
<QtUic Include="adjustTable.ui" /> <QtUic Include="adjustTable.ui" />
@ -163,6 +164,7 @@
<QtMoc Include="image2display.h" /> <QtMoc Include="image2display.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="View3D.h" />
<QtMoc Include="adjustTable.h" /> <QtMoc Include="adjustTable.h" />
<QtMoc Include="PowerControl.h" /> <QtMoc Include="PowerControl.h" />
<QtMoc Include="RobotArmControl.h" /> <QtMoc Include="RobotArmControl.h" />

View File

@ -139,6 +139,9 @@
<ClCompile Include="Carousel.cpp"> <ClCompile Include="Carousel.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="View3D.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="fileOperation.h"> <QtMoc Include="fileOperation.h">
@ -204,6 +207,9 @@
<QtMoc Include="Carousel.h"> <QtMoc Include="Carousel.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="View3D.h">
<Filter>Header Files</Filter>
</QtMoc>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="imageProcessor.h"> <ClInclude Include="imageProcessor.h">

View File

@ -320,6 +320,8 @@ void TwoMotorControl::displayRealTimeLoc(std::vector<double> loc)
tmp = round(loc[1] * 100) / 100; tmp = round(loc[1] * 100) / 100;
this->ui.ymotor_realTimeLoc_lineEdit->setText(QString::number(tmp)); this->ui.ymotor_realTimeLoc_lineEdit->setText(QString::number(tmp));
emit broadcastLocationSignal(loc);
} }
void TwoMotorControl::zeroStart() void TwoMotorControl::zeroStart()

View File

@ -84,6 +84,8 @@ signals:
void startLineNumSignal(int lineNum); void startLineNumSignal(int lineNum);
void sequenceComplete();//所有采集线正常运行完成 void sequenceComplete();//所有采集线正常运行完成
void broadcastLocationSignal(std::vector<double>);
private: private:
Ui::twoMotorControl_UI ui; Ui::twoMotorControl_UI ui;
QThread m_coordinatorThread; QThread m_coordinatorThread;

292
HPPA/View3D.cpp Normal file
View File

@ -0,0 +1,292 @@
#include "View3D.h"
#include <QHBoxLayout>
#include <QShowEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <Qt3DExtras/QForwardRenderer>
#include <QtMath>
#include <Qt3DRender/QAttribute>
#include <QGeometryRenderer>
View3D::View3D(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() 通常可用
m_view->defaultFrameGraph()->setClearColor(Qt::white);
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 View3D::initScene()
{
// ===== 创建 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, &View3D::onSceneLoaderStatusChanged);
m_baseTransform = new Qt3DCore::QTransform();
m_baseTransform->setTranslation(QVector3D(0, 0, 0));
baseModel->addComponent(baseLoader);
baseModel->addComponent(m_baseTransform);
// ===== 创建 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);
// 坐标轴依然挂在 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 View3D::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 View3D::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 View3D::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 View3D::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 View3D::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);
}
void View3D::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));
}

74
HPPA/View3D.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef VIEW3D_H
#define VIEW3D_H
#include <QWidget>
#include <QTimer>
#include <QPoint>
#include <QString>
#include <QQuaternion>
#include <QColor>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DRender/QCamera>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DRender/QSceneLoader>
#include <Qt3DExtras/QCylinderMesh>
class View3D : public QWidget
{
Q_OBJECT
public:
explicit View3D(const QString& baseModelPath,
const QString& armModelPath,
QWidget* parent = nullptr);
protected:
void showEvent(QShowEvent* event) override;
bool eventFilter(QObject* obj, QEvent* event) override;
private:
void initScene();
void initCamera();
void updateCameraPosition();
void createAxes();
private:
QString m_baseModelPath;
QString m_armModelPath;
Qt3DExtras::Qt3DWindow* m_view;
QWidget* m_container;
Qt3DCore::QEntity* m_rootEntity;
Qt3DCore::QEntity* m_baseEntity;
Qt3DCore::QEntity* m_armEntity;
Qt3DCore::QTransform* m_armTransform;
Qt3DCore::QTransform* m_baseTransform;
QTimer m_timer;
float m_angle = 0; // arm auto rotation
float m_t = 0;
// ----- Camera control -----
Qt3DRender::QCamera* m_camera = nullptr;
float m_distance = 5000.0f;
float m_yawDeg = 0.0f;
float m_pitchDeg = 0.0f;
QVector3D m_viewCenter = QVector3D(1000, 1000, -1000);
// Mouse state
bool m_mouseDragging = false; // left button: orbit
bool m_middleDragging = false; // middle button: pan
QPoint m_lastMousePos;
Qt3DCore::QTransform* m_baseRootTransform = nullptr;
Qt3DCore::QTransform* m_armRootTransform = nullptr;
public Q_SLOTS:
void setLoc(std::vector<double> loc);
};
#endif // VIEW3D_H