feat(vtk): 导入雷达入口移到顶部设备菜单(临时测试功能集中化)

This commit is contained in:
gaozheng 2026-06-30 22:41:54 +08:00
parent 11d7dd53b9
commit 1029bf5037
5 changed files with 84 additions and 72 deletions

View File

@ -129,14 +129,6 @@ QMenu* buildToolsMenu(QWidget* p)
return m; return m;
} }
QMenu* buildDeviceMenu(QWidget* p)
{
auto* m = new QMenu(QStringLiteral("设备"), p);
m->addAction(QStringLiteral("连接设备"));
m->addAction(QStringLiteral("设备管理"));
return m;
}
} // namespace } // namespace
TopBar::TopBar(QWidget* parent) : QWidget(parent) { TopBar::TopBar(QWidget* parent) : QWidget(parent) {
@ -220,7 +212,7 @@ TopBar::TopBar(QWidget* parent) : QWidget(parent) {
lay->addWidget(makeMenuButton(this, buildViewMenu())); lay->addWidget(makeMenuButton(this, buildViewMenu()));
lay->addWidget(makeMenuButton(this, buildProjectMenu())); lay->addWidget(makeMenuButton(this, buildProjectMenu()));
lay->addWidget(makeMenuButton(this, buildToolsMenu(this))); lay->addWidget(makeMenuButton(this, buildToolsMenu(this)));
lay->addWidget(makeMenuButton(this, buildDeviceMenu(this))); lay->addWidget(makeMenuButton(this, buildDeviceMenu()));
lay->addStretch(); lay->addStretch();
@ -333,6 +325,21 @@ QMenu* TopBar::buildProjectMenu() {
return m; return m;
} }
// 设备菜单。连接设备/设备管理为占位;「导入雷达测线」是后端未就绪期的过渡测试入口,集中到设备菜单。
// 原入口在三维体段头按钮(已移除);子项规范化/Impulse 分别 emit radarImportRequested(false/true)
// 由 main 接到既有导入流程。
QMenu* TopBar::buildDeviceMenu() {
auto* m = new QMenu(QStringLiteral("设备"), this);
m->addAction(QStringLiteral("连接设备"));
m->addAction(QStringLiteral("设备管理"));
QMenu* radar = m->addMenu(QStringLiteral("导入雷达测线"));
radar->addAction(QStringLiteral("规范化测线目录(.head/.data)…"), this,
[this] { emit radarImportRequested(false); });
radar->addAction(QStringLiteral("Impulse 测线目录(.iprb)…"), this,
[this] { emit radarImportRequested(true); });
return m;
}
bool TopBar::eventFilter(QObject* obj, QEvent* event) { bool TopBar::eventFilter(QObject* obj, QEvent* event) {
if (obj == userRow_ && event->type() == QEvent::MouseButtonRelease) { if (obj == userRow_ && event->type() == QEvent::MouseButtonRelease) {
if (userMenu_) if (userMenu_)

View File

@ -32,10 +32,13 @@ signals:
// 项目管理菜单中「直接嵌入」的 web 页被点击title=窗口标题target=嵌入页 target 路径。 // 项目管理菜单中「直接嵌入」的 web 页被点击title=窗口标题target=嵌入页 target 路径。
void webPageRequested(const QString& title, const QString& target); void webPageRequested(const QString& title, const QString& target);
void analysisViewRequested(); // 视图菜单「分析视图」→ 中央区切回默认工作台 void analysisViewRequested(); // 视图菜单「分析视图」→ 中央区切回默认工作台
// 设备菜单「导入雷达测线」(后端未就绪的过渡测试入口)false=规范化(.head/.data)true=Impulse(.iprb)。
void radarImportRequested(bool impulse);
private: private:
QMenu* buildViewMenu(); // 视图菜单(成员:「分析视图」需 emit 信号) QMenu* buildViewMenu(); // 视图菜单(成员:「分析视图」需 emit 信号)
QMenu* buildProjectMenu(); // 项目管理菜单成员webview 叶子项需 emit 信号) QMenu* buildProjectMenu(); // 项目管理菜单成员webview 叶子项需 emit 信号)
QMenu* buildDeviceMenu(); // 设备菜单(成员:「导入雷达测线」子项需 emit 信号)
QToolButton* wsBtn_ = nullptr; QToolButton* wsBtn_ = nullptr;
QToolButton* projBtn_ = nullptr; QToolButton* projBtn_ = nullptr;

View File

@ -1061,66 +1061,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
analysisTab->scrollItemToTop(qid); // 新三维体行尽量滚到分析栏顶部 analysisTab->scrollItemToTop(qid); // 新三维体行尽量滚到分析栏顶部
}); });
}); });
// 本地导入三维雷达测线(后端未就绪的过渡入口):入口=三维体段头「+ 导入雷达测线」按钮(CategorySection) // 本地导入三维雷达测线(后端未就绪的过渡测试入口):入口已迁至 TopBar「设备」菜单
// → analysisTab.radarImportRequested(impulse)。app 无原生菜单栏(menuBar 被 TopBar 经 setMenuWidget 占用), // →「导入雷达测线」二级项(emit TopBar::radarImportRequested)。接线在 topBar 创建后(见下方设备菜单接线)
// 故入口放可见的段头按钮。impulse=false 走规范化(.head/.data, 懒加载后台建体)true 走 Impulse(.iprb, eager)。 // 因 topBar 此处尚未构造;导入流程目标不变。
QObject::connect(
analysisTab, &geopro::app::CategoryAnalysisTab::radarImportRequested, &window,
[&window, scene3dRepo, refreshAnalysis, analysisTab, vtkLoading](bool impulse) {
if (!impulse) { // 规范化 .head/.data → registerRadarDataset(dd_radar_3d, 懒加载后台建体)
const QString dir = QFileDialog::getExistingDirectory(
&window, QStringLiteral("选择规范化三维雷达测线目录(含 *.head/*.data)"));
if (dir.isEmpty()) return;
bool ok = false;
const QString prefix = QInputDialog::getText(
&window, QStringLiteral("测线前缀"),
QStringLiteral("输入测线前缀(如 南同大道_000)"), QLineEdit::Normal, QString(), &ok);
if (!ok || prefix.isEmpty()) return;
// structParentId 暂空(P0 挂三维体段根P1 接 TM 归属)。
// coarse=1 全分辨率(沿线不抽稀):验收期要肉眼判读反射/双曲线/通道连续性,
// 不能被沿线抽稀糊掉。单线峰值内存 ~0.71.5GB(spec §8.4);若 OOM 退回 2。
const std::string newId = scene3dRepo->registerRadarDataset(
dir.toLocal8Bit().toStdString(), prefix.toLocal8Bit().toStdString(),
prefix.toStdString(), /*structParentId=*/std::string(), /*coarse=*/1);
{ const QSignalBlocker block(analysisTab); refreshAnalysis(); } // DS 进三维体段(不触发渲染)
const QString qid = QString::fromStdString(newId);
analysisTab->setItemChecked(qid, true); // 勾选 → addDatasetAsync → loadVolume 后台建体渲染
analysisTab->setItemBusy(qid, true); // spinner; 渲染完成由 datasetRendered 撤
analysisTab->scrollItemToTop(qid);
return;
}
// 明星路 Impulse(.iprb):复用现成 createGprVolume(eager 同步建体,预填 cachedGrid)。双数据集互证下游几何无关。
const QString dir = QFileDialog::getExistingDirectory(
&window, QStringLiteral("选择 Impulse 测线目录(含 *.iprb/*.ord)"));
if (dir.isEmpty()) return;
bool ok = false;
const QString prefix = QInputDialog::getText(
&window, QStringLiteral("测线前缀"),
QStringLiteral("输入测线前缀(如 明星路_010)"), QLineEdit::Normal, QString(), &ok);
if (!ok || prefix.isEmpty()) return;
vtkLoading->showOver(QStringLiteral("正在建Impulse体…"));
// 内层捕获 window 引用(非 [=] 值拷贝)QMainWindow 拷贝构造已删除,且 showToast 需非 const QWidget*。
QTimer::singleShot(0, &window, [=, &window]() {
std::string newId;
try {
newId = scene3dRepo->createGprVolume(dir.toLocal8Bit().toStdString(),
prefix.toLocal8Bit().toStdString(),
prefix.toStdString(), /*coarse=*/8);
} catch (const std::exception& e) {
vtkLoading->hide();
geopro::app::showToast(&window,
QStringLiteral("建体失败:%1").arg(QString::fromLocal8Bit(e.what())));
return;
}
{ const QSignalBlocker block(analysisTab); refreshAnalysis(); }
vtkLoading->hide();
const QString qid = QString::fromStdString(newId);
// createGprVolume 预填 cachedGrid → setItemChecked 内 loadVolume 同步渲染、datasetRendered 自动撤 busy
// 故此处【不要】再 setItemBusy(true)(否则 spinner 永久转圈)。
analysisTab->setItemChecked(qid, true);
analysisTab->scrollItemToTop(qid);
});
});
// 任一数据集(剖面/体)异步加载开始 → 列表项复选框转等待 spinner渲染完成 → 复原复选框。 // 任一数据集(剖面/体)异步加载开始 → 列表项复选框转等待 spinner渲染完成 → 复原复选框。
// 覆盖非三维体:勾选剖面首次渲染较慢时也有等待反馈(用户反馈)。 // 覆盖非三维体:勾选剖面首次渲染较慢时也有等待反馈(用户反馈)。
QObject::connect(sceneCtrl, &geopro::controller::VtkSceneController::datasetLoading, analysisTab, QObject::connect(sceneCtrl, &geopro::controller::VtkSceneController::datasetLoading, analysisTab,
@ -1772,6 +1715,66 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
centralStack->setCurrentWidget(dockManager); centralStack->setCurrentWidget(dockManager);
}); });
// 设备菜单「导入雷达测线」(后端未就绪的过渡测试入口):原入口在三维体段头按钮(已移除),集中到设备菜单。
// impulse=false 走规范化(.head/.data, 懒加载后台建体)true 走 Impulse(.iprb, eager)。导入流程目标不变。
QObject::connect(
topBar, &geopro::app::TopBar::radarImportRequested, &window,
[&window, scene3dRepo, refreshAnalysis, analysisTab, vtkLoading](bool impulse) {
if (!impulse) { // 规范化 .head/.data → registerRadarDataset(dd_radar_3d, 懒加载后台建体)
const QString dir = QFileDialog::getExistingDirectory(
&window, QStringLiteral("选择规范化三维雷达测线目录(含 *.head/*.data)"));
if (dir.isEmpty()) return;
bool ok = false;
const QString prefix = QInputDialog::getText(
&window, QStringLiteral("测线前缀"),
QStringLiteral("输入测线前缀(如 南同大道_000)"), QLineEdit::Normal, QString(), &ok);
if (!ok || prefix.isEmpty()) return;
// structParentId 暂空(P0 挂三维体段根P1 接 TM 归属)。
// coarse=1 全分辨率(沿线不抽稀):验收期要肉眼判读反射/双曲线/通道连续性,
// 不能被沿线抽稀糊掉。单线峰值内存 ~0.71.5GB(spec §8.4);若 OOM 退回 2。
const std::string newId = scene3dRepo->registerRadarDataset(
dir.toLocal8Bit().toStdString(), prefix.toLocal8Bit().toStdString(),
prefix.toStdString(), /*structParentId=*/std::string(), /*coarse=*/1);
{ const QSignalBlocker block(analysisTab); refreshAnalysis(); } // DS 进三维体段(不触发渲染)
const QString qid = QString::fromStdString(newId);
analysisTab->setItemChecked(qid, true); // 勾选 → addDatasetAsync → loadVolume 后台建体渲染
analysisTab->setItemBusy(qid, true); // spinner; 渲染完成由 datasetRendered 撤
analysisTab->scrollItemToTop(qid);
return;
}
// 明星路 Impulse(.iprb):复用现成 createGprVolume(eager 同步建体,预填 cachedGrid)。双数据集互证下游几何无关。
const QString dir = QFileDialog::getExistingDirectory(
&window, QStringLiteral("选择 Impulse 测线目录(含 *.iprb/*.ord)"));
if (dir.isEmpty()) return;
bool ok = false;
const QString prefix = QInputDialog::getText(
&window, QStringLiteral("测线前缀"),
QStringLiteral("输入测线前缀(如 明星路_010)"), QLineEdit::Normal, QString(), &ok);
if (!ok || prefix.isEmpty()) return;
vtkLoading->showOver(QStringLiteral("正在建Impulse体…"));
// 内层捕获 window 引用(非 [=] 值拷贝)QMainWindow 拷贝构造已删除,且 showToast 需非 const QWidget*。
QTimer::singleShot(0, &window, [=, &window]() {
std::string newId;
try {
newId = scene3dRepo->createGprVolume(dir.toLocal8Bit().toStdString(),
prefix.toLocal8Bit().toStdString(),
prefix.toStdString(), /*coarse=*/8);
} catch (const std::exception& e) {
vtkLoading->hide();
geopro::app::showToast(&window,
QStringLiteral("建体失败:%1").arg(QString::fromLocal8Bit(e.what())));
return;
}
{ const QSignalBlocker block(analysisTab); refreshAnalysis(); }
vtkLoading->hide();
const QString qid = QString::fromStdString(newId);
// createGprVolume 预填 cachedGrid → setItemChecked 内 loadVolume 同步渲染、datasetRendered 自动撤 busy
// 故此处【不要】再 setItemBusy(true)(否则 spinner 永久转圈)。
analysisTab->setItemChecked(qid, true);
analysisTab->scrollItemToTop(qid);
});
});
// 切换到「不同项目」时先清空中央区,避免新项目残留旧项目的三栏数据与 VTK 渲染。 // 切换到「不同项目」时先清空中央区,避免新项目残留旧项目的三栏数据与 VTK 渲染。
// 仅真正换项目用delete-refresh 等 switchProject(currentProjectId) 不走此处,避免误清)。 // 仅真正换项目用delete-refresh 等 switchProject(currentProjectId) 不走此处,避免误清)。
auto clearCentral = [emptyState, checkedProfiles, checkedAnalysis, auto clearCentral = [emptyState, checkedProfiles, checkedAnalysis,

View File

@ -50,8 +50,8 @@ CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* d
}); });
connect(sec, &CategorySection::generateVolumeRequested, this, connect(sec, &CategorySection::generateVolumeRequested, this,
&CategoryAnalysisTab::generateVolumeRequested); &CategoryAnalysisTab::generateVolumeRequested);
// 注:CategorySection 的「+导入雷达测线」入口已移除Task D1 迁至 TopBar。CategoryAnalysisTab // 注:「导入雷达测线」入口已迁至 TopBar「设备」菜单Task D1CategorySection 段头按钮与
// 自身仍保留 radarImportRequested 信号(main.cpp 的连接保持有效),待 D1 由 TopBar 新发射方接入 // CategoryAnalysisTab::radarImportRequested 信号均已移除
connect(sec, &CategorySection::detailRequested, this, &CategoryAnalysisTab::detailRequested); connect(sec, &CategorySection::detailRequested, this, &CategoryAnalysisTab::detailRequested);
connect(sec, &CategorySection::deleteDatasetRequested, this, connect(sec, &CategorySection::deleteDatasetRequested, this,
&CategoryAnalysisTab::deleteDatasetRequested); &CategoryAnalysisTab::deleteDatasetRequested);

View File

@ -40,7 +40,6 @@ public:
signals: signals:
void checkedDatasetsChanged(const QStringList& dsIds); // 5 段勾选并集 void checkedDatasetsChanged(const QStringList& dsIds); // 5 段勾选并集
void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds);
void radarImportRequested(bool impulse); // 三维体段头「+导入雷达测线」(false=规范化, true=Impulse)
void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); void detailRequested(const QString& dsId, const QString& ddCode, const QString& name);
void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除切片/异常 void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除切片/异常
// ── 三维体段操作转发(迁自旧 Column3DAnalysis全接── // ── 三维体段操作转发(迁自旧 Column3DAnalysis全接──