修复回放标定选择与曲线显示数据保留
让标定选择进入处理和缓存,避免显示设置清空曲线。102 项针对性检查通过,全量门禁仍有停止时序、模型尺寸与原生崩溃问题。
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
# Replay panel contract
|
||||
|
||||
The replay panel plays one recording — or one video — against a single cursor. Each
|
||||
capability states its requirement, data source and a falsifying check. The result format and
|
||||
playback semantics are owned by Part A ([replay-analysis.md](replay-analysis.md)) and Part B
|
||||
([replay-analysis-part-b.md](replay-analysis-part-b.md)).
|
||||
The replay panel plays one recording or video against one cursor. Part A
|
||||
([replay-analysis.md](replay-analysis.md)) and Part B
|
||||
([replay-analysis-part-b.md](replay-analysis-part-b.md)) own format and playback semantics.
|
||||
|
||||
Status: Parts A and B shipped at `cf49b08`, the depth channel at `9e20fd0`, the result-aware mode
|
||||
plan at `1aa4543`. The cache root and the lifetime sweep are implemented; the display-control
|
||||
@@ -11,12 +10,10 @@ separation (Part C) is not.
|
||||
|
||||
## 1. Load a video
|
||||
|
||||
Selecting a video always gives a playable timeline, and the panel says what the file is.
|
||||
`load_video` calls a folder holding `forces.csv` beside the video a recording; anything else
|
||||
opens as a bare video (`VideoOnlySource`) and plays, with `playback.video_only_opened` on the
|
||||
rail and `playback.video_only_notice` in the notes. A file that cannot be decoded is refused
|
||||
with its reason. What a bare video lacks is force rows *measured by a device*, and
|
||||
`session.json` metadata.
|
||||
`load_video` treats video beside `forces.csv` as a recording; otherwise it opens a bare video
|
||||
(`VideoOnlySource`), with `playback.video_only_opened` on the rail and
|
||||
`playback.video_only_notice` in the notes. Undecodable files are refused with their reason.
|
||||
Bare video lacks device-measured force rows and `session.json` metadata.
|
||||
|
||||
**A bare video can be analysed, and is asked how.** The two files the pass reads are *generated*
|
||||
for the video in an app-owned workspace and every later step is the existing recording path; the
|
||||
@@ -72,13 +69,13 @@ One cursor drives all three.
|
||||
|
||||
| View | Data source |
|
||||
|---|---|
|
||||
| Charts | the recorded `forces.csv` (`RecordingCurveSource`), or — over a bare video — the result's own recomputed trace (`AnalysisCurveSource`) |
|
||||
| Charts | recorded `forces.csv` (`RecordingCurveSource`), or a recomputed trace for bare videos and reconfigured recordings (`AnalysisCurveSource`) |
|
||||
| 2D canvas | the cached per-frame samples and depth, drawn at display time |
|
||||
| 3D pane | the packet built from the cached frame (`AnalysisSession.packet` → `Scene3DView.submit_packet`) |
|
||||
|
||||
The charts read one of two sources, and the header names which: `chart.mode_replay` for a
|
||||
recording's own `forces.csv` (*the* measurement — a device was in the loop) and
|
||||
`chart.mode_recomputed` for the trace the pass recomputed from a bare video
|
||||
`chart.mode_recomputed` for the recomputed trace
|
||||
(`FRAME_FLAG_FORCE`, 28 B/frame; `provenance.sources["forces"]` says which). With neither —
|
||||
nothing analysed yet, or a profile whose chain produced no force for this footage — the header
|
||||
states why (`chart.mode_no_trace`) rather than leaving an empty plot.
|
||||
@@ -98,6 +95,19 @@ sampled on the pass's own grid, so the frame carries that policy (`ImageFrame.ar
|
||||
Verify: `test_replay_analysis.py::test_the_3d_pane_is_fed_the_same_frame_the_canvas_draws`,
|
||||
`::test_a_display_change_that_moves_the_grid_is_refused_not_served`.
|
||||
|
||||
### Calibration choices and curve retention
|
||||
|
||||
Recording setups scope calibration, confirmed device, unloaded and tracker references to one
|
||||
directory; the profile stays locked. References use recorded IDs/times. Chosen calibration content and force-channel choice enter
|
||||
the cache key. A complete `sources.forces="recomputed"` result replaces the displayed CSV trace,
|
||||
labelled `chart.mode_recomputed`; original files remain unchanged. Failed/cancelled passes
|
||||
replace no trace. Without an override, recorded force retains priority.
|
||||
|
||||
Display controls preserve measurements, session time and partial axes, including FN-only.
|
||||
New live runs remain independent; manual graph reset may clear the graph. Storage remains
|
||||
bounded and reports drops. See the [SDK calibration contract](../../../../orisys-sdk/docs/calibration-model-contract.zh.md).
|
||||
Verify: `test_recording_recalibration.py`, `test_curve_retention.py`, `test_force_history.py`.
|
||||
|
||||
## 5. What the 2D view can show
|
||||
|
||||
The modes come from the frame's own fields and from whether a result exists (`plan_image`,
|
||||
@@ -171,7 +181,3 @@ wipe-on-exit preference and result export (≈70 MB per ten minutes).
|
||||
|
||||
* The render cost (≈1.4 ms) and the PNG estimate (180–540 MB per ten minutes) are the owner's
|
||||
bench; Part B §14's snapshots (4.2–4.9 kB each) suggest the estimate is high.
|
||||
* A chosen calibration can be applied to the **box** chain only (`Sensor(cal_path=…)`). The
|
||||
finger runtime opens its sensor without one, so a non-default curve for a finger profile is
|
||||
refused rather than silently ignored — the SDK has no entry point for it (reported, not
|
||||
worked around).
|
||||
|
||||
Reference in New Issue
Block a user