Utils/CloudView/Inc/PointCloudGLWidget.h

394 lines
12 KiB
C
Raw Normal View History

#ifndef POINT_CLOUD_GL_WIDGET_H
#define POINT_CLOUD_GL_WIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QMatrix4x4>
#include <QVector3D>
#include <QMouseEvent>
#include <QWheelEvent>
#include <vector>
#include "PointCloudConverter.h"
/**
* @brief
*/
enum class PointCloudColor
{
White,
Red,
Green,
Blue,
Yellow,
Cyan,
Magenta,
Original
};
/**
* @brief
*/
struct SelectedPointInfo
{
bool valid;
size_t index;
float x, y, z;
int cloudIndex;
int lineIndex; // 所属线索引
int pointIndexInLine; // 点在线中的索引
SelectedPointInfo() : valid(false), index(0), x(0), y(0), z(0), cloudIndex(-1), lineIndex(-1), pointIndexInLine(-1) {}
};
/**
* @brief 线
*/
enum class LineSelectMode
{
Vertical, // 纵向选线(同一条扫描线)
Horizontal // 横向选线(所有线的相同索引点)
};
/**
* @brief
*/
enum class EulerRotationOrder
{
ZYX, // Yaw-Pitch-Roll最常用
XYZ, // Roll-Pitch-Yaw
ZXY, // Yaw-Roll-Pitch
YXZ, // Pitch-Roll-Yaw
XZY, // Roll-Yaw-Pitch
YZX // Pitch-Yaw-Roll
};
/**
* @brief 线
*/
struct SelectedLineInfo
{
bool valid;
int cloudIndex; // 点云索引
int lineIndex; // 线索引(纵向选线时使用)
int pointIndex; // 点索引(横向选线时使用)
int pointCount; // 该线上的点数
LineSelectMode mode; // 选线模式
SelectedLineInfo() : valid(false), cloudIndex(-1), lineIndex(-1), pointIndex(-1), pointCount(0), mode(LineSelectMode::Vertical) {}
};
/**
* @brief 线
*/
struct LineSegment
{
float x1, y1, z1; // 起点
float x2, y2, z2; // 终点
float r, g, b; // 颜色 (0-1)
LineSegment() : x1(0), y1(0), z1(0), x2(0), y2(0), z2(0), r(1), g(1), b(1) {}
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)
: x1(_x1), y1(_y1), z1(_z1), x2(_x2), y2(_y2), z2(_z2), r(_r), g(_g), b(_b) {}
};
/**
* @brief 姿
*
*
* - X轴
* - Y轴绿
* - Z轴
*
* ZYXYaw-Pitch-Roll
* - rz: Z轴旋转Yaw
* - ry: Y轴旋转Pitch
* - rx: X轴旋转Roll
*/
struct PosePoint
{
float x, y, z; // 位置
float rx, ry, rz; // 欧拉角(度)
float scale; // 坐标系大小
PosePoint() : x(0), y(0), z(0), rx(0), ry(0), rz(0), scale(10.0f) {}
PosePoint(float _x, float _y, float _z, float _rx, float _ry, float _rz, float _scale = 10.0f)
: x(_x), y(_y), z(_z), rx(_rx), ry(_ry), rz(_rz), scale(_scale) {}
};
/**
* @brief OpenGL
*/
class PointCloudGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit PointCloudGLWidget(QWidget* parent = nullptr);
~PointCloudGLWidget() override;
void addPointCloud(const PointCloudXYZ& cloud, const QString& name = "");
void addPointCloud(const PointCloudXYZRGB& cloud, const QString& name = "");
void clearPointClouds();
void setPointCloudColor(PointCloudColor color);
void setPointSize(float size);
void resetView();
/**
* @brief
* @param rotX X轴旋转角度
* @param rotY Y轴旋转角度
* @param rotZ Z轴旋转角度
*/
void setViewAngles(float rotX, float rotY, float rotZ = 0.0f);
QVector<SelectedPointInfo> getSelectedPoints() const { return m_selectedPoints; }
SelectedLineInfo getSelectedLine() const { return m_selectedLine; }
void clearSelectedPoints();
void clearSelectedLine();
float calculateDistance(const SelectedPointInfo& p1, const SelectedPointInfo& p2);
/**
* @brief 线线
*/
bool selectLineByIndex(int lineIndex);
/**
* @brief 线线
*/
bool selectHorizontalLineByIndex(int pointIndex);
/**
* @brief 线
*/
void setLineSelectMode(LineSelectMode mode) { m_lineSelectMode = mode; }
/**
* @brief
*/
void setEulerRotationOrder(EulerRotationOrder order) { m_eulerRotationOrder = order; }
/**
* @brief
*/
EulerRotationOrder getEulerRotationOrder() const { return m_eulerRotationOrder; }
/**
* @brief
*/
void setMeasureDistanceEnabled(bool enabled) { m_measureDistanceEnabled = enabled; }
/**
* @brief
*/
bool isMeasureDistanceEnabled() const { return m_measureDistanceEnabled; }
/**
* @brief 线
* @return (x, y, z)
*/
QVector<QVector3D> getSelectedLinePoints() const;
/**
* @brief
* @param point
*/
void setListHighlightPoint(const QVector3D& point);
/**
* @brief
*/
void clearListHighlightPoint();
/**
* @brief
*/
bool getFirstCloudData(PointCloudXYZ& cloud) const;
/**
* @brief
*/
void replaceFirstCloud(const PointCloudXYZ& cloud, const QString& name);
/**
* @brief
*/
size_t getCloudCount() const { return m_pointClouds.size(); }
/**
* @brief 4x4
* @param matrix 4x4
*/
void transformAllClouds(const QMatrix4x4& matrix);
/**
* @brief 线
*/
void addLineSegments(const QVector<LineSegment>& segments);
/**
* @brief 线
*/
void clearLineSegments();
/**
* @brief 姿
*/
void addPosePoints(const QVector<PosePoint>& poses);
/**
* @brief 姿
*/
void clearPosePoints();
signals:
void pointSelected(const SelectedPointInfo& point);
void twoPointsSelected(const SelectedPointInfo& p1, const SelectedPointInfo& p2, float distance);
void lineSelected(const SelectedLineInfo& line);
void viewAnglesChanged(float rotX, float rotY, float rotZ);
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
void mousePressEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent* event) override;
void keyPressEvent(QKeyEvent* event) override;
private:
struct PointCloudData
{
std::vector<float> vertices;
std::vector<float> colors;
std::vector<int> lineIndices; // 每个点所属的线索引
std::vector<int> originalIndices; // 每个显示点在原始点云中的索引用于计算原始index
bool hasColor;
bool hasLineInfo; // 是否有线信息
QString name;
int colorIndex; // 点云颜色索引
int totalLines; // 总线数
int pointsPerLine; // 每线点数(网格化点云)
// VBO 缓冲区
QOpenGLBuffer vertexBuffer; // 顶点 VBO
QOpenGLBuffer colorBuffer; // 颜色 VBO
bool vboCreated; // VBO 是否已创建
PointCloudData()
: hasColor(false), hasLineInfo(false), colorIndex(0)
, totalLines(0), pointsPerLine(0)
, vertexBuffer(QOpenGLBuffer::VertexBuffer)
, colorBuffer(QOpenGLBuffer::VertexBuffer)
, vboCreated(false)
{}
// 移动构造函数QOpenGLBuffer 不支持拷贝)
PointCloudData(PointCloudData&& other) noexcept
: vertices(std::move(other.vertices))
, colors(std::move(other.colors))
, lineIndices(std::move(other.lineIndices))
, originalIndices(std::move(other.originalIndices))
, hasColor(other.hasColor)
, hasLineInfo(other.hasLineInfo)
, name(std::move(other.name))
, colorIndex(other.colorIndex)
, totalLines(other.totalLines)
, pointsPerLine(other.pointsPerLine)
, vertexBuffer(QOpenGLBuffer::VertexBuffer)
, colorBuffer(QOpenGLBuffer::VertexBuffer)
, vboCreated(false)
{
// VBO 需要在 GL 上下文中重建,标记为未创建
other.vboCreated = false;
}
PointCloudData& operator=(PointCloudData&& other) noexcept
{
if (this != &other) {
// 释放自身 VBO
if (vboCreated) {
vertexBuffer.destroy();
colorBuffer.destroy();
vboCreated = false;
}
vertices = std::move(other.vertices);
colors = std::move(other.colors);
lineIndices = std::move(other.lineIndices);
originalIndices = std::move(other.originalIndices);
hasColor = other.hasColor;
hasLineInfo = other.hasLineInfo;
name = std::move(other.name);
colorIndex = other.colorIndex;
totalLines = other.totalLines;
pointsPerLine = other.pointsPerLine;
// VBO 需要重建
other.vboCreated = false;
}
return *this;
}
// 禁止拷贝
PointCloudData(const PointCloudData&) = delete;
PointCloudData& operator=(const PointCloudData&) = delete;
};
void computeBoundingBox();
void setCurrentColor(PointCloudColor color);
void setColorByIndex(int colorIndex); // 根据索引设置颜色
SelectedPointInfo pickPoint(int screenX, int screenY);
void drawSelectedPoints();
void drawMeasurementLine();
void drawAxis();
void drawSelectedLine(); // 绘制选中的线
void drawLineSegments(); // 绘制线段
void drawPosePoints(); // 绘制姿态点
void uploadToVBO(PointCloudData& data); // 上传数据到 VBO
void releaseVBO(PointCloudData& data); // 释放 VBO 资源
std::vector<PointCloudData> m_pointClouds;
QMatrix4x4 m_projection;
QMatrix4x4 m_view;
QMatrix4x4 m_model;
float m_distance;
float m_rotationX;
float m_rotationY;
float m_rotationZ;
QVector3D m_center;
QVector3D m_pan;
QVector3D m_minBound;
QVector3D m_maxBound;
QPoint m_lastMousePos;
bool m_leftButtonPressed;
bool m_rightButtonPressed;
bool m_middleButtonPressed;
PointCloudColor m_currentColor;
float m_pointSize;
LineSelectMode m_lineSelectMode;
EulerRotationOrder m_eulerRotationOrder;
bool m_measureDistanceEnabled;
QVector<SelectedPointInfo> m_selectedPoints;
SelectedLineInfo m_selectedLine;
static const int MAX_SELECTED_POINTS = 2;
// 列表高亮点(与选点功能区分)
bool m_hasListHighlightPoint;
QVector3D m_listHighlightPoint;
int m_colorIndex; // 颜色轮换索引
static const int COLOR_COUNT = 7; // 可用颜色数量
// 线段和姿态点数据
QVector<LineSegment> m_lineSegments;
QVector<PosePoint> m_posePoints;
};
#endif // POINT_CLOUD_GL_WIDGET_H