From 42a7ed16d402724adba52849c1f9dec9b979dbe4 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Mon, 8 Jun 2026 09:13:25 +0800 Subject: [PATCH] =?UTF-8?q?fix(app):=20=E7=A7=BB=E9=99=A4=E4=BB=A4?= =?UTF-8?q?=E4=BA=BA=E5=9B=B0=E6=83=91=E7=9A=84=E3=80=8C=E4=BD=93=E7=B4=A0?= =?UTF-8?q?=E3=80=8D=E5=B7=A5=E5=85=B7=E6=9D=A1=E5=BC=80=E5=85=B3(?= =?UTF-8?q?=E4=B8=8E=E4=BA=8C=E7=BB=B4/=E4=B8=89=E7=BB=B4=E5=B9=B3?= =?UTF-8?q?=E7=BA=A7=E4=B8=94=E4=B8=8D=E5=9C=A8=E5=8E=9F=E5=9E=8B)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dd_voxel 体素引擎(buildVoxelFromScatters)保留:已 PNG 核对 + 单测验证,是合格积木。 - 但把它做成中央工具条开关是设计失误:与"二维/三维"互斥视图平级却是复选、且仅 3D 生效, 令人困惑(重蹈上会话"2维/3维/体素混淆"覆辙),且原型中央只有「二维地图|三维视图」。 - 中央恢复干净两视图(对齐原型)。体素待做 3D 图层控制(对齐原型「视图详情」浮层)再正经接入。 - 同步移除 app 内 CrsTransform/PROJ_DATA 等仅为该开关的接线; render 层引擎与测试不动。 --- docs/superpowers/STATUS.md | 6 +- .../plans/2026-06-07-m1-phase4-render.md | 2 +- src/app/main.cpp | 65 +------------------ 3 files changed, 7 insertions(+), 66 deletions(-) diff --git a/docs/superpowers/STATUS.md b/docs/superpowers/STATUS.md index 536ec1d..053c45b 100644 --- a/docs/superpowers/STATUS.md +++ b/docs/superpowers/STATUS.md @@ -16,7 +16,7 @@ - **左 对象树**:GS→TM→DS,复选框勾选 → 控制中央显示哪些测线。 - **中央 二维地图 / 三维视图**(两个**真内容**,非相机切换): - 二维地图 = `MapLineActor`:测线 `lat/lon` 轨迹**红线**俯视(浅底),像地图。 - - 三维视图 = `CurtainActor`:沿测线的**竖直断面墙**(分段色带,z 纵向夸张×3,沿弯曲测线弯)。工具条「体素」开关(仅 3D)= `buildVoxelFromScatters`:两交叉测线散点经 **EPSG:4547→GeoLocalFrame** 配准 + IDW 成体素(十字片),与帘面同纵向夸张叠加(派生产物;2 线→薄十字片,可信满体需≥3线)。 + - 三维视图 = `CurtainActor`:沿测线的**竖直断面墙**(分段色带,z 纵向夸张×3,沿弯曲测线弯)。中央工具条**仅**「二维地图/三维视图」(对齐原型,无体素按钮)。 - **下方 数据详情**:工具条「原数据/网格数据」切换 +「显示异常」开关(对齐原型命名)。单击数据集 → 网格数据=`GridContourActor` 平面剖面(#18,colorBar 真实非均匀分段值上色,纵向夸张×1.5);原数据=`ScatterActor` 彩色方块散点(#17,x=距离/y=深度取负,用散点自带色阶);显示异常=`AnomalyActor` 在上图叠加异常 dashed 折线(同纵向夸张对齐)。 - **右 属性**:名称/网格 nx×ny/vmin·vmax。 - 单元测试累计 **36 个全绿**(core/data/net/render;含 Scatter 2 + Anomaly 4 + VoxelRegister 1、修复了陈旧的 Curtain mapper 类型断言);离屏 `verify_section/map/curtain_3d/scatter/section_anomaly/voxel_top/voxel_3d.png` 均核对正确(scatter 吻合 ref_17、异常吻合 ref_18、体素 footprint 吻合 ref voxel_hslice 的两臂支撑)。 @@ -29,7 +29,7 @@ | P1 | core(LocalFrame/模型/ColorScale/IDW/CrsTransform/GeoLocalFrame) | ✅ | | P2 | data(解析器/LocalSampleRepository)+ 对象树 | ✅ | | P3 | 登录(RsaEncryptor/ApiClient/AuthService/LoginWindow) | ✅(**Credential 记住免登录未做**) | -| P4 | 渲染:render 层 + 二维地图(线)+ 三维视图(帘面/体素)+ 数据详情(#18/#17/异常) | 🔶 **三视图 + 散点#17 + 异常叠加 + dd_voxel回归 已对**;**DEM地形(需加gdal) / 底图瓦片 未做;交互切片(dd_slice)未做;布局对齐原型(左下数据列表/右上异常列表/电极/底图)未做** | +| P4 | 渲染:render 层 + 二维地图(线)+ 三维视图(帘面)+ 数据详情(#18/#17/异常) | 🔶 **三视图 + 散点#17 + 异常叠加 已对; dd_voxel 引擎已验证(UI 未接,待 3D 图层控制)**;**DEM地形(需加gdal) / 底图瓦片 / dd_slice / 布局对齐原型(左下数据列表/右上异常列表/电极/3D图层浮层) 未做** | ## 3. 构建约定(**机器本地**) @@ -67,7 +67,7 @@ 1. ~~**散点 #17**:`ScatterActor`(剖面原数据 2597 点彩色散点),数据详情"原数据"视图~~ ✅ **已完成**(2026-06-08,离屏 PNG 核对吻合 Python 真值,接入数据详情「反演剖面/原数据」切换;app 待人工登录肉眼复核交互)。 2. ~~**异常叠加**:`AnomalyActor`(markType 点/线/面)~~ ✅ **已完成**(2026-06-08,叠加在数据详情 #18/#17 上,「显示异常」开关默认开;离屏 `verify_section_anomaly.png` 折线位置吻合 ref_18;样本 3 异常均 markType=2 dashed;app 待人工登录复核)。**注**:dashed 点画在 VTK OpenGL2 下偏弱(几乎实线),几何/颜色/位置正确,纯观感项可后续调。 3. **DEM/影像地形**:加 vcpkg `gdal`;GDAL 读 dem.tif/image.tif;**影像 EPSG:3857 必须 PROJ 重投影到世界系**;`vtkWarpScalar` 地形面 + 纹理。 -4. ~~**dd_voxel 回归**~~ ✅ **已完成**(2026-06-08,CRS 已定 EPSG:4547)。`render::buildVoxelFromScatters`:散点 projX/Y→4547→4326→GeoLocalFrame 配准 + IDW(maxDist 裁剪)→ `buildVoxel`;接入 app 3D 视图「体素」开关(默认关,与帘面同纵向夸张)。离屏 `verify_voxel_top.png` 两臂支撑吻合 ref voxel_hslice、`verify_voxel_3d.png` profile1 片贴合帘面;+1 单测(VoxelRegister)。**注**:仅 2 交叉线→薄十字片(15.9% 充填),体绘制半透明偏淡(低不透明度固有);可信满体需≥3线(设计 §10/§14)。**dd_slice 交互切片未做**(buildVoxel 已暴露 image 供后续 reslice widget)。app 待人工登录复核 + 运行时须 PROJ_DATA(main() 已按候选路径自动设;部署须随包附带 proj 数据)。 +4. **dd_voxel 回归**:🔶 **引擎已完成并验证**(2026-06-08,CRS 已定 EPSG:4547)。`render::buildVoxelFromScatters`:散点 projX/Y→4547→4326→GeoLocalFrame 配准 + IDW(maxDist 裁剪)→ `buildVoxel`;离屏 `verify_voxel_top.png` 两臂支撑吻合 ref voxel_hslice、`verify_voxel_3d.png` profile1 片贴合帘面;+1 单测(VoxelRegister,需 PROJ_DATA)。**UI 未接入**:曾加"体素"工具条开关,但与二维/三维平级令人困惑且不在原型,**已移除**;待做 **3D 图层控制(对齐原型「视图详情」浮层)** 再正经接入(届时 main() 需设 PROJ_DATA + 部署随包附带 proj 数据)。**注**:仅 2 交叉线→薄十字片(15.9% 充填,半透明偏淡),可信满体需≥3线(设计 §10/§14)。**dd_slice 交互切片未做**(buildVoxel 已暴露 image 供 reslice widget)。 5. **底图瓦片**(二维地图,天地图/Mapbox):M1.5。 6. **Credential(QtKeychain)**:记住一个月免登录持久化(P3 Task2 未做)。 7. 多测线:当前样本仅 1 条 dd_section(grid1);多条共存机制已就绪,加数据即叠加。 diff --git a/docs/superpowers/plans/2026-06-07-m1-phase4-render.md b/docs/superpowers/plans/2026-06-07-m1-phase4-render.md index ee37075..7ce9b4a 100644 --- a/docs/superpowers/plans/2026-06-07-m1-phase4-render.md +++ b/docs/superpowers/plans/2026-06-07-m1-phase4-render.md @@ -4,7 +4,7 @@ > **⚠️ 状态(2026-06-07,务必先读 `2026-06-07-m1-view-redesign.md` + STATUS.md):** > - **Task 1(render 层 + 相机预设)**:✅ 已完成。但中央"单场景平躺剖面 + 2D/3D 仅换相机"的做法**已被 view-redesign 取代** —— 现在中央是 **二维地图(测线线)/ 三维视图(竖直帘面)两种内容**(详见 view-redesign 的"实施结果")。 -> - **Task 2(dd_voxel 体绘制+切片)**:🔶 **体绘制+回归 ✅ 已完成**(2026-06-08,CRS 已实证定 EPSG:4547)。`buildVoxelFromScatters`(散点→4547→4326→GeoLocalFrame 配准 + IDW)→ `buildVoxel`;接入 app 3D「体素」开关。离屏 PNG 两臂支撑吻合 ref voxel_hslice、profile1 片贴合帘面;+1 单测。**dd_slice 交互切片 ⬜ 未做**(image 已暴露供 reslice widget)。 +> - **Task 2(dd_voxel 体绘制+切片)**:🔶 **引擎+回归 ✅ 已验证**(2026-06-08,CRS 已实证定 EPSG:4547)。`buildVoxelFromScatters`(散点→4547→4326→GeoLocalFrame 配准 + IDW)→ `buildVoxel`;离屏 PNG 两臂支撑吻合 ref voxel_hslice、profile1 片贴合帘面;+1 单测。**UI 未接入**(曾加"体素"工具条开关,因与二维/三维平级困惑且不在原型,已移除;待 3D 图层控制对齐原型「视图详情」浮层再接)。**dd_slice 交互切片 ⬜ 未做**(image 已暴露供 reslice widget)。 > - **Task 3(散点#17 + 异常叠加)**:✅ **已完成**(2026-06-08)。散点#17=`ScatterActor`(吻合 ref_17);异常叠加=`AnomalyActor`(点/线/面,叠在数据详情#18/#17,「显示异常」开关,吻合 ref_18)。数据详情切换按原型命名「原数据/网格数据」。+6 单测,全 35 测试绿;app 待人工登录复核。布局对齐原型其余项见 STATUS §6.10。 > - **Task 4(DEM/影像地形)**:⬜ 未做(P4 下次,需先确认 CRS + 加 gdal)。 > 渲染必须用 `tests/spike/render_verify.cpp` 离屏 PNG 核对(本会话教训)。 diff --git a/src/app/main.cpp b/src/app/main.cpp index a83618b..560fe2f 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -3,9 +3,9 @@ // - 中央「二维地图 / 三维视图」:两个互斥视图(内容不同,不是同一物体换相机)。 // 二维地图 = 对每个勾选数据集 buildSurveyLine(lat/lon 红线俯视,z=0)+ applyTop2D(浅底背景)。 // 三维视图 = 对每个勾选数据集 buildCurtain(竖直断面墙),actor SetScale(1,1,3) 纵向夸张 + applyFree3D(白底)。 -// 工具条「体素」开关(仅三维有效)= 两交叉测线散点经 EPSG:4547→GeoLocalFrame 配准 IDW 成体素, -// 与帘面同纵向夸张叠加(派生产物,非对象树节点;输入仅 2 线→薄十字片,可信满体需≥3线)。 // 切视图 / 勾选变化 → 按当前勾选集重建对应内容。 +// 注:dd_voxel 体素引擎(render::buildVoxelFromScatters)已就绪并验证,但**不**作为工具条开关 +// (那样与二维/三维平级会令人困惑、且不在原型);待做 3D 图层控制(对齐原型「视图详情」浮层)再接。 // - 下方「数据详情」:独立 QVTK 小视图 + 工具条「原数据 / 网格数据」切换 +「显示异常」开关(对齐原型)。 // 单击某 DS → 显示该数据集: // 网格数据 = #18 banded 等值面+等值线(两 actor SetScale(1,1.5,1) 纵向夸张)。 @@ -24,9 +24,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -48,18 +46,15 @@ #include "CameraPreset.hpp" #include "Scene.hpp" -#include "VoxelFromScatters.hpp" #include "actors/AnomalyActor.hpp" #include "actors/CurtainActor.hpp" #include "actors/GridContourActor.hpp" #include "actors/MapLineActor.hpp" #include "actors/ScatterActor.hpp" -#include "geo/CrsTransform.hpp" #include "geo/GeoLocalFrame.hpp" #include -#include #include #include @@ -132,10 +127,6 @@ constexpr float kScatterPointSize = 4.0F; constexpr double kCurtainZScale = 3.0; constexpr double kDetailYScale = 1.5; -// 项目 CRS(实证确定,STATUS §4):散点 projX/Y -> 经纬,再经 GeoLocalFrame 配准体素到世界系。 -constexpr const char* kProjectCrs = "EPSG:4547"; // CGCS2000 / 3-degree GK CM 114E -constexpr const char* kWgs84 = "EPSG:4326"; - // 在给定 QMainWindow 上构建 M1 工作台。 // repo 生命周期须覆盖到事件循环结束(由调用方保证)。 void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& repo) @@ -162,15 +153,6 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re // 当前视图模式(全局共享,切视图/勾选时据此重建内容)。默认二维地图。 auto viewMode = std::make_shared(ViewMode::Map2D); - // 体素显隐 + 项目 CRS→WGS84 变换(体素配准用)。PROJ 失败则置空 → 体素开关无效(不崩)。 - auto showVoxel = std::make_shared(false); - std::shared_ptr crs; - try { - crs = std::make_shared(kProjectCrs, kWgs84); - } catch (const std::exception&) { - crs.reset(); - } - auto* dockManager = new ads::CDockManager(&window); window.setCentralWidget(dockManager); @@ -191,11 +173,6 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re viewGroup->addAction(act2D); viewGroup->addAction(act3D); act2D->setChecked(true); // 默认二维地图 - // 「体素」开关:仅三维视图有效,叠加 dd_voxel 体绘制(两交叉测线配准成十字片)。默认关。 - viewToolBar->addSeparator(); - auto* actVoxel = viewToolBar->addAction(QStringLiteral("体素")); - actVoxel->setCheckable(true); - actVoxel->setChecked(false); centerLayout->addWidget(viewToolBar); centerLayout->addWidget(vtkWidget, 1); @@ -265,8 +242,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re // 二维地图 = buildSurveyLine(红线俯视,浅底背景)+ applyTop2D。 // 三维视图 = buildCurtain(断面墙)SetScale(1,1,kCurtainZScale) + applyFree3D(白底)。 // frame 全局共享;切视图/勾选变化都调用此函数重建当前视图。 - auto rebuildCentral = [scene, rendererPtr, renderWindowPtr, viewMode, &repo, frame, tree, - showVoxel, crs]() { + auto rebuildCentral = [scene, rendererPtr, renderWindowPtr, viewMode, &repo, frame, tree]() { scene->clear(); const bool is2D = (*viewMode == ViewMode::Map2D); @@ -300,18 +276,6 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re } } - // 三维视图 + 体素开关:两交叉测线散点经 CRS 配准 IDW 成体素(十字片), - // 与帘面同纵向夸张对齐叠加(派生产物,非对象树节点)。 - if (!is2D && *showVoxel && crs) { - const auto profs = repo.loadVoxelScatters(); - const auto vcs = repo.loadScatterColorScale("grid1"); - auto vr = geopro::render::buildVoxelFromScatters(profs, vcs, *crs, *frame); - if (vr.valid()) { - vr.volume->SetScale(1.0, 1.0, kCurtainZScale); // 与帘面同纵向夸张 - rendererPtr->AddVolume(vr.volume); - } - } - if (is2D) geopro::render::applyTop2D(rendererPtr); else @@ -428,11 +392,6 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re *viewMode = ViewMode::View3D; rebuildCentral(); }); - // 「体素」开关:切换 dd_voxel 叠加 → 重建中央(仅三维视图可见)。 - QObject::connect(actVoxel, &QAction::toggled, vtkWidget, [showVoxel, rebuildCentral](bool on) { - *showVoxel = on; - rebuildCentral(); - }); // ── 启动默认:dd_section 已勾选,但 itemChanged 在 connect 之前触发故未渲染。 // 这里 connect 之后主动按默认视图(二维地图)重建一次中央内容。 @@ -447,24 +406,6 @@ int main(int argc, char* argv[]) QSurfaceFormat::setDefaultFormat(QVTKOpenGLStereoWidget::defaultFormat()); QApplication app(argc, argv); - // PROJ 数据(proj.db)定位:体素配准的 CrsTransform 需要。优先已设环境变量; - // 否则按 exe 旁 / 构建目录候选设置。部署时须随包附带 proj 数据并设此变量。 - if (qEnvironmentVariableIsEmpty("PROJ_DATA")) { - const QString appDir = QCoreApplication::applicationDirPath(); - const QStringList candidates = { - appDir + "/proj", - appDir + "/../../vcpkg_installed/x64-windows/share/proj", - QStringLiteral( - "D:/Git/lanbingtech/geopro/build/release/vcpkg_installed/x64-windows/share/proj"), - }; - for (const auto& c : candidates) { - if (QFile::exists(c + "/proj.db")) { - qputenv("PROJ_DATA", c.toUtf8()); - break; - } - } - } - // 网络层:共享会话 ApiClient + 登录编排 AuthService(RSA 公钥从 resources 读取)。 geopro::net::ApiClient api(QStringLiteral("http://tenant.geomative.cn/pop-api")); const std::string pem = readPem("D:/Git/lanbingtech/geopro/resources/rsa_public_key.pem");