CloudView优化控制
This commit is contained in:
parent
eb0cbdfc54
commit
c812176d84
@ -84,6 +84,16 @@ private slots:
|
||||
*/
|
||||
void onLineSelected(const SelectedLineInfo& line);
|
||||
|
||||
/**
|
||||
* @brief 点1坐标编辑完成(回车)
|
||||
*/
|
||||
void onPoint1CoordChanged();
|
||||
|
||||
/**
|
||||
* @brief 点2坐标编辑完成(回车)
|
||||
*/
|
||||
void onPoint2CoordChanged();
|
||||
|
||||
/**
|
||||
* @brief 处理视角旋转角度改变事件
|
||||
*/
|
||||
@ -255,6 +265,16 @@ private:
|
||||
QLabel* m_lblPoint2;
|
||||
QLabel* m_lblDistance;
|
||||
|
||||
// 点1坐标编辑控件
|
||||
QLineEdit* m_editPoint1X;
|
||||
QLineEdit* m_editPoint1Y;
|
||||
QLineEdit* m_editPoint1Z;
|
||||
|
||||
// 点2坐标编辑控件
|
||||
QLineEdit* m_editPoint2X;
|
||||
QLineEdit* m_editPoint2Y;
|
||||
QLineEdit* m_editPoint2Z;
|
||||
|
||||
// 点1姿态输入控件
|
||||
QLineEdit* m_editRx1;
|
||||
QLineEdit* m_editRy1;
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QMatrix4x4>
|
||||
#include <QVector3D>
|
||||
#include <QQuaternion>
|
||||
#include <QMouseEvent>
|
||||
#include <QWheelEvent>
|
||||
#include <vector>
|
||||
@ -150,6 +151,15 @@ public:
|
||||
void clearSelectedLine();
|
||||
float calculateDistance(const SelectedPointInfo& p1, const SelectedPointInfo& p2);
|
||||
|
||||
/**
|
||||
* @brief 更新选中点的坐标
|
||||
* @param index 点索引(0或1)
|
||||
* @param x 新的X坐标
|
||||
* @param y 新的Y坐标
|
||||
* @param z 新的Z坐标
|
||||
*/
|
||||
void updateSelectedPointCoord(int index, float x, float y, float z);
|
||||
|
||||
/**
|
||||
* @brief 通过线索引选择线(纵向)
|
||||
*/
|
||||
@ -372,6 +382,7 @@ private:
|
||||
float m_rotationX;
|
||||
float m_rotationY;
|
||||
float m_rotationZ;
|
||||
QQuaternion m_rotation; // 使用四元数存储旋转状态
|
||||
QVector3D m_center;
|
||||
QVector3D m_pan;
|
||||
QVector3D m_minBound;
|
||||
|
||||
@ -163,13 +163,15 @@ QGroupBox* CloudViewMainWindow::createViewGroup()
|
||||
float rotZ;
|
||||
};
|
||||
|
||||
// 坐标系定义:X向右,Y向下,Z朝后
|
||||
// 正视图:看XY平面,Z轴朝后
|
||||
ViewPreset presets[] = {
|
||||
{"正视", 0.0f, 0.0f, 0.0f},
|
||||
{"后视", 0.0f, 180.0f, 0.0f},
|
||||
{"左侧", 0.0f, -90.0f, 0.0f},
|
||||
{"右侧", 0.0f, 90.0f, 0.0f},
|
||||
{"俯视", -90.0f, 0.0f, 0.0f},
|
||||
{"仰视", 90.0f, 0.0f, 0.0f},
|
||||
{"正视", 0.0f, 0.0f, 0.0f}, // 看XY平面,Z朝后
|
||||
{"后视", 0.0f, 180.0f, 0.0f}, // 看XY平面,Z朝前
|
||||
{"左侧", 0.0f, 90.0f, 0.0f}, // 看YZ平面,X朝前
|
||||
{"右侧", 0.0f, -90.0f, 0.0f}, // 看YZ平面,X朝后
|
||||
{"俯视", 90.0f, 0.0f, 0.0f}, // 看XZ平面,Y朝后
|
||||
{"仰视", -90.0f, 0.0f, 0.0f}, // 看XZ平面,Y朝前
|
||||
};
|
||||
|
||||
QHBoxLayout* btnLayout = new QHBoxLayout();
|
||||
@ -230,7 +232,7 @@ QGroupBox* CloudViewMainWindow::createViewGroup()
|
||||
QPushButton* btnApply = new QPushButton("应用", group);
|
||||
btnApply->setMaximumWidth(50);
|
||||
btnApply->setMaximumHeight(24);
|
||||
connect(btnApply, &QPushButton::clicked, this, [this]() {
|
||||
auto applyAngles = [this]() {
|
||||
bool okX, okY, okZ;
|
||||
float rotX = m_editRotX->text().toFloat(&okX);
|
||||
float rotY = m_editRotY->text().toFloat(&okY);
|
||||
@ -238,9 +240,15 @@ QGroupBox* CloudViewMainWindow::createViewGroup()
|
||||
if (okX && okY && okZ) {
|
||||
m_glWidget->setViewAngles(rotX, rotY, rotZ);
|
||||
}
|
||||
});
|
||||
};
|
||||
connect(btnApply, &QPushButton::clicked, this, applyAngles);
|
||||
angleGrid->addWidget(btnApply, 0, 6);
|
||||
|
||||
// 连接回车信号到应用功能
|
||||
connect(m_editRotX, &QLineEdit::returnPressed, this, applyAngles);
|
||||
connect(m_editRotY, &QLineEdit::returnPressed, this, applyAngles);
|
||||
connect(m_editRotZ, &QLineEdit::returnPressed, this, applyAngles);
|
||||
|
||||
mainLayout->addLayout(angleGrid);
|
||||
|
||||
return group;
|
||||
@ -329,6 +337,14 @@ QWidget* CloudViewMainWindow::createLinePage()
|
||||
btnLayout->addWidget(m_btnClearLine2);
|
||||
inputLayout->addLayout(btnLayout);
|
||||
|
||||
// 连接输入线段坐标框的回车信号
|
||||
connect(m_editLineX1, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowInputLine);
|
||||
connect(m_editLineY1, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowInputLine);
|
||||
connect(m_editLineZ1, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowInputLine);
|
||||
connect(m_editLineX2, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowInputLine);
|
||||
connect(m_editLineY2, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowInputLine);
|
||||
connect(m_editLineZ2, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowInputLine);
|
||||
|
||||
layout->addWidget(inputLineGroup);
|
||||
layout->addStretch();
|
||||
return page;
|
||||
@ -356,6 +372,12 @@ QGroupBox* CloudViewMainWindow::createMeasureGroup()
|
||||
m_lblPoint1->setText("点1: --");
|
||||
m_lblPoint2->setText("点2: --");
|
||||
m_lblDistance->setText("--");
|
||||
m_editPoint1X->setText("--");
|
||||
m_editPoint1Y->setText("--");
|
||||
m_editPoint1Z->setText("--");
|
||||
m_editPoint2X->setText("--");
|
||||
m_editPoint2Y->setText("--");
|
||||
m_editPoint2Z->setText("--");
|
||||
});
|
||||
layout->addWidget(m_cbMeasureDistance);
|
||||
|
||||
@ -377,6 +399,34 @@ QGroupBox* CloudViewMainWindow::createMeasureGroup()
|
||||
m_lblPoint1->setStyleSheet("font-weight: bold; font-size: 11px;");
|
||||
layout->addWidget(m_lblPoint1);
|
||||
|
||||
// 点1坐标编辑(可修改)
|
||||
QHBoxLayout* coord1Layout = new QHBoxLayout();
|
||||
coord1Layout->setSpacing(5);
|
||||
coord1Layout->addWidget(new QLabel("X:", group));
|
||||
m_editPoint1X = new QLineEdit("--", group);
|
||||
m_editPoint1X->setMaximumWidth(70);
|
||||
m_editPoint1X->setMaximumHeight(24);
|
||||
coord1Layout->addWidget(m_editPoint1X);
|
||||
|
||||
coord1Layout->addWidget(new QLabel("Y:", group));
|
||||
m_editPoint1Y = new QLineEdit("--", group);
|
||||
m_editPoint1Y->setMaximumWidth(70);
|
||||
m_editPoint1Y->setMaximumHeight(24);
|
||||
coord1Layout->addWidget(m_editPoint1Y);
|
||||
|
||||
coord1Layout->addWidget(new QLabel("Z:", group));
|
||||
m_editPoint1Z = new QLineEdit("--", group);
|
||||
m_editPoint1Z->setMaximumWidth(70);
|
||||
m_editPoint1Z->setMaximumHeight(24);
|
||||
coord1Layout->addWidget(m_editPoint1Z);
|
||||
coord1Layout->addStretch();
|
||||
layout->addLayout(coord1Layout);
|
||||
|
||||
// 连接回车信号
|
||||
connect(m_editPoint1X, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onPoint1CoordChanged);
|
||||
connect(m_editPoint1Y, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onPoint1CoordChanged);
|
||||
connect(m_editPoint1Z, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onPoint1CoordChanged);
|
||||
|
||||
// 点1姿态输入(紧凑布局)
|
||||
QHBoxLayout* pose1Layout = new QHBoxLayout();
|
||||
pose1Layout->setSpacing(5);
|
||||
@ -402,6 +452,11 @@ QGroupBox* CloudViewMainWindow::createMeasureGroup()
|
||||
connect(m_btnShowPose1, &QPushButton::clicked, this, &CloudViewMainWindow::onShowPose1);
|
||||
layout->addWidget(m_btnShowPose1);
|
||||
|
||||
// 连接姿态输入框的回车信号
|
||||
connect(m_editRx1, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowPose1);
|
||||
connect(m_editRy1, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowPose1);
|
||||
connect(m_editRz1, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowPose1);
|
||||
|
||||
// 分隔线
|
||||
QFrame* line2 = new QFrame(group);
|
||||
line2->setFrameShape(QFrame::HLine);
|
||||
@ -414,6 +469,34 @@ QGroupBox* CloudViewMainWindow::createMeasureGroup()
|
||||
m_lblPoint2->setStyleSheet("font-weight: bold; font-size: 11px;");
|
||||
layout->addWidget(m_lblPoint2);
|
||||
|
||||
// 点2坐标编辑(可修改)
|
||||
QHBoxLayout* coord2Layout = new QHBoxLayout();
|
||||
coord2Layout->setSpacing(5);
|
||||
coord2Layout->addWidget(new QLabel("X:", group));
|
||||
m_editPoint2X = new QLineEdit("--", group);
|
||||
m_editPoint2X->setMaximumWidth(70);
|
||||
m_editPoint2X->setMaximumHeight(24);
|
||||
coord2Layout->addWidget(m_editPoint2X);
|
||||
|
||||
coord2Layout->addWidget(new QLabel("Y:", group));
|
||||
m_editPoint2Y = new QLineEdit("--", group);
|
||||
m_editPoint2Y->setMaximumWidth(70);
|
||||
m_editPoint2Y->setMaximumHeight(24);
|
||||
coord2Layout->addWidget(m_editPoint2Y);
|
||||
|
||||
coord2Layout->addWidget(new QLabel("Z:", group));
|
||||
m_editPoint2Z = new QLineEdit("--", group);
|
||||
m_editPoint2Z->setMaximumWidth(70);
|
||||
m_editPoint2Z->setMaximumHeight(24);
|
||||
coord2Layout->addWidget(m_editPoint2Z);
|
||||
coord2Layout->addStretch();
|
||||
layout->addLayout(coord2Layout);
|
||||
|
||||
// 连接回车信号
|
||||
connect(m_editPoint2X, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onPoint2CoordChanged);
|
||||
connect(m_editPoint2Y, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onPoint2CoordChanged);
|
||||
connect(m_editPoint2Z, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onPoint2CoordChanged);
|
||||
|
||||
// 点2姿态输入(紧凑布局)
|
||||
QHBoxLayout* pose2Layout = new QHBoxLayout();
|
||||
pose2Layout->setSpacing(5);
|
||||
@ -439,6 +522,11 @@ QGroupBox* CloudViewMainWindow::createMeasureGroup()
|
||||
connect(m_btnShowPose2, &QPushButton::clicked, this, &CloudViewMainWindow::onShowPose2);
|
||||
layout->addWidget(m_btnShowPose2);
|
||||
|
||||
// 连接姿态输入框的回车信号
|
||||
connect(m_editRx2, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowPose2);
|
||||
connect(m_editRy2, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowPose2);
|
||||
connect(m_editRz2, &QLineEdit::returnPressed, this, &CloudViewMainWindow::onShowPose2);
|
||||
|
||||
// 分隔线
|
||||
QFrame* line3 = new QFrame(group);
|
||||
line3->setFrameShape(QFrame::HLine);
|
||||
@ -838,6 +926,12 @@ void CloudViewMainWindow::onClearAll()
|
||||
m_lblPoint1->setText("点1: --");
|
||||
m_lblPoint2->setText("点2: --");
|
||||
m_lblDistance->setText("--");
|
||||
m_editPoint1X->setText("--");
|
||||
m_editPoint1Y->setText("--");
|
||||
m_editPoint1Z->setText("--");
|
||||
m_editPoint2X->setText("--");
|
||||
m_editPoint2Y->setText("--");
|
||||
m_editPoint2Z->setText("--");
|
||||
|
||||
// 清除选线信息
|
||||
m_lblLineIndex->setText("--");
|
||||
@ -859,6 +953,12 @@ void CloudViewMainWindow::onClearSelectedPoints()
|
||||
m_lblPoint1->setText("点1: --");
|
||||
m_lblPoint2->setText("点2: --");
|
||||
m_lblDistance->setText("--");
|
||||
m_editPoint1X->setText("--");
|
||||
m_editPoint1Y->setText("--");
|
||||
m_editPoint1Z->setText("--");
|
||||
m_editPoint2X->setText("--");
|
||||
m_editPoint2Y->setText("--");
|
||||
m_editPoint2Z->setText("--");
|
||||
statusBar()->showMessage("已清除选中的点");
|
||||
}
|
||||
|
||||
@ -901,41 +1001,45 @@ void CloudViewMainWindow::updateSelectedPointsDisplay()
|
||||
if (selectedPoints.size() >= 1 && selectedPoints[0].valid) {
|
||||
QString text;
|
||||
if (selectedPoints[0].lineIndex >= 0) {
|
||||
text = QString("点1: 线号:%1 点序:%2 x:%3 y:%4 z:%5")
|
||||
text = QString("点1: 线号:%1 点序:%2")
|
||||
.arg(selectedPoints[0].lineIndex)
|
||||
.arg(selectedPoints[0].pointIndexInLine)
|
||||
.arg(selectedPoints[0].x, 0, 'f', 3)
|
||||
.arg(selectedPoints[0].y, 0, 'f', 3)
|
||||
.arg(selectedPoints[0].z, 0, 'f', 3);
|
||||
.arg(selectedPoints[0].pointIndexInLine);
|
||||
} else {
|
||||
text = QString("点1: x:%1 y:%2 z:%3")
|
||||
.arg(selectedPoints[0].x, 0, 'f', 3)
|
||||
.arg(selectedPoints[0].y, 0, 'f', 3)
|
||||
.arg(selectedPoints[0].z, 0, 'f', 3);
|
||||
text = QString("点1:");
|
||||
}
|
||||
m_lblPoint1->setText(text);
|
||||
|
||||
// 更新坐标编辑框
|
||||
m_editPoint1X->setText(QString::number(selectedPoints[0].x, 'f', 3));
|
||||
m_editPoint1Y->setText(QString::number(selectedPoints[0].y, 'f', 3));
|
||||
m_editPoint1Z->setText(QString::number(selectedPoints[0].z, 'f', 3));
|
||||
} else {
|
||||
m_lblPoint1->setText("点1: --");
|
||||
m_editPoint1X->setText("--");
|
||||
m_editPoint1Y->setText("--");
|
||||
m_editPoint1Z->setText("--");
|
||||
}
|
||||
|
||||
if (selectedPoints.size() >= 2 && selectedPoints[1].valid) {
|
||||
QString text;
|
||||
if (selectedPoints[1].lineIndex >= 0) {
|
||||
text = QString("点2: 线号:%1 点序:%2 x:%3 y:%4 z:%5")
|
||||
text = QString("点2: 线号:%1 点序:%2")
|
||||
.arg(selectedPoints[1].lineIndex)
|
||||
.arg(selectedPoints[1].pointIndexInLine)
|
||||
.arg(selectedPoints[1].x, 0, 'f', 3)
|
||||
.arg(selectedPoints[1].y, 0, 'f', 3)
|
||||
.arg(selectedPoints[1].z, 0, 'f', 3);
|
||||
.arg(selectedPoints[1].pointIndexInLine);
|
||||
} else {
|
||||
text = QString("点2: x:%1 y:%2 z:%3")
|
||||
.arg(selectedPoints[1].x, 0, 'f', 3)
|
||||
.arg(selectedPoints[1].y, 0, 'f', 3)
|
||||
.arg(selectedPoints[1].z, 0, 'f', 3);
|
||||
text = QString("点2:");
|
||||
}
|
||||
m_lblPoint2->setText(text);
|
||||
|
||||
// 更新坐标编辑框
|
||||
m_editPoint2X->setText(QString::number(selectedPoints[1].x, 'f', 3));
|
||||
m_editPoint2Y->setText(QString::number(selectedPoints[1].y, 'f', 3));
|
||||
m_editPoint2Z->setText(QString::number(selectedPoints[1].z, 'f', 3));
|
||||
} else {
|
||||
m_lblPoint2->setText("点2: --");
|
||||
m_editPoint2X->setText("--");
|
||||
m_editPoint2Y->setText("--");
|
||||
m_editPoint2Z->setText("--");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1273,9 +1377,9 @@ void CloudViewMainWindow::onShowPose1()
|
||||
// 添加到显示
|
||||
m_glWidget->addPosePoints(poses);
|
||||
|
||||
statusBar()->showMessage(QString("已显示点1姿态 (%.3f, %.3f, %.3f) 旋转(%.1f°, %.1f°, %.1f°)")
|
||||
.arg(point.x).arg(point.y).arg(point.z)
|
||||
.arg(rx).arg(ry).arg(rz));
|
||||
statusBar()->showMessage(QString("已显示点1姿态 (%1, %2, %3) 旋转(%4°, %5°, %6°)")
|
||||
.arg(point.x, 0, 'f', 3).arg(point.y, 0, 'f', 3).arg(point.z, 0, 'f', 3)
|
||||
.arg(rx, 0, 'f', 1).arg(ry, 0, 'f', 1).arg(rz, 0, 'f', 1));
|
||||
|
||||
LOG_INFO("[CloudView] Show pose1 at (%.3f, %.3f, %.3f) with rotation (%.1f, %.1f, %.1f)\n",
|
||||
point.x, point.y, point.z, rx, ry, rz);
|
||||
@ -1338,9 +1442,9 @@ void CloudViewMainWindow::onShowPose2()
|
||||
// 添加到显示
|
||||
m_glWidget->addPosePoints(poses);
|
||||
|
||||
statusBar()->showMessage(QString("已显示点2姿态 (%.3f, %.3f, %.3f) 旋转(%.1f°, %.1f°, %.1f°)")
|
||||
.arg(point.x).arg(point.y).arg(point.z)
|
||||
.arg(rx).arg(ry).arg(rz));
|
||||
statusBar()->showMessage(QString("已显示点2姿态 (%1, %2, %3) 旋转(%4°, %5°, %6°)")
|
||||
.arg(point.x, 0, 'f', 3).arg(point.y, 0, 'f', 3).arg(point.z, 0, 'f', 3)
|
||||
.arg(rx, 0, 'f', 1).arg(ry, 0, 'f', 1).arg(rz, 0, 'f', 1));
|
||||
|
||||
LOG_INFO("[CloudView] Show pose2 at (%.3f, %.3f, %.3f) with rotation (%.1f, %.1f, %.1f)\n",
|
||||
point.x, point.y, point.z, rx, ry, rz);
|
||||
@ -1405,9 +1509,9 @@ void CloudViewMainWindow::onShowInputLine()
|
||||
float distance = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
|
||||
statusBar()->showMessage(QString("已显示线段 (%1,%2,%3) → (%4,%5,%6) 长度: %7")
|
||||
.arg(x1).arg(y1).arg(z1)
|
||||
.arg(x2).arg(y2).arg(z2)
|
||||
.arg(distance));
|
||||
.arg(x1, 0, 'f', 1).arg(y1, 0, 'f', 1).arg(z1, 0, 'f', 1)
|
||||
.arg(x2, 0, 'f', 1).arg(y2, 0, 'f', 1).arg(z2, 0, 'f', 1)
|
||||
.arg(distance, 0, 'f', 3));
|
||||
|
||||
LOG_INFO("[CloudView] Show input line from (%.3f, %.3f, %.3f) to (%.3f, %.3f, %.3f) length=%.3f\n",
|
||||
x1, y1, z1, x2, y2, z2, distance);
|
||||
@ -1665,3 +1769,95 @@ void CloudViewMainWindow::onViewAnglesChanged(float rotX, float rotY, float rotZ
|
||||
m_editRotZ->setText(QString::number(rotZ, 'f', 1));
|
||||
}
|
||||
|
||||
void CloudViewMainWindow::onPoint1CoordChanged()
|
||||
{
|
||||
auto selectedPoints = m_glWidget->getSelectedPoints();
|
||||
if (selectedPoints.isEmpty() || !selectedPoints[0].valid) {
|
||||
QMessageBox::warning(this, "提示", "请先选择点1");
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取编辑框中的坐标
|
||||
bool ok = true;
|
||||
float x = m_editPoint1X->text().toFloat(&ok);
|
||||
if (!ok) {
|
||||
QMessageBox::warning(this, "错误", "点1 X 值无效");
|
||||
return;
|
||||
}
|
||||
|
||||
float y = m_editPoint1Y->text().toFloat(&ok);
|
||||
if (!ok) {
|
||||
QMessageBox::warning(this, "错误", "点1 Y 值无效");
|
||||
return;
|
||||
}
|
||||
|
||||
float z = m_editPoint1Z->text().toFloat(&ok);
|
||||
if (!ok) {
|
||||
QMessageBox::warning(this, "错误", "点1 Z 值无效");
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新选中点的坐标
|
||||
m_glWidget->updateSelectedPointCoord(0, x, y, z);
|
||||
|
||||
// 如果启用了测距且有两个点,重新计算距离
|
||||
if (m_glWidget->isMeasureDistanceEnabled() && selectedPoints.size() >= 2 && selectedPoints[1].valid) {
|
||||
auto updatedPoints = m_glWidget->getSelectedPoints();
|
||||
if (updatedPoints.size() >= 2) {
|
||||
float distance = m_glWidget->calculateDistance(updatedPoints[0], updatedPoints[1]);
|
||||
m_lblDistance->setText(QString("%1 mm").arg(distance, 0, 'f', 3));
|
||||
statusBar()->showMessage(QString("点1坐标已更新,距离: %1 mm").arg(distance, 0, 'f', 3));
|
||||
}
|
||||
} else {
|
||||
statusBar()->showMessage(QString("点1坐标已更新为 (%1, %2, %3)").arg(x, 0, 'f', 3).arg(y, 0, 'f', 3).arg(z, 0, 'f', 3));
|
||||
}
|
||||
|
||||
LOG_INFO("[CloudView] Point1 coord updated to (%.3f, %.3f, %.3f)\n", x, y, z);
|
||||
}
|
||||
|
||||
void CloudViewMainWindow::onPoint2CoordChanged()
|
||||
{
|
||||
auto selectedPoints = m_glWidget->getSelectedPoints();
|
||||
if (selectedPoints.size() < 2 || !selectedPoints[1].valid) {
|
||||
QMessageBox::warning(this, "提示", "请先选择点2");
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取编辑框中的坐标
|
||||
bool ok = true;
|
||||
float x = m_editPoint2X->text().toFloat(&ok);
|
||||
if (!ok) {
|
||||
QMessageBox::warning(this, "错误", "点2 X 值无效");
|
||||
return;
|
||||
}
|
||||
|
||||
float y = m_editPoint2Y->text().toFloat(&ok);
|
||||
if (!ok) {
|
||||
QMessageBox::warning(this, "错误", "点2 Y 值无效");
|
||||
return;
|
||||
}
|
||||
|
||||
float z = m_editPoint2Z->text().toFloat(&ok);
|
||||
if (!ok) {
|
||||
QMessageBox::warning(this, "错误", "点2 Z 值无效");
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新选中点的坐标
|
||||
m_glWidget->updateSelectedPointCoord(1, x, y, z);
|
||||
|
||||
// 如果启用了测距,重新计算距离
|
||||
if (m_glWidget->isMeasureDistanceEnabled()) {
|
||||
auto updatedPoints = m_glWidget->getSelectedPoints();
|
||||
if (updatedPoints.size() >= 2) {
|
||||
float distance = m_glWidget->calculateDistance(updatedPoints[0], updatedPoints[1]);
|
||||
m_lblDistance->setText(QString("%1 mm").arg(distance, 0, 'f', 3));
|
||||
statusBar()->showMessage(QString("点2坐标已更新,距离: %1 mm").arg(distance, 0, 'f', 3));
|
||||
}
|
||||
} else {
|
||||
statusBar()->showMessage(QString("点2坐标已更新为 (%1, %2, %3)").arg(x, 0, 'f', 3).arg(y, 0, 'f', 3).arg(z, 0, 'f', 3));
|
||||
}
|
||||
|
||||
LOG_INFO("[CloudView] Point2 coord updated to (%.3f, %.3f, %.3f)\n", x, y, z);
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ PointCloudGLWidget::PointCloudGLWidget(QWidget* parent)
|
||||
, m_rotationX(0.0f)
|
||||
, m_rotationY(0.0f)
|
||||
, m_rotationZ(0.0f)
|
||||
, m_rotation(QQuaternion()) // 初始化为单位四元数
|
||||
, m_center(0, 0, 0)
|
||||
, m_pan(0, 0, 0)
|
||||
, m_minBound(-50, -50, -50)
|
||||
@ -128,18 +129,18 @@ void PointCloudGLWidget::paintGL()
|
||||
// 平移在相机空间中进行,使鼠标拖动方向与屏幕方向一致
|
||||
m_view.translate(-m_pan.x(), -m_pan.y(), -m_distance);
|
||||
|
||||
// 使用轨迹球旋转方式:先Y后X后Z,这样更直观
|
||||
m_view.rotate(m_rotationY, 0, 1, 0);
|
||||
m_view.rotate(m_rotationX, 1, 0, 0);
|
||||
m_view.rotate(m_rotationZ, 0, 0, 1);
|
||||
// 使用四元数旋转(物体坐标系旋转)
|
||||
m_view.rotate(m_rotation);
|
||||
|
||||
m_view.translate(-m_center);
|
||||
|
||||
// 调试输出:每100帧输出一次当前旋转角度
|
||||
static int frameCount = 0;
|
||||
if (++frameCount % 100 == 0) {
|
||||
LOG_INFO("[CloudView] Current rotation: rotX=%.1f, rotY=%.1f, rotZ=%.1f\n",
|
||||
m_rotationX, m_rotationY, m_rotationZ);
|
||||
// 从四元数转换为欧拉角用于显示
|
||||
QVector3D euler = m_rotation.toEulerAngles();
|
||||
LOG_INFO("[CloudView] Current rotation: pitch=%.1f, yaw=%.1f, roll=%.1f\n",
|
||||
euler.x(), euler.y(), euler.z());
|
||||
}
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
@ -427,7 +428,8 @@ void PointCloudGLWidget::resetView()
|
||||
|
||||
// 确保最小视距
|
||||
m_distance = qMax(maxSize * 2.0f, 10.0f);
|
||||
// 默认视角:右手坐标系,X轴朝右,Y轴朝上,Z轴朝向观察者
|
||||
// 重置旋转为单位四元数
|
||||
m_rotation = QQuaternion();
|
||||
m_rotationX = 0.0f;
|
||||
m_rotationY = 0.0f;
|
||||
m_rotationZ = 0.0f;
|
||||
@ -447,6 +449,9 @@ void PointCloudGLWidget::setViewAngles(float rotX, float rotY, float rotZ)
|
||||
m_rotationZ = rotZ;
|
||||
m_pan = QVector3D(0, 0, 0);
|
||||
|
||||
// 从欧拉角转换为四元数(ZYX顺序)
|
||||
m_rotation = QQuaternion::fromEulerAngles(rotX, rotY, rotZ);
|
||||
|
||||
LOG_INFO("[CloudView] setViewAngles: rotX=%.1f, rotY=%.1f, rotZ=%.1f\n", rotX, rotY, rotZ);
|
||||
|
||||
emit viewAnglesChanged(m_rotationX, m_rotationY, m_rotationZ);
|
||||
@ -548,6 +553,27 @@ float PointCloudGLWidget::calculateDistance(const SelectedPointInfo& p1, const S
|
||||
return std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::updateSelectedPointCoord(int index, float x, float y, float z)
|
||||
{
|
||||
if (index < 0 || index >= m_selectedPoints.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_selectedPoints[index].valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新选中点的坐标
|
||||
m_selectedPoints[index].x = x;
|
||||
m_selectedPoints[index].y = y;
|
||||
m_selectedPoints[index].z = z;
|
||||
|
||||
LOG_INFO("[CloudView] Updated selected point %d to (%.3f, %.3f, %.3f)\n", index, x, y, z);
|
||||
|
||||
// 刷新显示
|
||||
update();
|
||||
}
|
||||
|
||||
QVector<QVector3D> PointCloudGLWidget::getSelectedLinePoints() const
|
||||
{
|
||||
QVector<QVector3D> points;
|
||||
@ -901,10 +927,11 @@ void PointCloudGLWidget::drawSelectedLine()
|
||||
|
||||
void PointCloudGLWidget::drawAxis()
|
||||
{
|
||||
// 在右下角绘制坐标系指示器(右手坐标系)
|
||||
// 在右下角绘制坐标系指示器
|
||||
// 坐标系定义:X向右,Y向下,Z朝后
|
||||
// X轴:红色,指向右
|
||||
// Y轴:绿色,指向上
|
||||
// Z轴:蓝色,指向观察者(屏幕外)
|
||||
// Y轴:绿色,指向下
|
||||
// Z轴:蓝色,指向后(远离观察者)
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
@ -927,10 +954,10 @@ void PointCloudGLWidget::drawAxis()
|
||||
// 移动到右下角中心位置
|
||||
glTranslatef(axisX + axisSize / 2.0f, axisY + axisSize / 2.0f, 0.0f);
|
||||
|
||||
// 应用当前视图的旋转(与主视图同步)
|
||||
glRotatef(m_rotationY, 0, 1, 0);
|
||||
glRotatef(m_rotationX, 1, 0, 0);
|
||||
glRotatef(m_rotationZ, 0, 0, 1);
|
||||
// 应用当前视图的旋转(使用四元数转换为矩阵)
|
||||
QMatrix4x4 rotMatrix;
|
||||
rotMatrix.rotate(m_rotation);
|
||||
glMultMatrixf(rotMatrix.constData());
|
||||
|
||||
// 关闭深度测试,确保坐标系始终可见
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
@ -939,17 +966,17 @@ void PointCloudGLWidget::drawAxis()
|
||||
glLineWidth(2.0f);
|
||||
glBegin(GL_LINES);
|
||||
|
||||
// X 轴 - 红色(右手坐标系:向右)
|
||||
// X 轴 - 红色(向右)
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3f(axisLength, 0.0f, 0.0f);
|
||||
|
||||
// Y 轴 - 绿色(右手坐标系:向上)
|
||||
// Y 轴 - 绿色(向下,在屏幕坐标中是向上显示)
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3f(0.0f, axisLength, 0.0f);
|
||||
|
||||
// Z 轴 - 蓝色(右手坐标系:向观察者)
|
||||
// Z 轴 - 蓝色(向后,在屏幕坐标中是向观察者)
|
||||
glColor3f(0.0f, 0.0f, 1.0f);
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3f(0.0f, 0.0f, axisLength);
|
||||
@ -1060,15 +1087,37 @@ void PointCloudGLWidget::mouseMoveEvent(QMouseEvent* event)
|
||||
m_lastMousePos = event->pos();
|
||||
|
||||
if (m_leftButtonPressed) {
|
||||
// Alt+左键拖动:旋转rotZ(滚转)
|
||||
// Alt+左键拖动:绕视线方向旋转(滚转)
|
||||
if (event->modifiers() & Qt::AltModifier) {
|
||||
m_rotationZ += delta.x() * 0.5f;
|
||||
// 绕Z轴(视线方向)旋转(修正方向)
|
||||
float angle = -delta.x() * 0.5f; // 取反修正方向
|
||||
QQuaternion deltaRotation = QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), angle);
|
||||
m_rotation = deltaRotation * m_rotation;
|
||||
m_rotationZ += angle;
|
||||
} else {
|
||||
// 普通左键拖动:旋转rotX和rotY
|
||||
m_rotationY += delta.x() * 0.5f;
|
||||
m_rotationX += delta.y() * 0.5f;
|
||||
// 普通左键拖动:基于当前物体坐标系的旋转
|
||||
// 鼠标水平移动 -> 绕当前Y轴旋转
|
||||
// 鼠标垂直移动 -> 绕当前X轴旋转
|
||||
|
||||
// 计算旋转角度
|
||||
float angleX = delta.y() * 0.5f; // 垂直移动
|
||||
float angleY = delta.x() * 0.5f; // 水平移动
|
||||
|
||||
// 创建增量旋转四元数(在相机空间中)
|
||||
// 先绕X轴旋转(俯仰),再绕Y轴旋转(偏航)
|
||||
QQuaternion deltaRotationX = QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), angleX);
|
||||
QQuaternion deltaRotationY = QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), angleY);
|
||||
QQuaternion deltaRotation = deltaRotationY * deltaRotationX;
|
||||
|
||||
// 应用增量旋转(左乘,相机空间旋转)
|
||||
m_rotation = deltaRotation * m_rotation;
|
||||
|
||||
// 更新欧拉角(用于显示)
|
||||
m_rotationX += angleX;
|
||||
m_rotationY += angleY;
|
||||
}
|
||||
// 移除角度限制,允许无限旋转
|
||||
|
||||
// 发送角度变化信号
|
||||
emit viewAnglesChanged(m_rotationX, m_rotationY, m_rotationZ);
|
||||
update();
|
||||
} else if (m_middleButtonPressed) {
|
||||
@ -1077,7 +1126,11 @@ void PointCloudGLWidget::mouseMoveEvent(QMouseEvent* event)
|
||||
m_pan.setY(m_pan.y() + delta.y() * factor);
|
||||
update();
|
||||
} else if (m_rightButtonPressed) {
|
||||
m_rotationZ += delta.x() * 0.5f;
|
||||
// 右键拖动:绕视线方向旋转(滚转)(修正方向)
|
||||
float angle = -delta.x() * 0.5f; // 取反修正方向
|
||||
QQuaternion deltaRotation = QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), angle);
|
||||
m_rotation = deltaRotation * m_rotation;
|
||||
m_rotationZ += angle;
|
||||
emit viewAnglesChanged(m_rotationX, m_rotationY, m_rotationZ);
|
||||
update();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user