GrabBag/Tools/CloudView/Src/CloudViewMainWindow.cpp

708 lines
24 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "CloudViewMainWindow.h"
#include <QFileInfo>
#include <QDialog>
#include <QTextEdit>
#include <QTableWidget>
#include <QHeaderView>
#include <QVector3D>
#include "VrLog.h"
CloudViewMainWindow::CloudViewMainWindow(QWidget* parent)
: QMainWindow(parent)
, m_glWidget(nullptr)
, m_converter(std::make_unique<PointCloudConverter>())
, m_cloudCount(0)
, m_currentLineNum(0)
, m_currentLinePtNum(0)
, m_linePointsDialog(nullptr)
, m_linePointsTable(nullptr)
{
setupUI();
LOG_INFO("CloudViewMainWindow initialized\n");
}
CloudViewMainWindow::~CloudViewMainWindow()
{
}
void CloudViewMainWindow::setupUI()
{
// 创建中央控件
QWidget* centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
// 创建主布局
QHBoxLayout* mainLayout = new QHBoxLayout(centralWidget);
mainLayout->setContentsMargins(5, 5, 5, 5);
mainLayout->setSpacing(5);
// 创建分割器
QSplitter* splitter = new QSplitter(Qt::Horizontal, centralWidget);
// 左侧:点云显示区域
QWidget* viewerArea = createViewerArea();
splitter->addWidget(viewerArea);
// 右侧:控制面板
QWidget* controlPanel = createControlPanel();
splitter->addWidget(controlPanel);
// 设置分割器初始大小(左侧 70%,右侧 30%
splitter->setSizes({700, 300});
mainLayout->addWidget(splitter);
// 状态栏
statusBar()->showMessage("就绪");
}
QWidget* CloudViewMainWindow::createViewerArea()
{
QWidget* widget = new QWidget(this);
QVBoxLayout* layout = new QVBoxLayout(widget);
layout->setContentsMargins(0, 0, 0, 0);
m_glWidget = new PointCloudGLWidget(widget);
m_glWidget->setMinimumSize(400, 300); // 设置最小尺寸
m_glWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(m_glWidget);
// 连接信号
connect(m_glWidget, &PointCloudGLWidget::pointSelected,
this, &CloudViewMainWindow::onPointSelected);
connect(m_glWidget, &PointCloudGLWidget::twoPointsSelected,
this, &CloudViewMainWindow::onTwoPointsSelected);
connect(m_glWidget, &PointCloudGLWidget::lineSelected,
this, &CloudViewMainWindow::onLineSelected);
return widget;
}
QWidget* CloudViewMainWindow::createControlPanel()
{
QWidget* widget = new QWidget(this);
widget->setMaximumWidth(300);
QVBoxLayout* layout = new QVBoxLayout(widget);
layout->setContentsMargins(5, 5, 5, 5);
layout->setSpacing(10);
// 文件操作组
layout->addWidget(createFileGroup());
// 选点测距组
layout->addWidget(createMeasureGroup());
// 选线拟合组
layout->addWidget(createLineGroup());
// 点云列表组
layout->addWidget(createCloudListGroup());
// 添加弹性空间
layout->addStretch();
return widget;
}
QGroupBox* CloudViewMainWindow::createFileGroup()
{
QGroupBox* group = new QGroupBox("文件操作", this);
group->setMaximumWidth(300);
QVBoxLayout* layout = new QVBoxLayout(group);
m_btnOpenFile = new QPushButton("打开文件", group);
m_btnOpenFile->setMinimumHeight(30);
connect(m_btnOpenFile, &QPushButton::clicked, this, &CloudViewMainWindow::onOpenFile);
layout->addWidget(m_btnOpenFile);
m_btnClearAll = new QPushButton("清除所有", group);
connect(m_btnClearAll, &QPushButton::clicked, this, &CloudViewMainWindow::onClearAll);
layout->addWidget(m_btnClearAll);
m_btnResetView = new QPushButton("重置视图", group);
connect(m_btnResetView, &QPushButton::clicked, this, &CloudViewMainWindow::onResetView);
layout->addWidget(m_btnResetView);
return group;
}
QGroupBox* CloudViewMainWindow::createMeasureGroup()
{
QGroupBox* group = new QGroupBox("选点测距", this);
group->setMaximumWidth(300);
QVBoxLayout* layout = new QVBoxLayout(group);
// 操作说明
QLabel* lblTip = new QLabel("Ctrl+左键点击点云选择点", group);
lblTip->setWordWrap(true);
lblTip->setStyleSheet("color: gray; font-size: 10px;");
layout->addWidget(lblTip);
// 测距复选框
m_cbMeasureDistance = new QCheckBox("启用测距", group);
m_cbMeasureDistance->setChecked(false);
connect(m_cbMeasureDistance, &QCheckBox::toggled, this, [this](bool checked) {
m_glWidget->setMeasureDistanceEnabled(checked);
// 切换模式时清除已选点
m_glWidget->clearSelectedPoints();
m_lblPoint1->setText("--");
m_lblPoint2->setText("--");
m_lblDistance->setText("--");
});
layout->addWidget(m_cbMeasureDistance);
// 清除选点按钮
m_btnClearPoints = new QPushButton("清除选点", group);
connect(m_btnClearPoints, &QPushButton::clicked, this, &CloudViewMainWindow::onClearSelectedPoints);
layout->addWidget(m_btnClearPoints);
// 点1信息
QHBoxLayout* point1Layout = new QHBoxLayout();
QLabel* lblPoint1Title = new QLabel("点1:", group);
m_lblPoint1 = new QLabel("--", group);
m_lblPoint1->setWordWrap(true);
point1Layout->addWidget(lblPoint1Title);
point1Layout->addWidget(m_lblPoint1, 1);
layout->addLayout(point1Layout);
// 点2信息
QHBoxLayout* point2Layout = new QHBoxLayout();
QLabel* lblPoint2Title = new QLabel("点2:", group);
m_lblPoint2 = new QLabel("--", group);
m_lblPoint2->setWordWrap(true);
point2Layout->addWidget(lblPoint2Title);
point2Layout->addWidget(m_lblPoint2, 1);
layout->addLayout(point2Layout);
// 距离信息
QHBoxLayout* distLayout = new QHBoxLayout();
QLabel* lblDistTitle = new QLabel("距离:", group);
m_lblDistance = new QLabel("--", group);
m_lblDistance->setStyleSheet("font-weight: bold; color: green;");
distLayout->addWidget(lblDistTitle);
distLayout->addWidget(m_lblDistance, 1);
layout->addLayout(distLayout);
return group;
}
QGroupBox* CloudViewMainWindow::createLineGroup()
{
QGroupBox* group = new QGroupBox("选线", this);
group->setMaximumWidth(300);
QVBoxLayout* layout = new QVBoxLayout(group);
// 操作说明
QLabel* lblTip = new QLabel("Shift+左键点击点云选择线", group);
lblTip->setWordWrap(true);
lblTip->setStyleSheet("color: gray; font-size: 10px;");
layout->addWidget(lblTip);
// 选线模式选择
QHBoxLayout* modeLayout = new QHBoxLayout();
m_rbVertical = new QRadioButton("纵向", group);
m_rbHorizontal = new QRadioButton("横向", group);
m_rbVertical->setChecked(true);
connect(m_rbVertical, &QRadioButton::toggled, this, &CloudViewMainWindow::onLineSelectModeChanged);
modeLayout->addWidget(m_rbVertical);
modeLayout->addWidget(m_rbHorizontal);
layout->addLayout(modeLayout);
// 输入索引选择
QHBoxLayout* inputLayout = new QHBoxLayout();
m_lineNumberInput = new QLineEdit(group);
m_lineNumberInput->setPlaceholderText("输入索引");
m_btnSelectByNumber = new QPushButton("选择", group);
connect(m_btnSelectByNumber, &QPushButton::clicked, this, &CloudViewMainWindow::onSelectLineByNumber);
inputLayout->addWidget(m_lineNumberInput, 1);
inputLayout->addWidget(m_btnSelectByNumber);
layout->addLayout(inputLayout);
// 清除选线按钮
m_btnClearLine = new QPushButton("清除选线", group);
connect(m_btnClearLine, &QPushButton::clicked, this, &CloudViewMainWindow::onClearLinePoints);
layout->addWidget(m_btnClearLine);
// 显示线上点按钮
m_btnShowLinePoints = new QPushButton("显示线上点", group);
connect(m_btnShowLinePoints, &QPushButton::clicked, this, &CloudViewMainWindow::onShowLinePoints);
layout->addWidget(m_btnShowLinePoints);
// 线索引信息
QHBoxLayout* indexLayout = new QHBoxLayout();
QLabel* lblIndexTitle = new QLabel("索引:", group);
m_lblLineIndex = new QLabel("--", group);
indexLayout->addWidget(lblIndexTitle);
indexLayout->addWidget(m_lblLineIndex, 1);
layout->addLayout(indexLayout);
// 点数信息
QHBoxLayout* countLayout = new QHBoxLayout();
QLabel* lblCountTitle = new QLabel("点数:", group);
m_lblLinePointCount = new QLabel("--", group);
countLayout->addWidget(lblCountTitle);
countLayout->addWidget(m_lblLinePointCount, 1);
layout->addLayout(countLayout);
return group;
}
QGroupBox* CloudViewMainWindow::createCloudListGroup()
{
QGroupBox* group = new QGroupBox("点云列表", this);
group->setMaximumWidth(300);
QVBoxLayout* layout = new QVBoxLayout(group);
m_cloudList = new QListWidget(group);
m_cloudList->setMinimumHeight(100);
layout->addWidget(m_cloudList);
return group;
}
void CloudViewMainWindow::onOpenFile()
{
QString fileName = QFileDialog::getOpenFileName(
this,
"打开点云文件",
QString(),
"点云文件 (*.pcd *.txt);;PCD 文件 (*.pcd);;TXT 文件 (*.txt);;所有文件 (*.*)"
);
if (fileName.isEmpty()) {
return;
}
statusBar()->showMessage("正在加载点云...");
// 使用 PointCloudConverter 加载点云
PointCloudXYZ cloud;
int result = m_converter->loadFromFile(fileName.toStdString(), cloud);
if (result != 0) {
QMessageBox::critical(this, "错误",
QString("加载点云失败: %1").arg(QString::fromStdString(m_converter->getLastError())));
statusBar()->showMessage("加载失败");
return;
}
// 保存原始完整点云包含0,0,0点用于旋转
m_originalCloud = cloud;
// 添加到显示控件显示时会自动过滤0,0,0点
QFileInfo fileInfo(fileName);
QString cloudName = QString("Cloud_%1 (%2)").arg(++m_cloudCount).arg(fileInfo.fileName());
m_glWidget->addPointCloud(cloud, cloudName);
// 保存线信息(用于旋转功能)
int lineCount = m_converter->getLoadedLineCount();
if (lineCount > 0) {
m_currentLineNum = lineCount;
// 计算每线点数(假设均匀分布)
m_currentLinePtNum = static_cast<int>(m_converter->getLoadedPointCount()) / lineCount;
} else {
m_currentLineNum = 0;
m_currentLinePtNum = 0;
}
// 添加到列表
QString itemText;
if (lineCount > 0) {
itemText = QString("%1 - %2 点, %3 线").arg(cloudName).arg(m_converter->getLoadedPointCount()).arg(lineCount);
} else {
itemText = QString("%1 - %2 点").arg(cloudName).arg(m_converter->getLoadedPointCount());
}
m_cloudList->addItem(itemText);
statusBar()->showMessage(QString("已加载 %1 个点").arg(m_converter->getLoadedPointCount()));
}
void CloudViewMainWindow::onClearAll()
{
m_glWidget->clearPointClouds();
m_cloudList->clear();
m_cloudCount = 0;
m_currentLineNum = 0;
m_currentLinePtNum = 0;
m_originalCloud.clear();
// 清除选点信息
m_lblPoint1->setText("--");
m_lblPoint2->setText("--");
m_lblDistance->setText("--");
// 清除选线信息
m_lblLineIndex->setText("--");
m_lblLinePointCount->setText("--");
statusBar()->showMessage("已清除所有点云");
}
void CloudViewMainWindow::onResetView()
{
m_glWidget->resetView();
statusBar()->showMessage("视图已重置");
}
void CloudViewMainWindow::onClearSelectedPoints()
{
m_glWidget->clearSelectedPoints();
m_lblPoint1->setText("--");
m_lblPoint2->setText("--");
m_lblDistance->setText("--");
statusBar()->showMessage("已清除选中的点");
}
void CloudViewMainWindow::onPointSelected(const SelectedPointInfo& point)
{
if (!point.valid) {
return;
}
updateSelectedPointsDisplay();
// 状态栏显示:坐标、线号、索引号
QString statusMsg = QString("选中点: (%1, %2, %3)")
.arg(point.x, 0, 'f', 3)
.arg(point.y, 0, 'f', 3)
.arg(point.z, 0, 'f', 3);
if (point.lineIndex >= 0) {
statusMsg += QString(" | 线号: %1").arg(point.lineIndex);
if (point.pointIndexInLine >= 0) {
statusMsg += QString(" | 索引号: %1").arg(point.pointIndexInLine);
}
}
statusBar()->showMessage(statusMsg);
}
void CloudViewMainWindow::onTwoPointsSelected(const SelectedPointInfo& p1, const SelectedPointInfo& p2, float distance)
{
updateSelectedPointsDisplay();
m_lblDistance->setText(QString("%1 mm").arg(distance, 0, 'f', 3));
statusBar()->showMessage(QString("测量距离: %1 mm").arg(distance, 0, 'f', 3));
}
void CloudViewMainWindow::updateSelectedPointsDisplay()
{
auto selectedPoints = m_glWidget->getSelectedPoints();
if (selectedPoints.size() >= 1 && selectedPoints[0].valid) {
QString text;
if (selectedPoints[0].lineIndex >= 0) {
text = QString("线索引:%1 点索引:%2\nx: %3 y: %4 z: %5")
.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);
} else {
text = QString("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);
}
m_lblPoint1->setText(text);
} else {
m_lblPoint1->setText("--");
}
if (selectedPoints.size() >= 2 && selectedPoints[1].valid) {
QString text;
if (selectedPoints[1].lineIndex >= 0) {
text = QString("线索引:%1 点索引:%2\nx: %3 y: %4 z: %5")
.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);
} else {
text = QString("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);
}
m_lblPoint2->setText(text);
} else {
m_lblPoint2->setText("--");
}
}
void CloudViewMainWindow::onLineSelectModeChanged(bool checked)
{
if (checked) {
// 纵向模式
m_glWidget->setLineSelectMode(LineSelectMode::Vertical);
} else {
// 横向模式
m_glWidget->setLineSelectMode(LineSelectMode::Horizontal);
}
m_lineNumberInput->setPlaceholderText("输入索引");
}
void CloudViewMainWindow::onClearLinePoints()
{
m_glWidget->clearSelectedLine();
m_glWidget->clearListHighlightPoint(); // 清除列表选中的高亮点
m_lblLineIndex->setText("--");
m_lblLinePointCount->setText("--");
statusBar()->showMessage("已清除选线");
}
void CloudViewMainWindow::onLineSelected(const SelectedLineInfo& line)
{
// 重新选线时清除列表高亮点
m_glWidget->clearListHighlightPoint();
if (!line.valid) {
m_lblLineIndex->setText("--");
m_lblLinePointCount->setText("--");
return;
}
// 状态栏显示:线号/索引号、线点数
if (line.mode == LineSelectMode::Vertical) {
m_lblLineIndex->setText(QString::number(line.lineIndex));
statusBar()->showMessage(QString("选中线 | 线号: %1 | 线点数: %2")
.arg(line.lineIndex)
.arg(line.pointCount));
} else {
// 横向选线:显示索引号
m_lblLineIndex->setText(QString::number(line.pointIndex));
statusBar()->showMessage(QString("选中横向线 | 索引号: %1 | 线点数: %2")
.arg(line.pointIndex)
.arg(line.pointCount));
}
m_lblLinePointCount->setText(QString::number(line.pointCount));
// 如果线上点对话框已打开,刷新内容
updateLinePointsDialog();
}
void CloudViewMainWindow::onSelectLineByNumber()
{
if (m_glWidget->getCloudCount() == 0) {
QMessageBox::warning(this, "提示", "请先加载点云");
return;
}
QString text = m_lineNumberInput->text().trimmed();
if (text.isEmpty()) {
QMessageBox::warning(this, "提示", "请输入索引");
return;
}
bool ok;
int index = text.toInt(&ok);
if (!ok || index < 0) {
QMessageBox::warning(this, "提示", "请输入有效的索引(非负整数)");
return;
}
bool success = false;
if (m_rbVertical->isChecked()) {
// 纵向选线:直接使用索引
success = m_glWidget->selectLineByIndex(index);
if (!success) {
QMessageBox::warning(this, "提示", QString("索引 %1 不存在").arg(index));
}
} else {
// 横向选线:直接使用索引
success = m_glWidget->selectHorizontalLineByIndex(index);
if (!success) {
QMessageBox::warning(this, "提示", QString("索引 %1 不存在").arg(index));
}
}
}
QVector<QVector3D> CloudViewMainWindow::getOriginalLinePoints(const SelectedLineInfo& lineInfo)
{
QVector<QVector3D> points;
if (!lineInfo.valid || m_originalCloud.empty()) {
return points;
}
if (lineInfo.mode == LineSelectMode::Vertical) {
// 纵向选线:获取同一条扫描线上的所有点
for (size_t i = 0; i < m_originalCloud.points.size(); ++i) {
if (i < m_originalCloud.lineIndices.size() &&
m_originalCloud.lineIndices[i] == lineInfo.lineIndex) {
const auto& pt = m_originalCloud.points[i];
points.append(QVector3D(pt.x, pt.y, pt.z));
}
}
} else {
// 横向选线:获取所有线的相同索引点
if (m_currentLinePtNum > 0 && lineInfo.pointIndex >= 0) {
for (size_t i = 0; i < m_originalCloud.points.size(); ++i) {
int originalIdx = static_cast<int>(i);
if (originalIdx % m_currentLinePtNum == lineInfo.pointIndex) {
const auto& pt = m_originalCloud.points[i];
points.append(QVector3D(pt.x, pt.y, pt.z));
}
}
}
}
return points;
}
void CloudViewMainWindow::updateLinePointsDialog()
{
if (!m_linePointsDialog || !m_linePointsTable) {
return;
}
SelectedLineInfo lineInfo = m_glWidget->getSelectedLine();
if (!lineInfo.valid) {
m_linePointsTable->setRowCount(0);
m_linePointsDialog->setWindowTitle("线上点坐标");
m_currentLinePoints.clear();
return;
}
// 从原始数据获取线上点包含0,0,0
m_currentLinePoints = getOriginalLinePoints(lineInfo);
// 更新标题
QString title;
if (lineInfo.mode == LineSelectMode::Vertical) {
title = QString("线上点坐标 - 线号: %1 (共 %2 个点)")
.arg(lineInfo.lineIndex)
.arg(m_currentLinePoints.size());
} else {
title = QString("线上点坐标 - 索引号: %1 (共 %2 个点)")
.arg(lineInfo.pointIndex)
.arg(m_currentLinePoints.size());
}
m_linePointsDialog->setWindowTitle(title);
// 更新表格
m_linePointsTable->setRowCount(m_currentLinePoints.size());
// 斑马线颜色
QColor evenColor(245, 245, 245); // 浅灰色
QColor oddColor(255, 255, 255); // 白色
for (int i = 0; i < m_currentLinePoints.size(); ++i) {
const QVector3D& pt = m_currentLinePoints[i];
QColor rowColor = (i % 2 == 0) ? evenColor : oddColor;
// 序号
QTableWidgetItem* indexItem = new QTableWidgetItem(QString::number(i));
indexItem->setTextAlignment(Qt::AlignCenter);
indexItem->setBackground(rowColor);
indexItem->setFlags(indexItem->flags() & ~Qt::ItemIsEditable);
m_linePointsTable->setItem(i, 0, indexItem);
// X
QTableWidgetItem* xItem = new QTableWidgetItem(QString::number(pt.x(), 'f', 3));
xItem->setTextAlignment(Qt::AlignCenter);
xItem->setBackground(rowColor);
xItem->setFlags(xItem->flags() & ~Qt::ItemIsEditable);
m_linePointsTable->setItem(i, 1, xItem);
// Y
QTableWidgetItem* yItem = new QTableWidgetItem(QString::number(pt.y(), 'f', 3));
yItem->setTextAlignment(Qt::AlignCenter);
yItem->setBackground(rowColor);
yItem->setFlags(yItem->flags() & ~Qt::ItemIsEditable);
m_linePointsTable->setItem(i, 2, yItem);
// Z
QTableWidgetItem* zItem = new QTableWidgetItem(QString::number(pt.z(), 'f', 3));
zItem->setTextAlignment(Qt::AlignCenter);
zItem->setBackground(rowColor);
zItem->setFlags(zItem->flags() & ~Qt::ItemIsEditable);
m_linePointsTable->setItem(i, 3, zItem);
}
}
void CloudViewMainWindow::onShowLinePoints()
{
SelectedLineInfo lineInfo = m_glWidget->getSelectedLine();
if (!lineInfo.valid) {
QMessageBox::warning(this, "提示", "请先选择一条线");
return;
}
// 如果对话框已存在,刷新内容并显示
if (m_linePointsDialog) {
updateLinePointsDialog();
m_linePointsDialog->raise();
m_linePointsDialog->activateWindow();
return;
}
// 创建对话框
m_linePointsDialog = new QDialog(this);
m_linePointsDialog->resize(450, 500);
m_linePointsDialog->setAttribute(Qt::WA_DeleteOnClose);
// 对话框关闭时清理指针
connect(m_linePointsDialog, &QDialog::destroyed, this, [this]() {
m_linePointsDialog = nullptr;
m_linePointsTable = nullptr;
m_currentLinePoints.clear();
m_glWidget->clearListHighlightPoint();
});
QVBoxLayout* layout = new QVBoxLayout(m_linePointsDialog);
// 提示标签
QLabel* lblTip = new QLabel("点击行在3D视图中高亮显示", m_linePointsDialog);
lblTip->setStyleSheet("color: gray; font-size: 10px;");
layout->addWidget(lblTip);
// 创建表格控件
m_linePointsTable = new QTableWidget(m_linePointsDialog);
m_linePointsTable->setColumnCount(4);
m_linePointsTable->setHorizontalHeaderLabels({"序号", "X", "Y", "Z"});
m_linePointsTable->setFont(QFont("Consolas", 9));
m_linePointsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_linePointsTable->setSelectionMode(QAbstractItemView::SingleSelection);
m_linePointsTable->verticalHeader()->setVisible(false);
// 设置列宽
m_linePointsTable->setColumnWidth(0, 60); // 序号
m_linePointsTable->setColumnWidth(1, 110); // X
m_linePointsTable->setColumnWidth(2, 110); // Y
m_linePointsTable->setColumnWidth(3, 110); // Z
// 表头样式
m_linePointsTable->horizontalHeader()->setStretchLastSection(true);
m_linePointsTable->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);
connect(m_linePointsTable, &QTableWidget::cellClicked,
this, &CloudViewMainWindow::onLinePointTableClicked);
layout->addWidget(m_linePointsTable);
// 关闭按钮
QPushButton* btnClose = new QPushButton("关闭", m_linePointsDialog);
connect(btnClose, &QPushButton::clicked, m_linePointsDialog, &QDialog::close);
layout->addWidget(btnClose);
// 填充数据
updateLinePointsDialog();
m_linePointsDialog->show();
}
void CloudViewMainWindow::onLinePointTableClicked(int row, int column)
{
Q_UNUSED(column);
if (row >= 0 && row < m_currentLinePoints.size()) {
const QVector3D& pt = m_currentLinePoints[row];
m_glWidget->setListHighlightPoint(pt);
// 在状态栏显示选中点信息
statusBar()->showMessage(QString("列表选中点 %1: (%2, %3, %4)")
.arg(row)
.arg(pt.x(), 0, 'f', 3)
.arg(pt.y(), 0, 'f', 3)
.arg(pt.z(), 0, 'f', 3));
}
}