feat/vtk-3d-view #7

Merged
gaozheng merged 301 commits from feat/vtk-3d-view into main 2026-06-27 18:43:52 +08:00
Owner
No description provided.
gaozheng added 301 commits 2026-06-27 18:43:37 +08:00
faee28c007 docs(spec): VTK 三维视图补充需求设计稿
- 通读需求表「补充需求」页签 + 源码核实 VTK 现状
- 关键判断:中央 VTK 当前为空壳(编排层喂空数据,图层勾选死代码),
  但 render 层 actor 完整有测试,原型渲染原语未丢
- 逐行映射补充需求 → 现状/落地方式(§4)
- 设计 I3dSceneRepository 仓储接口(维度筛选/三维体/切片CRUD/异常体/任务),
  本轮 LocalSample 静态数据实现,预留后端
- 编排层 VtkSceneController + 交互层 interact/(切片/拾取/圈异常)
- 分期建议 P1复活渲染 → P2三维数据集栏 → P3切片交互 → P4异常/详情/任务 → P5二维底图
918088e67a docs(spec): VTK 3D spec v2(纳入评审+web实地分析) + P1复活渲染计划
- spec v2: 纳入架构评审硬伤修正(Scene加vtkProp入口/接口异步/任意切片钉死vtkImageReslice/去裸数组出参)
- 新增§1.5 web实地分析: web 3D=ThreeTile(Three.js)地球+多瓦片源;3D结果=2D反演剖面成帘面
- 关闭开放问题: 三栏=客户端新设计(web无三栏)/异常=切片面2D多边形/底图多源已确证
- 新增 P1 计划: VtkSceneController + I3dSceneRepository(LocalSample异步) + Scene加vtkProp, TDD分6步
0f521c5b24 feat(vtk): P1 复活中央渲染 — VtkSceneController + I3dSceneRepository + Scene加vtkProp
复活被 6241eb3 摘除的中央 VTK 数据驱动渲染:
- Scene 新增 addViewProp(vtkProp*):体绘制 vtkVolume(非 vtkActor)经此进场
- I3dSceneRepository(异步回调契约) + LocalSample3dRepository:dimensionOf 维度映射 /
  loadVolume→VolumeGrid(std::array 去裸数组) / loadTerrainPaths;data 层零 VTK 依赖
- VtkSceneController(QObject) 取代 main.cpp 死掉的 rebuildCentral lambda + 裸 show* 标志:
  勾选数据集/视图模式/图层/比例 → 经仓储取 core::* → I3dSceneView 重建场景;
  QPointer+generation 守异步回调生命周期与新鲜度;inRebuild_ 避免同步路径双 render
- I3dSceneView 抽象解耦编排与 VTK(VtkSceneView 真实现 + 测试 fake)
- 删除被取代的 CentralScene;main.cpp 接线 对象勾选/2D-3D/图层/主题(主题 context 用 sceneCtrl 防悬垂)
- 新增测试 14(Scene/3d-repo/VtkSceneController),ctest 172/172 全绿

构建基建修复(本就潜在缺陷,任何 clean 构建/新人 checkout 都会撞):
- vcpkg.json 加 builtin-baseline:新版 vcpkg manifest 模式必需,否则全新 checkout 无法 configure
- build.bat 修 vswhere(VS2026 预览 -latest 恒空 → -all -prerelease -requires VC.Tools)
  + 括号块内路径变量加引号(防 Program Files (x86) 的 ) 提前闭合)
53ccdc07b0 fix(vtk): 勾选数据集时隐藏中央引导层,露出 P1 渲染
P1 接了 VtkSceneController 渲染但漏接 emptyState 显隐(main.cpp:368 注释本就要求
'接入真实数据后依是否为空调 setVisible'),不透明引导层盖住渲染。补:勾选有数据→隐藏、
取消→恢复。
3dea339ddc feat(vtk): P2 三维数据集栏 — 坐标轴/比例/快捷视图/Zoom
- CameraPreset 扩 6 向快捷视图(前后左右上下) + zoomBy(透视改视角/正交改parallelScale) + fitView
- AxesActor(新, vtkCubeAxesActor): 显示模式 标准(外缘)/三维立体(静态边+网格线)/不显示;
  刻度 无/米/英尺(×3.28084)/经纬度(GeoLocalFrame反算); 字号12(字体待1.0确认)
- GeoLocalFrame 补 toLatLon 反算(等距圆柱)
- I3dSceneView 扩 setAxes/applyCameraView/zoom/fitView; VtkSceneController 加对应槽
  (坐标轴随场景重建; 快捷视图/zoom 仅改相机不重建)
- main.cpp 三维视图工具条: 坐标轴/刻度下拉(枚举绑itemData)+比例滑块(1-10)+6向钮+Zoom钮, 仅3D显示
- 测试 +24(toLatLon往返/相机6向/坐标轴单位换算/控制器编排), ctest 196/196

评审修复:
- HIGH rebuildAxes 异步路径坐标轴 prop 累积 → 持 currentAxes_ 重建前先移除(幂等)
- MEDIUM combo index 魔数 → itemData/currentData 取枚举值(防项序调整静默错位)

注: 坐标轴标准/立体语义 + 字体 + O点 为合理近似, 待 Geopro 1.0 实地确认精修
73deb2b159 fix(ui): P2 三维数据集栏控件深色主题 — 修白底浅字看不清
工具条只设了文字色未设控件背景,下拉/按钮保持默认白底→浅字不可读。
补:QComboBox/QPushButton/QSlider 深色背景+边框+hover/pressed+下拉弹窗配色(canvas/* token)。
86e07722e5 fix(ui): P2 工具条去 border-radius,消除原生GL上四角浅色直角
对齐左上「视图详情」浮层做法:悬于 GL 画布的浮层不设圆角(圆角四角露父级浅底),
改直角矩形+不透明底。控件自身圆角(落在不透明frame上)保留。
85d4ff57df feat(vtk): P3 三维分析切片交互(核心) — 轴向/任意切片+滚轮+拾取+正视
interact/ 交互层(README早规划,本期落地):
- SlicePlaneMath: 纯几何(法向/45°/滚轮平移/双击正视相机含竖直兜底/最近切片), 25 单测
- SliceTool: 封装 vtkImagePlaneWidget — 轴向(上下/前后/左右,角度固定)+任意45°(Origin/Pt1/Pt2),
  套色阶LUT, reslice着色(非cutter), close幂等
- PickInteractorStyle: 继承TrackballCamera+vtkCellPicker, 拾取/双击/滚轮回调
- InteractionManager: 活动切片/选中态/滚轮分发/拾取联动/翻转, 体素变更先closeAll再附着
- VtkSceneView 暴露 currentVolumeImage_(含VE) + onVolumeChanged; main.cpp 切片工具条(上下/前后/左右/任意/翻转/关闭)
- ctest 221/221

评审修复:
- H1 vtkTrivialProducer 提为成员(局部变量构造后析构→管线断裂崩溃)
- H2 uninstallStyle 向 interactor 注销 style
- H3 safeRender 统一守 destroying_ 跳过析构期 Render
- M1 advance 刚性平移 origin+point1+point2(只移origin致轴向切面变形)
- M2 closeSelected 选中位就近不跳0; M4 sliceBar 加 BottomLeftAnchor 随resize

范围外(P4): 切片保存/导出/删除为数据集/三维分析树/右键菜单/异常圈定/详情
87b90a2022 fix(vtk): P3 切片交互手感修复(用户实测反馈)
- 删左上「视图详情」遗留的禁用「切片」复选框(P1占位,已被P3工具条取代)
- 点击跳变 + 绕点旋转无效: onPicked 焦点与相机位置同步平移同一delta,
  图像不跳、旋转中心移到命中点(原来只改焦点致视图突变)
- 双击正视无效: 弃 vtkRenderHWindowInteractor::GetRepeatCount(QVTK+Win不可靠),
  改 std::chrono 手动判双击(间隔<350ms且位置相近); 避开 vtkTimerLog 依赖
- 选中移除: 随上面拾取修复,单击切片可选中→关闭移除选中项(不再只能倒序)
ff3ce27978 fix(vtk): 切片 widget InteractionOff —— 修点击选中/双击/绕点旋转全失效
实测根因: vtkImagePlaneWidget 默认消费落在切片面上的左键(窗位/光标), 自定义
PickInteractorStyle 收不到 → 单击选中/双击正视/绕点旋转/滚轮推进选中项 全失效;
滚轮看似只对最后新增切片有效, 实为选中从未改变(addSlice 设的 last)。
关掉 widget 自身交互(Interaction off): 其事件回调提前 return 不设 AbortFlag →
事件穿透到样式; 切片面 actor 可被 cellPicker 拾取 → 选中/双击/旋转恢复。切面移动由滚轮 advance 驱动。
8a06014e0b fix(vtk): 切片单击=仅选中(不动相机,去跳)+高亮反馈
- onPicked 去掉改相机焦点/位置(实测仍致点击跳变)→ 单击仅选中命中切片;
  拖动旋转回归默认 TrackballCamera(绕场景中心,不跳)。'以切片为中心旋转'(C38)
  因致跳且预期不清,暂去, 后续用更稳方式再加。
- SliceTool::setSelected: 选中切片边框高亮(亮黄粗线)、其余暗灰; InteractionManager
  在 单击/新增/关闭/双击 后 updateSelectionVisual → 解决'选中无视觉反馈'。
- ctest 221/221
eb8cb9e7ee fix(vtk): 切片旋转支点用切片中心而非点击点(根因修复,据日志证据)
诊断日志证据: onPicked 改相机后 dir(视向) before==after, 补偿正确、点击瞬间画面不变;
但命中点 world 明显偏离体中心 → 之前以'点击点'为焦点, 拖动绕偏心点旋转→大幅摆动(=用户的'跳')。
根因修复: 旋转焦点设为**切片中心**(slices_[idx]->center(), ≈体中心, spec C38 '以切片为中心'),
焦点+位置同步平移保持画面不变 → 点击不跳、拖动绕切片中心居中旋转、不甩。
未命中切片则不动相机。
43f8228e49 fix(vtk): 切片单击仅选中+高亮,不动相机(终态) — 切换切片不再跳
据用户实测: '按切片中心移焦点'(eb8cb9e)在切换两切片时仍跳(两次焦点跳动), 且切片中心≈体中心
→ 与默认绕中心旋转视觉等价、价值低。终态: 单击=仅选中+高亮, 拖动=默认 TrackballCamera 绕
场景/体中心旋转(稳定、永不跳)。spec C38 '以体为中心' 由此满足; 切片本身不自转(符合语义)。
87c5cc910e fix(vtk): 恢复任意切片可调(F25)+触碰选中+正视按钮(不再砍功能)
之前用 InteractionOff 砍掉了切片可调(F25),错。改回:
- widget 交互保持开启 → 任意切片可拖动调整角度/位置(F25 恢复); 拖切面=widget 处理。
- 选中改为监听 widget StartInteractionEvent(SliceTool::onInteract → selectByTool):
  触碰某切片即选中+高亮(widget 开交互后独占切面事件,拾取式选中失效,故改观察式)。
- 正视(E54)从双击改为工具条「正视」按钮(faceSelected): 双击会被 widget 抢、QVTK 上本不稳。
- 滚轮推进/关闭 仍作用于选中切片; 相机旋转=空白处拖动(默认 trackball)。
- ctest 221/221
f3a1ba9f99 fix(vtk): 恢复原型切片可拖动配置(SLICE_MOTION)+双击正视(去按钮)
据用户指出'原型阶段切片可拖动调整',查 git(f57291a)原型配置:
  SetLeftButtonAction(VTK_SLICE_MOTION_ACTION) + SetMiddleButtonAction(VTK_CURSOR_ACTION)
我的 SliceTool 漏了这两行→默认左键是窗位调整(无用)→拖切片面无反应=用户的'不能调'。
- 补回两行: 左键拖动=移动切面; 切面边缘 margins 拖动=旋转角度(F25 任意切片可调)。
- 双击正视(D40)改用 widget StartInteractionEvent 检测(同一切片350ms内两次=双击→正视),
  恢复 spec 的双击交互, 去掉上一版擅自加的'正视'按钮(改了需求, 错)。
- 选中=触碰(onInteract); 滚轮/关闭=选中切片; 相机旋转=空白处拖动。ctest 221/221
a7edfa5c78 fix(vtk): 轴向切片禁用旋转(G22-24 角度不能再调整),仅任意切片可转(F25)
上一版让所有切片都能拖边缘旋转,违反 G22-24(上下/前后/左右角度不能再调整)。
修: 轴向切片 SetMarginSizeX/Y(0) 去掉旋转抓取区→只能移动不能转;
任意切片(Oblique)保留默认 margin→可拖边缘旋转(F25)。ctest 221/221
8d94247dd9 feat(vtk): D39 以选中三维体/切片为中心旋转视图(不跳)
正确做法: 点击只选中(不动相机)→切换点选不跳; 在'按下开始拖动'那刻才把焦点设到
选中切片中心(焦点+位置同步补偿 delta→视向/距离不变、画面不跳), 之后默认 TrackballCamera
即绕该中心旋转。PickInteractorStyle 加 getRotateCenter 回调, InteractionManager 提供
选中切片中心; 无选中则绕默认焦点。ctest 221/221
5809b88a44 fix(vtk): D39 改为自定义 Rotate 绕支点增量旋转(真不跳)
前法错: 设焦点=切片中心会把相机位置挪走(透视视差)→画面平移=跳; 诊断只验了视向、漏看位置。
正确: 按下完全不动相机(不跳); 重写 Rotate(): 有选中物时, 用 T(c)R(up)R(right)T(-c) 把
相机 position/focal/up 绕选中切片中心 c 增量旋转→c 在世界/屏幕都不动、场景绕它转、无跳。
无选中回退默认绕焦点。ctest 221/221
37b433208e fix(vtk): 帘面消隐无数据(NaN)格,根治真实反演剖面渲染崩溃(0xc0000005)
真实反演 v 矩阵大量 null→Grid 存 NaN→vtkBandedPolyDataContourFilter 裁剪运算崩(经真实API数据+崩溃栈定位)。
消隐含 NaN 的点(ghost)使其不入表面/色带滤镜+标量填0兜底;顺带清洗色带等值线值(去非有限/去重)。保留色带功能。
b2740898f6 feat(vtk): parseInversionGrid 解析 lat/lon,弯曲测线渲染为曲面帘面
之前丢弃经纬度→所有剖面退化成 y=0 平面。解析后 CurtainActor 经 GeoLocalFrame 按真实测线摆位:
37/136 弯曲测线→曲面帘面,直线/无geo→平面(正确)。
fe04bb1266 feat(vtk): 帘面按首个真实剖面 lat/lon 重锚 GeoLocalFrame 原点(②)
默认原点取自样本、可能离真实数据很远→局部坐标巨大、轴刻度无意义。每次 clear 后首个带经纬剖面
到达时把原点重锚到其 lat/lon 中心:坐标从0附近起、轴刻度有意义,同一选择内多剖面共用→相互地理配准。
无经纬剖面是平面、不受影响。
b261374cc9 feat(vtk): 客户端生成三维体流程(#1)-多源IDW插值+按类型分流体素/帘面
- core::buildVolume 共享管线(散点→GridSpec→IDW→值域),LocalSample/Api 同源,消除调参漂移
- VolumeBuildParams:参数必存(源ds+插值模型/参数+色阶);不冻结gridSpec,改用"源ds锁定"不变式(留校验TODO)
- Api3dRepository:内存体存储 + createVolume/volumeRows/isVolumeDataset + 多源loadVolume
  (复用loadSection走inversion.grid,竖向=g.y高程,与帘面构造性对齐;绕开scatter端点y/z语义坑)
- loadVolume 回调改交付(VolumeGrid, ColorScale):体色阶=源剖面色阶(mock体在dsRepo无条目)
- UI:Column3DDataset(源数据栏)多选+右键「生成三维体」+ VolumeParamsDialog(IDW;克里金占位)
- 生成的体归三维分析栏(Column3DAnalysis,设计§2.1),非数据集栏;main.cpp 两栏勾选聚合下发,体不被后端刷新冲掉
- VtkSceneController 按 isVolumeDataset 分流体素/帘面,取代失效的全局 showVoxel/showCurtain

编译链接绿(build.bat app exit 0);未GUI实测(Claude无法验VTK渲染)。设计/计划见 docs/superpowers/plans/2026-06-17-vtk-3d-volume-create-flow.md
afdd98f416 feat(vtk): 切片右键菜单(VTK视图)+切片持久化mock+导出图片(切片本身,高清)/dat (#3a)
- VTK视图切片右键菜单(设计§2.3):正视图/翻转/关闭(接现有交互)、导出图片/导出dat、保存、创建异常(占位→#4)
  - 右键经 InteractionManager 高优先级(1.0)交互器观察者实现:先于 vtkImagePlaneWidget 消费右键
    (widget 会抢右键并 abort,故 InteractorStyle::OnRightButtonDown 不触发);命中切片或回退选中切片→弹菜单
- 切片持久化 mock:Api3dRepository createSlice/saveSlice/deleteSlice 内存态 + sliceRows()
  (ddCode=dd_slice,parentId=所属体→三维分析栏树中挂父体下,符合需求 R19 对象/三维体/切片结构)
- 导出为图片=导出切片本身(需求 R52):切片重采样 2D → 上采样至最长边2048(保长宽比) → 切片色阶LUT上色 → PNG
  (非整窗截图);导出dat=切片重采样标量网格
- 三维分析栏接线(#5部分):显示/隐藏(VtkSceneView::toggleDatasetVisibility)、切片删除、色阶占位
- main.cpp refreshAnalysis 合并 volumeRows+sliceRows 注入三维分析栏

编译链接绿(build.bat app exit 0);右键菜单/保存/导出图片(切片·高清)已用户实测通过。
3b 待做:已保存切片在分析栏勾选后的重渲染(从 spec 重建)、分析栏保存/另存/导出;#4 异常接真实后端。
d56e35f93d feat(vtk): 切片生命周期重构(3b/3c)-已存切片重渲染+保存链接+场景列表同步
切片"未保存↔已保存"统一状态模型,修复多项交互不一致(用户实测通过):
- 保存=链接当前切片到新 dd_slice(不重绘)+三维分析栏自动展开勾选(syncSlices 按 dsId 去重)→
  不再出现"保存后旧渲染还在、再勾选出现两个"的重复切片
- 持久化存精确三点(Origin/Point1/Point2)+axis(SliceSpec),重渲染逐点精确还原 → 尺寸/朝向一致
  (修"重渲染切片明显变大")
- VTK视图「关闭」已保存切片 → onSliceClosed → 取消列表勾选(场景↔列表双向同步)
- VTK视图「保存」按"未保存/已保存"分派:未保存→createSlice+link+autocheck;已保存→saveSlice 覆盖位姿
- 已保存切片在三维分析栏勾选→在当前活动体上按 spec 还原渲染;取消→移除;靠 onVolumeChanged→syncSlices
  解决"父体异步到场"排序(SliceTool 还原构造/dsId 标签;InteractionManager showSavedSlice/hideSavedSlice/
  selectSavedSlice;Api isSliceDataset/sliceSpec)
- 菜单统一/精简:VTK视图与列表导出统一为「导出▸(图片·dat)」;移除列表(三维体/切片)的"显示/隐藏"(勾选即显隐);
  列表保存=覆盖位姿、保存为=另存新切片
- 修 Column3DAnalysis::setDatasets:按 dsId 保留勾选态 + 仅勾选集变化才发信号 →
  保存切片不再连带取消三维体勾选/重置列表

编译链接绿(build.bat app exit 0);上述场景已用户实测通过。
4e1b8e7635 feat(vtk): 异常3D基础(#4a)-Anomaly补3D几何+buildAnomaly3D+视图异常方法+Api mock持久化(挂三维体)
异常功能地基(对象→三维体→异常;异常挂三维体非切片,见记忆 vtk-3d-persistence-structure):
- core::Anomaly 补 id/volumeDsId(=remarkSourceId)/consortiumId/worldPts(3D世界点)/planeNormal·planeOrigin,
  保留 2D localPts(剖面详情兼容)
- render::buildAnomaly3D(单异常→世界坐标 点/折线/闭合多边形 actor,不翻y/不压z;抽 buildActor 共享 2D/3D)
- I3dSceneView + VtkSceneView:addAnomaly/removeAnomaly/clearAnomalies/setAnomalyVisible(按 id 跟踪 actor,
  worldPts 已含VE 故不再 SetScale;clear 一并清异常)
- Api3dRepository:StoredAnomaly + saveAnomaly/loadAnomalyTree(按 volumeDsId 过滤+consortiumId 分组异常体)/
  deleteAnomaly/deleteAnomalyGroup 内存 mock(取代 stub onErr)

同时修复测试漂移(此前 3a 加 isVolumeDataset 纯虚 + 3c 改 loadVolume 回调签名后,geopro_tests 一直未随之更新):
- FakeView 补异常方法;FakeSceneRepo 补 isVolumeDataset(可配置 volumeIds)+修 loadVolume 签名
- test_3d_repo loadVolume 回调改 (VolumeGrid,ColorScale)
- 控制器测试 View3DWithVoxelAddsVolume 按新"类型分流"语义重写为 View3DVolumeDatasetAddsVolume(体素XOR帘面)

编译全绿(build.bat all);228/228 单元测试通过。4a 为地基(无 UI 接线、尚不可见),圈定/保存见 4b。
6210d615f3 feat(vtk): 异常圈定+保存闭环(#4b)+多项交互修复
#4b 异常圈定→保存→渲染→持久 闭环(异常挂三维体,mock 持久化):
- AnomalyDrawTool:切片平面上圈定多边形(屏幕射线-平面求交落点);左键加点(醒目黄圆点)、
  鼠标移动虚线橡皮筋(末点→光标跟手)、双击/右键/回车闭合、Esc 取消、左上屏幕提示;高优先级观察者绘制期独占输入
- AnomalySaveDialog:名称/异常类型(mock)/备注 + 截图预览及尺寸(R50)
- 切片右键「创建异常」接通:圈定→草稿渲染→截图→保存对话框→saveAnomaly(挂三维体)→红色多边形渲染
- onVolumeChanged→reloadAnomalies:体到场重载其异常(= 显示过滤"随数据集"默认档)
- SliceExport 加 captureRenderWindowPng(异常截图,带尺寸);Anomaly 补 exceptionTypeId/remark

交互修复(用户实测确认):
- 生成三维体**按勾选集合**(checkbox)收集源,不再受行高亮/右键项影响(撤销错误的多选子类)
- buildVolume 网格**覆盖全程**:包络过大时放大间距(fitAxis)而非截断 → 跨 TM 多剖面不再丢远端剖面
- 滚轮回退为"推进当前选中切片";点击切片外**取消选中**(取消后滚轮恢复相机缩放)
- 修圈定闭合误触切片:闭合事件提前 abort,避免漏给切片 widget 触发 slice-motion

文档:plans/2026-06-18-vtk-3d-anomaly.md §6 摆放决策(3D异常控制在三维分析区/右侧总表为全集)+§7/§8 状态;
  design spec 顶部更正块(异常挂三维体/remarkSourceType=标注形态/无截图字段/独立显隐);HANDOFF 更新到 4a/4b。

编译链接绿(build.bat app exit 0);4b 闭环 + 交互修复已用户实测通过。下一步 4c:三维分析区 3D 异常控制(树+过滤R86-87+VTK选中联动R84+显隐+删除)。
324d4ac605 feat(vtk): 三维分析区 3D 异常控制(#4c-1)-列表+显示过滤+单条显隐+删除
三维分析栏加 3D 异常控制(异常挂三维体,mock):
- 布局:数据集树 + 「异常」分组框(显示过滤下拉 + 异常列表)放进可拖拽竖向 Splitter,数据集树占多
- 显示过滤(R86-87):全部显示/随GS/随数据集/全部隐藏 —— 独立于体勾选控制 VTK 异常可见性
  (随GS 暂同随数据集;loadAnomalyTree 空key=全部、非空=该体)
- 单条显隐勾选 → setAnomalyVisible;右键「删除异常」→ deleteAnomaly + 刷新
- refreshAnomalies:按档位算异常集合 → clear+addAnomaly 重渲染 + 填列表 + Render
  (修过滤切换后 VTK 不重绘、与列表脱节的 bug)
- 创建异常后经 refreshAnomalies 入列表

编译链接绿(build.bat app exit 0);用户实测通过。
待做:4c-2 列表选中→VTK 高亮联动(R84,需视图 setAnomalySelected);4c-3 异常属性面板(R83);单条显隐态持久化。
44d31a824d feat(vtk): 异常列表选中→VTK高亮联动(#4c-2, R84 list→VTK)
- I3dSceneView::setSelectedAnomaly + VtkSceneView 实现(选中异常 actor 加粗高亮、其余恢复);
  anomalyProps_ 改 vtkActor 以设线宽/点尺寸
- main:Column3DAnalysis::anomalySelected → sceneView->setSelectedAnomaly
- FakeView 补 setSelectedAnomaly 空实现

编译全绿(build.bat all);用户实测通过。
反向(VTK点异常→回选列表)本期未做(需异常 actor 拾取)。
c83f63a8f5 feat(vtk): 异常属性对话框(#4c-3, R83)-双击异常列表弹只读属性
- AnomalyPropertiesDialog:名称/类型/标记类型/归属三维体/异常体/顶点世界坐标/备注,只读
- Column3DAnalysis:留存 anomalies_,双击 itemDoubleClicked 按 id 回查发 anomalyPropertiesRequested
- main:接线打开对话框
- 截图字段:模型/端点无,不展示(保存对话框截图为mock未持久化)

编译绿(build.bat app);用户实测通过。#4 异常功能收口。
b97ea68109 feat(vtk): 三维体/切片数据详情对话框(#6)-右键属性表+体统计持久化
- VolumePropertiesDialog/SlicePropertiesDialog 只读属性对话框(仿异常详情)
- Api3dRepository::volumeInfo 取参数+统计;StoredVolume 持久化聚合测点数(finalizeVolume)
- main.cpp 右键「数据详情」按 ddCode 分派(dd_voxel→体/dd_slice→切片);接口与 LocalSample 零改动
- 切片不含统计(切面网格仓储不持久化,守 YAGNI);体统计仅 loaded 时显示,否则占位
- 单测 +2(volumeInfo loaded前/未知id) → 230/230 绿
05041299fa chore(installer): Windows 安装包打包工具(Inno Setup)
- build_installer.ps1 一键打包:stage→windeployqt补Qt运行时(绕过ADS卡死)→VC运行时→ISCC
- geopro.iss:中文/英文向导,Program Files安装,自动装vc_redist,快捷方式,卸载
- lang/ChineseSimplified.isl 向导简体中文语言包
- .gitignore 排除 installer 生成物(staging/dist/redist)
5beb13c5e2 fix(login): RSA 公钥内嵌二进制(qrc),修复他机登录 invalid public key pem
main.cpp 原先从写死的开发机绝对路径 D:/Git/lanbingtech/geopro/resources/
rsa_public_key.pem 读公钥;readPem 读不到时静默返回空串,RsaEncryptor 解析
失败抛 invalid public key PEM。安装包从未打包该 pem,故仅本机可登录。

改为经 Qt 资源 :/keys/rsa_public_key.pem 读取(公钥可安全内嵌),运行时零
外部文件依赖,任意机器一致,安装包脚本无需改动。

- 新增 src/app/resources/keys.qrc(alias 指向仓库根 pem 单一来源)
- CMakeLists 把 keys.qrc 加入 geopro_desktop 源
- main.cpp 改 QFile 读 qrc;删除孤儿 readPem 及其专用 fstream/sstream
b3b030767d fix(startup): 样本/PROJ 数据随包+相对定位+启动防护,修复他机登录后无界面崩溃
登录成功后 buildWorkbench 同步调 repo.loadGrid("grid1") 构建世界系,而
LocalSampleRepository 指向写死的开发机绝对路径 docs/剖面网格数据...;该路径
在他机不存在,readFile 打开失败抛 runtime_error,沿未加保护的调用链冒泡出
main 触发 std::terminate,进程在 window->show() 前消失——表现为登录框关闭
后既无主界面也无进程。本机因该路径存在而正常。

- main.cpp 改为运行时定位样本目录:优先 exe 旁 sampledata/,回退源码树开发
  路径;PROJ_DATA 候选已含 exe 旁 proj/。均不依赖写死绝对路径。
- main.cpp 给 buildWorkbench 包 try/catch:启动期同步加载失败弹可见错误而非
  静默退出(防护 PROJ/数据缺失等任意启动异常)。
- build_installer.ps1 随包 sampledata/(样本演示数据)与 proj/(PROJ 数据)到
  exe 旁,使他机 2D 演示视图与 3D CRS 配准可用。
5e60446210 feat(vtk): 色阶编辑器(2D/3D共享)+模板库后端+剖面着色修正+二维数据集足迹
本会话主要交付:
- 色阶配置对话框 1:1 复刻原版(colorLevel/contourLevel/contourLine/colorEditor + colorUtils):
  左三列⚙表格(层级/线形/颜色) + 层级⚙/线形⚙/颜色⚙ 子对话框 + 连续渐变(直方图/读出/min-max/反转)
  + .lvl/.clr 导入导出;文案/校验对齐原版精确 i18n。
- lvl/clr 模板库接真实后端:IColorTemplateRepository + ApiColorTemplateRepository,
  另存/打开/新建色阶/配色方案下拉 经仓储注入 2D(GridDataChartView)与 3D(主对话框)。
- 剖面帘面着色对齐原版 threeContour.js getTerrainColor:上界 stop 取色 + 满 RGB,
  修正"色带整体下移一格 / 发浅发灰 / 丢 alpha"导致与原版差异大的问题。
- 二维数据集视图首切片:勾选轨迹类数据集 → 足迹平铺进 View3D 地图
  (Api3dRepository::loadMapLine 走 dd/ert/trajectory/line + MapLineActor + col2D 接线),
  view2DMode 控摆放高度,顶/底锚真实地表高程(zRefElev)。
- 测试 252 全绿。

并含本分支前序未提交的 UI 工作(ToastOverlay/TopBar/Theme/DynamicForm/若干 panel),
经 CMakeLists/main.cpp 纠缠,随此 checkpoint 一并提交。未纳入未跟踪的 png/yml 及审查报告 txt。
8e91351dab fix(vtk): 二维足迹不可见 + 台湾区天地图底图全占位图
三处缺陷,均由「勾选二维数据集 → VTK 看不到渲染/底图」串起:

1) 摆放默认关闭致足迹静默丢弃
   Column2DDataset「2D视图」下拉可见默认项为 Z=0(setCurrentIndex(1)),
   但该初始信号在 connect 前发射、且组件早于 main.cpp 接线构造 → 永不送达控制器,
   控制器 placement2dMode_ 仍为 0(关闭),勾选被记录却不入场(setChecked2DDatasets
   守卫 placement!=0 不通过)。改:控制器默认 1、main.cpp view2dMode 默认 1,
   与下拉可见默认项对齐,彻底摆脱对信号时序的依赖。

2) 足迹未重锚 frame → 投到数百公里外、移动视角也找不到
   GeoLocalFrame 启动锚在样本 grid1 中位经纬;addCurtain 会重锚到剖面真实经纬,
   但 addMapLine 未重锚 → 台湾足迹(经120.8/纬24.7)按样本锚点投到世界原点数十万米外。
   改:抽出 anchorFrameIfNeeded(剖面/足迹共用),首个带经纬数据(无论帘面或足迹)
   重锚原点;控制器 setChecked2DDatasets 在空场景首批足迹时取景(fitOnArrival)。

3) 台湾区天地图卫星只覆盖到 z16,z17/z18 返回固定「无影像」占位图
   底图四叉树拉近时细分到 kMaxZoom=18 → 台湾中心瓦片全是占位图(实测 z17/z18
   字节恒等 size=4769/MD5 c0edbdcb,z16 为真实影像;内地有 z18 故正常)。
   改:TileBasemap 加自适应 satMaxZoom_,isTiandituNoImagery 按 大小+MD5 精确识别
   占位图 → 学习把卫星上限降到 z-1 并重铺(台湾 18→16 收敛,用 z16 真实影像放大);
   refineTile 卫星层用学习上限,街道矢量仍到 z18;show()/换源复位、refresh 保留。
   内地项目零影响(z18 有影像,永不触发降级)。

测试:253/253 通过;新增 TwoDDefaultPlacementRendersAtZeroOnCheck 回归,
原依赖「默认关闭」的两个用例改为显式 set2DPlacement(0)。
959f030c98 feat(ui): 表单渲染单一真相层(formkit)+只读渲染器(KeyValueView),统一编辑/只读/详情表单
把分散在各文件手搭的表单收敛到唯一实现,杜绝"同类控件各处不一"的漂移:
- 新增 FormKit(DetailForm/buildDetailDialog + makeEditForm/editLabel/capField/addSection)
- 新增 KeyValueView 为唯一只读键值渲染器(§6.4);DynamicFormView 改为内嵌它
- 三维体/切片/异常详情对话框由裸 QFormLayout 迁到 DetailForm+KeyValueView(随内容自适应)
- 生成三维体对话框 + DynamicFormEditor 改用 formkit 可编辑套件(标签列/行距/分组逐像素一致)
- 分组标题统一为 formkit::addSection(编辑态与只读态共用同一段代码)

控件一致性:
- 下拉框/日期框扁平 chevron 箭头(qrc 内嵌 SVG),去 Fusion 原生斜角;日期框补齐输入框同款 box
- 无候选项的"选择"字段退化为 QLineEdit,不再用几何异类的可编辑下拉框
- QComboBox/QDateEdit/QTimeEdit min-height/padding 与 QLineEdit 对齐 → 同高

规范:§7.0.2 标签列宽由区间改精确常量(可编辑100/只读72);新增 §7.0.10 实现纪律
(唯一实现、禁手搭 QFormLayout、精确常量、控件构造一致性、新表单并排验收)
08b8ebbf01 feat(ui): 统一对话框外壳+全局控件高度,数据集属性改只读
对话框外壳(formkit)统一,编辑态与只读态同款卡片/分组/边距/按钮栏:
- 新增 dialogRoot/formCard/cardBody/addDialogButtons;buildDetailDialog 复用 formCard
- 生成三维体/导入/导出/异常保存/对象新建/等值线/色阶/设置等对话框迁到统一外壳
- FormKit.hpp 直接 include QLabel/QFrame(editLabel/formCard 返回类型在调用点需完整)

全局控件高度/外观一次补齐(QSS,覆盖所有对话框):
- QSpinBox/QDoubleSpinBox 经 QAbstractSpinBox 统一 box,与输入框/下拉框同高;上下按钮扁平 chevron
- QPlainTextEdit/QTextEdit 补输入框同款边框/圆角/底色
- 新增 chevron-up.svg(数字框上箭头)

数据集属性改为纯只读:移除"修改描述"功能(QTextEdit+保存+saved 信号+repo 依赖),
DatasetAttrPanel 构造简化、main.cpp 相应接线清理
12813bd8d0 feat(detail): 数据集详情视图交互复刻(measurement/inversion/grid)
对照原版 web 1:1 复刻数据集详情视图的写操作交互,补齐既有视图的全部
可交互能力。

基础设施
- 新增写操作命令仓储 IDatasetCommandRepository + ApiDatasetCommandRepository
  (26 个写/查接口,端点逐字对照原版 apis),回调式异步沿用 ApiColorTemplateRepository 模式
- 写操作注入链平行 setColorTemplateRepo:main→Panel→Page→DetailViewFactory→视图,
  透传 cmdRepo + dsIdGetter
- 新增共享对话框 InversionFormDialog/SaveAsDialog/ScatterFilterDialog/GridWizardDialog/
  WhiteningDialog/FilterDialog/ExceptionDialog/ExceptionDetailDialog/AutoAnnotationDialog
- 纯函数 InversionFormParse/ScatterDataOps/InversionProcessOps/ContourSimplify + 单测

measurement(M1-M13):可见性持久化、数据过滤、X/Y/V轴、值类型、色阶配置、
  生成视电阻率、反演运算、另存为、导出DAT、信息点选
inversion 网格(I1-I15):网格化向导、白化、滤波、等值线提示、简化容差(真生效)、
  异常增删改查+定位、自动标注、描述保存、另存为
inversion 原数据(O1-O3) + grid 反演(G1,functionList 驱动)

后置/降级(台账 §6.4):M14框选、M2行级可见性、M3过滤直方图、I9图上绘形、
  I14富文本(Qt无Quill)、I3白化tmObjectId透传

测试 285/285 通过
b509795ffd docs(gpr): 三维体三方案 spec(A/B/C) + POC 实现计划
B/C 对等双方案(用户运行时按需切换),A 并入 B;含 opus 评审修订
(VTKHDF Writer 写不了规则体→裸分块落盘、量化贯穿、最小真实核外分页器)。
c395921ca8 feat(io/gpr): 新增 .iprh 头解析器(纯 C++17,零 Qt/VTK)
- IprHeader/parseIprHeader:按行解析 KEY: value,支持含空格键名
  (LAST TRACE/SOIL VELOCITY/DISTANCE INTERVAL)
- SOIL VELOCITY 由 m/µs 统一换算为 m/s 存储(×1e6)
- 缺 SAMPLES/LAST TRACE/CHANNELS 任一抛 std::runtime_error
- CMake 接线:src/io(gpr) 静态库 geopro_io_gpr + tests 链接
- TDD:2 个新用例,全测试套件 100% 通过
0d7f646941 feat(io/gpr): 实现 .iprb B-scan 二进制读取器
readIprb 读取 int16 雷达剖面(布局 [trace*samples + s]):
traces=lastTrace+1;校验文件字节数=samples*traces*2,
不符或打不开抛 std::runtime_error。纯 C++17,零 Qt/VTK。
379875dff0 fix(io/gpr): traces/大小计算改 64 位防溢出
MSVC 的 long 是 32 位,samples*traces 大体下会溢出。
BScan.traces 改 std::int64_t;大小校验 expected 与 data
分配均在 64 位域计算,为后续整卷(数十亿体素)立纪律。
0bbed9c0c3 feat(io/gpr): GPR 几何-通道横偏解析与采样深度换算
新增 geopro::io::gpr 两个纯 C++17 几何函数:
- parseChannelXOffsets: 解析 .ord 末列==1 的有效通道横向偏移
- depthOfSample: 按物理把采样序号换算为深度米(samples<=1 防除零)

含失败先行的单测,GprGeometry.cpp 接入 geopro_io_gpr,
test 接入 geopro_tests。
c6ff9c2271 feat(core): 新增 int16 量化体类型 ScalarVolumeI16 + Quant
GPR 三维体地基:int16 量化标量体,内存/显存/磁盘为 double 体的 1/4。
- Quant: 物理值↔int16 映射,toQ 下钳保留 INT16_MIN 给 kBlank 哨兵
- ScalarVolumeI16: 与 double ScalarVolume 并列,i 最快 k 最慢布局
- idx(i,j,k) 64 位计算(整卷可达约 96 亿体素,防 int 溢出)
- header-only,纯 C++17,零 Qt/VTK
ec4a7e81ef feat(detail): 补全详情视图剩余交互(框选/绘形/直方图/行级可见性/富文本/白化)
继续数据集详情视图 100% 复刻,补齐上批后置/降级的 6 项。

- M2 measurement 列表行级可见性:DataTableView 载荷驱动可交互开关列
  (仅 measurement 启用),行级 popconfirm → saveDisplayStatus
- M3 数据过滤直方图:新增自绘 ScatterHistogramView,分布柱 + 选区高亮 +
  与 min/max 输入联动
- M14 散点框选:ScatterMarqueePicker 橡皮筋框选 + ScatterPlotItem 选中高亮,
  显示/隐藏对选中子集操作
- I9 异常图上绘形:ContourDrawTool 在等值面上交互绘制 点/线/面/文字
  (先弹窗填类型/名称→图上绘制→newException),坐标表保留为兜底
- I14 富文本描述:DescriptionPanel 升级富文本(粗体/斜体/下划线/字色/字号/
  标题/列表) + QuillDelta 与 Quill Delta 常见格式往返(非 Quill 不可字节级1:1)
- I3 白化 tmObjectId:openWhitening 经 getDsObjectDetail 取 structParentId

修复 ScatterHistogram 命名冲突(widget 改名 ScatterHistogramView,与
ScatterDataOps 的分箱结构 struct 区分),desktop 目标恢复可链接。

抽纯函数 ChartPickGeometry/QuillDelta/buildScatterHistogram + 单测。
build app + test 全绿,318/318 通过。
a9e8eb9d5c feat(core): GPR 结构化建体 buildGprVolume(X/Z 落格 + Y 向 1D 线性插值 → int16 量化体)
- 新增 GprSurvey 规则化建体输入模型(放 core/model 保持 geopro_core 自洽,避免 core->io 反向依赖)
- buildGprVolume: X/Z 取最近道/采样落格,仅跨通道 Y 做 1D 线性插值,边界外不外推
- int16 量化用值域中点为 offset 对称铺满 ~64000 码位,两端留余量不撞 int16/kBlank
- 整型乘积索引走 size_t
8f167b62c9 fix(detail): 白化 tmObjectId 经 open 链路从数据集列表透传(修模板列表为空)
白化「白化模板/模型」方式文件列表为空:原 plan A 用 getDsObjectDetail(dsId)
取 structParentId,实测该响应不含此字段。原版 web 取自数据集行所属 TM
(dsFileRow.structParentId)。

改为 plan B:tmObjectId 从 datasetsLoaded(tmObjectId) 存入树节点新角色
kDsTmObjectIdRole,双击/右键打开时读出,经 openDataset→datasetOpened 信号
→Panel→Page→DetailViewFactory→GridDataChartView 透传,openWhitening 直接用,
删除 getDsObjectDetail 懒拉。

build all(app 链接) + test 全绿,320/320。
d908556166 feat(store): GPR 三维体分块压缩落盘 ChunkedVolumeStore
新增 geopro_store 库(B/C 方案共用基座):int16 体逐块 qCompress 压缩写入
data.bin + nlohmann-json sidecar(meta.json 记几何/量化/逐块偏移索引)。
write/readMeta/readBrick 三接口 + 边缘块(< brick)支持;偏移/长度全程 64 位。
不引入 vtkHDFWriter,不加 vcpkg 依赖(压缩用 QtCore 自带 zlib)。
b362156364 feat(render): VoxelActor 新增 buildVoxelI16 量化域体绘制
int16 量化体经 vtkShortArray 填 vtkImageData,vtkSmartVolumeMapper GPU 体绘制。
传递函数在量化域取控制点:qmin/qmax=q.toQ(vmin/vmaxPhys),颜色对每量化级用
q.toPhys 反查物理值再经 ColorScale 取色;kBlank→不透明度0(透明)。抽 assembleVolume
公用 mapper/property 配置,double 版 buildVoxel 行为不变。附无窗冒烟测试。
cc3c5bf755 feat(render): IVolumeRenderSource 接缝 + WholeVolumeSource(B) 整卷重组
新增 B/C 共用的体渲染数据源接口 IVolumeRenderSource(meta/update/
currentImages/sliceSource),并实现 B 的 WholeVolumeSource:构造时读
ChunkedVolumeStore,遍历所有 brick 按全局坐标(vtkIdType 64 位)重组为
整卷 VTK_SHORT vtkImageData(含边缘块),供整卷体绘制与切片 reslice。

VoxelActor 新增 buildVoxelI16FromImage 重载:直接以预构建 VTK_SHORT
图像成体,传函/着色复用量化域逻辑(抽出 assembleVolumeI16),不改动
Task 7 现有 buildVoxel/buildVoxelI16 行为。

geopro_render 链 geopro_store;新增 test_whole_volume_source 校验
dims/类型/边缘块重组位置。
4a1fecb149 fix(detail): inversion 处理类对话框视觉返工对齐原版(白化/网格化/滤波/另存)
之前用客户端 FormKit 外壳导致与原版 web modal 系统性不一致,以原版为准返工:
- 白化:550px、第2项"白化文件"、边界扩展改文本框、确认/取消顺序、标签右对齐
- 网格化:步1 500/步2 800px、网格参数/数据值设置双分组栅格、"数据值保存为"、
  补恢复默认值按钮 + 间距↔点数双向联动 + 分项校验
- 滤波:900px 左树右设置双卡片、"忽略"、矩阵行列表头 + 奇偶校验
- 另存为(Inversion):标题"另存为新的网格数据"、400px、默认名"网格数据1"、确认/取消
- 工具条:异常标注/自动标注/另存为、原数据另存为 右对齐

API 端点/请求体字段未动(已 1:1)。build all + test 324/324 绿。
c15555dd8a feat(io/gpr): 多通道 .iprb+.ord 装配 GprSurvey
assembleGprSurvey 把一条测线若干通道 .iprb(同名 .iprh)+.ord 装配为
geopro::core::GprSurvey:校验各通道 samples 一致、ntraces 取最小值对齐、
按 .ord 横偏 Y 升序重排通道(values 同步置换)、x0/z0=0、dx=道距、
dz=depthOfSample(1,h);通道数与 .ord 有效通道数不符抛 runtime_error。
索引 64 位。纯 C++17,零 Qt/VTK。
687edfeca1 feat(store): ChunkedVolumeStore 增加多分辨率金字塔与每块 min/max
- buildPyramid(levels): level 0 全分辨率(复用 data.bin),level 1..levels
  逐级 2x 平均降采样(ceil(n/2));非 blank 取均值 round,全 blank 置 kBlank。
  各级独立 data_L<level>.bin + 逐块 qCompress。
- 每级每块计算并存 (min,max)(跳过 kBlank;全 blank 块 = (kBlank,kBlank)),
  写入 meta.json 的 levels 数组并回填原 bricks 索引。
- 新增 levels()/bricksX|Y|Z(level)/dims(level)/readBrick(level,...)/
  brickRange(level,...);保留兼容重载 readBrick(bx,by,bz)==readBrick(0,...)。
- 不破坏 Task 6/8:write/readBrick(bx,by,bz)/meta/bricksXYZ() 语义不变;
  老 store 无 levels 时 levels()=1,brickRange(0,...) 惰性读块计算。
c21226a3d7 fix(detail): measurement 对话框/工具条视觉返工对齐原版
以原版 web 为准返工 measurement 散点交互视觉:
- 数据过滤:1000px;左直方图(hover柱变红+tooltip)+右信息区(数值范围/占比/原始点数/
  当前点数橙色高亮)+底部双手柄范围滑块(新增RangeSlider)+计算分布/重置;min/max输入
  最大在上最小在下;三方联动(输入↔滑块↔直方图)
- 另存为(RawData):280px、标题"数据另存为"、确认/取消
- 色阶/另存/过滤成功 toast
- 信息面板 A红/B蓝/M绿/N橙(#F4B008);tooltip"查看散点属性"/"散点的点选"
- X/Y/V/值类型下拉固定宽 120/160/160/120;无高程禁用 X/Y
- 导出置工具条最右(页头HeaderAction跨ddCode静态)

API 字段未动。build all 绿。
86e2b6b8a8 fix(store): brickRange 用 hasRange 标志替代 (0,0) 哨兵
(0,0) 是合法值域(真实全零块,kBlank=INT16_MIN 非 0),旧实现用
(vmin==0&&vmax==0) 当未计算哨兵会误判,导致全零块每次 brickRange
都无谓解压重算,且 buildPyramid 后仍走惰性。

- BrickEntry 加 bool hasRange 显式标志
- brickRange: hasRange 真→直接返回;假→惰性算并就地缓存(mutable levels_)
- meta.json 序列化/反序列化带 hasRange(老 store 缺字段→false,惰性兼容)
- buildPyramid 回填值域时一并置 hasRange=true
- 补测试:真实全零块 brickRange 返回 (0,0) 不退化(金字塔/老 store 两路)
5dbbb2576c feat(render): brick 分页器(LRU 工作集,内存恒定核外渲染)
实现 geopro::render::BrickPager:驻留 ≤ budget 个解压块,
按 LRU 淘汰,与体总大小无关。requestVisible 按请求顺序更新
LRU 并淘汰至预算;get 命中返回数据指针、不改 LRU。
键为完整 BrickId(含 level);std::list 记录 recency +
unordered_map 存数据与迭代器,touch/淘汰均 O(1)。
TDD:test_brick_pager 验证恒定驻留与最早块淘汰。
6bc7c23a8c fix(detail): inversion 异常/自动标注/描述交互返工对齐原版 + 修 getExceptionName
- I9 文字标注:落点后弹 ExceptionTextDialog(字体/大小/颜色/不透明度/内容)写 customLegend;
  补"新增异常类型"按钮(完整子流程标注待办);Anomaly 增 Text=4 + 文字字段
- 修 getExceptionName:原版 data 为纯字符串,客户端误当对象解析→名称回填失败;
  改 wireString 解析,回调签名改 (bool,QString,QString);切类型每次回填
- I10 删除文案对齐原版 contourContentDelete
- I11 详情返工:380px 抽屉式双Tab(图例/坐标),线样式改只读,坐标系切换(图形/经纬度/投影)
  +顶点数+导出txt(经纬度/投影无换算数据,标注;图形坐标可用),提交体仍 {id,exceptionName,remark}
- I13 自动标注返工:1400px,规则卡片(标题/折叠/删除),阈值模式 radio(切换清空),
  右上统计(max/min/mean/median),预览表序号+逐条删除(等值线预览图高成本待办)
- I14 富文本补 背景色/对齐/字体族 工具栏 + QuillDelta 字体族往返;去下划线/列表(原版无)

build all 绿,339/339。GPR/金字塔 WIP 未碰。
bfd7d4aafd feat(poc): gpr_poc headless 度量 CLI(地基端到端串联)
串起 assembleGprSurvey→buildGprVolume→ChunkedVolumeStore::write→
buildPyramid→WholeVolumeSource,提供 build/load/selftest 三子命令,
输出建体耗时/维度/体积/压缩比/加载/峰值内存指标(Psapi 峰值工作集)。

selftest 合成数据端到端 PASS。真实明星路数据 BLOCKED:前置 readIprb
的 traces=lastTrace+1 严格校验与真实文件「道数=lastTrace」系统性不符,
装配阶段即抛异常,未擅自改前置/其单测,如实记录于 poc-results-B.md。
d75a52e519 fix(io/gpr): readIprb 以文件大小为权威推导道数
真实明星路数据规律为「道数 == LAST TRACE」(非 lastTrace+1),旧实现硬假设
traces=lastTrace+1 并严格校验文件字节相等,导致真实 .iprb 装配抛错。

改为 traces = fileBytes / (samples*2),要求字节数为 samples*2 整数倍(否则抛),
lastTrace 仅作 header 提示不再决定道数。更新单测:新增
FileSizeIsAuthoritativeNotLastTracePlusOne(lastTrace=N 但文件含 N 道 → traces==N),
ReadsInt16AndLayout/ThrowsOnSizeMismatch 语义不变仍通过。
6fa0a31f3e docs(poc): 补齐 POC-B 真实数据实测指标 + Z 尺度诊断结论
readIprb 修复后线 001 (cellXY=0.2,cellZ=0.05,levels=2) 端到端跑通:
体维度 11120x8x162、体素 14.4M、压缩比 1.88x、build≈22.6s/峰值 4.98GB、
load 335ms/38MB。深度链路验证正确:dz≈0.009778m、nz=162(非旧 §3 误报的 1,
为 soilVelocity 换算缺失时代的遗留),CLI specFromSurvey 无需修改。
75cf8d40ba fix(detail): 反演动态表单支持11种控件+必填校验 + grid按钮视觉 + 色阶templateId
- InversionFormDialog 动态表单不再一律下拉:复用项目既有 parseEditableForm +
  DynamicFormEditor(与对象/结构编辑同款),按 displayComponentType 渲染 11 种控件
  (文本/只读/复选/下拉/日期/时间/日期时间/多行/数字按dataType+limit/树选降级/步进)
  + requiredType 必填校验/只读禁用。生成视电阻率纯select行为不变。
  删除被孤立的 InversionFormParse + 其测试。
- grid 反演按钮行:左"电法列表"radio + 右蓝色主按钮 space-between(仅dd_grid)
- 色阶保存带 templateId(ScatterPayload+DTO捕获色阶detail顶层templateId,measurement
  与反演原数据两路;空可省,对照原版)

后续项(未动,与3D共享风险):ColorScaleConfigDialog 另存覆盖/散点模板库可用。
build all 绿,336/336。GPR/金字塔/.superpowers WIP 未碰。
03805f4326 feat(poc): POC-B 离屏 GPU 渲染基准(offscreen-smoke 闸门 + renderB 体绘制/切片 fps)
- gpr_poc 新增 offscreen-smoke: 离屏 vtkRenderWindow + cube + 读回像素, 闸门验证离屏 GL 可用
- gpr_poc 新增 renderB: 整卷 VTK_SHORT 体绘制(旋相机) + 切片扫描(reslice 沿 Z) fps 实测
- 关键发现: line 001 cellXY=0.05 整卷 44476x29x162, X 维超 GL_MAX_3D_TEXTURE_SIZE(16384),
  vtkVolumeTexture 上传失败, 体绘制 fps 如实标 INVALID(绝不上报假帧率); 切片 54.6fps 真实流畅
- 用 CapturingOutputWindow 捕获纹理维度错误 + 维度超限双判据, 避免误把空纹理假帧率当性能
- CMakeLists 补 RenderingVolume/RenderingVolumeOpenGL2/ImagingCore/InteractionStyle 组件
0212fb5d2e feat(detail): 自动标注对话框补等值线预览图(I13 1:1)
右上补轻量 QwtPlot+ContourPlotItem 渲染反演网格等值面(复用 GridDataChartView 同款
渲染器与 ColorMapService);执行自动标注后 parseDatasetAnomalies 解析预演异常实时叠加,
删除预览行同步移除。构造改收 Grid+ColorScale(统计从 grid.values 算)。

build all 绿,336/336。
3dfe8b54f5 feat(detail): 色阶编辑器另存覆盖 + 散点模板库可用(1:1)
- IColorTemplateRepository/Api 加 updateLvlTemplate(PUT /business/lvlTemplate
  {id,templateName,properties}),对照原版 updateLvlTemplate
- ColorScaleConfigDialog 另存为改自定义弹窗:名称+「覆盖原模板」复选(仅 lvlTemplateId
  非空可勾)→勾选 updateLvlTemplate / 否则 saveLvlTemplate;ctor 增 lvlTemplateId(默认空)
- 散点路径接通模板库:工厂给 Scatter 视图注入 colorTplRepo,构造色阶编辑器传
  colorTplRepo+projectId+data_.templateId→另存/打开/覆盖可用(原 nullptr 禁用)
- 3D 体色阶编辑器(main.cpp)及网格(GridDataChartView)用默认空 templateId,行为不变

build all 绿,336/336。
6cc973a183 feat(detail): 异常详情坐标系/网格色阶templateId/新增异常类型 收尾1:1
- I11 异常详情经纬度/投影坐标:Anomaly 加 lonLatPts/eastNorthPts,parseDatasetAnomalies
  按原版响应字段(latitudeLongitude.latLon / geographicalCoordinates.coordinates)解析;
  坐标系下拉条件显示(有 latLon 才给三项,对照原版 latLon.length===0),纯展示不换算
- 网格剖面色阶 templateId:ContourPayload 加 templateId,inversion.grid 加载/重载解析
  getDetail 顶层 templateId,GridDataChartView 传入色阶编辑器→网格色阶另存覆盖可用
- 新增异常类型:仓储加 newCustomExceptionType(POST /business/customExceptionType
  {projectId,exceptionTypeName}),ExceptionDialog 按钮接通+刷新类型下拉

build all 绿,338/338。
438ed78aad feat(detail): 新增异常类型完整1:1(ExceptionTypeDialog 880px双Tab图例编辑器)
替换最小版,完整复刻原版 ExceptionLabel 子弹窗:
- 新建 ExceptionTypeDialog(880px,双Tab异常属性/标注名称):
  异常属性Tab(类型名称/代号必填/标准编号/标准名称/说明 + 按markType点/线/面/文字的
  图例样式编辑器:形状/大小/颜色/不透明度/线形/填充/字体,选项默认对照原版)
  标注名称Tab(自定义格式+分隔符+可增删名称列表 fieldName/fieldCode)
- 仓储 newCustomExceptionType 替换为 addExceptionType(POST /business/exceptionType,
  body 全字段对照原版 handleBeforeOk:legend/exceptionNameList/type:2/exceptionMarkType)
- ExceptionDialog「新增异常类型」按钮接通,成功刷新类型下拉并选中

build all 绿,341/341。
2beb97fa73 feat(vtk): 核外分块体绘制 OutOfCoreSource + renderC 基准(POC-C 命门探针)
OutOfCoreSource 实现 IVolumeRenderSource:相机选 LOD + 视锥裁剪选视野块 →
BrickPager(LRU,内存恒定)→ 每块 ≤64³ vtkImageData(带世界坐标)。renderC 用
vtkMultiBlockVolumeMapper 渲染工作集,绕开 GL_MAX_3D_TEXTURE_SIZE(16384)单轴墙。

实测(单线 store nx=44476>16384,renderB INVALID):
- 分块核外真渲出(非空像素,无纹理维度错),对照 renderB 整卷上传失败。
- 内存恒定:budget=64 驻留 64 块 / 220MB,与体总量无关。
- 静态工作集 9.5 fps;动态换页 1.45 fps(qUncompress 解压+每帧重建 mapper 177ms/帧,
  撞墙);fps 随块数近似反比劣化(256 块 0.47 fps)。结论与缓解见 poc-results-C.md。

含单元测试(纹理安全/budget 恒定/块世界坐标)。
f51706b4b3 feat(poc): renderC-partitioned 单 mapper SetPartitions 整卷体绘制 fps 探针
整卷喂单个 vtkOpenGLGPUVolumeRayCastMapper + SetPartitions(ceil(nx/16384),1,1),
绕过 GL_MAX_3D_TEXTURE_SIZE 纹理墙。双闸(纹理错捕获+真实回读非空像素)防假帧率。

实测(44476x29x162,398MB):SetPartitions(3,1,1) 真渲出(非空 1264px,无纹理错),
体绘制 ~8.8-11fps,峰值内存 ~556-653MB。绕过纹理墙成功但未达交互级(<15fps),
与 renderC MultiBlock 9.5 静态同档 → 瓶颈在全分辨率整卷 ray cast 本身,
非每块一 mapper。VTK 这条路交互级天花板暴露。
7d0e72dec2 feat(ui): 全局下拉空态优化 EmptyAwareComboBox(占位+暂无数据,对齐Arco)
下拉无数据时原为空白框+空弹窗,不优雅。新增统一空态感知下拉对齐原版 Arco ASelect:
- EmptyAwareComboBox(QComboBox 子类):showPopup 无真实项时临时插禁用灰色「暂无数据」
  条(关闭即移除,不污染取值),仍可点开;占位经 setPlaceholderText(currentIndex=-1)显示
- FormKit 加 comboBox(placeholder) 统一入口
- 全局替换全部 37 处 new QComboBox:7 处数据驱动给占位(白化文件/异常类型/反演模型/
  导入类型脚本/导出模板),30 处仅换类保留自动选首项语义(逐处判断,不破坏取值)

build all 绿,341/341。
824898a65c feat(poc): gpr_poc renderLOD 探针验证 LOD-fps 全量交互渲染可行性
四件事全离屏双闸实测(本机 RTX3060):
(a)粗层概览 level2 ~752fps (b)全分辨率局部 level0 ~380fps
(c)LOD 切换过渡切换帧 ~5.5ms 无可感知卡顿 (d)存 3 张对比 PNG。
双闸:无 3D 纹理维度错误 + 三段均回读非空像素,fps 可信。
判据:两端均达交互级且切换无卡顿 -> LOD-based C 路线钉死可行。
最低配未验,需目标机复测。tools CMake 加 IOImage 供 PNG 截图。
bec6a376d5 fix(ui): 详情对话框页脚/表单改走 FormKit 符合视觉规范(去Arco式大按钮)
之前为"像原版"手搭 QFormLayout + Arco式页脚(45%等宽/两端对齐/多主按钮/顺序反),
违反 Geopro3.0 视觉规范 §6.7/§7.5/§7.0.10。改为规范实现(字段结构/API 不动):
- 白化/另存/滤波/网格化:页脚改 formkit::addDialogButtons(右对齐 取消+确定,主按钮蓝);
  异步确认改接 Ok 按钮 clicked(校验/whitenData/save 成功才 accept);表单改 makeEditForm
  +editLabel+capField+addSection;宽度按规范(白化560/另存420/滤波保留宽/网格分组)
- 滤波"保存设置"作次按钮(ActionRole)不抢 primary;网格化 上一步(次)左+取消/确定右
- 快查:ScatterFilterDialog 可编辑输入改 makeEditForm;AutoAnnotation 主操作 setDefault
- 异常各弹窗/反演表单 已合规未动

build all 绿,341/341。
27905511e6 fix(vtk): 空态浮层钳进视图不溢出+文案更新;切项目清空中央区
- CenterOverlay::reposition 钳制浮层尺寸≤host、偏移取非负,缩小子视图时不再超界;
  空态标题/提示改为与当前功能一致(勾选左侧三维/二维/三维分析栏数据集渲染),标签换行
- 切换项目(topBar projectSwitchRequested / ProjectListDialog projectChosen,带 id≠当前
  守卫避开 delete-refresh)先 clearCentral:清三栏(col3D/col2D/colAnalysis setDatasets({}))
  + 清勾选集(checkedProfiles/Analysis/Slice)下发空到 VTK(pushChecked/syncSlices/
  setChecked2DDatasets({})) + 恢复空态浮层

build all 绿,341/341。
bdc6c90db8 fix(gpr_poc): view 概览整卷渲染修空窗 + 控制台 UTF-8 修乱码
概览/中远视角相机选中粗层时,viewRefreshBlocks 升到最细的整卷各轴
≤16384 的 level(本数据 level0/1 长线 X 超 16384 → 升 level2),用
buildLevelImage 整卷重组单块渲(忽略 budget),不再被 budget=64 砍成
64/696 稀疏块;仅相机选中 level0 全分辨率才走分块+budget(同 12c)。
main 入口 SetConsoleOutputCP(CP_UTF8) 修 Windows 中文控制台 GBK 乱码。
251046f885 fix(vtk): 切项目 clearCentral 补清底图瓦片(basemap->hide)
切项目时帘面/体素/切片/2D足迹已清,但底图瓦片(锚在旧项目地理位置)残留。
clearCentral 增 basemap->hide() 移除全部瓦片;新项目数据到来 onFrameReanchored
按新位置重显。至此切项目中央区(三栏+渲染图元+底图)全部清空。

build all 绿,341/341。
07309da1b3 fix(gpr_poc): 修复 view 子命令无限渲染循环导致窗口卡死
EndEvent 观察者会在每次 Render() 结束触发,而回调内部又调用
rw->Render(),那次 Render 再触发 EndEvent → 再进回调,形成无限
递归重渲,窗口无响应、fps 趋近 0。

- 删除 rw->AddObserver(EndEvent, cb) 自激源
- 保留 iren EndInteractionEvent 观察者(仅松手触发一次,不自激)
- viewOnInteract 加 inCb 防重入布尔(双保险)
- 整卷粗层 cachedWholeLevel 缓存不变,概览级别不变时不重建 image
e62e2cdc8d fix(vtk): 切项目复位重锚标志,修底图清空后再选不重显的回归
上一改 basemap->hide() 引入回归:切项目后再次勾选数据集,底图不再渲染。
根因:勾选是增量渲染、不走 VtkSceneView::clear(),frameAnchoredToData_ 残留为
旧项目的 true → anchorFrameIfNeeded 直接 return 不重锚 → onFrameReanchored 不触发
→ 被 hide() 的底图永不再 show(hide 前底图一直挂着才显得"正常")。
修:VtkSceneView 加 resetFrameAnchor(),clearCentral 中 hide() 前复位 →
新项目首个数据重锚→onFrameReanchored→底图按新项目位置重显。

build all 绿,341/341。
b1a8d1365d fix(gpr_poc): view 默认取景改局部段+加 --preview+fps 显真实帧率
修 view 开窗空白:默认相机框整条 2.2km 线(横截面 1:34),即便 exagg=8
也是隐形细带。三处修复:
1. 默认取景改对准沿线中段一个 ~256 道(4 brick 列)的全分辨率局部体,
   ResetCamera+Zoom 框满画面,首帧即见层状结构(同 lod-tuned-local.png 取景)。
2. 新增 view --preview:用与真窗口完全相同的相机/source/exagg/传函离屏渲一帧
   存 view-default.png,旋 N 帧报真实 fps+结构像素数(排除深蓝灰背景)+纹理错。
3. fps 文本改为松手时连渲 3 帧累计实际 Render 耗时取均值,不再把空闲间隔算进去。

实测 preview:默认视角有结构(结构像素>0)、无纹理错、真实渲染 ~185fps。
9af363080a feat(poc): view 视觉调参画廊 4 组离屏 preview
view 加 --gallery / --preview --variant N:同一沿线中段局部段+同一相机框法,渲 4 组不同视觉参数(不透明度包络/配色/取景/背景)各存 PNG 供挑选。

新增 makeSeismicColorScale(红白蓝高对比)、makeJetColorScale(全程高饱和)、makeSolidVolumeProperty(V形实体感包络:近零背景压低但可见、中高值段普遍 0.3~0.85、半透明实心内部层次可读)、meanBrightness(画面均亮度度量)。

基线默认结构像素仅 0.07%(几乎全黑、缩角落);4 组拉到 17~30%,亮度显著提升,fps 76~86(≫30)。推荐 var4 作默认。
f4922dd6e2 feat(gpr_poc): view 交互窗口默认视觉参数采用 gallery var4
无 --gallery/--preview 的交互窗口此前用旧暗默认,现统一为 var4:
seismic 配色 + V 形实体不透明度包络(floor0.035/mid0.38/max0.84) +
取景(El18/Az22/Zoom2.0) + exagg8 + 略亮冷灰背景。

- 抽出 kViewDefaultVariant 引用 kGalleryVariants 末项(var4)作单一来源,
  交互默认与 view-var4 走同一份参数,避免复制粘贴漂移(DRY)。
- 新增 makeVariantProperty 统一按包络建体属性,gallery 与交互默认共用。
- viewSetupDefaultFrame 取景角度改取自 var4;cmdView 配色/包络/背景/exagg
  默认改为 var4;--exagg/--opacity 显式传入仍覆盖。
- 验证:view --preview 产出 view-default.png 与 view-var4 一致
  (结构像素 30.18% vs 30.11%、亮度 33.9 vs 33.7、fps 77 vs 75);
  view --smoke 仍 OK。
fb175d6d3d fix(gpr_poc): view 交互窗口统一走单纹理快路,去 MultiBlock 分块
交互 view 任何相机位置都只渲一张 vtkImageData + 单 vtkSmartVolumeMapper,
与 --preview 走完全同一条产单图 + 同一 mapper 的路径:

- LOD 选层:远观/中景升到最细的整卷各轴<=16384 层(L2/L3)整卷一张纹理;
  拉近取 level0 视野覆盖的 X 子区域重组一张纹理。两条都用 buildLevelImage /
  buildLocalLevel0Image 产单图。
- 去掉交互路径的 OutOfCoreSource/BrickPager/MultiBlock + budget 分块渲染
  (renderC 等 POC 子命令仍保留)。
- LOD 随缩放真切换,只在 EndInteraction 重组一次。
- 新增 view --preview --near 拉近预览(view-near.png),与真窗口同路径。
- parseArgs 支持无值布尔旗标(--preview --near 不再误吞)。

修复:开窗+拉近无缺块(整张纹理),fps 从个位数升到几十~上百。
0537e938b4 feat(vtk): 12d 打磨探针-梯度不透明度+光照,出体内部对比3图
新增 gpr_poc polish 子命令:同一全分辨率 level0 局部段 + 斜穿俯视视角离屏渲三图对比体内部白雾能否靠打磨解决。梯度不透明度 piecewise 按实测梯度幅值分布(median/p90/p99)标定。三图唯一变量为梯度不透明度/光照:a 基线白雾、b 加梯度不透明度、c 加梯度+光照。各报结构像素/亮度/真实fps。结论:打磨消雾并让强梯度层界面浮出,但沿线长均匀段固有偏雾,梯度不透明度无法凭空长出层。
c2ec1d34b4 feat(io): IprbReader 新增 readIprbRange 道区间读取
只 seek 并读取 [t0,t1) 道,不载全文件,供流式 slab 装配内存有界。
偏移与读取字节数全 64 位防大文件溢出;越界与文件打不开抛 std::runtime_error。
不改动 readIprb 现有行为。
9d3b103e32 docs(api): 三维体/切片/异常 OpenAPI 设计稿(贴合存量 dsObject 面)
三件套 Swagger(JSON):
- 三维体/切片 = 纯元数据 dsObject:增删改查/属性复用存量 dsObject 面,
  各加 1 个登记端点;体素字节/切面数据全在客户端,后端零数据端点。
- 异常复用整套 /business/exception 端点(实体无关),异常体(consortium)
  分组为存量已有;3D 仅扩展 location 几何(worldPts+plane)与截图(R88)。
- 归属结构 TM → 三维体(dd_voxel) → 切片(dd_slice),异常挂三维体。
81e18ebd2d feat(gpr): 加 assembleGprSurveySlab 装配道区间 slab
只装配 [t0,t1) 道段的 GprSurvey,各通道用 readIprbRange 只读该段,
内存只随 slab 大小。x0=t0*dx 使 slab 世界 X 与全线对齐(B4 拼接靠此)。
抽公共 assembleFromScans helper 复用校验/标尺/Y 升序置换/值转置,
不改 assembleGprSurvey 公开行为。新增 slab 对拍与越界/通道数测试。
5ffc784792 feat(store): ChunkedVolumeStore 增量写 StreamingVolumeWriter
逐块增量写 level0 store,建体不必持有整卷。产出与非流式 write 逐 brick + meta
完全一致:data.bin 逐块 qCompress 追加(块按 finalize 时固定顺序 bz 最慢/bx 最快
索引),meta.json 结构同 write,故 ChunkedVolumeStore/readBrick 可照常读;偏移 64 位。

DRY 复用 write 的压缩/索引/meta 序列化逻辑(compressBrick/brickIndexJson/
writeMetaGeometry)。约定:每块只写一次(重复抛),缺块 finalize 抛,体素数不符抛。

核心测试 test_streaming_write.cpp:流式(乱序写)vs 非流式 write 逐块对拍 + meta
一致;含重复/缺块/尺寸不符三类错误用例。不破坏 write/readBrick/buildPyramid 现有行为。
4bb846cf07 feat(data): 流式建体 buildGprVolumeStreaming(沿X分slab,内存有界)
沿X按brick对齐分slab逐块建level0体:assembleGprSurveySlab→共享采样核
sampleGprPoint→writeBrick→释放,峰值内存只随单slab,不持整卷。产出与非流式
buildGprVolume+ChunkedVolumeStore::write逐brick+meta完全一致(对拍守护)。

- 真DRY:抽buildGprVolume的逐点采样核(X/Z落格+Y向1D插值+quant.toQ)为共享自由
  函数geopro::core::sampleGprPoint,整卷版与流式版同调,零漂移;原对拍测试守护
  buildGprVolume公开行为不变。
- 依赖方向:StreamingVolumeBuilder置src/data,命名空间geopro::data,编进
  geopro_store(store增链geopro_io_gpr;io_gpr仅依赖core,无环),core保持纯净。
- 全局量化一致:扫全线全部道tile定vmin/vmax(每次只持一道块),scale/offset与
  buildGprVolume同式,逐体素量化一致。
- B3 MEDIUM:StreamingVolumeWriter改持久ofstream成员(构造开/writeBrick复用/
  finalize关),消除每块open/close;同步更新对应回归测试的writer作用域。
77cbe4a305 feat(store): 流式金字塔 buildPyramidStreaming 逐块由盘上邻块降采样
level L 每块由 level L-1 的 ≤2×2×2 邻块(readBrick 从盘读)降采样 + 逐块增量写
data_L<L>.bin 得到,不重组整卷,任意时刻只持几个邻块+一个块,内存有界。

复用 buildPyramid 同一降采样核(downsampleVoxel 2×2×2 非 blank 平均 round、
全 blank→kBlank)、computeRange 与 finalizePyramidMeta 收尾(DRY),产出各级
dims/每块体素/min-max/hasRange/meta 与 buildPyramid 逐块一致。

测试:Pyramid.StreamingMatchesInRam 系列(128 整除、100/127 非整除奇数、
70×33×50 各向异性小 brick、全 blank 体)流式 vs 重组整卷逐块对拍;不破坏
buildPyramid/write/readBrick(store/streaming/pyramid 20 例全绿)。
aa559c2bb7 docs: 后端 API 设计会话交接文档(三维体/切片/异常)
记录本会话设计定论、剩余工作、待确认问题与代码地图,
配套 docs/api/vtk-3d-openapi.json 与实现交接 HANDOFF-vtk-3d.md。
fa348a2a9f feat(render): C1 视野自适应 LOD 选层(纯逻辑 headless)
selectLod(VolumeView,CameraView,maxTextureDim=16384)→LodSelection:
透视相机参数构 5 视锥面(左/右/上/下/近),保守 p-vertex 裁剪求该层可见
brick 区间;按 worldPerPixel 定最细不过采样层 Lmin,再逐级变粗直到区间
重组单纹理各轴 ≤maxTextureDim。远观→粗层整卷、近观→细层小块、视锥外→empty。
零 VTK/Qt 依赖,与 OutOfCoreSource 几何约定一致(level L 间距×2^L、维度 ceil(n/2^L))。
10 例 headless 单测覆盖远/近/侧/视锥外/极小 maxTextureDim/视距-层单调。
0da5accebe fix(lod): selectLod 最粗层兜底裁剪,保证返回区间恒不超 maxTextureDim
最粗层 fits||maxLevel 分支原先无条件返回,不校验 fits;合并体最粗层
全可见区间仍 >maxTextureDim 时返回区间会突破单纹理硬上限,C2 重组撞
GL 16384 纹理墙退回慢路。

新增 clampAxisToMaxTexture,在所有返回路径前按可见中心对称裁三轴到
重组单纹理各轴 <= maxTextureDim 的子区间;brick 本身 > maxTextureDim
的退化情形返回单块并由 C2 体素级再裁(契约见 hpp)。补 3 例边界测试
(brick>maxTextureDim、最粗层整卷超限、改写 RespectsMaxTextureDimAlways
为 brick!=maxTextureDim),原有用例全绿。
fc9ea58cb5 feat(vtk): ViewAdaptiveVolumeSource 视野区域单纹理重组(C2)
用 C1 selectLod 选层选区,从 ChunkedVolumeStore 把当前视野区域重组为单张
VTK_SHORT vtkImageData(各轴 ≤16384,世界 origin/spacing 按 level+exagg),实现
IVolumeRenderSource。核心 updateView(CameraView,VolumeView) headless 可测。
gpr_poc view 切到该源(退掉 MultiBlock/budget 简化路径),--preview 渲默认视角存
PNG,--smoke 离屏不崩且 LOD 随缩放切换。
fa34cb0bc3 feat(render): C3-1 AsyncRegionBuilder 后台异步重组 + 双缓冲交接
抽公共重组核 reorganizeRegion(RegionReorganizer.{hpp,cpp})为单一真源:
C2 ViewAdaptiveVolumeSource 改委托、C3 AsyncRegionBuilder 也调它(真 DRY)。

AsyncRegionBuilder:后台 worker 调重组核构建 vtkImageData,主线程非阻塞
takeLatest 取最新就绪;requestTarget supersede 收敛最新不堆积。线程安全:
vtkImageData refcount 增减全在 mutex 内/单线程独占,析构置 stop 唤醒干净 join。

测试:5 个异步用例(同步一致/supersede 收敛/析构忙时干净 join/并发 400 次不崩
不死锁/takeLatest 非阻塞)全绿;C1+C2 的 17 个 ViewAdaptive* 抽核后回归全绿。
cec41e3539 feat(vtk): ViewAdaptive 接异步重组(update 不阻塞,view 拖动不卡)+修 C2 维度用 store.dims
把 C3-1 AsyncRegionBuilder 接进 ViewAdaptiveVolumeSource:updateView 只提交目标
(selectLod→RegionTarget→requestTarget),不在主线程重组、立即返回;currentImages/
sliceSource 经 builder.takeLatest 取最新已就绪(没新结果用上一张),空选区不提交、
保留上一张。新增 AsyncRegionBuilder::takeLatest(int&) 非破坏式重载随结果回传 level,
供 lastLevel 同步。

C2 MEDIUM:RegionReorganizer 维度改用 store.dims(level)(单一真源),弃自算
ceil(n/2^level),防 store 降采样规则漂移。

gpr_poc view 切异步:拖动中 InteractionEvent 持续提交目标(非阻塞)+33ms 重复定时器
非阻塞拉取后台就绪纹理换上→主线程不被重组卡住(跟手);preview/smoke/默认取景用
阻塞轮询保证拿到首图。

测试:ViewAdaptive 9 测(原 6 调为异步轮询版+新增 3:AsyncUpdateEventuallyReady/
UpdateDoesNotBlock(<50ms)/UsesStoreDimsNotSelfComputed),AsyncRegionBuilder 5 测仍绿;
全量 382 测通过。
ced2ca7811 feat(render): AsyncRegionBuilder 就绪缓存LRU+预取+相同目标短路
C3-3:为 AsyncRegionBuilder 加按 RegionTarget 键的有界 LRU 就绪缓存
(容量N默认6)、prefetch 后台低优先预取(不抢占主目标)、getReady 非阻塞
缓存命中,并短路 requestTarget 相同目标(修 C3-2 LOW)。worker 每轮主
目标优先,否则建预取队列最新;缓存/refcount 增减全在锁内,析构干净 join。
ViewAdaptiveVolumeSource:updateView 提交主目标后预测下一目标(细一层
同区+沿相机方向平移一格 brick 列)并 prefetch;currentImages 走
getReady(主目标)命中即用否则沿用上一张。线程安全延续 C3-1。
a4db37735a perf(vtk): view 开交互式采样距离自适应修长板填屏 ray-march 慢
POC 当初为离屏基准把 AutoAdjustSampleDistances/InteractiveAdjustSampleDistances
关掉(求恒定全质量),交互场景长板填屏每像素沿超长轴海量采样 → 2.8fps。开启二者
并设 interactor DesiredUpdateRate(15)/StillUpdateRate(0.5):拖动期按目标帧率拉大
SampleDistance 降采样(快、跟手),松手恢复小步长全质量。--preview 加交互态(降采样)
fps 与全质量静态对照量化提速。merged_b6 全路段实测提速 14.9x~21.2x,交互态 ≥15fps。
fb944f706f feat(vtk): 常驻粗底图+局部高清叠加(永不空白)
ViewAdaptiveVolumeSource 构造时一次性在主线程建整卷最粗「各轴≤16384」层
单纹理底图 baseImage(),永远持有、永不释放、绝不被异步路径触碰——任何视角/
任何运动中底图都盖住整个体,拖动/缩放绝不空白。高清(currentImages)异步重组
当前视野后叠在底图之上局部覆盖,未就绪时只显底图。gpr_poc view 用两个 vtkVolume
(底图先渲、高清叠加),新增 --preview --base 出整卷概览底图截图。为 morph(C3-4)/
运动跟踪(C3-7)打两层结构。
8edc1f30ac feat(vtk): build-geo 按真实RTK几何把多线拼成统一路向三维体
新增 GpsTrack(.gps解析+经纬→局部米+里程插值/航向) 与 GeoVolumeBuilder
(PCA路向旋转+多线统一网格重叠均值+量化落盘), gpr_poc 加 build-geo 子命令。
消除顺序拼接退化扁带: 真实明星路20线建体 4474x52x82(≈预测4472x43x81),
填充率62%, 旋转-89.5°, 峰值内存258MB, 各轴≤16384整卷单纹理可渲。
复用 readIprb/IprHeader/GprGeometry/ChunkedVolumeStore/Quant, 未重造IO/store。
d028994324 feat(vtk): C4 体绘制梯度不透明度+光照,内部分层界面透出
view --gallery 改为 4 组 C4 对照(纯标量/+梯度不透明度/+光照/全开):
- GalleryVariant 增 useGradientOpacity/useShade 字段(默认关,不改既有行为)
- makeVariantProperty 叠加 SetGradientOpacity(按实测梯度分位 median/p90/p99
  标定:均匀层透明、界面/异常显形)+ ShadeOn(Ambient/Diffuse/Specular 立体明暗)
- 纯标量组 max0.45;开梯度门的组 max0.6(净不透明度=标量×梯度,层面才浮实)
- 交互 view 默认变体(var4 全开)从常驻底图实测梯度分布标定阈值

tmp/geo 真实全路段体(4474x52x82)实测:纯标量糊成半透明实心块仅端面可读;
开梯度不透明度后均匀块透出内部水平分层界面,光照令界面带立体感。
fps:纯标量155→梯度门48(画廊),交互默认98静态/267拖动态,均交互级。
398 测试全过。
90abeaa9b6 fix(vtk): 垂直夸张只放大深度Z(修路被压胖) + 底图按高清块cropping挖空消双渲发白 + 降高光
三处真视觉 bug 修复(tmp/geo 全路段体上复现):
- exagg 轴误用:view 的底图/高清两 actor 原 SetScale(1,exagg,exagg) 把横向路宽(Y)
  与深度(Z)一起放大,2237m 长路被压成胖块;改为 SetScale(1,1,exagg) 只放大深度,
  路恢复真实细长(长:宽≈86:1,4474:52 cells)。两 actor scale 保持一致。
- 两层重叠双渲:底图(整卷)与高清(局部)vtkVolume 空间重叠,重叠区双渲发白且随相机
  移动;给底图 mapper 开 Cropping,裁剪平面=高清单图模型盒(GetBounds,与底图同坐标系),
  CroppingRegionFlags=0x7ffffff&~VTK_CROP_SUBVOLUME(挖掉中心盒、渲盒外),高清换位时
  同步更新;高清未就绪/base 预览时关 cropping 全渲(永不空白)。
- 降高光:var4 光照 Specular 0.2→0.05,消除旋转时视角相关高光游走形成的移动白斑,
  保留 ambient/diffuse 立体感。
- 验收:--preview --shots 多旋转角离屏出图;398 测试全过。
509ba35a47 feat(geo): build-geo 新增中心线曲线坐标网格化(--curvilinear)+距离加权
取最长线 GPS 轨迹作中心线,把每点投影得(沿路里程 s,带符号横偏 d),
网格 X=s/Y=d/Z=深度,把弯路拉直消假鳍;横向范围用带符号 d 的[1%,99%]分位
(鲁棒于离群桩线、不浪费空白半侧);重叠按到 cell 中心的距离加权(w=1/(1+d^2))
代替等权均值。保留 PCA 版供对照(curvilinear 默认 false)。

GpsTrack 新增 projectToCenterline/resampleAndSmooth(纯函数,含直/弯线单测);
GeoVolumeBuilder 新增 distanceWeight 纯函数。

真实数据(明星路 20 线,cellXY 0.5):曲线版 4487x45x82 填充 68.8%,
PCA 版 4474x52x82 填充 62.2% —— ny 更小(拉直)、填充更密、假鳍明显减少。
eceb964aa1 docs: VTK 三维分类视图重构 spec + 三维体归属层级修订
- 新增 spec: 按数据类型大类(电阻率/视电阻率/瞬变电磁/三维体/切片)分组视图; 对象树 GS 三态双开关联动 + 项目根固定; 装置类型(arrayType)/采集时间(collectTime)筛选; VTK 画布工具条; createVolume/createSlice 组装真实请求体 DTO(走 mock)
- vtk-3d-openapi.json v0.5-draft: 三维体归属由 TM 改为 GS/项目根(structParentConfType=1)
- 经 opus 子代理评审并据评审修订(GS 三态停用 AutoTristate 改手动/properties 两接口形态澄清/帘面勾选链承接等)
ef10c354c9 docs: VTK 重构实施 plan + 生成三维体入口/归属调整
- 新增实施计划(8 phase/12 task, TDD bite-sized)
- 客户确认变动: 新增三维体入口回段头(数据类型层面)+对话框「生成位置」选归属; 归属放开 GS/项目根/TM(structParentConfType 1或2, 默认单GS挂该GS/跨GS挂项目根)
- spec 同步该变动; openapi 升 v0.6-draft
1978a31fa7 feat(tree): GS 三态状态机(停 AutoTristate)+右键 ds/tm + checkedSourcesChanged 源集合
合并 plan Task 4+5:plan Task 4 右键代码已引用 Task 5 的 emitCheckedSources,
二者均改 ObjectTreePanel 且循环依赖,合并实现避免中间不可编译态。
checkedSourcesChanged 与旧 checkedTmsChanged 并存,Task 12 接线切换后删旧。
0efd84544c feat(gpr3dv): 拷入 3DGPRViewer 数据生成链(geopro_gpr3dv 静态库)+冒烟
把参考实现的"多通道测线→GPRDataModel立方体→RadarProcessor处理"链
原样 vendored 进 external/gpr3dviewer/(算法零改动),生产管线A地基。

- 拷入: GPRDataModel.h/SurveyGeometry.h/RadarTypes.h/IprhParser/
  ImpulseMultiChannelConverter/Rd3Parser/RadarProcessor/PerformanceLogger
  + third_party/kissfft/*(逐字复制,未动算法体)。
- CMake: geopro_gpr3dv 静态库,链 Qt6::Core+Gui(QVector3D)+OpenMP+kissfft;
  enable_language(C)使kissfft .c入编;接进根构建。
- .gitignore: /external/* + 例外 !/external/gpr3dviewer/ 使 vendored 入库,
  qwt-src/vtk-install 仍忽略。
- 冒烟 tools/gpr3dv_smoke: 走原版 API loadImpulseMultiChannel→buildVolumeData
  →runPipeline(默认流水线)。线001冒烟: 通道数=14(读自数据)、立方体
  14x45305x821、处理前后平均绝对幅值 393.58→360.34(处理生效)。
- 全量构建通过,425/425 测试通过。
a32822f7d6 feat(gpr3dv): 桥接处理后立方体→geopro量化/分块/VTK体绘制(P2 渲第一条线真三维体)
把 gpr3dv(P1)处理链产出的处理后立方体桥接到 geopro 已有的量化+ChunkedVolumeStore
+VTK 体绘制,渲出第一条线(明星路_001)的真三维体。算法零改动,仅复用 geopro 量化/
store/渲染。

- 新增桥接 src/io/gpr/Gpr3dvVolumeBridge.{hpp,cpp}(独立 target geopro_gpr3dv_bridge,
  不污染纯 C++17 解析层):走 P1 原版 API load→buildVolumeData→runPipeline(默认链)
  →再 buildVolumeData(处理后),得 volumeData[通道][道][样本];轴映射 X=道/Y=通道/
  Z=样本;扫值域定 Quant(offset=中点);世界 spacing(dx=道距/dy=通道横距/dz=深度采样距)。
- gpr_poc 加子命令 build-line <lineDir> <linePrefix> --out <store> [--levels N]:
  桥接→ChunkedVolumeStore::write+buildPyramid,报维度/量化/spacing/内存/耗时;view 渲。
- 测试 tests/io/gpr/test_gpr3dv_volume_bridge.cpp:合成 2 通道 Impulse 测线走真链,
  校验轴映射/spacing/量化(offset=中点)/稠密体无 kBlank/缺线抛异常。

真实数据验收(明星路_001):体维度 45305×14×796(道×通道×样本,样本由 821 经零时校正
裁至 796),处理后值域[-9249,9206] scale=0.288 offset=-21.5,spacing dx=0.049/dy=0.105/
dz=0.0101m,落盘 845MB 压缩比 1.14x;view --preview/--base 渲出无纹理错、整卷盖全。
全量测试通过。
7a294e13ab fix(vtk): 逐线处理后三维体修可见性(传函2/98分位标定+段落取景+段直读)
P2 逐线处理后体(tmp/line001_proc 45305x14x796)渲染近黑。根因:处理后值多集中±360窄带、少量离群±9000,view传函按meta全量化域(±9249)映射→窄带信号近透明→全黑。

修:① 新增 sampleScalarPercentiles 扫该体实际值取2%/98%分位作色阶/不透明度物理端点(裁离群),wired 进 cmdView(底图基准)与 runGalleryVariant(局部段基准);② 默认取景:viewSetupDefaultFrame 直读 level0 沿线中段子体喂高清 mapper(绕开异步LOD在框一段视距下仍选最粗整条细带层),并只框该段包围盒,相机改从+Y正对X-Z宽面(B-scan墙)、小角度取景;梯度不透明度+光照(var4)与exagg仅深度均保留。

效果(tmp/line001_proc --preview):结构像素 0.07%→2.7%(level0),清晰可见GPR内部分层(横向层叠+通道竖纹+基底强反射),fps~78/127(静/交互态)。431 测试全过。
4330e12c3e feat(vtk): 逐线三维体调亮调清晰(gallery 4 组对照)
P3 默认(seismic+严格梯度门+低 ambient)整体偏暗、均匀层被门全透成空。
本次只调视觉(配色/不透明度/梯度门松弛/光照),不动建体/桥接/异步/LOD:
- 新增调亮版 seismic、增强灰度两套配色
- GalleryVariant 加 gradGateRelax(梯度门松弛 0~1)与 ambient 字段
- makeVariantProperty 按松弛度抬低梯度地板+左移阈值,保留弱结构;ambient 由变体控
- 4 组对照重排:var1 暗版基线 / var2 提亮 seismic / var3 jet 高对比 / var4 增强灰度(默认)
- gallery --out 让出图落在 store 目录(tmp/line001_proc),便于就地对照
- 端点仍按该体 2/98 分位自适应,非写死

实测(tmp/line001_proc):默认 var4 平均亮度 21.97→43.28、结构像素 3.9%→23.1%,
明显更亮更清晰;fps 约 51(交互级)。
4e2bdc3b81 feat(gpr): build-line 健壮支持任意测线 + 新增 build-all 批量建体(磁盘守护/coarse 下采样)
- 桥接 buildLineVolumeFromGpr3dv 增 coarse 参数:沿测线(道/X 轴)按步长下采样,
  spacing.x ×stride 保持真实世界尺度;通道/样本保留全分辨率。默认 coarse=1 全分辨率,
  对现有调用与测试零影响。
- build-line 增 --coarse F;单线建体核心抽出 buildOneLine,加体维度退化守护
  (短桩线 nx<2 等报因跳过不落盘),整条 try/catch 不崩。
- 新增 build-all <lineDir> --outBase <baseDir> [--levels N] [--coarse F]
  [--minFreeGB G]:扫 *_A<NN>.iprh 发现全部测线,逐条建到 baseDir/<line>/;
  每条建前查磁盘剩余,低于阈值(默认 3G)停并报已建哪些;单条异常捕获跳过不中断批量;
  末尾打印各线状态(成功/跳过+因/维度/大小)与合计占用。
- 通道/道/样本全从数据读,不写死;不破坏现有 gpr/bridge 测试(12/12 通过)。
d70590cbef feat(data): 逐线 GPR 体反量化适配器 + GprVolumeRepository
新增数据层方案A纯数据通道,把逐线 GPR 处理后 int16 量化体(io::gpr
buildLineVolumeFromGpr3dv 产 BuiltI16)反量化成 app 渲染链吃的稠密 float 体
(data::VolumeGrid),使真实雷达三维体可经现成 loadVolume->addVolume->buildVoxel
显示(替 mock),零碰并行会话 UI/树/异常热文件。

- builtI16ToVolumeGrid:纯函数适配器,逐体素 Quant::toPhys 反量化,
  kBlank 空值哨兵->NaN(下游 buildVoxel 映射透明),origin/spacing/vmin-vmax 搬运。
- createGprVolumeGrid(lineDir,linePrefix,coarse=4):走 P1/P2 链建逐线体->适配。
- 单测:适配器逐值反量化/维度/spacing/origin/kBlank->NaN;全链合成多通道
  .iprb 走真链产出有效 VolumeGrid;缺线抛异常。434 测试全过,无回归。
0a0d3ba017 feat(gpr_poc): 加 view-all 子命令——20 条独立体按真实 GPS 位置/航向摆进同一 3D 场景一起渲
发现 storesDir 下所有 明星路_NNN 体;公共世界原点取全体 .gps 最小经纬;
每条线按其 .gps 起点平移 + 起→止航向绕 Z 旋转定 vtkTransform,整卷体套
UserTransform 全加进同一 renderer 一起渲;仅 Z 方向 exagg 夸张;传函复用 P4
默认醒目版(var4)逐体 2/98 分位标定。--preview 出俯视+斜视两图。
真实位置下同路多趟会重叠成一带,加 --spread M 可沿垂直航向铺开成可分辨测区。
复用 geopro::io::gpr::GpsTrack(parseGps/lonLatToLocalM)。
f713c15366 feat(gpr3dv): 移植精确坐标/轨迹/世界网格(CGCS2000)+测绘级逐线世界对齐建体
复制 CoordinateTransform/TrajectoryCalculator/CScanGridder/PosParser(逐字节一致)进
external/gpr3dviewer;新增 Gpr3dvSurveyVolumeBridge 按 CGCS2000+逐道GPS轨迹建世界对齐体;
gpr_poc 加 build-survey-all/view-survey-all(各体自带世界origin,精确就位跟GPS弯)。
72e82be63c feat(gpr_poc): view-all 摆放升级到精确 CGCS2000(密实立方体+测绘级坐标)
view-all 起点投影从 lonLatToLocalM(简化等距)换成 CoordinateTransform::wgs84ToCgcs2000
(CGCS2000 高斯克吕格3°带,与P8桥接同口径);公共带号+公共原点,每条密实立方体刚体
摆放(平移CGCS2000起点+绕Z航向+Z-only exagg)→ 密实+精确坐标一起渲。
7bdb291fb4 fix(gpr): 修世界网格路径短线建体失败(007 深度0 网格无效)
根因:CGCS easting 含带号约 4.0e7 米,存入 QVector3D(float32)后该量级
ULP 约 4 米;近正北短线 007 的东向跨度仅 0.81 米被浮点量化抹平成同值,
CScanGridder 内 maxX<=minX 判退,返回空网格触发「深度0 网格无效」。

桥接层修法(不碰 verbatim 算法):存入 float 轨迹前先平移到局部原点
(首点 floor 到整米),坐标降到约 10^2 米量级,float 亚毫米精度无损;
CScanGridder/TrajectoryCalculator 全程仅用差分/距离/IDW,对常量平移不变,
输出与未平移一致;最后把平移量加回 built.origin 还原真实 CGCS2000 世界米。

007 建成 23x347x195(东x北x深,78.5% 填充);001 不回归(18x1451x199,
world origin 与基线 sub-meter 一致);external/gpr3dviewer 算法文件零改动。
46f0144287 perf(vtk): view-all 每条体接入视野自适应引擎修拉近纹理墙
每条线改用 ViewAdaptiveVolumeSource(LOD+视锥裁剪+异步重组,复用未重写),
恒产 ≤16384 单纹理 → 根除拉近时 GL MAX_3D_TEXTURE_SIZE 纹理维度错误。
相机逐线逆变换到局部帧喂引擎选层选区;按世界 AABB 与相机视锥面比对裁屏外线
(base+hires 两层皆隐);mapper 开 Auto/InteractiveAdjustSampleDistances 拖动降采样。
世界摆放 T(Scale-RotateZ-Translate) 与原 makePlacedVolume 同口径,CGCS2000 定位不变。

实测(20条全分辨率,exagg=8):spread 60 线条分离时拉近裁掉 13/20、提速 1.72x
(概览 29.7fps→拉近 50.9fps);两场景纹理维度错误均消除。
f52d38d97b perf(gpr_poc): view-all 概览每线单体 LOD,40 体→20 体修 1fps 卡顿
P11 cmdViewAll 每条线把 baseVolume(常驻底图)+hiresVolume(高清)两层都加进
renderer,20 线=40 体每帧 ray-cast,概览全可见(culled 0)→1.1fps。

改为每线只渲一个体:起步喂 baseImage()(粗 whole,小且不空,≤16384),引擎
按相机备好更合适 LOD 单图(currentImages)后整图换上 → 任何时刻每线 ≤1 体,
最多 20 体。视锥裁剪 toggle 唯一体可见性,拖动降采样保留,静止只渲就绪纹理
不重建。复用 ViewAdaptiveVolumeSource 引擎,未改库。

概览 1.1fps→42.98fps;体数 40→20(20 visible/0 culled);拉近 22.85fps
(17 visible/3 culled,视锥裁剪生效);无纹理维度错误,满帧非空白。
7de221ddce perf(gpr_poc): view-all 拖动中只视锥裁剪不重建,修转动/缩放thrash卡死
拖动中 viewAllOnInteracting 原每次都提交20条体引擎目标→反复异步重建+上传GPU→
GPU100% thrash→转一下卡死. 改为拖动中只做视锥裁剪(切可见性,便宜)、绝不重建;
重建只在松手EndInteraction触发一次(异步+supersede,快速缩放自动只建最后目标).
70f77c1736 refactor(vtk): 退役旧三维数据集/三维分析栏(Task 12 #6)-删 Column3D* 及全部死接线
旧 col3D_/colAnalysis_ 自分段重构后已 hide() 不入 tab、运行时不发信号,其 18 处
connect 全为死接线。本次彻底退役:
- 删 main.cpp 中 10 个 c3(Column3DDataset)+7 个 ca(Column3DAnalysis)+1 个 col3D() VE 接线
- 删 ColumnDrawer 的 col3D_/colAnalysis_ 成员/访问器/实例化/include/前向声明
- 删 4 个源文件 Column3DDataset.{hpp,cpp} / Column3DAnalysis.{hpp,cpp} + CMake 条目

唯一运行时仍在跑的 ca 消费是 refreshAnomalies(读 anomalyFilterMode 写 setAnomalies):
档位改恒「全部显示」(=隐藏 ca 的当前等效行为),异常列表已由 refreshAnalysis 经
voxelTree 全量注入新分段 tab,故去掉 ca->setAnomalies。零可见回归。

已知遗留(旧栏退役暴露,均非本次引入,待新分段段补 API):
- 新建/关闭切片不再自动勾选/取消列表(CategorySection 无 setItemChecked)
- 异常显示过滤档位、列表选中→VTK高亮(R84)随 ca 信号退役,待新段补信号

构建:configure+app 链接通过;测试 isolated 全绿(AsyncRegionBuilder 预取测试满载 flaky,
隔离复跑 3/3 过,属 GPR 域与本次无关)
a2770ba49d fix(vtk): 坐标轴设置交互修复(批1/#5)-增量渲染+VE滑块+隐藏轴全隐+关闭按钮
- 5.1 关闭按钮空白:全局 QPushButton padding(6px14px) 挤掉 ×,显式 setStyleSheet padding:0
- 5.2 取消某轴「显示」时禁用其 min/max 编辑框(show toggled→lo/hi setEnabled,回灌同步)
- 5.3 隐藏轴后刻度数字仍在:SetXAxisVisibility 只关线,补 SetXAxisLabelVisibility/TickVisibility
- 5.4 应用即全量重绘→改增量:setAxesConfig 不再 rebuildInternal(clear场景),改
       view_.setAxes+setAxesRanges+renderIncremental(仅重建坐标轴 prop,不动数据/相机)
- 5.5 放大系数下拉→滑块(1~10×,恢复重构前交互):拖动实时改标签,sliderReleased 才发
       verticalExaggerationChanged 触发一次重建(VE 改几何须重建但不在拖动中连续重建)
       main.cpp 接 applied(去scale) + verticalExaggerationChanged(→控制器+底图)

构建:app 链接通过
b497fe547c fix(ui): 分段树修复(批2)-选中高亮统一对象树+结构还原TM挂载+缩进一致
- #2 DatasetCardDelegate 选中/hover 改与对象树(ObjectRowDelegate)一致:整行方角填充
     (去圆角卡)+左2px accent竖条满高+选中标题加粗;保留双行卡片(创建时间·类型副标题)
- #4 CategorySection 树结构:派生 ds(反演剖面)带派生父指向已被筛掉/属别段的原始 ds 时,
     按 parentId 挂载失败→ds 浮到根平铺。改:派生父在本段保留嵌套(体>切片),否则回退挂
     结构容器 structParentId(TM),还原 项目/GS/TM/DS 真实层级
- #6 三维体段体相对TM缩进过大:容器节点(项目/GS/TM)不画复选框但保留同宽复选框列,使
     各级缩进只差一个树级(原先容器无列宽→子级带框缩进多撑出复选框列宽),与对象树一致

构建:app 链接通过
6a371c9fa9 fix(ui): 筛选行+分析tab滚动重构(批3/#3#7)
- #3 时间筛选下拉:QToolButton 套与 QComboBox 一致的 box(同高/边框/圆角/padding)+右侧统一
     SVG chevron(:/icons/chevron-down.svg),去掉手写粗糙的「▾」字符;修高度比装置下拉矮
- #7 分析tab滚动:各段在 tab 内 stretch=1(内容都少时四段平分高度填满、与VTK区等高不出滚动条);
     段体 list 关内层纵/横滚动条 + 最小高度=可见项内容总高(有副标题52/否则30,同delegate sizeHint),
     内容多则整段拉长、超视口由外层 QScrollArea 统一出单滚动条;去掉末尾 addStretch

构建:app 链接通过
7ff6f184e9 fix(vtk): 坐标轴/树/筛选跟进修复 + VE保留相机重建 + 异常删除刷actor
坐标轴(5.4/5.5):
- 放大系数改回「点应用才生效」(不再实时):VE 回 applied 信号一并下发;滑块 setPageStep(1)
  修「点轨道直接跳到10」;放大系数组与上方留间距
- 5.4 改VE不再先跳远视角:setVerticalExaggeration 走保留相机重建(preserveCameraOnRebuild)→
  render(resetCamera=false) 不 ResetCamera、fitOnArrival=false,异步到场数据在当前相机下重绘
树:
- #2 撤销 #6 容器复选框列预留(它造成容器名与展开图标间大留白);容器名紧跟展开图标(小留白)
- #3 时间下拉 chevron 跑左上角:`right 8px center` 是CSS偏移语法Qt不认→改 `right center`+origin
异常:
- 右键删除异常只刷列表没刷actor(场景仍渲染)→ deleteAnomaly 成功回调加 refreshAnomalies(技术债)

CLAUDE.md:新增「发现技术债务必须修,不以'非本轮引入'为由搁置」绑定规则

构建:app 链接通过
a6cdd2ff80 feat(3d): createSlice 打印 SliceGenerateRequest 请求体到 log(供后端联调)
createVolume(req) 已打印 [volreq] 请求体;补 createSlice 打印 [slicereq] registerSlice 请求体
(对齐 SliceGenerateRequest / POST /business/dsObject/slice/generate):volumeDsId/name/axis/
三点位姿 origin·point1·point2/colorScaleId。projectId 由真实请求层据当前项目填(mock 无上下文留空)。

构建:app 链接通过
961af652d7 fix(ui): #1 两 tab 平分抽屉宽度,消除旧3栏遗留的右侧空白第三栏位
旧布局 3 栏(三维数据集/二维数据集/三维分析)三分横向空间;重构成 2 tab 后全局 QSS 让 tab 取
内容宽度左对齐,宽抽屉右侧留出约一栏空白(用户感知为"空着的第三栏位")。带样式表的 tab 不响应
setExpanding,故在 ColumnDrawer::resizeEvent 按 barWidth/n 给每个 tab 显式宽度,两 tab 平分填满。

构建:app 链接通过
63fe99dba5 docs: 新增全局待优化清单 OPTIMIZATION-BACKLOG.md
后续所有「能用但不够理想、需更大改造」的优化点登记于此并随进展更新状态(区别于当场修的bug)。
首条 OPT-001=放大系数(VE)完全无重绘的即时缩放(当前保留相机重建仍有一次重绘,纯actor缩放待办)。
09a48d846b fix(ui): 栏位勾选增量保留 + tab去箭头 + 缩进 + 滑块跳位 + 清日志警告
- 栏位状态增量(最关键):CategorySection::rebuildList 记住已勾选 ds、重建后复原;之前每次刷新
  (勾选对象/建体/存切片/建异常都触发)清空全部勾选→渲染被重置。复原后 emitChecked 上抛同集,
  控制器据 diff 增量保留已渲染图元
- #1 tab 左右滚动箭头:上轮宽度算法没扣 padding 致溢出。扣开销(~42)稍欠宽 + setUsesScrollButtons(false) 兜底
- #6 缩进:容器文本左缘对齐子级复选框列起点(pad 12,非整列36),「容器→带框子级」缩进=树级(14),
  与「带框→带框」一致,且名称仍紧邻展开图标(无 #2 大留白)
- 5.5 滑块点轨道跳位:ClickJumpSlider 用 QStyle::sliderValueFromPosition 点哪跳哪(点手柄正常拖动)
- 日志 201× QFont pointSize<=0(-1) 警告:ObjectRowDelegate 去掉多余 setPointSizeF(-1)(setPixelSize 直接生效)

构建:app 链接通过
652b37b672 fix(vtk): 修创建切片/异常清空体·切片选择(issue1)+异常副标题补时间+新切片自动勾选
- issue1 真因:voxel(三维体)段数据来自 mock voxelTree,但 setBuckets 用 splitByCategory 的空桶
  (对象树 ds 里无 dd_voxel→必空)先 setDatasets(空) 清掉其勾选,随后 section("voxel")->setDatasets
  (voxelTree) 重填时勾选已丢→「创建切片/异常后体/切片选择被清空」。修:setBuckets 跳过 voxel 段
- 异常副标题没时间:saveAnomaly 没设 createTime(main 构建 Anomaly 也没设)→补当前时间(mock)
- 新切片自动勾选:CategorySection::setChecked(dsId) + 保存切片回调在 refreshAnalysis 后勾选新切片
  (恢复旧行为,避免刚存的切片因未勾被 syncSlices 隐藏)

未解(下轮):issue2 选第二个体时第一个体切片消失=单"当前体"模型固有限制(syncSlices 只显示
volumeDsId==currentVolumeDsId 的切片),需多体并发切片渲染改造

构建:app 链接通过
62b7cde5cd fix(ui): 筛选时间换 QComboBox(与装置同款) + 异常复选框驱动显隐(①)
- #3/#4 DateRangeEdit 重写为 QComboBox 子类(覆写 showPopup 弹双日历):外观与装置下拉完全一致
  (同款原生下拉箭头/高度/边框),消除 QToolButton 方案的 popup「must be top level window」告警
- ① 创建异常后取消勾选仍渲染:异常行复选框现驱动显隐——itemChanged 对 dd_anomaly 发
  anomalyVisibilityChanged→setAnomalyVisible;异常默认勾选=显示(新项默认勾,曾取消的保留);
  refreshAnomalies 按三维体段复选框设各异常可见性;异常创建回调改为先 refreshAnalysis 再 refreshAnomalies

构建:app 链接通过
b2904c211e fix(vtk): 坐标轴面板预热(4a)+装置枚举到达重刷下拉+树→VTK选中联动正向(②)
- 4a 坐标轴面板首开卡顿:启动时 ensurePolished+adjustSize 预热样式/布局,避免首次点开同步解析卡UI
- 装置下拉空:枚举异步加载(可能晚于数据)→在 listArrayTypes 回调里 refreshArrayFilters 重填各段下拉
- ② 树选中切片/异常→VTK高亮:CategorySection 发 datasetSelected→main 对 dd_anomaly setSelectedAnomaly
  /dd_slice selectSavedSlice。反向(VTK→树)需拾取回调,并入 OPT-002

构建:app 链接通过
40c8d6ccb4 fix(ui): 创建三维体对话框 左侧源/右侧生成位置 改树型结构(4b)
- 左「已选择对象」:QListWidget 平铺 → QTreeWidget(项目/GS/TM 容器树 + 可勾选源 ds 挂各自结构归属下,
  容器按源 ds 的 structParentId 向上剪枝)
- 右「生成位置」:QComboBox 平铺 → QTreeWidget(GS/项目根/TM 层级单选);confType 据所选节点 type 推导
- ctor 改签名:传 VolumeSourceItem(含 structParentId)+ StructNode 结构 + defaultMountId;main 同步传 structParentId

构建:app 链接通过
69e8790810 feat(vtk): 多三维体并发切片渲染重构(OPT-002:issue2+③+反向②)
核心:InteractionManager 单 image_ → 按 volumeDsId 的多体 map;各切片附着到各自体的 image。
- issue2 选第二个体→第一个体切片消失:setVolumeImage 不再 closeAll 全部切片;改 upsert 某体(同体重建
  才关该体切片)。syncSlices 改为「勾选 + 父体已渲染」即显示(不再限当前体)→ 多体切片并存
- ③ 右键体却建到 current 体:sliceRequested 带目标体 dsId;addSlice(axis,volumeDsId) 用该体 image;
  保存切片/创建异常的 volumeDsId 改用 selectedSliceVolumeDsId(选中切片所属体)而非 currentVolume
- 反向② VTK→树:InteractionManager.onSliceSelectionChanged(selectByTool/onPicked 触发)→
  CategorySection::selectItem 程序化选中(屏蔽信号防环路)
- VtkSceneView 按 dsId 存 volumes_(image/cs/vmin/vmax);addVolume 登记/removeDataset 移除并回退
  current/clear 清空;volume(dsId) 取指定体→色阶编辑支持非当前体;SliceTool 加 volumeDsId 标签
- nearestSlice 阈值/onWheel 步长/导出上色 改用切片所属体的 bounds/色阶

未解:④ 切片拾取串选(nearestSlice 启发式,VTK9.6 不暴露切片 actor 难精确化;widget 交互选中是精确的)

构建:app 链接通过;434/434 测试通过
63cda568e5 fix(vtk): ④ 切片拾取串选-体 actor 设 PickableOff,拾取只落切片平面
点击落到体内部时 picker 命中体、worldPoint 落体内 → nearestSlice 按平面距离选错切片(常选最前的
上下切片)。改:addVolume 后 volume->PickableOff() → 光标拾取只命中切片纹理平面(及帘面),worldPoint
落在光标下那张切片 → 选对。onPick 仅在命中时触发(未命中不误选);旋转支点用选中切片不受影响;
widget 直接交互(selectByTool)本就精确、不受影响。重叠切片仍按最前优先(合理)。

构建:app 链接通过;434/434 测试通过
63ebf7d4f1 fix(ui): 修日期日历面板错乱-popup 父对象改顶层窗口避开下拉项样式
DateRangeEdit 改 QComboBox 子类后,日历 popup 成 QComboBox 后代 → 日历内部日期网格
(QAbstractItemView)吃到全局「QComboBox QAbstractItemView::item」(padding 6px10px/min-height 20px)
下拉列表项样式 → 日期格重叠错位、无星期表头。修:popup 父对象用顶层 window() 而非本 combo,
日历不再是 QComboBox 后代,该 QSS 不匹配 → 日历恢复正常渲染。

注:本地链接因 app 运行中 exe 被锁(LNK1104)未完成,obj 已编译通过;关 app 后重 build 即生效。
5edfc8e5e8 fix(ui): 装置筛选稳健匹配+诊断日志 + 生成位置改下拉框(树形下拉面板)
- 装置下拉空:arrayTypeList 请求成功(日志确认),但匹配只认 itemValue(键)。改稳健匹配——ds 装置属性
  存 itemValue 或中文名都认(命中键取中文名/命中值用原名),data 存实际属性值供 passesFilters 比对。
  仍空则打 [arrayfilter] 诊断日志(枚举大小+首行属性 confFieldId=value)定位是枚举空还是值不匹配。
- 生成位置:QTreeWidget(常显树)→ QComboBox 下拉框,下拉面板用 QTreeView+QStandardItemModel 树模型
  (GS/项目根/TM 层级);mountTargetId/confType 从树视图当前项读(树模型下比 combo currentData 可靠)。

构建:app 链接通过;434/434 测试通过
98bbc9f947 fix(ui): 生成位置下拉树面板加宽,避免长节点名被截断
QComboBox 树 popup 默认只取 combo 宽度+缩进 → GS/TM 长名被遮(用户反馈)。按最长节点名文本宽
(QFontMetrics) + 缩进/箭头/滚动条余量(120px)定 view 最小宽,下限 260px,保证全名可见。

注:obj 已编译通过;本地链接因 app 运行中 exe 被锁(LNK1104)未完成,关 app 后重 build 即生效。
1742b7508b fix(data): 装置筛选空-parseDsRows 兼容对象形态 properties+顶层装置字段 + CLAUDE规则
诊断(自读日志[arrayfilter]):enum=15(枚举正常)但 row0[](行 properties 空)→装置值没进 row.properties。
DsObjectDataVO.properties 是泛型 JSON(可能对象而非数组),旧 parseDsRows 只 toArray()→对象形态丢空。
修:properties 数组/对象两种形态都解析;顶层 arrayType/arrayTypeName 也收为属性兜底。
另加 [dsrow-raw] 一次性打印首行原始 JSON,若仍空可据此精准定位装置字段实际位置。

生成位置下拉:combo 自身按内容加宽(对话框随之变宽)→ popup 宽=combo 宽,不再外溢出对话框。

CLAUDE.md:新增「能自己做的绝不让用户做」绑定规则——日志/数据/构建/诊断都自己来,只在 LNK1104
需关 app、或真正产品决策时才找用户。
31ad7a4750 chore: 撤诊断日志([dsrow-raw]/[arrayfilter]),保留 parseDsRows 对象形态解析健壮性
诊断结论(自读日志):data/page 所有 ds 行(文件/网格/反演)均不带字段属性(properties=文件元数据或null,
attachedParameters=null,无 arrayType);结构树节点亦无 arrayType。装置类型纯属脚本配置(ScriptInfoVO),
不在任何现有拉取数据里 → 装置筛选需新接脚本配置并按 ds→测线→脚本 串联(数据来源待定)。
2f6ec7dae2 fix(ui): 类型筛选改用组内数据自带类型值(typeName/dsTypeCode),不再依赖缺失的arrayType
按用户口径:类型筛选=按加载到该段的数据其自身携带的类型值的范围筛选。装置/arrayType 实测不在
ds 行数据上(data/page 不返回),故改用 ds 已带的 typeName(多为中文)作筛选维度,缺失回退 dsTypeCode
(必要时全局枚举翻译)。下拉列出组内实际出现的类型;passesFilters 按 typeName/dsTypeCode 比对。

构建:app 链接通过
cdd7613d53 docs(api): vtk-3d-openapi 对齐实测实现(0.6.1)
按客户端实测口径修正文档偏差:
- DsPage: 行在 data.list(非 data.value)+total;补注与 structNode/exception 用 data.value 的差异
- DsRow: 从5字段扩为实测解析全字段——name(=类型名,JSON键是name非typeName)/dsTypeCode/createTime/
  sourceShowParentId(+parentId回退)/structParentId/structParentConfType/properties(泛型JSON,数组或对象)/
  file;ddCode 是通用 dd 码(非仅 voxel/slice),data/page 返回各类 dsObject
- data/page 描述补实测:行在list/返回各类ds/classifyType==1走file·page/**业务字段值(含装置arrayType)不在行上**
  (装置属测线脚本配置)→ 类型筛选改按 typeName/dsTypeCode 范围筛
- registerSlice 描述补:客户端 mock 当前 projectId 为空,接真后端需补 nav.currentProjectId

未变(已与实现一致):VoxelGenerateRequest/SliceGenerateRequest/SliceSpec/VolumeBuildParams/DsPageRequest/
StructNode(L)/ExceptionList(均 data.value)
fb911a9d85 fix(ui): 坐标轴面板硬编码颜色 token 化(深色模式合规,规范§1/§6.7)
按视觉规范审计修 AxesSettingsPanel 硬编码(深色模式下会失效):
- 应用按钮 #2f6fed/#2a63d4/radius6 → setDefault(true) 走全局 QPushButton:default(accent/primary,随主题)
- 关闭按钮 #888/#2f6fed → token(text/secondary / accent/primary)
- 放大系数标签 + 最小/最大值标签 #888 → token(text/secondary / text/tertiary)
- 面板圆角 10px → 8px(radius/lg,规范§3.2 画布浮窗)

构建:app 链接通过
d6e52cb51f fix(ui): 三维分析分段面板视觉打磨(段头/新增按钮/顶部留白,规范§4.3/§6.7)
用户反馈分段面板难看,逐项重做:
- 可折叠段头:去原生小三角(难看)→chevron 文本前缀 ▾/▸(随主题/hover 变色);标题改 title 字号
  +半粗(原默认字体);加浅底分段条 bg/panel-subtle + 底分隔线 divider 作视觉分段;hover 转 accent
- 「+新增三维体」:裸 autoRaise 文字 → 描边强调按钮(border/文字 accent/primary,hover 浅强调底,
  radius/sm,caption 字号),符合§6.7 次级强调按钮
- 顶部留白:CategoryAnalysisTab 内容区加 top margin → 首段段头不再贴顶
- 筛选行 setSpacing 一致化

构建:app 链接通过
85636931af fix(ui): 分段折叠时向上收起(不再停在原位中间格)
根因:各段 addWidget(sec,1) 等高平分 stretch,折叠后该段仍占等分高度→段头浮在那格顶部、下方留空,
看着像"停在当前位置中间"(仅面板不出滚动条/内容short于视口时可见)。
修法:据折叠态动态重排 stretch——展开段=1(吸收余量铺满)、折叠段=0(只占段头高);末加尾部弹簧,
全部折叠时置 1 把段头顶到顶部。CategorySection 暴露 isExpanded()+collapsedChanged() 信号驱动重排。
保留"全展开等高铺满"原行为(#7)。

构建:app 链接通过
56e4b3a7ff fix(ui): 登录验证码图形容器背景改白底
#captchaImg 背景 bg/hover(浅灰) → 白底。后端验证码图是浅底,白底贴合图边、两侧不再露灰条;
两种主题下验证码图都是浅底,故用白色字面值(随主题反而割裂)。

构建:app 链接通过
75c1327aa4 feat(3d): 创建异常截图改相机重构图(方案A,frame-to-fit selection)
异常截图原为整窗口截图。改为业界 frame/zoom-to-fit selection 范式:
captureFramedRegionPng 把相机临时重新取景到圈定 worldPts 外扩区域(padFactor=1.4≈异常占画面~70%
带周边语境),视角方向不变仅推近/缩放(ResetCamera),后台缓冲+关交换截图屏幕不闪,截后还原相机。
点(零体积)/线面共面(某轴零厚度)用切片尺寸 0.25×min(e1,e2) 作框景半径兜底。
main 调用处从 worldPts 算世界包围盒 + 从切片 o/p1/p2 算兜底尺寸。

构建:app 链接通过
c6756aafc5 feat(3d): 异常类型下拉接平台真实类型(去 mock,与平台一致)
AnomalySaveDialog 原硬编码 4 个 mock 类型。改为按标注形态(remarkSourceType)异步拉平台异常类型
(cmdRepo.listExceptionTypes,label→显示/value→id)填充下拉,与平台保持一致。net 层已把扁平
data 数组归一为 value→wireArray 可读。空/失败由 EmptyAwareComboBox 空态提示。
当前面(Polygon)固定 remarkSourceType=3;P2 接点/线后由菜单形态决定 1/2/3。

构建:app 链接通过
58544ffb3c feat(3d): 创建异常支持点/线/面三态(子菜单+统一双击·回车提交)
按原型「创建异常→点/线/面」改造:
- 右键菜单单项「创建异常」→ 点/线/面 子菜单;形态(1/2/3)同时驱动绘制 mode、a.markType、
  对话框查平台类型的 remarkSourceType(core::AnomalyMarkType 与 remarkSourceType 同值,一个 shape 贯通)
- AnomalyDrawTool 泛化 DrawMode{Point,Line,Face}:点≥1(再点重定位微调)/线≥2(开放)/面≥3(闭合);
  最少点数按模式;分形态屏幕提示
- 交互按锁定规范:**双击/回车 提交**(去掉右键提交,右键绘制中消费不响应保留菜单语义);
  **Backspace/Delete 撤上一点**;Esc 取消
- AnomalyActor 已支持点(verts)/折线/闭合多边形三态渲染,无需改

测试:439/439 通过
3ed1ea75ac feat(3d): 异常样式接平台 legend(与平台一致,不依赖 mock 保存)
修正前一轮误判:异常样式("与平台一致")不依赖真后端保存链——getDetail/{id} 端点存在且返回 legend。
- 新增 getExceptionTypeDetail(typeId) → GET /business/exceptionType/getDetail/{id}(wireObject 取 data)
- AnomalySaveDialog 选中类型变化时拉其 legend,按形态(1点 pointColor / 2线·3面 polylineColor+Width+
  Shape→dashed)派生样式;首项自动预取
- main accept 后用 dlg.styleColor/Width/Dashed 覆盖默认(#ff3030/2/实线)→异常按平台类型样式渲染

注:真保存(newException)仍卡——实测真后端无任何登记三维体/切片为 dsObject 的端点(voxel/slice
generate 无、通用 dsObject create 也无),异常 remarkSourceId 无真实实体可指,是后端缺端点的硬依赖。

测试:通过
04af569b7d fix(3d): 创建异常返工(点交互/点渲染/截图/类型空态)——前一轮质量不过关
#1 点模式还拉线:updateRubber 点模式直接 return,不画末点→光标橡皮筋。
#3 点不是小球:AnomalyActor 点分支 + 绘制预览均开 RenderPointsAsSpheres,点径 13px → 真小球(非扁平方点)。
#4 截图整窗方框→改对:captureAnomalyShotFromSlice 只从切片 2D 剖面彩图、按异常几何向外缓冲一圈裁剪
   (GIS buffer+掩膜:点→圆/线→胶囊带/面→外扩多边形,缓冲外透明,再描轮廓);worldPts 经平面 o/e1/e2
   归一映射到图像像素(Qt QPainterPath/Stroker)。无切片图时回退相机框景。
#2 类型/样式选择"消失":异常类型下拉补占位「请选择异常类型」,空(该形态平台无类型)时显灰占位+「暂无数据」。

注:本项目平台「点」类型为空,故点的类型下拉确实无项——需平台先建点类异常类型。

测试:439/439 通过
d470dc8154 fix(3d): 双击与单击隔离 + 异常类型下拉误显「暂无数据」
双击结束时"第一下"会先触发单击(点会移/线多一段/面多一条边)。修:每次单击前快照 pts_,双击时
先回滚那一下(pts_=快照)再 finish → 双击纯结束,不再附带加点/移点。

EmptyAwareComboBox::realItemCount 用 itemData(i,UserRole-1) 取 flags 是错的(非 Qt flags 角色),
对正常项恒判不可选 → 计数恒 0 → 有真实项(异常区)也误插「暂无数据」。改用 model()->flags()。

构建:app 链接通过
4ae8286bb0 fix(3d): 异常截图配色与切面一致——取 widget 同源着色输出(非另建 LUT)
用户实测异常截图与切面渲染配色差异极大(切面暖色彩虹、截图偏冷蓝绿)。根因:selectedSliceColorImage
另建 buildLut(v->cs,vmin,vmax) 上色, 与屏幕切片 widget 的实际着色可能分歧(范围/血缘处理不同)。
改:SliceTool 暴露 coloredResliceImage() = widget->GetColorMap()->GetOutput()(屏幕切片所贴的同一
RGBA 像素, 逐像素一致, 外区 alpha=0); selectedSliceColorImage 改取它再双线性上采样到 2048。
captureAnomalyShotFromSlice 处理 RGBA → 外区透明(顺带消除截图蓝边)。导出图片同样受益(与屏幕一致)。

测试:439/439 通过
1a70ca0072 feat(3d): 异常对话框加样式预览(选中类型 legend 可视化)
应用户要求,在异常类型下拉下方加「样式」预览行:据选中类型的平台 legend 按形态画——
点=实心色球 / 线=按线宽·虚实的线 / 面=描边矩形+淡填充。选类型变化或样式拉到后实时刷新;
未取到时显占位「—」。

构建:app 链接通过
b48684a0ba fix(3d): 右键色阶去省略号 + 关闭切片取消列表勾选 + 异常取消选中清高亮
1) 数据列表三维体/切片右键「色阶…」→「色阶」(去省略号)。
3) VTK 右键关闭已保存切片后,数据列表仍勾选:onSliceClosed 此前从未连接 → 接 setChecked(dsId,false)。
4) 异常取消选中(选别的对象/点 VTK 空白)后异常图形仍高亮:
   - 选中非异常对象 → setSelectedAnomaly("") 清异常高亮;
   - onSliceSelectionChanged 收到空 dsId(点空白/清选) → 一并清异常高亮。

构建:app 链接通过
91a71064b2 feat(3d): 创建异常结束手势按业界通用做法重做(点单击/线双击/面点起点闭合)
双击作主手势别扭(与单击天然冲突)。按业界通用改:
- 点:左键单击即落点并完成(无需双击/回车)。
- 线:双击完成(保留)。
- 面:点回起点闭合(≥3点,屏幕邻近 12px 吸附);光标近起点时橡皮筋指向起点预览闭合,提示文案更新。
Esc 取消 / Backspace 撤点不变。
d7ab7705c9 feat(3d): 切片保存后定稿锁定(不可移动/旋转)+ 菜单去保存·另存
按用户口径:切片保存后即定稿,不可再改。
- SliceTool::setInteractive(false) 关 widget 鼠标交互(锁移动/旋转,纹理仍显示;拾取选中/右键由
  PickInteractorStyle 独立处理不受影响)。tagSelectedSlice(临时→保存)与 showSavedSlice(重显已保存)均锁定。
- VTK 右键「保存」仅对未保存(临时)切片显示;已保存切片无保存项。
- 数据列表切片右键去掉「保存/另存」(列表中切片均为已保存=锁定),留 详情/导出/色阶/删除。

测试:439/439 通过
306d7bc46e fix(3d): 异常绘制提示移右上角美化 + 线双击结束含双击位置
1) 操作提示从左上角(被工具条挡)移到右上角:深底+accent描边+右对齐+分行(标题/结束方式/取消),
   按当前形态显示对应结束方式。
2) 线双击结束改为"含双击位置"(同地图工具):去掉之前的回滚——双击第一下的落点即为末顶点。
   单/双击不再需要回滚隔离(双击第二下只 finish 不加点,无重复顶点)。
9782a2b93e feat(ui): 删除切片/异常加确认 + 弹框按钮全局中文化
3) 删除切片/异常前弹确认框(警告图标 + 明确「删除/取消」中文按钮 + 不可撤销提示)。
4) 弹框默认英文 OK/Cancel/Yes/No 全局中文化:
   - 安装 Qt 自带 zh_CN 翻译(QMessageBox/QDialogButtonBox/QFileDialog 等标准按钮);加载兼顾
     dev(Qt 安装路径)与部署版(exe 旁 translations\)。
   - formkit::addDialogButtons 默认按钮 QString()→「确定/取消」(不依赖翻译就位,覆盖自建对话框)。
   - 打包脚本补拷 qtbase_zh_CN.qm(windeployqt --no-translations 不带)。

测试:439/439 通过
f230ca8dd1 fix(3d): 异常绘制提示中文乱码(改 QLabel 浮层) + 列表切到别对象清切片选中
1) 提示"乱码":vtkTextActor 用 VTK 内置字体不含中文字形 → 中文渲染不出(只剩 ASCII)。
   移除 VTK 文本提示,改 app 层右上角 QLabel 浮层:Qt 渲染中文 + QSS(深底/accent描边/圆角),
   绘制开始按形态显示结束方式、结束/取消隐藏;不挡画布鼠标。
2) 列表选中切片后切到别的对象(三维体/异常),VTK 切片仍高亮:datasetSelected 选非切片对象时
   未清切片选中。加 InteractionManager::deselectSlice();选异常/其它对象均清切片高亮(异常↔切片互斥)。

测试:439/439 通过
1648ccb8c4 fix(ui): 异常提示浮层圆角外露白底 → WA_TranslucentBackground
QLabel 默认不透明,QSS border-radius 只画圆角矩形,四角(圆角外三角区)露出 widget 白底色。
加 WA_TranslucentBackground → 圆角外透明(露画布),圆角矩形(深底0.85)正常。

构建:app 链接通过
e8bb2f82e7 fix(ui): 异常提示浮层去圆角+不透明深底(消白角/灰底)
上一版 WA_TranslucentBackground 让半透明背景在 GL 子控件上渲染成灰底。改为方角+不透明深底
(#0E1A2D)+accent 描边:方角无"圆角外三角区"故不露白,不透明深底不被白底冲淡成灰。
c1a824e292 fix(data): 二维维度分类对齐数据字典 DD0623(去已删除轨迹类型)
据数据字典 DD0623:足迹型 2D 只 dd_trajectory_data 为统一通用轨迹「保留」(已并入
dd_radar_rtk_trajectory);dd_transient_electromagnetic_trajectory_data / dd_radar_channel_trajectory /
dd_radar_rtk_trajectory 字典均标「删除」。dimensionOf(Api3d/LocalSample3d)从 4 种轨迹收敛为
dd_trajectory_data;同步更新测试。(dd_raster=本次新增 2D 栅格,与渲染一并放第二步)

测试:439/439 通过
227ee8fdef docs(spec): 二维分析锁定俯视相机+内容显隐+高程拖动 spec
一个场景两相机:二维分析=同一 3D 地形场景的锁定近俯视(禁旋转,仅平移缩放);切 tab 翻另一方数据集
可见标志(不清空,性能零代价);2D 内容选中后沿 Z 高程拖动分离(锁 XY,实时读数);dd_raster 过滤+地理
配准贴地形(C期,依赖端点)。含与雷达反馈的边界、维度口径(对齐 DD0623)、分期 A/B/C、风险、验收。
6a10975b6b feat(3d-view): 二维分析A期(一场景两相机)+视图切换/底图/增量修复
- 切「二维分析」tab:锁近俯视(下压12°≈78°)、禁旋转(左键平移=仅平移+缩放)、
  按维度翻 actor 可见(轨迹↔体/帘面/异常,不清空)、切片 SetEnabled 显隐、坐标轴在二维移除;
  地形+底图常驻。ColumnDrawer 新增 analysisModeChanged 信号串起三处协作。
- 修复切回三维数据不取景:按目标维度重置取景基线(VtkSceneController::onAnalysisModeChanged),
  computeDataBounds 只计可见 prop,render 朝向认 analysisMode2D_。
- 修复底图在远离锚点的数据处为空(如台湾,frame 锚深圳):底图取瓦片中心+距离剔除
  改用相机焦点(cenX_/cenY_)而非坐标系原点。
- 修复删到空不重锚致底图错位:removeDataset 清空 dsProps_ 时复位 frameAnchoredToData_。
- 修复二维分析列表非增量:对象树勾选刷新保留已勾选足迹(对齐 CategorySection::rebuildList),
  不再清空渲染/丢失列表选中。
- 新增控制器回归测试 2 项(切模式取景基线)。
bdebe54859 feat(3d-view): 二维分析B期(足迹高程Z拖动)+选择联动/滚轮升降/工具条禁用
- B期:二维分析里选中足迹(单击/Ctrl 多选)→ 竖向拖动只改世界 Z(锁 XY)、
  顶部实时高程读数浮层;Z 偏移按 dsId 持久(切走再回/全量重建保留)。
  VtkSceneView 加 pickMapLineAt/nudgeSelectedMapLinesZ/selectedMapLineZ(vtkCellPicker
  +PickFromList 只拾可见足迹、选中黄高亮加粗、mapLineZOffset_ 持久);PickInteractorStyle
  lock2D 下命中足迹→Z 拖动(onPick2D/onDrag2D/onDrag2DEnd + worldPerPixelZ 像素→世界Z);
  InteractionManager::pickStyle() 暴露样式;main.cpp 接回调 + 读数浮层。
- 列表↔VTK 双向选择联动:Column2DDataset 多选行 + selectedDatasetsChanged/setSelectedDsIds;
  VtkSceneView onMapLineSelectionChanged/setSelectedMapLines;两向各自断环。
- 滚轮升降:onWheel2D——有选中足迹时滚轮改其 Z(一格≈拖动24px)、消费滚轮,否则缩放;
  读数浮层滚轮后 1.2s 自动隐藏。
- 工具条:二维分析激活禁用 6 向快捷视图(会改朝向破坏近俯视锁定),切回三维恢复。
5bf3a8e5dd docs(backlog): 登记 OPT-003 二维分析C期 dd_raster(阻塞·待后端栅格端点)
A/B 期已实现(6a10975/bdebe54);C 期=dd_raster 栅格地理配准渲染,阻塞在后端无
栅格数据端点(实测 business_OpenAPI.json 无 dd_raster/栅格影像端点)。须后端提供
返回「像素+四至/仿射+投影」的端点后方可落地。
cf1c06cde8 feat(gpr): 三维体 LOD 多线渲染 + 全局切片(深度/横切/顺路) + 诊断
渲染架构改 LOD 中心:各线独立 mapper + 视野自适应 LOD,弃 multi-volume 单遍。
实测确诊多线卡顿真因是"没用 LOD、渲整卷大贴图"(passcost 排除固定开销;
overlapStat 实测重叠 ~9× 非 20×;ESS 实测仅 ~2× 不解决重叠),非渲染器问题。

切片(view-all --slice [updown|leftright|frontback]):
- 深度 C-scan:逐线整张水平片(深度共面→拼成完整 C-scan,全覆盖、原生分辨率)
- 横切/顺路:全局世界面 reslice 各线到同一面 + blend(竖直面几何上每线只切细断面)
- ↑↓ 整片扫过 / [ ] 体透明度 / v 体显隐 / --sliceAt 跳位

其他:通道插值(2.5cm,从.ord读)接入 gpr_poc;--bgSuppress 压背景突出反射;
slice 命令复用桌面端 SliceTool 切单线。

诊断命令:ess-stat(空块潜力)/--overlapStat(重叠层数)/passcost(N遍vs重叠隔离)。
分析文档:性能确诊(否定 ESS/OSPRay,LOD 为通用解)。
fadcd12239 fix(gpr): 补 Api3dRepository::createGprVolume 声明 + 仓储透传 targetDy
HEAD 的 Api3dRepository.cpp 已定义 createGprVolume,但 .hpp 缺该声明
(成员定义无声明 → geopro_data 编译不过)。本提交补上声明,修复构建。

并把线内通道插值 targetDy(默认 2.5cm) 透传到 createGprVolumeGrid →
app 渲染链也得密 Y 体(与 io::gpr 桥同口径,0=不插值)。
d5e3522bfa feat(project-menu): 项目管理菜单按Excel接入web嵌入页
- 项目管理一级菜单仅保留需「直接嵌入」的4个子菜单(在线监测/工具组件/批量导出/
  告警管理,共10项,对应Excel「单个项目」页签第10~21行带嵌入地址者);其余全部隐藏
  (数据视图/项目配置/数据管理/业务管理/项目资料管理/自动任务/模板管理)
- 新增 ProjectWebView(内嵌QWebEngineView):DocumentCreation阶段注入
  localStorage['token']=登录token,早于页面脚本执行
- 中央区用QStackedWidget承载:page0=工作台,page1=web整窗;点菜单项整窗加载,
  顶部视图菜单「分析视图」切回工作台
- URL: tenant.geomative.cn/#/embed?space=3&projectId=<运行时项目id>&target=<target>
  (space=3为项目空间常量;两个OpenAPI文档均无embed相关space字段)
9b4f172809 fix(3d-view): 二维/三维分析切换时取消前视图选中
三维分析选中切片后切到二维分析,残留的selected_使InteractionManager::onWheel
持续消费滚轮(二维下无法缩放),且切回三维仍残留高亮。setMode2D进入二维时清切片
选中+高亮,并经onSliceSelectionChanged("")联动清三维分析列表选中行与异常高亮。
与VtkSceneView::setAnalysisMode2D离开二维时clearMapLineSelection清足迹选中相对称。
4f6abf0c83 feat(3d-view): 三维体渲染稳定性修复 + 透明度可调/交互优化
- 修偶发"不渲染/淡蓝/很实"根因:合并体值域取"首个到达源色阶"随网络到达
  顺序抖动→改取所有源色阶 vmax 中位者(确定性+抗单线离群)
- 体素标量 double→float:GPU 体绘制对 double 处理不稳/间歇出空,float 更稳且省显存
- 源剖面加载瞬时失败(如后端 502)自动重试,避免一条抖动致整体建不出;失败弹 toast 不再静默
- 退化薄体(共面剖面 ny/nz=1)网格每维补到≥2,避免 vtkGPUVolumeRayCastMapper 拒绝渲染
- 三维体透明度可调:工具条「透」按钮+弹出滑块(默认 0.30,实时改已渲染体)
- 工具条 z 序修复:引导层挂 vtkWidget 并 raise,工具条/提示再 raise 其上(缩小渲染区不再被挡)
- 收起左栏同步 QSplitter 尺寸,消除残留空白
- 切换项目清空三维体/切片/异常列表
- VTK 警告/错误转 Qt 日志,不再弹独立 vtkOutputWindow 窗口
- 勾选非三维体 ds 首次加载也显示等待动画(复选框↔spinner)
- 新建三维体后该行多拍重试滚动到分析栏顶部
gaozheng merged commit c653a659b2 into main 2026-06-27 18:43:52 +08:00
gaozheng deleted branch feat/vtk-3d-view 2026-06-27 18:43:53 +08:00
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: gaozheng/geopro#7
No description provided.