plan: M1 Phase 0 环境引导+Spike预研 实现计划

This commit is contained in:
gaozheng 2026-06-07 17:44:28 +08:00
parent a55a958e28
commit 308361d935
1 changed files with 357 additions and 0 deletions

View File

@ -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 1vcpkg 基线锁定 + 首次构建(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 2gtest 工具链冒烟(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 3ADS 停靠集成 + 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 <DockManager.h>
#include <DockWidget.h>
#include <DockAreaWidget.h>
// ... 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 <QLabel>`。)
- [ ] **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 <fstream>
#include <vector>
#include <string>
#include <nlohmann/json.hpp>
#include <vtkNew.h>
#include <vtkImageData.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkBandedPolyDataContourFilter.h>
#include <vtkLookupTable.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkWindowToImageFilter.h>
#include <vtkPNGWriter.h>
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<std::vector<double>>(); // 100, 规则
auto y = g["y"].get<std::vector<double>>(); // 22, 规则
auto v = g["v"].get<std::vector<std::vector<double>>>(); // [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<vtkImageData> img;
img->SetDimensions(nx, ny, 1);
img->SetOrigin(x[0], y[0], 0.0);
img->SetSpacing(dx, dy, 1.0);
vtkNew<vtkDoubleArray> 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<double> stops;
for (auto& pr : cb) stops.push_back(std::stod(pr[0].get<std::string>()));
std::sort(stops.begin(), stops.end());
vtkNew<vtkDataSetSurfaceFilter> surf;
surf->SetInputData(img);
vtkNew<vtkBandedPolyDataContourFilter> banded;
banded->SetInputConnection(surf->GetOutputPort());
banded->GenerateValues((int)stops.size(), stops.front(), stops.back());
banded->GenerateContourEdgesOn(); // 同时产出等值线边
vtkNew<vtkLookupTable> lut;
lut->SetNumberOfTableValues((int)stops.size());
lut->SetTableRange(stops.front(), stops.back());
// 颜色解析略spike 阶段可先用 lut->Build() 默认色带验证管线,色彩精确映射放 render 层
lut->Build();
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(banded->GetOutputPort());
mapper->SetScalarModeToUseCellData();
mapper->SetLookupTable(lut);
mapper->SetScalarRange(stops.front(), stops.back());
vtkNew<vtkActor> actor; actor->SetMapper(mapper);
vtkNew<vtkRenderer> ren; ren->AddActor(actor); ren->SetBackground(1,1,1); ren->ResetCamera();
vtkNew<vtkRenderWindow> rw; rw->SetOffScreenRendering(1); rw->AddRenderer(ren); rw->SetSize(1100, 320); rw->Render();
vtkNew<vtkWindowToImageFilter> w2i; w2i->SetInput(rw);
vtkNew<vtkPNGWriter> 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 5Spike 门槛结论
**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 一致。