GrabBag/Tools/CloudView/Src/CloudViewMainWindow.cpp

708 lines
24 KiB
C++
Raw Normal View History

2026-01-16 01:04:43 +08:00
#include "CloudViewMainWindow.h"
#include <QFileInfo>
#include <QDialog>
#include <QTextEdit>
#include <QTableWidget>
#include <QHeaderView>
#include <QVector3D>
2026-01-16 01:04:43 +08:00
#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)
2026-01-16 01:04:43 +08:00
{
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);
2026-01-16 01:04:43 +08:00
// 清除选点按钮
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);
2026-01-16 01:04:43 +08:00
// 线索引信息
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)")
2026-01-16 01:04:43 +08:00
.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);
2026-01-16 01:04:43 +08:00
}
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;
2026-01-16 01:04:43 +08:00
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);
2026-01-16 01:04:43 +08:00
}
m_lblPoint1->setText(text);
} else {
m_lblPoint1->setText("--");
}
if (selectedPoints.size() >= 2 && selectedPoints[1].valid) {
QString text;
2026-01-16 01:04:43 +08:00
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);
2026-01-16 01:04:43 +08:00
}
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(); // 清除列表选中的高亮点
2026-01-16 01:04:43 +08:00
m_lblLineIndex->setText("--");
m_lblLinePointCount->setText("--");
statusBar()->showMessage("已清除选线");
}
void CloudViewMainWindow::onLineSelected(const SelectedLineInfo& line)
{
// 重新选线时清除列表高亮点
m_glWidget->clearListHighlightPoint();
2026-01-16 01:04:43 +08:00
if (!line.valid) {
m_lblLineIndex->setText("--");
m_lblLinePointCount->setText("--");
return;
}
// 状态栏显示:线号/索引号、线点数
2026-01-16 01:04:43 +08:00
if (line.mode == LineSelectMode::Vertical) {
m_lblLineIndex->setText(QString::number(line.lineIndex));
statusBar()->showMessage(QString("选中线 | 线号: %1 | 线点数: %2")
2026-01-16 01:04:43 +08:00
.arg(line.lineIndex)
.arg(line.pointCount));
} else {
// 横向选线:显示索引号
2026-01-16 01:04:43 +08:00
m_lblLineIndex->setText(QString::number(line.pointIndex));
statusBar()->showMessage(QString("选中横向线 | 索引号: %1 | 线点数: %2")
2026-01-16 01:04:43 +08:00
.arg(line.pointIndex)
.arg(line.pointCount));
}
m_lblLinePointCount->setText(QString::number(line.pointCount));
// 如果线上点对话框已打开,刷新内容
updateLinePointsDialog();
2026-01-16 01:04:43 +08:00
}
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));
}
}