From 308361d9355a12fc5806a165996f8fa7fe1ce1e7 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Sun, 7 Jun 2026 17:44:28 +0800 Subject: [PATCH] =?UTF-8?q?plan:=20M1=20Phase=200=20=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=BC=95=E5=AF=BC+Spike=E9=A2=84=E7=A0=94=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plans/2026-06-07-m1-phase0-spikes.md | 357 ++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-07-m1-phase0-spikes.md diff --git a/docs/superpowers/plans/2026-06-07-m1-phase0-spikes.md b/docs/superpowers/plans/2026-06-07-m1-phase0-spikes.md new file mode 100644 index 0000000..ffec735 --- /dev/null +++ b/docs/superpowers/plans/2026-06-07-m1-phase0-spikes.md @@ -0,0 +1,357 @@ +# M1 Phase 0:环境引导 + Spike 预研 实现计划 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 证明全 vcpkg(Qt+VTK[qt] 共用一份 Qt)工具链可编译/运行/部署,并跑通三个最高风险技术点(构建部署、ADS+QVTK 停靠稳定、真实样本 banded contour 渲染),作为展开完整 M1 实现的前置门槛。 + +**Architecture:** 在已铺好的工程骨架(`src/app` 冒烟程序)上,先打通构建与部署,再增量接入 ADS,最后用一个独立 render spike 复刻设计图 #18(网格等值面)验证 VTK 管线选型。每个 spike 有明确的「通过判据」。 + +**Tech Stack:** CMake 3.21+ / vcpkg(manifest) / MSVC 2022 / Qt 6.8 / VTK 9.3+ / ADS / GoogleTest。 + +**前置条件(由你完成,见 `docs/ENV_SETUP_Windows.md`):** 已装 VS2022(C++ 桌面开发 + AddressSanitizer)、Git、vcpkg 并设 `VCPKG_ROOT`。所有命令在 **x64 Native Tools for VS 2022** 命令行、项目根目录执行。 + +**通过判据汇总(三 spike 全绿才进入 Phase 1):** +- S1 构建/部署:`cmake --build` 出 `geopro_desktop.exe`,运行显示锥体;exe 目录只有一份 `Qt6*.dll`;`ctest` 通过。 +- S2 ADS+QVTK:VTK 面板可停靠/浮动/重停靠,**无黑屏/崩溃**,相机交互正常。 +- S3 渲染管线:用真实 `剖面网格数据1.txt` + 色阶,VTK 渲染出 banded 等值面+等值线,目视对照 `docs/_validate/ref_18_grid.png` 一致。 + +--- + +## Task 1:vcpkg 基线锁定 + 首次构建(Spike S1:构建) + +**Files:** +- Modify: `vcpkg.json`(写入 builtin-baseline) + +- [ ] **Step 1: 锁定依赖基线** + +Run: +```powershell +vcpkg x-update-baseline --add-initial-baseline +``` +Expected: `vcpkg.json` 新增 `"builtin-baseline": "<40位SHA>"`。`git diff vcpkg.json` 可见该字段。 + +- [ ] **Step 2: 首次 configure(会编译 Qt+VTK,耗时长)** + +Run: +```powershell +cmake --preset msvc-debug +``` +Expected: 末尾 `-- Configuring done / -- Generating done`。首次会构建 qtbase/vtk 等,可能数十分钟到数小时(建议先配 `VCPKG_BINARY_SOURCES` 缓存)。 +若报 `qt-advanced-docking-system` 端口不可用 → 暂时从 `vcpkg.json` 移除该项重跑(ADS 改 Task 3 用 FetchContent),记录该事实。 + +- [ ] **Step 3: 构建冒烟程序** + +Run: +```powershell +cmake --build build/debug --target geopro_desktop +``` +Expected: 生成 `build/debug/src/app/geopro_desktop.exe`,无编译/链接错误。 + +- [ ] **Step 4: 运行,肉眼验证渲染** + +Run: +```powershell +.\build\debug\src\app\geopro_desktop.exe +``` +Expected: 弹出深色背景窗口,中央显示一个白色**锥体**,可被默认 VTK 交互器旋转。 + +- [ ] **Step 5: 验证单一 Qt(无双份)** + +Run: +```powershell +Get-ChildItem build\debug\src\app\Qt6Core.dll | Select-Object FullName +Get-ChildItem build\debug\src\app -Filter "Qt6*.dll" | Measure-Object | Select-Object Count +``` +Expected: 仅一份来自 vcpkg 的 `Qt6Core.dll`(路径在 exe 目录);无另一处官方 Qt 混入。 + +- [ ] **Step 6: 提交** + +```powershell +git add vcpkg.json +git commit -m "build: 锁定 vcpkg 基线, 打通全 vcpkg Qt+VTK 构建(spike S1)" +``` + +--- + +## Task 2:gtest 工具链冒烟(Spike S1:测试) + +**Files:** +- 已存在 `tests/CMakeLists.txt` / `tests/smoke_test.cpp`(脚手架) + +- [ ] **Step 1: 构建测试目标** + +Run: +```powershell +cmake --build build/debug --target geopro_tests +``` +Expected: 生成 `build/debug/tests/geopro_tests.exe`,无错误。 + +- [ ] **Step 2: 运行 ctest** + +Run: +```powershell +ctest --test-dir build/debug --output-on-failure +``` +Expected: `100% tests passed`(`SmokeTest.ToolchainWorks`)。 + +- [ ] **Step 3: 提交(若有 CMake 调整)** + +```powershell +git commit -am "test: 验证 gtest+ctest 工具链(spike S1)" --allow-empty +``` + +--- + +## Task 3:ADS 停靠集成 + VTK 面板稳定性(Spike S2) + +**Files:** +- Modify: `src/app/CMakeLists.txt`(链接 ADS) +- Modify: `src/app/main.cpp`(用 ADS CDockManager 承载 VTK 面板) +- Modify: `CMakeLists.txt`(find_package ADS 或 FetchContent) + +- [ ] **Step 1: 在 CMake 接入 ADS** + +在 `CMakeLists.txt` 顶层依赖区追加(端口名以 vcpkg 实际为准,二选一): +```cmake +# 优先 vcpkg 端口(名称在 spike 期确认,常见为 qtadvanceddocking-qt6) +find_package(qtadvanceddocking-qt6 CONFIG QUIET) +if(NOT qtadvanceddocking-qt6_FOUND) + include(FetchContent) + FetchContent_Declare(ads + GIT_REPOSITORY https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git + GIT_TAG 4.3.1) + set(ADS_VERSION 4.3.1 CACHE STRING "" FORCE) + set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(ads) +endif() +``` +Expected: configure 时 ADS 可被找到或拉取。 + +- [ ] **Step 2: app 链接 ADS** + +在 `src/app/CMakeLists.txt` 的 `target_link_libraries(geopro_desktop PRIVATE ...)` 追加 ADS 目标(名称二选一,configure 报错时换): +```cmake +target_link_libraries(geopro_desktop PRIVATE ads::qt6advanceddocking) +# 若上者不存在,试 ads::ads 或 qt6advanceddocking +``` + +- [ ] **Step 3: 改 main.cpp:用 ADS 承载 VTK 面板** + +将 `src/app/main.cpp` 的 `setCentralWidget` 替换为 ADS 停靠管理器,VTK widget 放入一个 DockWidget: +```cpp +#include +#include +#include +// ... main() 内,创建 vtkWidget 后: +auto* dockManager = new ads::CDockManager(&window); +auto* vtkDock = new ads::CDockWidget(QStringLiteral("三维视图")); +vtkDock->setWidget(vtkWidget); +dockManager->addDockWidget(ads::CenterDockWidgetArea, vtkDock); +// 再加两个占位 dock 以便测试停靠/浮动: +auto* leftDock = new ads::CDockWidget(QStringLiteral("对象列表")); +leftDock->setWidget(new QLabel(QStringLiteral("(占位)"))); +dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock); +// 移除原 window.setCentralWidget(vtkWidget); +``` +(顶部补 `#include `。) + +- [ ] **Step 4: 构建并运行** + +Run: +```powershell +cmake --build build/debug --target geopro_desktop +.\build\debug\src\app\geopro_desktop.exe +``` +Expected: 窗口出现「对象列表」「三维视图」两个停靠面板,三维面板里是锥体。 + +- [ ] **Step 5: 手工稳定性测试(S2 判据)** + +操作:把「三维视图」面板**拖出浮动 → 再拖回停靠 → 切换到不同停靠区**,反复 3 次。 +Expected: 每次重停靠后锥体**正常渲染、不黑屏、不崩溃**。若黑屏 → 记录,按设计 §K-9 改用 `QVTKOpenGLStereoWidget`(已在用)并将 VTK 面板设为不可浮动 `vtkDock->setFeature(ads::CDockWidget::DockWidgetFloatable, false)` 后复测。 + +- [ ] **Step 6: 提交** + +```powershell +git add -A +git commit -m "feat(app): ADS 停靠承载 VTK 面板, 验证浮动/重停靠稳定(spike S2)" +``` + +--- + +## Task 4:真实样本 banded contour 渲染(Spike S3) + +验证设计 §4.3 网格管线选型:`vtkImageData(+warp) → vtkDataSetSurfaceFilter → vtkBandedPolyDataContourFilter(GenerateContourEdgesOn)` 能复刻图 #18。本任务产出一个独立小程序,代码后续移入 `render/actors/GridContourActor`。 + +**Files:** +- Create: `tests/spike/grid_contour_spike.cpp` +- Create: `tests/spike/CMakeLists.txt` +- Modify: `tests/CMakeLists.txt`(add_subdirectory spike) +- 读数据:`docs/剖面网格数据的色阶数据2等文件/剖面网格数据1.txt`、`剖面网格数据的色阶数据1.txt` + +- [ ] **Step 1: 写 spike 程序(读网格 JSON → vtkImageData → banded contour → 截图)** + +Create `tests/spike/grid_contour_spike.cpp`: +```cpp +// Spike S3:用真实网格样本验证 banded contour 管线,离屏渲染保存 PNG, +// 目视对照 docs/_validate/ref_18_grid.png。 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using json = nlohmann::json; + +int main(int argc, char** argv) { + const std::string dir = "../../docs/剖面网格数据的色阶数据2等文件/"; // 相对 build/debug/tests/spike + std::ifstream gf(dir + "剖面网格数据1.txt"); + json g = json::parse(gf)["data"]; + auto x = g["x"].get>(); // 100, 规则 + auto y = g["y"].get>(); // 22, 规则 + auto v = g["v"].get>>(); // [22][100] = [j=y][i=x] + const int nx = (int)x.size(), ny = (int)y.size(); + const double dx = x[1] - x[0], dy = y[1] - y[0]; + + vtkNew img; + img->SetDimensions(nx, ny, 1); + img->SetOrigin(x[0], y[0], 0.0); + img->SetSpacing(dx, dy, 1.0); + vtkNew sc; + sc->SetName("v"); + sc->SetNumberOfTuples(nx * ny); + for (int j = 0; j < ny; ++j) + for (int i = 0; i < nx; ++i) + sc->SetValue(j * nx + i, v[j][i]); // i 最快,匹配 vtkImageData 点序 + img->GetPointData()->SetScalars(sc); + + // 色阶 → 离散 LUT + std::ifstream cf(dir + "剖面网格数据的色阶数据1.txt"); + json cb = json::parse(cf)["data"]["properties"]["colorBar"]; + std::vector stops; + for (auto& pr : cb) stops.push_back(std::stod(pr[0].get())); + std::sort(stops.begin(), stops.end()); + + vtkNew surf; + surf->SetInputData(img); + + vtkNew banded; + banded->SetInputConnection(surf->GetOutputPort()); + banded->GenerateValues((int)stops.size(), stops.front(), stops.back()); + banded->GenerateContourEdgesOn(); // 同时产出等值线边 + + vtkNew lut; + lut->SetNumberOfTableValues((int)stops.size()); + lut->SetTableRange(stops.front(), stops.back()); + // 颜色解析略:spike 阶段可先用 lut->Build() 默认色带验证管线,色彩精确映射放 render 层 + lut->Build(); + + vtkNew mapper; + mapper->SetInputConnection(banded->GetOutputPort()); + mapper->SetScalarModeToUseCellData(); + mapper->SetLookupTable(lut); + mapper->SetScalarRange(stops.front(), stops.back()); + + vtkNew actor; actor->SetMapper(mapper); + vtkNew ren; ren->AddActor(actor); ren->SetBackground(1,1,1); ren->ResetCamera(); + vtkNew rw; rw->SetOffScreenRendering(1); rw->AddRenderer(ren); rw->SetSize(1100, 320); rw->Render(); + + vtkNew w2i; w2i->SetInput(rw); + vtkNew png; png->SetFileName("spike_grid_contour.png"); + png->SetInputConnection(w2i->GetOutputPort()); png->Write(); + return 0; +} +``` + +- [ ] **Step 2: 写 spike 的 CMake** + +Create `tests/spike/CMakeLists.txt`: +```cmake +find_package(nlohmann_json CONFIG REQUIRED) +add_executable(grid_contour_spike grid_contour_spike.cpp) +target_link_libraries(grid_contour_spike PRIVATE ${VTK_LIBRARIES} nlohmann_json::nlohmann_json) +vtk_module_autoinit(TARGETS grid_contour_spike MODULES ${VTK_LIBRARIES}) +``` +在 `tests/CMakeLists.txt` 末尾追加: +```cmake +add_subdirectory(spike) +``` + +- [ ] **Step 3: 构建** + +Run: +```powershell +cmake --build build/debug --target grid_contour_spike +``` +Expected: 生成 `build/debug/tests/spike/grid_contour_spike.exe`,**编译通过**(关键:证明 `vtkImageData→surface→banded contour` 管线类型正确,设计 §4.3 的 B-1/B-2 修正成立)。 + +- [ ] **Step 4: 运行并对照** + +Run: +```powershell +cd build\debug\tests\spike +.\grid_contour_spike.exe +cd ..\..\..\.. +``` +Expected: 生成 `build/debug/tests/spike/spike_grid_contour.png`,呈现网格的 banded 填色面 + 等值线,**形态与 `docs/_validate/ref_18_grid.png` 一致**(色彩精确映射后续在 render 层做,此处只验证管线与形态)。 + +- [ ] **Step 5: 提交** + +```powershell +git add tests/spike/ tests/CMakeLists.txt +git commit -m "spike(S3): 真实样本验证 vtkImageData->surface->banded contour 管线(图#18)" +``` + +--- + +## Task 5:Spike 门槛结论 + +**Files:** +- Create: `docs/superpowers/plans/2026-06-07-m1-phase0-spike-report.md` + +- [ ] **Step 1: 记录三 spike 结果** + +写一份简短报告,逐项记录 S1/S2/S3 是否通过、实际遇到的偏差(如 ADS 端口名、是否需禁浮动、是否需调 VTK 模块),以及对设计文档的回写项(若有)。 + +- [ ] **Step 2: 门槛判定** + +- 三项全绿 → 标记 Phase 0 完成,进入 Phase 1(写 core 基础层实现计划)。 +- 任一红 → 按报告中的偏差更新设计 §4/§9/§11/§15,调整后复测,**不进入 Phase 1**。 + +- [ ] **Step 3: 提交** + +```powershell +git add docs/superpowers/plans/2026-06-07-m1-phase0-spike-report.md +git commit -m "docs: Phase 0 spike 结论与门槛判定" +``` + +--- + +## 后续计划(spike 通过后逐份编写) + +1. **Phase 1 — core 基础层**:`geo`(LocalFrame/CrsTransform + PROJ,轴向/Z 基准/rebase)、`algo`(IdwInterpolator→ScalarVolume)、`model`、colorBar→LUT 逻辑。纯 C++ + gtest,以 `tools/validate_samples.py` 产出为地面真值。 +2. **Phase 2 — data 层**:Repository(异步契约)+ LocalSampleRepository + 各格式解析器 + DTO 映射。 +3. **Phase 3 — net/登录**:ApiClient + AuthService(验证码+JSEncrypt RSA+login2)+ QtKeychain;登录页样式复刻。 +4. **Phase 4 — render 层**:Scene/actors(散点/网格/异常/体素/地形)/相机预设/交互工具/切片。 +5. **Phase 5 — view+controller**:ADS 三区工作台 + 七面板 + 三 controller 联动。 +6. **Phase 6 — 集成与 M1 验收**(对照设计 §13 M1-a/M1-b)。 + +--- + +## Self-Review 备注 + +- 覆盖:本计划覆盖设计 §15 三个 spike + 工具链/测试 bring-up;不涉及业务实现(留后续 Phase)。 +- 无占位:命令与 spike 代码均为具体内容;ADS 目标名/端口名标注了「configure 报错时切换」的真实不确定性(spike 的本职)。 +- 类型一致:spike 代码中 `v[j][i]`(j=y,i=x)灌点序与设计 §6.1 一致;`vtkImageData→DataSetSurfaceFilter→BandedPolyDataContourFilter` 与设计 §4.3 一致。