feat: v0.1.0更新

This commit is contained in:
2026-01-14 18:07:26 +08:00
commit efd8a7cc20
55 changed files with 6200 additions and 0 deletions

View File

@@ -0,0 +1,259 @@
#include "gui/PointCloudGLWidget.h"
#include <QDebug>
#include <cmath>
#include <cfloat>
PointCloudGLWidget::PointCloudGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
, m_program(nullptr)
, m_vertexBuffer(nullptr)
, m_vao(nullptr)
, m_pointCount(0)
, m_orthoSize(2000.0f) // 正交投影视野大小
, m_rotationX(0.0f) // 从正面看0度
, m_rotationY(0.0f) // 从正面看0度
, m_translation(0.0f, 0.0f, 0.0f)
, m_leftButtonPressed(false)
, m_rightButtonPressed(false)
{
setMinimumSize(400, 400);
}
PointCloudGLWidget::~PointCloudGLWidget()
{
makeCurrent();
if (m_vao) {
m_vao->destroy();
delete m_vao;
}
if (m_vertexBuffer) {
m_vertexBuffer->destroy();
delete m_vertexBuffer;
}
if (m_program) {
delete m_program;
}
doneCurrent();
}
void PointCloudGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_PROGRAM_POINT_SIZE);
setupShaders();
// 创建VAO和VBO
m_vao = new QOpenGLVertexArrayObject(this);
m_vao->create();
m_vertexBuffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
m_vertexBuffer->create();
qDebug() << "[PointCloudGLWidget] OpenGL initialized";
}
void PointCloudGLWidget::setupShaders()
{
m_program = new QOpenGLShaderProgram(this);
// 顶点着色器
const char *vertexShaderSource = R"(
#version 330 core
layout(location = 0) in vec3 position;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(position, 1.0);
gl_PointSize = 2.0;
}
)";
// 片段着色器
const char *fragmentShaderSource = R"(
#version 330 core
out vec4 fragColor;
void main() {
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
)";
if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource)) {
qDebug() << "[PointCloudGLWidget] Vertex shader error:" << m_program->log();
}
if (!m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource)) {
qDebug() << "[PointCloudGLWidget] Fragment shader error:" << m_program->log();
}
if (!m_program->link()) {
qDebug() << "[PointCloudGLWidget] Shader link error:" << m_program->log();
} else {
qDebug() << "[PointCloudGLWidget] Shaders compiled and linked successfully";
}
}
void PointCloudGLWidget::resizeGL(int w, int h)
{
m_projection.setToIdentity();
// 使用正交投影代替透视投影,避免"喷射状"效果
float aspect = float(w) / float(h);
m_projection.ortho(-m_orthoSize * aspect, m_orthoSize * aspect,
-m_orthoSize, m_orthoSize,
-50000.0f, 50000.0f); // 近平面和远平面
}
void PointCloudGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (m_pointCount == 0 || !m_program) {
return;
}
// 每帧重新计算正交投影矩阵确保使用最新的m_orthoSize
m_projection.setToIdentity();
float aspect = float(width()) / float(height());
m_projection.ortho(-m_orthoSize * aspect, m_orthoSize * aspect,
-m_orthoSize, m_orthoSize,
-50000.0f, 50000.0f);
// 设置view矩阵
m_view.setToIdentity();
m_view.rotate(m_rotationX, 1.0f, 0.0f, 0.0f);
m_view.rotate(m_rotationY, 0.0f, 1.0f, 0.0f);
m_view.translate(m_translation);
// 设置model矩阵
m_model.setToIdentity();
// 计算MVP矩阵
QMatrix4x4 mvp = m_projection * m_view * m_model;
// 绑定shader和设置uniform
m_program->bind();
m_program->setUniformValue("mvp", mvp);
// 绑定VAO和绘制
m_vao->bind();
glDrawArrays(GL_POINTS, 0, m_pointCount);
m_vao->release();
m_program->release();
}
void PointCloudGLWidget::mousePressEvent(QMouseEvent *event)
{
m_lastMousePos = event->pos();
if (event->button() == Qt::LeftButton) {
m_leftButtonPressed = true;
} else if (event->button() == Qt::RightButton) {
m_rightButtonPressed = true;
}
}
void PointCloudGLWidget::mouseMoveEvent(QMouseEvent *event)
{
QPoint delta = event->pos() - m_lastMousePos;
m_lastMousePos = event->pos();
if (m_leftButtonPressed) {
// 左键:旋转
m_rotationX += delta.y() * 0.5f;
m_rotationY += delta.x() * 0.5f;
update();
} else if (m_rightButtonPressed) {
// 右键:平移(根据正交投影视野大小调整平移速度)
float scale = m_orthoSize * 0.002f;
m_translation.setX(m_translation.x() + delta.x() * scale);
m_translation.setY(m_translation.y() - delta.y() * scale);
update();
}
}
void PointCloudGLWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
m_leftButtonPressed = false;
} else if (event->button() == Qt::RightButton) {
m_rightButtonPressed = false;
}
}
void PointCloudGLWidget::wheelEvent(QWheelEvent *event)
{
// 滚轮:缩放(调整正交投影视野大小)
float delta = event->angleDelta().y() / 120.0f;
m_orthoSize *= (1.0f - delta * 0.1f);
m_orthoSize = qMax(100.0f, qMin(m_orthoSize, 10000.0f)); // 范围100-10000
update(); // 触发重绘paintGL会使用新的m_orthoSize
}
void PointCloudGLWidget::updatePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
if (!cloud) {
return;
}
// 过滤全零点并转换为顶点数组
m_vertices.clear();
float minX = FLT_MAX, maxX = -FLT_MAX;
float minY = FLT_MAX, maxY = -FLT_MAX;
float minZ = FLT_MAX, maxZ = -FLT_MAX;
for (const auto& point : cloud->points) {
if (point.z > 0.01f) {
m_vertices.push_back(point.x);
m_vertices.push_back(point.y);
m_vertices.push_back(point.z);
// 统计坐标范围
if (point.x < minX) minX = point.x;
if (point.x > maxX) maxX = point.x;
if (point.y < minY) minY = point.y;
if (point.y > maxY) maxY = point.y;
if (point.z < minZ) minZ = point.z;
if (point.z > maxZ) maxZ = point.z;
}
}
m_pointCount = m_vertices.size() / 3;
// 添加调试日志
static int updateCount = 0;
if (updateCount < 3 || updateCount % 100 == 0) {
qDebug() << "[PointCloudGLWidget] Update" << updateCount << "- Points:" << m_pointCount
<< "Total cloud size:" << cloud->size();
qDebug() << " X range:" << minX << "to" << maxX;
qDebug() << " Y range:" << minY << "to" << maxY;
qDebug() << " Z range:" << minZ << "to" << maxZ;
}
updateCount++;
updateBuffers();
update();
}
void PointCloudGLWidget::updateBuffers()
{
if (m_vertices.empty() || !m_vao || !m_vertexBuffer) {
return;
}
makeCurrent();
m_vao->bind();
m_vertexBuffer->bind();
m_vertexBuffer->allocate(m_vertices.data(), m_vertices.size() * sizeof(float));
// 设置顶点属性指针
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
m_vertexBuffer->release();
m_vao->release();
doneCurrent();
}