14 KiB
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:
vcpkg x-update-baseline --add-initial-baseline
Expected: vcpkg.json 新增 "builtin-baseline": "<40位SHA>"。git diff vcpkg.json 可见该字段。
- Step 2: 首次 configure(会编译 Qt+VTK,耗时长)
Run:
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:
cmake --build build/debug --target geopro_desktop
Expected: 生成 build/debug/src/app/geopro_desktop.exe,无编译/链接错误。
- Step 4: 运行,肉眼验证渲染
Run:
.\build\debug\src\app\geopro_desktop.exe
Expected: 弹出深色背景窗口,中央显示一个白色锥体,可被默认 VTK 交互器旋转。
- Step 5: 验证单一 Qt(无双份)
Run:
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: 提交
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:
cmake --build build/debug --target geopro_tests
Expected: 生成 build/debug/tests/geopro_tests.exe,无错误。
- Step 2: 运行 ctest
Run:
ctest --test-dir build/debug --output-on-failure
Expected: 100% tests passed(SmokeTest.ToolchainWorks)。
- Step 3: 提交(若有 CMake 调整)
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 实际为准,二选一):
# 优先 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 报错时换):
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:
#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:
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: 提交
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:
// 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:
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 末尾追加:
add_subdirectory(spike)
- Step 3: 构建
Run:
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:
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: 提交
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: 提交
git add docs/superpowers/plans/2026-06-07-m1-phase0-spike-report.md
git commit -m "docs: Phase 0 spike 结论与门槛判定"
后续计划(spike 通过后逐份编写)
- Phase 1 — core 基础层:
geo(LocalFrame/CrsTransform + PROJ,轴向/Z 基准/rebase)、algo(IdwInterpolator→ScalarVolume)、model、colorBar→LUT 逻辑。纯 C++ + gtest,以tools/validate_samples.py产出为地面真值。 - Phase 2 — data 层:Repository(异步契约)+ LocalSampleRepository + 各格式解析器 + DTO 映射。
- Phase 3 — net/登录:ApiClient + AuthService(验证码+JSEncrypt RSA+login2)+ QtKeychain;登录页样式复刻。
- Phase 4 — render 层:Scene/actors(散点/网格/异常/体素/地形)/相机预设/交互工具/切片。
- Phase 5 — view+controller:ADS 三区工作台 + 七面板 + 三 controller 联动。
- 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 一致。