# 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 一致。