diff --git a/src/app/TopBar.cpp b/src/app/TopBar.cpp index aba8d82..f9ec52c 100644 --- a/src/app/TopBar.cpp +++ b/src/app/TopBar.cpp @@ -129,14 +129,6 @@ QMenu* buildToolsMenu(QWidget* p) return m; } -QMenu* buildDeviceMenu(QWidget* p) -{ - auto* m = new QMenu(QStringLiteral("设备"), p); - m->addAction(QStringLiteral("连接设备")); - m->addAction(QStringLiteral("设备管理")); - return m; -} - } // namespace 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, buildProjectMenu())); lay->addWidget(makeMenuButton(this, buildToolsMenu(this))); - lay->addWidget(makeMenuButton(this, buildDeviceMenu(this))); + lay->addWidget(makeMenuButton(this, buildDeviceMenu())); lay->addStretch(); @@ -333,6 +325,21 @@ QMenu* TopBar::buildProjectMenu() { 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) { if (obj == userRow_ && event->type() == QEvent::MouseButtonRelease) { if (userMenu_) diff --git a/src/app/TopBar.hpp b/src/app/TopBar.hpp index e19478a..4c11c8a 100644 --- a/src/app/TopBar.hpp +++ b/src/app/TopBar.hpp @@ -32,10 +32,13 @@ signals: // 项目管理菜单中「直接嵌入」的 web 页被点击:title=窗口标题,target=嵌入页 target 路径。 void webPageRequested(const QString& title, const QString& target); void analysisViewRequested(); // 视图菜单「分析视图」→ 中央区切回默认工作台 + // 设备菜单「导入雷达测线」(后端未就绪的过渡测试入口):false=规范化(.head/.data),true=Impulse(.iprb)。 + void radarImportRequested(bool impulse); private: QMenu* buildViewMenu(); // 视图菜单(成员:「分析视图」需 emit 信号) QMenu* buildProjectMenu(); // 项目管理菜单(成员:webview 叶子项需 emit 信号) + QMenu* buildDeviceMenu(); // 设备菜单(成员:「导入雷达测线」子项需 emit 信号) QToolButton* wsBtn_ = nullptr; QToolButton* projBtn_ = nullptr; diff --git a/src/app/main.cpp b/src/app/main.cpp index a72fb18..70db0f5 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -1061,66 +1061,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re analysisTab->scrollItemToTop(qid); // 新三维体行尽量滚到分析栏顶部 }); }); - // 本地导入三维雷达测线(后端未就绪的过渡入口):入口=三维体段头「+ 导入雷达测线」按钮(CategorySection) - // → analysisTab.radarImportRequested(impulse)。app 无原生菜单栏(menuBar 被 TopBar 经 setMenuWidget 占用), - // 故入口放可见的段头按钮。impulse=false 走规范化(.head/.data, 懒加载后台建体);true 走 Impulse(.iprb, eager)。 - 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.7–1.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); - }); - }); + // 本地导入三维雷达测线(后端未就绪的过渡测试入口):入口已迁至 TopBar「设备」菜单 + // →「导入雷达测线」二级项(emit TopBar::radarImportRequested)。接线在 topBar 创建后(见下方设备菜单接线), + // 因 topBar 此处尚未构造;导入流程目标不变。 // 任一数据集(剖面/体)异步加载开始 → 列表项复选框转等待 spinner;渲染完成 → 复原复选框。 // 覆盖非三维体:勾选剖面首次渲染较慢时也有等待反馈(用户反馈)。 QObject::connect(sceneCtrl, &geopro::controller::VtkSceneController::datasetLoading, analysisTab, @@ -1772,6 +1715,66 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re 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.7–1.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 渲染。 // 仅真正换项目用(delete-refresh 等 switchProject(currentProjectId) 不走此处,避免误清)。 auto clearCentral = [emptyState, checkedProfiles, checkedAnalysis, diff --git a/src/app/panels/columns/CategoryAnalysisTab.cpp b/src/app/panels/columns/CategoryAnalysisTab.cpp index 894cf91..8c12088 100644 --- a/src/app/panels/columns/CategoryAnalysisTab.cpp +++ b/src/app/panels/columns/CategoryAnalysisTab.cpp @@ -50,8 +50,8 @@ CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* d }); connect(sec, &CategorySection::generateVolumeRequested, this, &CategoryAnalysisTab::generateVolumeRequested); - // 注:CategorySection 的「+导入雷达测线」入口已移除(Task D1 迁至 TopBar)。CategoryAnalysisTab - // 自身仍保留 radarImportRequested 信号(main.cpp 的连接保持有效),待 D1 由 TopBar 新发射方接入。 + // 注:「导入雷达测线」入口已迁至 TopBar「设备」菜单(Task D1);CategorySection 段头按钮与 + // CategoryAnalysisTab::radarImportRequested 信号均已移除。 connect(sec, &CategorySection::detailRequested, this, &CategoryAnalysisTab::detailRequested); connect(sec, &CategorySection::deleteDatasetRequested, this, &CategoryAnalysisTab::deleteDatasetRequested); diff --git a/src/app/panels/columns/CategoryAnalysisTab.hpp b/src/app/panels/columns/CategoryAnalysisTab.hpp index dfcba5c..61cabbe 100644 --- a/src/app/panels/columns/CategoryAnalysisTab.hpp +++ b/src/app/panels/columns/CategoryAnalysisTab.hpp @@ -40,7 +40,6 @@ public: signals: void checkedDatasetsChanged(const QStringList& dsIds); // 5 段勾选并集 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 deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除切片/异常 // ── 三维体段操作转发(迁自旧 Column3DAnalysis,全接)──