geopro/docs/superpowers/plans/2026-06-07-m1-phase0-spikes.md

360 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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。
> ⚠️ **本计划部分步骤将按「方案②-修订」更新**(官方 MSVC Qt + 源码 VTK + vcpkg 非 Qt 依赖)。当前 Task 1/3 的"全 vcpkg"描述待改写;**权威构建步骤见设计 §11 + `docs/ENV_SETUP_Windows.md`(§4/§5)**。核心差异:Qt 用官方 MSVC kit(不 vcpkg)、VTK 源码编到 `external/vtk-install`、ADS/QtKeychain 走 FetchContent。
**前置条件(由你完成,见 `docs/ENV_SETUP_Windows.md`):** 已装 **VS18(MSVC 14.51)**、Git、vcpkg 并设 `VCPKG_ROOT`、**官方 Qt 6.11.1 的 MSVC 2022 64-bit kit**。所有命令在 **x64 Native Tools** 命令行、项目根目录执行。
**通过判据汇总(三 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 一致。