ykcheungab
|
fa2703968e
|
added ruff test
|
2026-09-27 19:20:43 +08:00 |
|
ykcheungab
|
ccedb9ddd9
|
migrate pyqt5 to pyside6
|
2026-09-21 09:34:56 +08:00 |
|
ykcheungab
|
e276b5de0f
|
autocal layout first design
|
2026-09-20 21:15:39 +08:00 |
|
ykcheungab
|
c2293d4d41
|
界面:三维可选「深度响应 / 光流幅值」上色(默认深度),并加一个「诊断信息」开关收拾面板脚下的文字
- What(颜色来源): `DisplaySettings` 增 `field`(`"depth"` 默认 / `"flow"`),随显示设置持久化
(`scene3d/prefs.py`:新增 `FIELD_CHOICES`/`DEFAULT_FIELD`,手改文件里的非法值修回默认)。
`FingerFrameAdapter` 按所选字段先试、失败再用另一个,并把"换了量"这件事记在
`last_substitution`(新诊断码 `field_substituted`,info 级);两个字段都拿不到时,
`last_diagnostic` 取**信息量最大**的那条(域不符/过期/未声明 > 没这个字段),而不是"所选字段"的
那条空话。设置对话框新增「颜色来源」下拉,下面一行 `field_note` 直接写"这一帧画的是 X,不是所选的 Y";
图例(`legend_label`)永远标注**实际**画出来的量,所以设定与画面不一致时两处都能看出来。
深度响应 `[1]`、光流幅值 `[px]`,两者都是 `approximate`——代码与文案都不把它们说成毫米。
- What(诊断信息开关): 视图菜单新增 `诊断信息`(可勾选、持久化 `show_diagnostics`、**默认关**,
由 `DisplayPrefsController` 持有并推给两个面板)。关掉后:2D 面板只留"画面 + 计划说明 + 深度色标",
三条解释流水线的标签(箭头按位移放大、原始图像 → 算法输出、全部帧)隐藏;3D 面板只留
色条 + 一行图例 + 来源,info 级诊断隐藏。**永不隐藏**:warning/error 级诊断(测量是否过期、
字段是否本帧的、是否与设备核对过——`geometry_unverified` 虽然是 info 也白名单保留)与
深度色标。3D 图例改成 `ShrinkableLabel`(一行、裁切 + tooltip,不再折行),色标数值从 4 位有效数字
收到 3 位("0.0334 – 0.899")。设置对话框控件宽度 88 → 108 px(不再需要迁就 240 px 面板)。
- What(取景脚本): `tools/ui_snapshot.py --scene flow3d` 现在同时给 flow 与 depth(各带 provenance),
所以「颜色来源」开关有东西可切;再加 `.repro/shot_variants.py` 一次出四张图
(深度版 / 光流版 / 诊断开 / 设置对话框)。
- What(测试): `test_scene3d_adapters.py` 增 3 项(默认深度、换量时给出 `field_substituted` 并在恢复后
清掉、depth 不在场景栅格时按 `field_domain_mismatch` 拒绝而不是缩放);`test_scene3d_view.py` 增
1 项(field 的持久化与修复,并把 `field in FIELD_CHOICES` 加进"手改文件会被修复"的参数化);
`test_scene3d_pane_ui.py` 增 3 项(两种量可选 + 说明行 + 恢复的偏好会移动下拉;诊断开关只隐藏 info、
保留 warning 与"未核对";2D 脚注三标签的显隐与窗口开关一致);`test_display_prefs.py` 增 1 项
(开关推到两个面板、写偏好)。`test_ui_smoke.py` 与 `tools/ui_check.py` 里"箭头图例可见"的四条断言
改为按新规则检查(默认隐藏、开诊断后可见、关掉再隐藏)。
- Why: ①"深度"比"光流"更贴近操作员口中的"压得多深",但两者都只是近似量,所以做成开关而不是替换——
并且换量必须说出来(否则画面会被读成所选的量)。②面板脚下的解释文字是"内部管线"而不是"画面是什么",
拍视频与日常看都只需要后者;用一个开关收起,比做一个滚动日志面板诚实(这些是每帧状态,不是事件)。
- Verification: pytest shared/tests apps/studio/tests(offscreen)658 passed / 0 failed / 15 skipped;
真 GL 组(gl_smoke + view + pane_ui)70 passed / 0 failed / 1 skipped;
`tools/ui_check.py` 590 项检查 0 失败;`.repro/locale_check.py` 0 缺失(新增 7 个 key 双语齐备)。
目视验收:同一批合成数据渲染的四张图(深色主题)——深度版(默认)、光流版、诊断打开、设置对话框。
- Not in this change: 不改采集/记录/契约之外的三维渲染;不做页签容器与窄窗口回退;曲线量程仍是出厂 ±20 N。
真机待验证:手指路径上 `packet.depth` 的栅格是否就是场景的 300×280(若不是,面板会写明并回退到光流)。
|
2026-09-15 21:23:18 +08:00 |
|
ykcheungab
|
650578d738
|
界面:三维面板只留画面与图例,全部配置进「三维显示设置」对话框;三维占比提为最宽
- What(隐藏配置): `ThreeDPanel` 把**所有设置**收进一个块
(`controls_widget`:总开关、观察方向、显示外壳、放大形变+增益、色标模式与范围、显示帧率、
复位按钮、显示统计),面板本身只保留读图需要的东西:色条 + 一行紧凑图例(数量/自动色标范围/
来源)+ 状态行。新增 `scene3d/settings_dialog.py` 的 `Scene3dSettingsDialog`:非模态
(调参时画面还在动),承载的就是面板那套控件本身(同一批 widget,信号通路不变),
关闭只是隐藏(控件必须活着,下一次读设置还要用)。
两个入口:视图菜单新增 `三维显示设置…`(`act_scene3d_settings` → `Mesh3dPanel.open_settings()`)
与面板标题栏的齿轮;无三维可配时(box 传感器 / 无 GL / 无场景包)菜单项会把面板上的原因
原样提示出来,而不是弹一个空对话框。标题栏另有「复位视角」图标(新画的 `reset_view` 图标,
环形箭头,随主题着色)。
- What(提高占比): live/replay 预设把三维面板设为最宽:`VIEW_SPLITTER_SIZES` (620, 300, 520)、
`DEFAULT_SPLITTER_SIZES` (620, 320, 500)、`DEFAULT_3D_PANE_WIDTH` 340 → 620、
`MIN_PANEL_WIDTHS["mesh3d"]` 260 → 200(面板里没有表单要放了,画面才是重点)、
`ViewLayoutController.apply_panel_visibility` 的拉伸权重 2 → 5(2D 3、曲线 4)。
1440×880 实测:三维约 430 px(原约 280)、2D 约 265、曲线约 320。
- What(拍视频/评审用): `tools/ui_snapshot.py` 新增 `--scene flow3d`:驱动一批**带真实光流场**的
packets(适配器只接受声明了 provenance 的字段),所以三维面板真的有颜色、曲线也真的在动;
这是本次界面评审与演示视频的取景脚本。配 `--sensor finger --panels 3d --preset live`。
- What(测试): 新增 `apps/studio/tests/test_scene3d_pane_ui.py`(5 项):面板只有图例没有设置、
对话框承载的是面板自己的控件且设置信号照旧、关闭只隐藏不销毁、标题栏两个动作可用、
无场景时 `open_settings()` 返回 False、`reset_view` 转发、`reset_view` 图标两种主题都能画、
视图菜单项能打开对话框(无 GL 时给原因)。`test_view_layout.py` 增一条"出厂 live 布局里
三维最宽"的断言(并更正我自己那条 340 的旧期望)。
- 文档: `studio-3d-stages.md` 的「尚未完成」第 1 条(阶段 8 第二批)改写为"部分已做",
写清已完成的部分与仍留后的四项(页签容器/窄窗口回退/曲线量程开关/独立诊断抽屉)。
- Why: 三维面板原来下半屏全是表单,画面被挤成一小块——拍视频要的是"三维是主角"。
配置不是不需要,而是不该和画面抢地方;放进对话框后画面变大、参数反而更好找(一处看全)。
- Verification: pytest shared/tests apps/studio/tests(offscreen)650 passed / **2 failed** / 15 skipped,
两个失败都是 `shared/tests/test_worker_frame_rate.py` 的**墙钟计时**用例(30 fps 设备被测成
24–25 fps):已在 `d539ce9` 的干净 worktree 上复现同样的失败,属本机负载(DSH/Cursor/飞书 占 CPU)
而非本次改动;真 GL 用例 `test_scene3d_gl_smoke` + `test_scene3d_view` 61 项 0 失败(1 跳过);
`tools/ui_check.py` 587 项检查 0 失败;`.repro/locale_check.py` 0 缺失(新增 6 个 key 双语齐备)。
目视验收:`--scene flow3d` 渲染的 1440×880 截图(拆分前后各一张)见提交说明附言。
- Not in this change: 不改三维渲染/契约/记录;不做页签容器与窄窗口回退;
曲线量程仍是出厂 ±20 N(演示取景脚本会临时调窄,产品默认值另议)。
|
2026-09-15 20:55:33 +08:00 |
|
ykcheungab
|
d539ce93ad
|
文档:阶段记录补上「阶段 10:app_window 按职责拆分」与遗留项
- What: docs/architecture/studio-3d-stages.md 新增阶段 10 记录:A1/A2/B/C1/C2 与标定收尾各自搬到哪个文件、
做法(strangler 式搬运 + *Host Protocol + 旧名转发以保住回归门)、数字(app_window 3044→2309 行、
四个控制器 1703 行、新增 41 项控制器单测、测试 603→644)、以及对三维接口无影响的说明
(阶段 4 记录里的 _sync_3d_source/_shows_3d/_splitter_sizes_for 现在住在 view_layout.py)。
- What: 「尚未完成」补两条:窗口里约 40 个过渡转发(下次改动顺手清)、仍留在窗口的预览与 2D 渲染胶水。
- Why: 阶段文档是三维交付的验收记录,读者会按它找代码位置;拆分之后那些位置变了,必须留下指路。
- Verification: 纯文档改动;同批源码验证为 pytest 644 passed / 0 failed / 15 skipped、
tools/ui_check.py 587 项 0 失败、.repro/locale_check.py 0 缺失。
- Not in this change: 不改代码;不改历史阶段(1–9)的记录内容,只在阶段 10 里说明它们提到的窗口方法现在的去处。
|
2026-09-15 10:03:05 +08:00 |
|
ykcheungab
|
b37c861254
|
文档:刷新架构报告的指标与结论(app_window 拆分已落地)
- What: `docs/architecture/studio-architecture.md` 的数字与结论按当前源码重扫后刷新:
- 分层图/纯文本图:`app_window` 3044 → **2309 行 / fan-out 37**,并新增一层
"②b Studio 控制器"(session_controller 437 / replay_controller 641 / view_layout 398 /
display_prefs 227);领域服务与共享层的行数一并更新(replay 291、calibration_service 194、
coordinator 619、camera 238、view 757、asset_source 256、gl_backend 870;
shared scene3d 4565 / acquisition 2627 / record 3008 / force 3057 / 基础设施 1507)。
- 边界规则:模块数 89(studio 32 + shared 57)→ **94(studio 37 + shared 57)**,环 0 个不变。
- 指标表:新增 `replay_controller`(641) 与 `session_controller`(437) 两行,并写明
"app_window 的 fan-out 仍是最高(37),因为它本来就是装配器——但规则已经不在它里面"。
- 生产面/验证面:studio 生产 14 655 行、shared 14 764、测试 15 639(shared 7226/334 项 +
studio 8413/310 项)、工具 4046(ui_check 3401);验证面 19.7k > 生产面 14.7k。
- 评估第 1 条与"一句话结论"改写为:上帝对象已按职责拆开,并**诚实记账**留下的东西——
约 40 个过渡转发(给 tests/`ui_check` 的桥,属过渡层)、仍留在窗口的预览与 2D 渲染
(它们同时属于面板与相机),以及 fan-out 从 36 升到 37 的原因。
- 建议表第 1 条标记为已完成(写清五个去处与新增 41 项控制器单测),新增第 1b 条
"下次改动顺手删掉对应转发",并补第 7 条"真机与 ARM 验收"(本机无设备/板卡,是当前最大空白)。
- What: `studio-architecture.svg` / `.png` 由 `.repro/make_studio_svg.py` 重新生成:
窗口框改为"2309 行 · 158 方法 · fan-out 37 · 装配 + 信号转发",右侧四个控制器小框,
面板/服务/共享层/验证面的行数与测试项数同步;底部结论改为"已按职责拆开 + 剩下的胶水"。
顺带修好 `svg_to_png.py` 里写死的 1560×1180(现在读 SVG 自己的尺寸),否则海报加高后会被裁掉。
- Why: 这份报告是"判断组织是否合理"的依据,数字或结论一旦过期就会误导决策;
拆分改变最大的一处正是它第 1 条风险与第 1 条建议,必须同步。
- Verification: 图表脚本重跑无异常(SVG well-formed,PNG 1560×1210 已目视检查);
同批源码的验证为 pytest 644 passed / 0 failed / 15 skipped(offscreen)、
tools/ui_check.py 587 项 0 失败、.repro/locale_check.py 0 缺失。
- Not in this change: 不改代码;不改 `.repro` 下的扫描脚本口径(仍以扫描输出为准)。
|
2026-09-15 10:02:37 +08:00 |
|
ykcheungab
|
8d374e5850
|
refactor(studio): 回放引擎改名 ReplayEngine —— 把「引擎」与「窗口级控制器」的名字分开
- What: `apps/studio/src/orisys_studio/replay.py` 的 `ReplayController` 改名为 `ReplayEngine`
(引用只有 4 处:`app_window.py` 的 import 与构造、`ui_check.py` 的一处 import、模块内定义);
模块 docstring 写明它为什么叫 engine(只回答"t 时刻是什么",不知道传输策略、不知道控件),
并指路即将落地的窗口级 `ReplayController`;`app_window.replay` 这个属性名**不动**(36 处使用)。
同步更新两份既有文档里的类名(`apps/studio/docs/shell-lifecycle.md`、`record-channel.md`、
`docs/architecture/studio-architecture.md` 的框图标签)。
- Why: 用户已同意分拆 `app_window.py`,并选定"引擎改名 ReplayEngine + 新类叫 ReplayController"
这一方案(另一方案是让两个名字 `ReplayController`/`ReplayCoordinator` 并存,容易进错门)。
这一步是后续把窗口里那 30 个回放方法搬进 `ReplayController` 的前提:先把名字腾出来,
否则搬迁时无法区分"引擎"与"控制器"。
- Verification: shared+apps 同一次运行 **588 项 0 失败 15 跳过**;`ui_check` 587 项 0 失败;
全仓 `grep ReplayController` 只剩两处有意保留的提及(`replay.py` docstring 里指路、
`app_window.py` 注释里指路),没有悬空引用。
- Not in this change: 不搬运任何方法、不改行为——`app_window.py` 仍是 3043 行;`SessionController`、
`ReplayController`、`ViewLayoutController`、`DisplayPrefsController` 四个模块的搬迁尚未开始
(顺序与契约见 docs/architecture/studio-architecture.md 建议 1)。
|
2026-09-15 08:41:44 +08:00 |
|
ykcheungab
|
dd0ee2c71e
|
docs(architecture): Studio 架构图与可维护性评估(按源码实际 import 关系生成)
- What:
1. `docs/architecture/studio-architecture.md`:分层视图(Mermaid + 纯文本版)、运行时/线程视图、
二维/三维显示子系统视图、边界规则与证据表、指标表(模块行数 × 扇出、稳定核心 fan-in、验证面规模)、
可维护性评估(5 条优点 / 7 条风险,逐条带证据)、6 条建议(按性价比排序)。
2. `docs/architecture/studio-architecture.svg`(浏览器直接打开)与同名 `.png`(由 SVG 经 QtSvg 栅格化,
给没有 SVG 渲染器的场景):分层海报,层间流动用箭头表示,跨模块关系写在框内。
3. 数据来源(在 `.repro/`,可重跑):`studio_arch_scan.py` 扫 89 个模块的 import 图并给出 fan-in/fan-out
与**模块级环**;`studio_arch_imports.py` 分别统计"import 时就拉 Qt/GL/SDK"与"函数内惰性 import",
并在**新解释器**里逐个验证"导入 X 是否会拉进 PyQt5/OpenGL/SDK";`make_studio_svg.py`/`svg_to_png.py`
生成图。原始数据 `studio_arch.json`、`studio_arch_imports.json`。
- Why: 用户要看架构图来判断"软件组织是否合理、是否容易维护"。因此所有框与数字都从源码实际 import 关系
生成,而不是画一个理想分层:报告里同时给出**成立**的边界规则(无环、共享层 import 时不依赖 Qt/GL、
三维调度与相机无 Qt 可脱离 GUI 测试)与**不成立**的一条(`force/calibration_io` 在 import 时 import
orisys,于是力相关单测必须装 SDK),以及最贵的单点 `app_window.py`(3044 行 / 158 方法 / fan-out 36)。
- Verification:
· 扫描结果:89 个模块(studio 32 + shared 57)模块级**环 0 个**;import 时拉 PyQt5 的 21 个模块**全部**
在 `orisys_studio.*`;OpenGL 只在 `gl_backend`/`widget` 函数内惰性加载;新解释器验证
`scene3d.contracts/composer`、`acquisition.arrows/sinks`、`record.playback`、`theme`、
`studio.scene3d.coordinator/camera` 均为"干净"(不含 PyQt5/OpenGL/SDK),而 `force.history` 会拉进 SDK。
· 规模:studio src 13 376 行(三维 4 326)、shared 14 820 行(三维 4 576 / 记录 2 673 / 力 2 645 /
采集 2 343)、测试 11 633 行、工具 5 272 行;`scene3d.contracts` fan-in 22 为全仓最高。
· 图的自检:SVG 由 `ET.parse` 验证为良构 XML,并栅格化成 PNG 后逐版目视检查过(第一版箭头穿框,已改为
层间箭头 + 框内关系文字)。
- Not in this change: 不改任何产品代码;建议 1(拆 `app_window`)等 6 条尚未实施,它们属于下一轮工作,
每条都写了收益、成本与回归门。
|
2026-09-15 08:25:20 +08:00 |
|
ykcheungab
|
cf45e654e1
|
docs(studio-3d): 阶段 7–9 交付说明 + 接口骨架同步 + 保护包的应用侧配置
- What:
1. `docs/architecture/studio-3d-stages.md` 新增三节:**阶段 7**(二维图像后端统一与回放入口收口,含起因、
做法、验收表格)、**阶段 8 第一批**(能力控件/真实色标/复位语义/命名)、**阶段 9 上半**(限速、真实统计、
无位移复用几何、保护包密钥),并新开一节「尚未完成」把两项写清楚:阶段 8 第二批(画布布局与曲线量程)与
阶段 9 的门禁运行(GUI 2 小时长时 + 两块 ARM 板的探针/性能/长时报告),外加阶段 6 遗留的真机验证项。
文首进度与依赖关系图同步。
2. `docs/architecture/studio-3d-contracts.pyi`:新增 `SceneCapabilities`;`RenderStats` 增
`paint_calls`/`scale_lower`/`scale_upper`/`scale_mode` 并注明 `displayed_frames` 是"按帧身份的唯一帧"
而不是绘制次数;`RenderFrame` 增 `compose_ms`。
3. `tools/scene_assets/README.md`:新增「Studio 应用侧的配置」——`scene3d_verify_key`/
`scene3d_content_key_file` + `scene3d_content_key_id`/`scene3d_require_signature` 的用法、为什么没有验签
公钥就打不开签名包、以及"密钥文件缺失是状态而非崩溃、记录里只留布尔与路径"。
- Why: 规格 §13 要求每阶段同时交出实现、测试、输入样例、失败样例、兼容说明与平台诊断报告;阶段 6 的文档提交
之后又落了阶段 7/8/9 的接口改动,骨架文件必须跟上,否则下一阶段会照着过期文档实现。同时把"没做完的两项"
写在文档里(而不是留在对话里),下一个接手的人不需要猜。
- Verification: 文档改动本身不执行测试;其中的数字全部来自本仓可复现的命令:`pytest`(shared+apps 同一次
运行 588 项 0 失败 15 跳过)、真 GL 冒烟 14 项 0 失败、`ui_check.py` 587 项 0 失败、`locale_check.py`
0 缺失、`bench_scene.py --cpu-only`(20k 顶点 1.03 ms / 真实包 0.17 ms)、`validate_scene.py`(重编包
全项 ok)与两份 `.repro/probe_stage6_*.json`。
- Not in this change: 不改代码;阶段 8 第二批与阶段 9 门禁仍未做(见文档「尚未完成」一节);ARM 板卡报告
按用户先前的意思仍是暂缓项。
|
2026-09-14 22:02:43 +08:00 |
|
ykcheungab
|
bf643de93d
|
docs(studio-3d): 阶段 6 交付说明(正确性与失效状态)+ 接口骨架同步
- What:
1. `docs/architecture/studio-3d-stages.md` 新增「阶段 6:运行正确性与失效状态(批次 A)—— 已完成」:
做(epoch/字段级来源/设备几何身份/加载请求号/工具与重编包)、验收表格(含两份探针的
before/after 与全量计数)、"这一阶段抓到的" 7 条、兼容说明 6 条;文首进度改成阶段 6 已完成、
7/8/9 未开始;依赖关系图扩展为 6→7/8→9。
2. `docs/architecture/studio-3d-contracts.pyi` 与本阶段的契约改动同步:`SceneState` 加 `'stale'`;
`SurfaceFieldFrame`/`RenderFrame` 加 `computed_frame_id`;`ExpectedGeometry` 加 `source_geometry_id`
并注明米制 id 何时为空;`SceneAssets` 加 `source_geometry_id`/`compatible_sensor_model`/
`compatible_hardware_revisions`;`ThreeDCoordinator.__init__` 加 `clock`/`stale_grace_s`,新增
`note_field_failure()`/`show_rest()`/`epoch`/`last_presented()`。
- Why: 规格 §13 要求每阶段同时交出实现、测试、输入样例、失败样例、兼容说明与平台诊断报告;阶段 6 的
契约改动(`SceneState`、两个 `computed_frame_id`、`ExpectedGeometry`/`SceneAssets` 的新身份字段、
协调器新参数)必须先落到接口骨架里,否则下一阶段会照着过期文档实现。审查报告本身不修改
(`_review_scene3d_20260914/` 保持原样),结论与反号证据写进本仓文档。
- Verification:
· 阶段末全量复核(与本提交同一工作树):apps/studio 234 项 0 失败(14 跳过 = offscreen 下的真 GL 用例,
用 `QT_QPA_PLATFORM=windows` 单独跑为 14 项 0 失败 0 跳过);shared 316 项 0 失败 1 跳过;
`ui_check` 587 项 0 失败;`locale_check` 0 缺失(zh/en 各 398 键,仅有键集合相同);
`validate_scene.py` 对重编发布包 `source geometry recorded 46a03a5fbac1eace` 等全项 ok。
· 复现证据:`.repro/probe_stage6_r1.py`(R1/R7-b 反号)、`.repro/probe_stage6_device.py`
(R3:同尺寸不同映射被拒、表面不同被拒、设备不声明 → unverified),输出 JSON 与扫描件留在 `.repro/`。
- Not in this change: 不改代码(本提交只动文档与接口骨架);阶段 7/8/9 的计划条目(二维后端统一、
回放入口收口、能力控件、限速与真实统计、保护包密钥注入、ARM 与 2 小时门禁)尚未开始;
真机上"算法链失败时 `VRAW` 是否也过期"这一条仍待实测(风险项已写进阶段 6 小节)。
|
2026-09-14 21:13:57 +08:00 |
|
ykcheungab
|
981c250559
|
feat(studio-3d): 历史回放里的三维面板 —— 由「重算」通道喂它,并标注来源
- What: `VIEW_SHOWS_3D` 加入 `replay`;`app_window` 新增 `_shows_3d()`(可见性与布局共用一个判据)
与 `_splitter_sizes_for()`(预设表里的 3D 槽是"二维布局"的描述,面板打开时从最宽的面板借
`DEFAULT_3D_PANE_WIDTH=340`);`ThreeDPanel` 新增第三个来源标签(实时采集 / 回放:录像不含三维场 /
重算通道:由录像重算,非记录值)与 `set_source_kind()`;`ThreeDCoordinator.show_rest()` 把参考模型
放回屏幕并停止主张测量值(重算停止时调用,否则最后一帧会留在屏幕上);`Mesh3dPanel` 转发这两者,
并新增"加载中"状态的修正:切换传感器再切回来时若该包已加载,直接显示已就绪的画面而不是一条永远
不会被替换的"正在加载"。
- Why: 录像里没有三维场(raw_*.mp4 是原始相机图像,`depth.stored=false`,CSV 只有力值),所以纯回放只能
显示参考模型;但「从视频重算力值」本来就把同一个运行路径指向录像的原始视频,而采集线程上的三维 sink
早已注册——因此重算一开始面板就会收到真实的形变帧。这两件事必须由界面区分:一个是"没有测量",
一个是"当前算法对这段录像会说什么",把后者当成记录值展示就是另一种 `display_illustrative`。
- Verification: apps/studio 全量通过(test_scene3d_view.py 32 项,含"回放里面板可见且标注正确""重算时
标注切换""停止重算后清回参考模型""实时视图标为实时";test_scene3d_coordinator.py 15 项,含 show_rest
与"停止时在飞的帧不会随后被显示");ui_check 570 项 0 失败(新增"已安装包必须被加载并标注来源");
locale_check 0 缺失;仓库内工程包经 validate_scene 全部 ok。
- Not in this change: 逐帧保存展开场/深度(记录格式变更,设计文档明确否掉);重算通道本身(已存在,本次
只是把它的帧接到面板上);示意位移(仍需 SDK lift + 已确认尺度)。
|
2026-09-14 17:13:37 +08:00 |
|
ykcheungab
|
2226bdde68
|
docs(studio-3d): 阶段 5 补全测试计数,并记录与本功能无关的 Windows 计时器粒度失败
|
2026-09-14 16:49:30 +08:00 |
|
ykcheungab
|
8c8a97e8d6
|
docs(studio-3d): 阶段 5 兼容说明补齐「最小交付」与「客户包无私钥」的证据来源
|
2026-09-14 16:49:07 +08:00 |
|
ykcheungab
|
5cd92254e1
|
feat(studio-3d): 阶段 5 —— 发布保护(签名/可选加密/平台锁定)与性能长时报告
- What: 新增 `scene3d/protect.py`(封套 v2:Ed25519 签名 + 可选 AES-256-GCM,nonce/salt 每包唯一、
元数据作 AAD、明文摘要进签名、KeyProvider 只问 get_content_key)与 `record/visualization3d.py`
(session.json 的 visualization3d 块:写入版本化、读取时缺块=不支持);`package.py` 支持 v2
(payload=plain 仅签名 / aes-gcm 签名+加密)并继续读 v1,新增解压比上限与"写入后自读回"校验;
`contracts.py` 新增 PlatformLock/PlatformInfo/check_platform_lock、Sealing、platform_mismatch 诊断码;
`Scene3DView` 在装配前查 OS/架构、拿到 capabilities 后查图形半区,违反即撤下场景并在面板显示原因;
工具 `compile_scene.py` 新增 --sign-key/--write-verify-key/--encrypt-key-id/--key-file/--lock-from-probe,
`validate_scene.py` 新增 --key-file/--key-id/--verify-key/--require-signature(发布门禁),
新增 `bench_scene.py`(p50/p95 分阶段 + --cpu-only + --vertices N + --package)与
`soak_scene.py`(RSS 四分位速率 + 队列上界 + 抽稀采样);两份报告落到 docs/architecture/。
- Why: 规格 §5.2 的保护目标是"提高复制成本"而不是"防提取",所以要的是签名(来源)+ 可选认证加密(机密性)
+ 密钥隔离,而不是自制加密或把 ZIP 当加密;§12 的"包保护/性能/长时"三行需要可复现的数字与判定标准,
而不是一次性的观感。平台锁定还必须只降级三维:锁定不通过时二维照常。
- Verification: shared 全量通过(新增 test_scene3d_protect.py 35 项:封套往返/篡改/密钥/锁定/记录块/
compile→validate 端到端发布流程;test_scene3d_package.py 20 项含 v1↔v2 兼容);apps/studio 全量通过
(test_scene3d_view.py 30 项含锁定拒绝与 session.json 块);ui_check 566 项 0 失败;locale_check 0 缺失;
真实资产端到端:1032 顶点编译出 signed+sealed+locked 包(56 927 B 密文),validate --require-signature 退出 0,
改一个字节退出 2;性能报告(perf-report-windows-dev.json):1032 顶点 compose p50 0.50 ms(30 fps 上限内),
20022 顶点/39480 三角形 compose p50 6.15 ms(约 33 ms 帧的 18%),采集线程 submit p95 < 0.4 ms(合成器被人为放慢到 50 ms);
长时报告(soak-report-windows-dev.json):无窗口 10 min/60 fps 尾段 0.354 MB/min,GUI 4 min/30 fps 尾段 0.809 MB/min,
队列上界(mailbox=1、单飞行合成)两者均成立。过程中修掉:GUI 进程里的合成器计时被 GIL/vsync 污染(98.8 ms vs 真值 6.1 ms)、
跨线程读 last_stats 撕裂、key id 无 provider 时会静默写明文包、soak 工具自身记时间列表会无界增长、RSS 读取失败伪装成零增长、
平台锁定不是终态诊断。
- Not in this change: ARM 板卡的能力报告与 2 小时门禁运行(按用户要求暂缓;命令与判定标准已写入阶段 5 文档);
GPU 显存随时间的测量(无可移植 API,报告说明渲染器缓冲估计恒定且更新路径不新建 GPU 对象);
`cryptography` 在此环境无法联网安装,本机验收用的是本机已有的 cp310 构建(pyproject 里已声明为可选 extra
`protected-assets`)。
|
2026-09-14 16:44:33 +08:00 |
|
ykcheungab
|
ac4dcd643f
|
feat(studio): 三维视图接入产品(阶段 4:界面、生命周期与记录隔离)
- What: `Scene3DView` 装配(widget/相机/渲染器/合成器/协调器/适配器),`asset_source`
只查找并后台加载已编译的 `.oryscene` 包,`scene3d/prefs` 持久化并**修复**显示设置,
`ui/mesh3d_panel` 用真实容器替换占位标签(无 GL/无包/包被拒/传感器不匹配各显示一行原因),
`main.py` 在 `QApplication` 之前选定 GL profile,`app_window` 接线:3D 作为采集线程上的
第二个 sink、`_on_run_tick` 驱动 `tick()`、视图切换与 `closeEvent` 释放、preferences 落盘。
- Why: 阶段 4 的验收要求"三维开关不影响采集/记录/力曲线",并把阶段 1 留下的
"开/关三维 CSV 一致"这条补上;同时把"没有 context"从"看起来像在工作"变成可显示的终态。
- Verification: app 侧 test_scene3d_view 28 项、test_scene3d_gl_smoke 14 项(真实 GPU)、
adapters 17 项、skeleton 4 项、stage1 24 项、coordinator 13 项、ui_smoke 86 项;
shared 侧 contract 26 / assets 33 / package 19 / live 25;`ui_check.py` 566 项检查 0 失败
(新增 "3D pane" 段 12 项);`locale_check.py` 302 个字面 key 0 缺失、中英各 377 key 对齐;
记录隔离:同一 96 帧会话挂/不挂 3D 消费者,`forces.csv` 逐字节相同、有效样本数与记录问题数相同;
生产者预算:合成器放慢到 50 ms 时 `submit_packet` p99 < 1 ms。
- Not in this change: 示意位移(`displacement_sensor_m`)仍未接入(需 SDK lift 与已确认尺度);
ARM 板卡适配(按用户要求暂缓);包签名/AES-GCM 与长时性能报告(阶段 5);
仓库中仍未提供 `.oryscene` 包(发布产物,且其单位与变换必须由人声明)。
|
2026-09-14 15:47:32 +08:00 |
|
ykcheungab
|
ea1027e5a6
|
阶段 3:实时数据 —— 采样、合成、最新帧调度与适配器 - What: sampling.py 实现 SurfaceSampler(向量化四点双线性:无效 tap 不计入也不致无效、任一**正权** tap 无效即整顶点无效且值为 NaN、域/形状不符先拒;采样表只在加载时构建)与 remap_to_domain(按 unroll 映射 gather,空洞保持 NaN 且 valid=False,保留尾随轴以支持矢量场)。composer.py 实现 SceneComposer.compose(域校验 → 采样 → 位移 → **从形变后位置重算法线**;scalar 绝不成以 display_gain;approximate 位移产生 display_illustrative(info) 诊断、calibrated 不产生、无位移则着色并报 field_unavailable)与 build_rest_frame(参考帧:scalar 全 NaN、valid 全假、descriptor=unavailable/display_only),gl_backend.rest_surface 改为委托它,避免两处定义。coordinator.py 实现完整调度:容量 1 双 mailbox、generation/来源/会话三重过期拒绝并计数、**最多一次合成在飞行**、可见性挂起/恢复、设置变更(倍率变化重合成**屏幕上那一帧**)、close 幂等;submit 只做身份与形状的廉价校验,绝不等显示。adapters.py 实现 Finger/Box 适配器:|flow| 或 depth 响应、可选经 unroll 映射 remap、设备 valid_mask 优先、域不符时**发布空**并报出所见的两个形状;一律不造位移(未标定的毫米不如没有),并新增 display_illustrative 到诊断码表(info)。assets.py 从"桩类堆"改成门面:re-export 真正实现 + SceneCompiler.compile(外壳 GLB 与预算检查;加密请求明确拒绝并指向阶段 5)。测试:shared/tests/test_scene3d_live.py 25 项(采样/无效语义/倍率只影响位置/示意形变标注/法线重算/remap 空洞/参考帧/只读数组)、apps/studio/tests/test_scene3d_coordinator.py 13 项(状态机、过期、替换计数、单飞行、submit p99<1ms、切换场景丢弃在飞结果、隐藏挂起、倍率重合成、close 幂等)、test_scene3d_adapters.py 13 项;并把三处"桩仍未实现"的过时断言改成对已实现行为的断言。docs/architecture/studio-3d-stages.md 阶段 3 记为完成。 - Why: 阶段 3 决定"屏幕上的颜色和力值到底对应什么"。三条最容易错且肉眼看不出来的规则必须由代码而不是约定来保证:无效点不是 0(NaN 与 valid 分离,否则缺口会被画成一个测量值)、显示倍率只动位置不动测量(否则色标悄悄变了含义)、以及显示永远不能给采集施加背压(容量 1 mailbox + 单飞行合成 + 廉价 submit)。 - Verification: shared 全量通过(scene3d 相关 103 项:contracts 26、assets 33、package 19、live 25);studio 全量通过(scene3d 相关 54 项:stage1 24、skeleton 4、coordinator 13、adapters 13;GL 冒烟 10 项在真实 context 下另行通过);ui_check 554 项 0 失败。过程中修掉 3 个真实缺陷:倍率变化时用 incoming.peek() 取不到"屏幕上那一帧"(已被消费)导致改了倍率画面不动——改为保留 _last_field_frame;display_illustrative 不在码表里被默认成 error;assets.py 里与 package/legacy 同名的重复桩类(会误导集成者,已改为门面)。另修正两处我自己的错误断言(对称凸起顶点法线本就竖直;pytest.approx 不能直接 .all())。 - Not in this change: 手势与面板(阶段 4);示意位移的真实来源(需要 SDK lift + 已确认尺度,现阶段 adapter 一��� displacement=None);app_window 接线与记录隔离(阶段 4)。
|
2026-09-14 15:21:39 +08:00 |
|
ykcheungab
|
d0dcac743f
|
阶段 2:资产合同 —— 旧 NPZ 导入、坐标/单位、绑定、包容器与工具 - What: shared/scene3d 新增四个模块与两个工具的真实现。digest.py:规范化内容摘要(C 连续小端字节 + 排序 JSON;DIGEST_SCHEMA 版本化),geometry_id(只看 part 角色/顶点/三角形,故意不含法线材质与 LOD 名——改颜色不得让标定失效)、binding_id、field_domain_id(形状、flip_v、source_scale、原点/索引约定、映射内容)、asset_hash(条目摘要 + 去自引用字段的 manifest)。legacy.py:LegacyFingerImporter 按"先单位、后刚体"两步转换(meters_per_source_unit 必填且不得猜、validate_rigid_transform 拒绝含缩放/镜像/非仿射的 4x4);split_at_uv_seams 按 (源顶点, 量化 UV) 拆点,接缝处不平均 UV;vertex_normals 面积加权并给无面顶点有限回退;uv_to_pixel 采用实测约定 x=u*(W-1)、y=(1-v)*(H-1)(flip_v 时);build_binding 生成四点双线性采样表(域内裁剪、零权 tap 丢弃并重分配、未用项 -1/0);uv_correspondence_residual 用 Procrustes 残差把"UV 是否对得上 world_xyz"变成可断言的事实;estimate_meters_per_source_unit 只报告不应用。glb.py:glTF 2.0 子集读取(GLB 头/chunk 校验、accessor/bufferView/stride、节点 TRS 与矩阵烘焙进顶点、法线用逆转置再归一化、缺法线则计算),明确拒绝 Draco/meshopt/量化扩展、稀疏 accessor、外部 buffer、骨骼、形态目标、非 TRIANGLES、越界索引、非有限坐标与超预算三角形;with_housing 把外壳作为独立 part 加入且不动感知几何 id。package.py:.oryscene(zip:envelope.json + manifest.json + sensing/housing *.npy,无 pickle 无代码执行),写入原子(先写 .partial 再替换)、读取逐一校验 magic/envelope 版本/payload 状态/条目路径/manifest 自哈希/逐条目 sha256/dtype/shape/**从包内数组重算 geometry_id 与 binding_id**,加密封套明确报"本版本只开明文包"。tools/scene_assets/validate_scene.py 与 compile_scene.py 真实现(含 --json 报告与退出码:0 通过、2 检查失败、1 参数/文件问题;未给单位时停在 needs_units 并打印实测候选尺度)。测试:shared/tests/test_scene3d_assets.py 33 项(真实 1032 导出与 1005 对比资产的输入样例、接缝/法线/绑定/单位/变换/摘要的失败样例、GLB 往返与拒绝样例)、test_scene3d_package.py 24 项(往返、外壳条目、以及篡改条目/篡改 manifest 哈希/自洽但错误的几何/非有限坐标/多余条目/缺条目/路径穿越/dtype 与 shape 不符/未来版本/加密封套/key provider 的拒绝)。docs/architecture/studio-3d-stages.md 阶段 2 记为完成并附验收结果。 - Why: 阶段 2 要回答的是"这份几何到底是什么、单位是什么、它和哪套 UV 域配套、以及这份包有没有被动过",这些一旦错了会以"三维看起来有点怪"的形式出现且事后无法追溯。因此把 UV 约定做成可测量的事实(真实资产残差 0.0064 vs 错误翻转 0.59)、把单位做成必填参数而不是默认值、把 identity 做成内容摘要并**在读取时重算**,同时用真实资产当输入样例、用篡改后的包当失败样例。 - Verification: 真实资产导入:1032 顶点/1974 三角形/域 300×280/尺寸 15.81×15.0×7.5 mm,validate_assets 通过;UV 残差 0.0064(错翻转 0.59);两套资产混用被拒(geometry_mismatch);缩放/镜像/非仿射变换被拒;compile→validate 端到端 ok(包内条目哈希与 manifest 自哈希全部通过);shared 全量 244 passed;studio 118 passed;ui_check 554 项 0 失败;.repro/verify_assets.py 22 项 0 失败。过程中修掉 5 个真实缺陷:np.load 需要真实文件对象(手写内存 stub 抛空消息异常)、包可以"自洽却错误"(改数组+改哈希后无人重算几何 id,现已重算并比对)、binding 行数不匹配被误报为域错误、np.ptp 平铺比较无意义(换算/不变性断言改为按轴)、以及合成 PoC 场景自己用字符串当 geometry_id(所有人都会抄它,等于绕过检查)。 - Not in this change: 签名与 AES-GCM(阶段 5);LOD 简化;calibration.py 侧的资产哈希登记;三维视图仍未被应用导入(阶段 4 接线)。
|
2026-09-14 15:08:29 +08:00 |
|
ykcheungab
|
5767b4bf11
|
阶段 1:平台 PoC —— 真实 GL 上跑通静态场景,并修掉它抓出的相机/上下文错误 - What: 按 docs/architecture/studio-3d-stages.md 阶段 1 落地图形栈。OrbitCamera 全部实现(target/distance/yaw/pitch 表示;fit 按包围球与较窄的那个视场轴定距离;orbit/pan/zoom 有界;set_preset 从 eye/target 反解角度使拖动可延续;matrices 输出只读 float32 view/projection;另加 depth_range_m() 便于断言)。gl_backend:GLDispatch.bind_current_context 真正绑定 PyOpenGL 并读 vendor/renderer/GL/GLSL/max texture、判软件渲染、profile 不达标时抛 ThreeDUnsupported 并带回能力;GLRenderer 实现 initialize(两个 program,desktop33/gles30 共用同一份着色器主体、只换头部)、upload_scene(每 part 一套 VAO/VBO/EBO,交错 layout position/normal/scalar/valid = 8 float)、update_surface(只对感知面 glBufferSubData,绝不重建索引)、draw(绑 Qt 的 defaultFramebufferObject、深度测试、按 role 选 program、housing 隐藏即跳过、scalar 经 LUT 纹理与 range uniform 上色,Python 不生成 RGB 数组)、release(幂等);纯函数 pack_part/pack_scene_part/estimate_gpu_bytes/rest_surface/shader_source/shader_header/lut_rgba/is_software_renderer/profile_from_renderable_type 都可在无 GPU 环境测试。Sensor3DWidget 实现 initializeGL/paintGL/resizeGL/release_resources/aboutToBeDestroyed/showEvent/hideEvent 与鼠标事件;加载场景时先采用资产自带的默认视角再 fit;一帧几何不匹配只"拒绝该帧"(计数 + 诊断 + 用 rest_surface 清掉上次测量)而不是把整个视图打成不可用。shared/scene3d/synthetic.py 提供 PoC 与测试共用的已知场景(20mm 感知板 + 外壳盒,米、sensor 坐标系、带默认三视角预设)。tools/scene_assets/probe_gl.py 真实现:真实窗口取 context 并输出 JSON 报告(平台/Qt/PyOpenGL/vendor/renderer/GL/GLSL/DPR/framebuffer/是否软件渲染),退出码即门禁(0 通过、3 软件渲染、4 无上下文);apps/studio/pyproject.toml 增加 [three-d] 可选依赖(仅 PyOpenGL;Open3D 不进运行时)。测试:apps/studio/tests/test_scene3d_stage1.py 24 项(相机数学、PoC 场景合规、打包布局、着色器两方言共用主体、LUT、软件渲染识别、renderableType 映射、GPU 预算、参考帧语义,全部无需 GPU)+ test_scene3d_gl_smoke.py 8 项(真实 context:能力、两个 part 都画出来、外壳可隐藏、参考帧中性 vs 色图有差异、动态更新不动 housing 缓冲、坏几何帧被拒且视图存活、resize 跟随、release 幂等且新 context 能重传场景、探针如实报告);offscreen 下后者自动 skip。docs/architecture/gl-report-windows-dev.json 为本机平台报告。 - Why: 用户要求"从骨架搭起→计划阶段→逐阶段实现与验收",并明确 ARM 暂缓。阶段 1 的产出本身就是一份能回答"这块板的图形栈能不能用"的报告,所以先把它做实、把 profile 冻结点定在真实 context 上,而不是先堆屏幕上的东西。 - Verification: 真实 context(QT_QPA_PLATFORM=windows)下 8 项 GL 验收全过;offscreen 下 24 项 CPU 项全过、GL 项按设计 skip;shared 全量 187 passed;studio 全量 116 passed(含新 32 项);ui_check 554 项 0 失败;probe_gl 输出 verdict=ok(NVIDIA RTX 4080 SUPER、GL 3.3 Core、GLSL 3.30、非软件渲染)。过程中这套验收抓出并修掉了 7 个真实缺陷:Qt renderableType 映射反了(NVIDIA 兼容 ES 着色器所以本机看不出,Intel/ARM 会直接失败)、观察相机是左手基导致整模型镜像(det=-1)、近平面过近使 NDC z 全挤在 0.99(深度精度归零、外壳与感知面会 z-fighting)、手动 makeCurrent 早于 Qt 首次绘制会把 GPU 对象建在被丢弃的 context 里(glBindVertexArray 报 INVALID_OPERATION)、context 重建后不重传场景、一帧几何不匹配把整个视图打死、以及 grabFramebuffer 是 BGRA+stride 导致颜色断言全部读错通道。 - Not in this change: 未接入 app_window/main.py(三维对现有应用仍完全惰性,故"开/关三维 CSV 行序一致"这条验收随阶段 4 做);阶段 2 的资产导入/坐标/包格式;ARM 平台实测(probe 已可在板上直接运行)。
|
2026-09-14 14:55:45 +08:00 |
|
ykcheungab
|
0b309e7edf
|
三维显示骨架:可执行合同 + 模块签名 + 分阶段计划 - What: 按 docs/architecture/studio-3d-design.md 与 studio-3d-contracts.pyi 搭建骨架(阶段 0)。shared/src/orisys_app_shared/scene3d/:contracts.py 把 .pyi 的规格变成可执行代码——全部 DTO/枚举(FrameIdentity/FieldDescriptor/SurfaceFieldFrame/MeshPart/SurfaceBinding/CameraPreset/ExpectedGeometry/SceneAssets/ColorScale/DisplaySettings/VertexFields/RenderFrame/CameraMatrices/GLCapabilities/RenderStats/CompileOptions/CompileReport)、标准诊断码表(DIAGNOSTIC_SEVERITY,含 stale_frame=info、field_unavailable=warning 等)、ThreeDError、freeze()(拥有数据 + C 连续 + 只读)、五个校验器(validate_surface_frame/validate_binding/validate_mesh_part/validate_assets/validate_display_settings/validate_render_frame)、LatestFrameMailbox(容量 1、替换计数、锁内只换引用)、UNAVAILABLE_DESCRIPTOR/rest_descriptor() 与 summarize_parts(),以及全部 Protocol;该模块不 import Qt/OpenGL/SDK。assets.py/sampling.py/composer.py 为签名骨架(未实现处抛 NotImplementedError 并写明归属阶段)。apps/studio/src/orisys_studio/scene3d/:camera/adapters/coordinator/gl_backend/widget/panel 签名骨架,其中 configure_surface_format() 已实现(QApplication 之前调用,desktop33=GL3.3 Core / gles30=GLES3.0,深度 24、无 MSAA);模块级一律不 import GL 绑定,PyOpenGL 只在 GLDispatch.bind_current_context 里加载。tools/scene_assets/{probe_gl,validate_scene,compile_scene}.py 提供入口与参数,未实现时输出 not_implemented 并返回 2(避免被 CI 当成通过)。docs/architecture/studio-3d-stages.md:阶段 0-5 的产出、每阶段的验收矩阵、并行度与回归门。测试:shared/tests/test_scene3d_contracts.py 26 项(freeze 拥有数据、可写/非连续数组被拒、scalar 与 valid 形状一致、位移缺 quality 被拒、非有限 scalar 标为 valid 只报警不静默、绑定越界/-1 约定/权重和为 1、三角形索引越界、感知法线单位长度、恰好一个 sensing part、binding 必须属于 sensing part、设备几何/域/尺寸不符被拒、色标 lower<upper、邮箱替换计数与多线程不阻塞生产者、身份区分 source/generation、骨架可导入且不引入 PyOpenGL);apps/studio/tests/test_scene3d_skeleton.py 4 项(骨架不 import OpenGL、surface format 两个 profile、widget 构造不需要 context、各 stub 报出归属阶段)。 - Why: 用户要求"先从骨架搭起,然后计划功能实现顺序,最后逐阶段实现与验收"。骨架阶段的价值在于把接口变成可执行的(.pyi 本身无法被测试),并把"数组只读、单位与质量必须声明、近似位移不得当毫米、参考帧不得冒充测量、显示丢帧不得计入记录丢帧"这些容易在实现时被绕过的规则先固定下来;同时明确不 import Qt/OpenGL 的边界,使采集线程与 CI 能在无 GPU 环境导入它。 - Verification: shared 全量 187 passed(原 161 + 26);studio 95 passed(原 91 + 4);ui_check 554 项检查 0 失败;compileall 通过;probe_gl --profile desktop33 在未实现时返回 2 并说明将产出什么报告。 - Not in this change: 三维功能本身(阶段 1 起);app_window/main.py 未接线,骨架对现有应用完全惰性(无任何模块被应用导入)。
|
2026-09-14 14:32:38 +08:00 |
|
ykcheungab
|
c10e579371
|
update 3d scafold
|
2026-09-14 13:55:36 +08:00 |
|