将视图控制封装到CloudView3D中

This commit is contained in:
snso 2026-08-08 17:41:02 +08:00
parent 176a833bb2
commit 3156f82339
4 changed files with 2640 additions and 2286 deletions

View File

@ -17,17 +17,17 @@
#include <QLineEdit> #include <QLineEdit>
#include <QRadioButton> #include <QRadioButton>
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox> #include <QComboBox>
#include <QDialog> #include <QDialog>
#include <QStringList> #include <QStringList>
#include <memory> #include <memory>
#include "CloudView3D.h" #include "CloudView3D.h"
#include "PointCloudConverter.h" #include "PointCloudConverter.h"
class QTextEdit; class QTextEdit;
class QTableWidget; class QTableWidget;
class QCloseEvent; class QCloseEvent;
/** /**
* @brief * @brief
@ -37,55 +37,55 @@ class CloudViewMainWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
public: public:
struct StartupFiles struct StartupFiles
{ {
QStringList displayFiles; QStringList displayFiles;
QStringList bboxFiles; QStringList bboxFiles;
QStringList circleFiles; QStringList circleFiles;
QStringList rectangleFiles; QStringList rectangleFiles;
QStringList surfaceFiles; QStringList surfaceFiles;
QStringList triangleFiles; QStringList triangleFiles;
bool sequential = false; bool sequential = false;
}; };
explicit CloudViewMainWindow(QWidget* parent = nullptr);
~CloudViewMainWindow() override;
bool loadStartupFiles(const StartupFiles& files);
bool loadDisplayFile(const QString& fileName);
bool loadCircleShapeFile(const QString& fileName);
bool loadRectangleShapeFile(const QString& fileName);
bool loadSurfaceShapeFile(const QString& fileName);
bool loadTriangleShapeFile(const QString& fileName);
void fitViewToContent();
protected: explicit CloudViewMainWindow(QWidget* parent = nullptr);
bool eventFilter(QObject* obj, QEvent* event) override; ~CloudViewMainWindow() override;
void closeEvent(QCloseEvent* event) override;
bool loadStartupFiles(const StartupFiles& files);
private: bool loadDisplayFile(const QString& fileName);
enum class StartupFileType bool loadCircleShapeFile(const QString& fileName);
{ bool loadRectangleShapeFile(const QString& fileName);
Display, bool loadSurfaceShapeFile(const QString& fileName);
BBox, bool loadTriangleShapeFile(const QString& fileName);
Circle, void fitViewToContent();
Rectangle,
Surface, protected:
Triangle bool eventFilter(QObject* obj, QEvent* event) override;
}; void closeEvent(QCloseEvent* event) override;
struct StartupItem private:
{ enum class StartupFileType
StartupFileType type; {
QString fileName; Display,
}; BBox,
Circle,
void buildStartupSequence(const StartupFiles& files); Rectangle,
bool loadStartupItem(const StartupItem& item); Surface,
bool loadCurrentStartupSequenceItem(); Triangle
};
private slots:
struct StartupItem
{
StartupFileType type;
QString fileName;
};
void buildStartupSequence(const StartupFiles& files);
bool loadStartupItem(const StartupItem& item);
bool loadCurrentStartupSequenceItem();
private slots:
/** /**
* @brief * @brief
*/ */
@ -146,11 +146,6 @@ private slots:
*/ */
void onPoint2CoordChanged(); void onPoint2CoordChanged();
/**
* @brief
*/
void onViewAnglesChanged(float rotX, float rotY, float rotZ);
/** /**
* @brief 线线 * @brief 线线
*/ */
@ -211,11 +206,11 @@ private slots:
void onSavePointCloud(); // 保存 txt 点云 void onSavePointCloud(); // 保存 txt 点云
void onSavePlyPcdCloud(); // 保存 ply/pcd 点云 void onSavePlyPcdCloud(); // 保存 ply/pcd 点云
void onBatchConvertTxtToPly(); // 批量转换 txt -> ply void onBatchConvertTxtToPly(); // 批量转换 txt -> ply
void onConvertEulerMatrix(); void onConvertEulerMatrix();
void onShowCircleShape(); void onShowCircleShape();
void onShowRectangleShape(); void onShowRectangleShape();
void onShowSurfaceShape(); void onShowSurfaceShape();
void onShowTriangleShape(); void onShowTriangleShape();
/** /**
* @brief 姿 * @brief 姿
@ -243,11 +238,6 @@ private:
*/ */
QGroupBox* createFileGroup(); QGroupBox* createFileGroup();
/**
* @brief 3D视图左侧
*/
QWidget* createViewToolbar();
/** /**
* @brief * @brief
*/ */
@ -276,14 +266,14 @@ private:
/** /**
* @brief * @brief
*/ */
void updateSelectedPointsDisplay(); void updateSelectedPointsDisplay();
void clearMeasureResultDisplay(); void clearMeasureResultDisplay();
void updateMeasureResultDisplay(const SelectedPointInfo& p1, void updateMeasureResultDisplay(const SelectedPointInfo& p1,
const SelectedPointInfo& p2, const SelectedPointInfo& p2,
float distance, float distance,
const QString& statusPrefix = QString()); const QString& statusPrefix = QString());
/** /**
* @brief 线0,0,0 * @brief 线0,0,0
*/ */
QVector<QVector3D> getOriginalLinePoints(const SelectedLineInfo& lineInfo); QVector<QVector3D> getOriginalLinePoints(const SelectedLineInfo& lineInfo);
@ -310,12 +300,12 @@ private:
* @return * @return
*/ */
bool loadBoundingBoxFile(const QString& fileName); bool loadBoundingBoxFile(const QString& fileName);
void applyTransformToAllClouds(const QMatrix4x4& matrix); void applyTransformToAllClouds(const QMatrix4x4& matrix);
void addGeneratedCloud(const PointCloudXYZ& cloud, const QString& name); void addGeneratedCloud(const PointCloudXYZ& cloud, const QString& name);
void showBasicShape(const QString& shapeName, void showBasicShape(const QString& shapeName,
const QVector<LineSegment>& segments, const QVector<LineSegment>& segments,
const QVector<BasicShapePoint>& points = QVector<BasicShapePoint>()); const QVector<BasicShapePoint>& points = QVector<BasicShapePoint>());
void showBasicSurface(const QString& shapeName, const QVector<SurfaceQuad>& surfaces, const QVector<LineSegment>& outlines); void showBasicSurface(const QString& shapeName, const QVector<SurfaceQuad>& surfaces, const QVector<LineSegment>& outlines);
// 点云显示控件 // 点云显示控件
PointCloudGLWidget* m_glWidget; PointCloudGLWidget* m_glWidget;
@ -328,18 +318,13 @@ private:
QPushButton* m_btnOpenBBox; QPushButton* m_btnOpenBBox;
QPushButton* m_btnClearAll; QPushButton* m_btnClearAll;
// 视图角度输入控件
QLineEdit* m_editRotX;
QLineEdit* m_editRotY;
QLineEdit* m_editRotZ;
// 选点测距控件 // 选点测距控件
QCheckBox* m_cbMeasureDistance; QCheckBox* m_cbMeasureDistance;
QPushButton* m_btnClearPoints; QPushButton* m_btnClearPoints;
QLabel* m_lblPoint1; QLabel* m_lblPoint1;
QLabel* m_lblPoint2; QLabel* m_lblPoint2;
QLabel* m_lblDistance; QLabel* m_lblDistance;
QLabel* m_lblDeltaXYZ; QLabel* m_lblDeltaXYZ;
// 点1坐标编辑控件 // 点1坐标编辑控件
QLineEdit* m_editPoint1X; QLineEdit* m_editPoint1X;
@ -407,14 +392,10 @@ private:
QTableWidget* m_linePointsTable; QTableWidget* m_linePointsTable;
QVector<QVector3D> m_currentLinePoints; // 当前线的原始点坐标 QVector<QVector3D> m_currentLinePoints; // 当前线的原始点坐标
// 悬浮缩放按钮 // 启动参数序列显示
QToolButton* m_btnZoomIn; QVector<StartupItem> m_startupSequence;
QToolButton* m_btnZoomOut; int m_startupSequenceIndex;
bool m_startupSequentialMode;
// 启动参数序列显示 };
QVector<StartupItem> m_startupSequence;
int m_startupSequenceIndex;
bool m_startupSequentialMode;
};
#endif // CLOUD_VIEW_MAIN_WINDOW_H #endif // CLOUD_VIEW_MAIN_WINDOW_H

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QMatrix4x4> #include <QMatrix4x4>
#include <QVector3D> #include <QVector3D>
#include <QQuaternion> #include <QQuaternion>
@ -11,8 +12,13 @@
#include <QWheelEvent> #include <QWheelEvent>
#include <vector> #include <vector>
#include "CloudView3DTypes.h" #include "CloudView3DTypes.h"
#include "VZNL_Types.h" #include "VZNL_Types.h"
class QToolButton;
class QPushButton;
class QPinchGesture;
class QResizeEvent;
/** /**
* @brief * @brief
@ -84,58 +90,58 @@ struct SelectedLineInfo
/** /**
* @brief 线 * @brief 线
*/ */
struct LineSegment struct LineSegment
{ {
float x1, y1, z1; // 起点 float x1, y1, z1; // 起点
float x2, y2, z2; // 终点 float x2, y2, z2; // 终点
float r, g, b; // 颜色 (0-1) float r, g, b; // 颜色 (0-1)
float lineWidth; // 线宽0 表示使用默认值(来自 RGBA 中 A > 1 的值) float lineWidth; // 线宽0 表示使用默认值(来自 RGBA 中 A > 1 的值)
LineSegment() : x1(0), y1(0), z1(0), x2(0), y2(0), z2(0), r(1), g(1), b(1), lineWidth(0) {} LineSegment() : x1(0), y1(0), z1(0), x2(0), y2(0), z2(0), r(1), g(1), b(1), lineWidth(0) {}
LineSegment(float _x1, float _y1, float _z1, float _x2, float _y2, float _z2, float _r = 1.0f, float _g = 1.0f, float _b = 1.0f, float _lw = 0) LineSegment(float _x1, float _y1, float _z1, float _x2, float _y2, float _z2, float _r = 1.0f, float _g = 1.0f, float _b = 1.0f, float _lw = 0)
: x1(_x1), y1(_y1), z1(_z1), x2(_x2), y2(_y2), z2(_z2), r(_r), g(_g), b(_b), lineWidth(_lw) {} : x1(_x1), y1(_y1), z1(_z1), x2(_x2), y2(_y2), z2(_z2), r(_r), g(_g), b(_b), lineWidth(_lw) {}
}; };
/** /**
* @brief * @brief
*/ */
struct SurfaceQuad struct SurfaceQuad
{ {
QVector3D p1, p2, p3, p4; QVector3D p1, p2, p3, p4;
float r, g, b, a; float r, g, b, a;
SurfaceQuad() : p1(), p2(), p3(), p4(), r(0.0f), g(0.8f), b(1.0f), a(0.5f) {} SurfaceQuad() : p1(), p2(), p3(), p4(), r(0.0f), g(0.8f), b(1.0f), a(0.5f) {}
SurfaceQuad(const QVector3D& _p1, SurfaceQuad(const QVector3D& _p1,
const QVector3D& _p2, const QVector3D& _p2,
const QVector3D& _p3, const QVector3D& _p3,
const QVector3D& _p4, const QVector3D& _p4,
float _r = 0.0f, float _r = 0.0f,
float _g = 0.8f, float _g = 0.8f,
float _b = 1.0f, float _b = 1.0f,
float _a = 0.5f) float _a = 0.5f)
: p1(_p1), p2(_p2), p3(_p3), p4(_p4), r(_r), g(_g), b(_b), a(_a) {} : p1(_p1), p2(_p2), p3(_p3), p4(_p4), r(_r), g(_g), b(_b), a(_a) {}
}; };
struct BasicShapePoint struct BasicShapePoint
{ {
float x, y, z; float x, y, z;
float r, g, b; float r, g, b;
float pointSize; float pointSize;
BasicShapePoint() : x(0), y(0), z(0), r(1), g(1), b(1), pointSize(8.0f) {} BasicShapePoint() : x(0), y(0), z(0), r(1), g(1), b(1), pointSize(8.0f) {}
BasicShapePoint(float _x, BasicShapePoint(float _x,
float _y, float _y,
float _z, float _z,
float _r = 1.0f, float _r = 1.0f,
float _g = 1.0f, float _g = 1.0f,
float _b = 1.0f, float _b = 1.0f,
float _size = 8.0f) float _size = 8.0f)
: x(_x), y(_y), z(_z), r(_r), g(_g), b(_b), pointSize(_size) {} : x(_x), y(_y), z(_z), r(_r), g(_g), b(_b), pointSize(_size) {}
}; };
/** /**
* @brief 姿 * @brief 姿
* *
* *
* - X轴 * - X轴
* - Y轴绿 * - Y轴绿
@ -168,15 +174,15 @@ public:
explicit PointCloudGLWidget(QWidget* parent = nullptr); explicit PointCloudGLWidget(QWidget* parent = nullptr);
~PointCloudGLWidget() override; ~PointCloudGLWidget() override;
void addPointCloud(const PointCloudXYZ& cloud, const QString& name = ""); void addPointCloud(const PointCloudXYZ& cloud, const QString& name = "");
void addPointCloud(const PointCloudXYZRGB& cloud, const QString& name = ""); void addPointCloud(const PointCloudXYZRGB& cloud, const QString& name = "");
void appendPointCloud(const PointCloudXYZRGB& cloud, const QString& name = ""); void appendPointCloud(const PointCloudXYZRGB& cloud, const QString& name = "");
void clearPointClouds(); void clearPointClouds();
void setPointCloudColor(PointCloudColor color); void setPointCloudColor(PointCloudColor color);
void setPointSize(float size); void setPointSize(float size);
void resetView(); void resetView();
void fitToContent(); void fitToContent();
void zoomIn(); void zoomIn();
void zoomOut(); void zoomOut();
/** /**
* @brief * @brief
@ -308,26 +314,26 @@ public:
*/ */
void clearLineSegments(); void clearLineSegments();
/** /**
* @brief 线 * @brief 线
*/ */
void setBasicShapeSegments(const QVector<LineSegment>& segments); void setBasicShapeSegments(const QVector<LineSegment>& segments);
/** /**
* @brief 线 * @brief 线
*/ */
void appendBasicShapeSegments(const QVector<LineSegment>& segments); void appendBasicShapeSegments(const QVector<LineSegment>& segments);
/** /**
* @brief * @brief
*/ */
void appendBasicShapeSurfaces(const QVector<SurfaceQuad>& surfaces); void appendBasicShapeSurfaces(const QVector<SurfaceQuad>& surfaces);
void appendBasicShapePoints(const QVector<BasicShapePoint>& points); void appendBasicShapePoints(const QVector<BasicShapePoint>& points);
/** /**
* @brief 线 * @brief 线
*/ */
void clearBasicShapeSegments(); void clearBasicShapeSegments();
/** /**
* @brief 姿 * @brief 姿
@ -339,20 +345,21 @@ public:
*/ */
void clearPosePoints(); void clearPosePoints();
signals: signals:
void pointSelected(const SelectedPointInfo& point); void pointSelected(const SelectedPointInfo& point);
void twoPointsSelected(const SelectedPointInfo& p1, const SelectedPointInfo& p2, float distance); void twoPointsSelected(const SelectedPointInfo& p1, const SelectedPointInfo& p2, float distance);
void measurementFinished(const SelectedPointInfo& p1, void measurementFinished(const SelectedPointInfo& p1,
const SelectedPointInfo& p2, const SelectedPointInfo& p2,
float distance, float distance,
float dx, float dx,
float dy, float dy,
float dz); float dz);
void lineSelected(const SelectedLineInfo& line); void lineSelected(const SelectedLineInfo& line);
void viewAnglesChanged(float rotX, float rotY, float rotZ); void viewAnglesChanged(float rotX, float rotY, float rotZ);
protected: protected:
void initializeGL() override; bool event(QEvent* event) override;
void initializeGL() override;
void resizeGL(int w, int h) override; void resizeGL(int w, int h) override;
void paintGL() override; void paintGL() override;
void mousePressEvent(QMouseEvent* event) override; void mousePressEvent(QMouseEvent* event) override;
@ -361,6 +368,7 @@ protected:
void wheelEvent(QWheelEvent* event) override; void wheelEvent(QWheelEvent* event) override;
void mouseDoubleClickEvent(QMouseEvent* event) override; void mouseDoubleClickEvent(QMouseEvent* event) override;
void keyPressEvent(QKeyEvent* event) override; void keyPressEvent(QKeyEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
private: private:
struct PointCloudData struct PointCloudData
@ -455,34 +463,69 @@ private:
PointCloudData& operator=(const PointCloudData&) = delete; PointCloudData& operator=(const PointCloudData&) = delete;
}; };
void computeBoundingBox(); void computeBoundingBox();
void updateProjection(const QMatrix4x4& modelView); void updateProjection(const QMatrix4x4& modelView);
float minimumCameraDistance() const; float fittedCameraDistance(float padding = 1.05f) const;
void setCurrentColor(PointCloudColor color); float minimumCameraDistance() const;
void setColorByIndex(int colorIndex); // 根据索引设置颜色 QVector3D colorForIndex(int colorIndex) const;
SelectedPointInfo pickPoint(int screenX, int screenY); SelectedPointInfo pickPoint(int screenX, int screenY);
void drawSelectedPoints(); void drawSelectedPoints();
void drawMeasurementLine(); void drawMeasurementLine();
void drawAxis(); void drawAxis();
void drawSelectedLine(); // 绘制选中的线 void drawSelectedLine(); // 绘制选中的线
void drawLineSegments(); // 绘制线段 void drawLineSegments(); // 绘制线段
void drawBasicShapeSurfaces(); // 绘制基础图形面片 void drawBasicShapeSurfaces(); // 绘制基础图形面片
void drawBasicShapeSegments(); // 绘制基础图形 void drawBasicShapeSegments(); // 绘制基础图形
void drawBasicShapePoints(); void drawBasicShapePoints();
void drawLineSegmentList(const QVector<LineSegment>& segments); void drawLineSegmentList(const QVector<LineSegment>& segments);
void drawPosePoints(); // 绘制姿态点 void drawPosePoints(); // 绘制姿态点
void drawAxisLabels(); // 绘制坐标轴 XYZ 标注 void drawAxisLabels(); // 绘制坐标轴 XYZ 标注
void uploadToVBO(PointCloudData& data); // 上传数据到 VBO void uploadToVBO(PointCloudData& data); // 上传数据到 VBO
void releaseVBO(PointCloudData& data); // 释放 VBO 资源 void releaseVBO(PointCloudData& data); // 释放 VBO 资源
// GLES2 shader 渲染
bool ensureShader();
void drawCloud(PointCloudData& data, float pointSize);
void drawPrimitives(const QMatrix4x4& mvp,
const float* positions,
int vertexCount,
GLenum mode,
const float* colors,
const QVector3D& uniformColor,
float pointSize,
float alpha,
bool depthTest);
void resetRenderState();
// 覆盖控件:左侧竖向视图按钮 / 左下角旋转角度 / 右侧缩放
void createOverlayControls();
void repositionOverlayControls();
void showViewAngleDialog();
void updateViewAngleDisplay();
bool handlePinchGesture(QPinchGesture* gesture);
std::vector<PointCloudData> m_pointClouds; std::vector<PointCloudData> m_pointClouds;
QMatrix4x4 m_projection; QMatrix4x4 m_projection;
QMatrix4x4 m_view; QMatrix4x4 m_view;
QMatrix4x4 m_model; QMatrix4x4 m_model;
QMatrix4x4 m_mvp; // 当前帧的模型视图投影矩阵(点云主渲染用)
float m_distance; // GLES2 shader 渲染资源
float m_rotationX; QOpenGLShaderProgram* m_shader;
QOpenGLBuffer m_dynamicVbo; // 动态叠加图元(选中点/线/轴/姿态等)的临时 VBO
bool m_shaderReady;
GLint m_mvpLocation;
GLint m_positionLocation;
GLint m_colorLocation;
GLint m_pointSizeLocation;
GLint m_alphaLocation;
GLint m_useVertexColorLocation;
GLint m_uniformColorLocation;
float m_distance;
float m_pinchStartDistance;
float m_rotationX;
float m_rotationY; float m_rotationY;
float m_rotationZ; float m_rotationZ;
QQuaternion m_rotation; // 使用四元数存储旋转状态 QQuaternion m_rotation; // 使用四元数存储旋转状态
@ -513,12 +556,19 @@ private:
int m_colorIndex; // 颜色轮换索引 int m_colorIndex; // 颜色轮换索引
static const int COLOR_COUNT = 7; // 可用颜色数量 static const int COLOR_COUNT = 7; // 可用颜色数量
// 线段和姿态点数据 // 线段和姿态点数据
QVector<LineSegment> m_lineSegments; QVector<LineSegment> m_lineSegments;
QVector<LineSegment> m_basicShapeSegments; QVector<LineSegment> m_basicShapeSegments;
QVector<SurfaceQuad> m_basicShapeSurfaces; QVector<SurfaceQuad> m_basicShapeSurfaces;
QVector<BasicShapePoint> m_basicShapePoints; QVector<BasicShapePoint> m_basicShapePoints;
QVector<PosePoint> m_posePoints; QVector<PosePoint> m_posePoints;
};
// 覆盖控件
QWidget* m_viewToolbar; // 左侧竖向视图按钮容器
QVector<QToolButton*> m_viewButtons;
QPushButton* m_viewAngleButton; // 左下角旋转角度显示按钮
QToolButton* m_zoomInButton;
QToolButton* m_zoomOutButton;
};
#endif // POINT_CLOUD_GL_WIDGET_H #endif // POINT_CLOUD_GL_WIDGET_H

File diff suppressed because it is too large Load Diff