diff --git a/docs/dev/requirements.md b/docs/dev/requirements.md index f1a3179..5e447df 100644 --- a/docs/dev/requirements.md +++ b/docs/dev/requirements.md @@ -605,6 +605,19 @@ Editing rhythm depends on the hands staying put: reaching for a menu breaks the edit the same way it breaks the pace of a cull. A binding nobody can discover is the same as no binding, which is why the generated book is part of the requirement rather than documentation of it. +**FR-DEV-20 — Perspective correction.** Framing shall include perspective correction — a vertical +and a horizontal keystone — applied before the crop. It runs in the coordinate chain after the +crop and the straightening and before the stored orientation and the lens warp, so that "vertical" +means vertical in the photograph as it is shown and the lens is still corrected on the full frame +it projected. It is part of framing and carries its `Compose` attribute, so a settings paste +withholds it by default for the same reason it withholds the crop. The correction never exposes +undefined area on its own; where it is combined with a straightening angle, the crop that avoids +the empty corners (`max_inscribed_crop`) accounts for it, and the crop is refitted when the gesture +ends. +Converging verticals are the commonest geometric fault in architectural and interior work, and +correcting them reframes the image — which is why the order relative to the crop is not a +preference, and why the correction belongs to composition and not to the colour operations. + ### 3.4 Display and interaction **FR-DSP-1 — Proxy-resolution rendering.** The develop view renders at the resolution actually diff --git a/docs/dev/traceability.md b/docs/dev/traceability.md index e0f438a..03871f9 100644 --- a/docs/dev/traceability.md +++ b/docs/dev/traceability.md @@ -11,16 +11,16 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n |---|---| | Source files scanned | 441 | | TRACES tags found | 1725 | -| Requirements defined | 189 | +| Requirements defined | 190 | | Requirements deferred (post-v1) | 24 | | Requirements covered | 158 | -| **Coverage** | **83.6%** (158/189) | +| **Coverage** | **83.2%** (158/190) | ### By type | Type | Covered | Defined | |---|---|---| -| FR | 120 | 131 | +| FR | 120 | 132 | | NFR | 34 | 51 | | R | 4 | 7 | @@ -65,7 +65,7 @@ _None._ | FR-DEV-10 | [`core/dr-gpu/src/mask.rs:1039`](../../core/dr-gpu/src/mask.rs#L1039), [`core/dr-gpu/src/mask.rs:1263`](../../core/dr-gpu/src/mask.rs#L1263), [`core/dr-gpu/src/mask.rs:1522`](../../core/dr-gpu/src/mask.rs#L1522), [`core/dr-gpu/src/mask.rs:422`](../../core/dr-gpu/src/mask.rs#L422), [`core/dr-gpu/src/mask.rs:464`](../../core/dr-gpu/src/mask.rs#L464), [`core/dr-gpu/src/mask.rs:58`](../../core/dr-gpu/src/mask.rs#L58), [`core/dr-gpu/src/mask.rs:60`](../../core/dr-gpu/src/mask.rs#L60), [`core/dr-gpu/src/mask.rs:846`](../../core/dr-gpu/src/mask.rs#L846), [`core/dr-gpu/src/mask.rs:85`](../../core/dr-gpu/src/mask.rs#L85), [`core/dr-gpu/src/mask.rs:925`](../../core/dr-gpu/src/mask.rs#L925), [`core/dr-gpu/src/shaders/mask.wgsl:117`](../../core/dr-gpu/src/shaders/mask.wgsl#L117), [`core/dr-gpu/src/shaders/mask.wgsl:59`](../../core/dr-gpu/src/shaders/mask.wgsl#L59), [`core/dr-gpu/tests/range_masks.rs:119`](../../core/dr-gpu/tests/range_masks.rs#L119), [`core/dr-gpu/tests/range_masks.rs:147`](../../core/dr-gpu/tests/range_masks.rs#L147), [`core/dr-gpu/tests/range_masks.rs:175`](../../core/dr-gpu/tests/range_masks.rs#L175), [`core/dr-gpu/tests/range_masks.rs:1`](../../core/dr-gpu/tests/range_masks.rs#L1), [`core/dr-gpu/tests/range_masks.rs:94`](../../core/dr-gpu/tests/range_masks.rs#L94), [`core/dr-pipeline/src/mask.rs:125`](../../core/dr-pipeline/src/mask.rs#L125), [`core/dr-pipeline/src/mask.rs:2890`](../../core/dr-pipeline/src/mask.rs#L2890), [`core/dr-pipeline/src/mask.rs:2903`](../../core/dr-pipeline/src/mask.rs#L2903), [`core/dr-pipeline/src/mask.rs:2922`](../../core/dr-pipeline/src/mask.rs#L2922), [`core/dr-pipeline/src/mask.rs:2936`](../../core/dr-pipeline/src/mask.rs#L2936), [`core/dr-pipeline/src/mask.rs:2946`](../../core/dr-pipeline/src/mask.rs#L2946), [`core/dr-pipeline/src/mask.rs:710`](../../core/dr-pipeline/src/mask.rs#L710), [`core/dr-pipeline/src/mask.rs:749`](../../core/dr-pipeline/src/mask.rs#L749), [`core/dr-pipeline/src/mask.rs:809`](../../core/dr-pipeline/src/mask.rs#L809), [`core/dr-pipeline/src/mask.rs:828`](../../core/dr-pipeline/src/mask.rs#L828), [`core/dr-pipeline/src/mask.rs:852`](../../core/dr-pipeline/src/mask.rs#L852), [`core/dr-pipeline/src/mask.rs:864`](../../core/dr-pipeline/src/mask.rs#L864), [`core/dr-pipeline/src/mask.rs:876`](../../core/dr-pipeline/src/mask.rs#L876), [`core/dr-pipeline/src/sidecar.rs:1369`](../../core/dr-pipeline/src/sidecar.rs#L1369), [`core/dr-pipeline/src/sidecar.rs:1548`](../../core/dr-pipeline/src/sidecar.rs#L1548), [`core/dr-pipeline/src/sidecar.rs:1637`](../../core/dr-pipeline/src/sidecar.rs#L1637), [`core/dr-pipeline/src/sidecar.rs:1741`](../../core/dr-pipeline/src/sidecar.rs#L1741), [`core/dr-pipeline/src/sidecar.rs:1949`](../../core/dr-pipeline/src/sidecar.rs#L1949), [`core/dr-pipeline/tests/mask_sidecar.rs:1157`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1157), [`core/dr-pipeline/tests/mask_sidecar.rs:1186`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1186), [`core/dr-pipeline/tests/mask_sidecar.rs:1204`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1204), [`core/dr-pipeline/tests/mask_sidecar.rs:1234`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1234), [`ui/dr-ui/src/develop/mask_ops.rs:341`](../../ui/dr-ui/src/develop/mask_ops.rs#L341), [`ui/dr-ui/src/develop/mask_ops.rs:638`](../../ui/dr-ui/src/develop/mask_ops.rs#L638), [`ui/dr-ui/src/develop/mask_ops.rs:665`](../../ui/dr-ui/src/develop/mask_ops.rs#L665), [`ui/dr-ui/src/develop/mask_ops.rs:697`](../../ui/dr-ui/src/develop/mask_ops.rs#L697), [`ui/dr-ui/src/develop/mask_ops.rs:721`](../../ui/dr-ui/src/develop/mask_ops.rs#L721), [`ui/dr-ui/src/develop/mask_ops.rs:727`](../../ui/dr-ui/src/develop/mask_ops.rs#L727), [`ui/dr-ui/src/develop/mask_ops.rs:734`](../../ui/dr-ui/src/develop/mask_ops.rs#L734), [`ui/dr-ui/src/develop/mask_ops.rs:754`](../../ui/dr-ui/src/develop/mask_ops.rs#L754), [`ui/dr-ui/src/labels.rs:63`](../../ui/dr-ui/src/labels.rs#L63), [`ui/dr-ui/src/masks_ui.rs:1216`](../../ui/dr-ui/src/masks_ui.rs#L1216), [`ui/dr-ui/src/masks_ui.rs:797`](../../ui/dr-ui/src/masks_ui.rs#L797) | | FR-DEV-12 | [`core/dr-pipeline/ops/colour_grading.yaml:1`](../../core/dr-pipeline/ops/colour_grading.yaml#L1) | | FR-DEV-16 | [`ui/dr-ui/src/lib.rs:441`](../../ui/dr-ui/src/lib.rs#L441), [`ui/dr-ui/src/masks_ui.rs:713`](../../ui/dr-ui/src/masks_ui.rs#L713), [`ui/dr-ui/ui/adjust.slint:956`](../../ui/dr-ui/ui/adjust.slint#L956), [`ui/dr-ui/ui/app.slint:2398`](../../ui/dr-ui/ui/app.slint#L2398), [`ui/dr-ui/ui/app.slint:2411`](../../ui/dr-ui/ui/app.slint#L2411), [`ui/dr-ui/ui/masks.slint:853`](../../ui/dr-ui/ui/masks.slint#L853) | -| FR-DEV-17 | [`core/dr-pipeline/src/orphan.rs:145`](../../core/dr-pipeline/src/orphan.rs#L145), [`core/dr-pipeline/src/orphan.rs:1`](../../core/dr-pipeline/src/orphan.rs#L1), [`ui/dr-ui/src/develop/framing.rs:1109`](../../ui/dr-ui/src/develop/framing.rs#L1109), [`ui/dr-ui/src/develop/framing.rs:133`](../../ui/dr-ui/src/develop/framing.rs#L133), [`ui/dr-ui/src/develop/framing.rs:169`](../../ui/dr-ui/src/develop/framing.rs#L169), [`ui/dr-ui/src/develop/framing.rs:235`](../../ui/dr-ui/src/develop/framing.rs#L235), [`ui/dr-ui/src/develop/framing.rs:243`](../../ui/dr-ui/src/develop/framing.rs#L243), [`ui/dr-ui/src/develop/session.rs:110`](../../ui/dr-ui/src/develop/session.rs#L110), [`ui/dr-ui/src/develop_ui.rs:1061`](../../ui/dr-ui/src/develop_ui.rs#L1061), [`ui/dr-ui/src/develop_ui.rs:972`](../../ui/dr-ui/src/develop_ui.rs#L972), [`ui/dr-ui/src/develop_ui.rs:998`](../../ui/dr-ui/src/develop_ui.rs#L998), [`ui/dr-ui/src/lib.rs:2207`](../../ui/dr-ui/src/lib.rs#L2207), [`ui/dr-ui/src/lib.rs:613`](../../ui/dr-ui/src/lib.rs#L613), [`ui/dr-ui/ui/adjust.slint:683`](../../ui/dr-ui/ui/adjust.slint#L683), [`ui/dr-ui/ui/adjust.slint:687`](../../ui/dr-ui/ui/adjust.slint#L687), [`ui/dr-ui/ui/app.slint:2641`](../../ui/dr-ui/ui/app.slint#L2641), [`ui/dr-ui/ui/crop.slint:51`](../../ui/dr-ui/ui/crop.slint#L51) | +| FR-DEV-17 | [`core/dr-pipeline/src/orphan.rs:142`](../../core/dr-pipeline/src/orphan.rs#L142), [`core/dr-pipeline/src/orphan.rs:1`](../../core/dr-pipeline/src/orphan.rs#L1), [`ui/dr-ui/src/develop/framing.rs:1109`](../../ui/dr-ui/src/develop/framing.rs#L1109), [`ui/dr-ui/src/develop/framing.rs:133`](../../ui/dr-ui/src/develop/framing.rs#L133), [`ui/dr-ui/src/develop/framing.rs:169`](../../ui/dr-ui/src/develop/framing.rs#L169), [`ui/dr-ui/src/develop/framing.rs:235`](../../ui/dr-ui/src/develop/framing.rs#L235), [`ui/dr-ui/src/develop/framing.rs:243`](../../ui/dr-ui/src/develop/framing.rs#L243), [`ui/dr-ui/src/develop/session.rs:110`](../../ui/dr-ui/src/develop/session.rs#L110), [`ui/dr-ui/src/develop_ui.rs:1061`](../../ui/dr-ui/src/develop_ui.rs#L1061), [`ui/dr-ui/src/develop_ui.rs:972`](../../ui/dr-ui/src/develop_ui.rs#L972), [`ui/dr-ui/src/develop_ui.rs:998`](../../ui/dr-ui/src/develop_ui.rs#L998), [`ui/dr-ui/src/lib.rs:2207`](../../ui/dr-ui/src/lib.rs#L2207), [`ui/dr-ui/src/lib.rs:613`](../../ui/dr-ui/src/lib.rs#L613), [`ui/dr-ui/ui/adjust.slint:683`](../../ui/dr-ui/ui/adjust.slint#L683), [`ui/dr-ui/ui/adjust.slint:687`](../../ui/dr-ui/ui/adjust.slint#L687), [`ui/dr-ui/ui/app.slint:2641`](../../ui/dr-ui/ui/app.slint#L2641), [`ui/dr-ui/ui/crop.slint:51`](../../ui/dr-ui/ui/crop.slint#L51) | | FR-DEV-18 | [`core/dr-pipeline/src/ops/dehaze.rs:1`](../../core/dr-pipeline/src/ops/dehaze.rs#L1), [`core/dr-pipeline/src/ops/dehaze.rs:221`](../../core/dr-pipeline/src/ops/dehaze.rs#L221) | | FR-DEV-19 | [`core/dr-pipeline/src/mask.rs:1341`](../../core/dr-pipeline/src/mask.rs#L1341) | | FR-DEV-19a | [`core/dr-gpu/src/mask.rs:655`](../../core/dr-gpu/src/mask.rs#L655), [`core/dr-gpu/src/mask.rs:773`](../../core/dr-gpu/src/mask.rs#L773), [`core/dr-gpu/tests/local_adjustments.rs:793`](../../core/dr-gpu/tests/local_adjustments.rs#L793), [`core/dr-gpu/tests/local_adjustments.rs:841`](../../core/dr-gpu/tests/local_adjustments.rs#L841), [`core/dr-pipeline/src/mask.rs:1022`](../../core/dr-pipeline/src/mask.rs#L1022), [`core/dr-pipeline/src/mask.rs:1633`](../../core/dr-pipeline/src/mask.rs#L1633), [`core/dr-pipeline/src/mask.rs:2964`](../../core/dr-pipeline/src/mask.rs#L2964), [`core/dr-pipeline/src/mask.rs:3085`](../../core/dr-pipeline/src/mask.rs#L3085), [`core/dr-pipeline/src/mask.rs:3120`](../../core/dr-pipeline/src/mask.rs#L3120), [`core/dr-pipeline/src/mask.rs:929`](../../core/dr-pipeline/src/mask.rs#L929), [`core/dr-pipeline/src/mask.rs:964`](../../core/dr-pipeline/src/mask.rs#L964), [`core/dr-pipeline/src/sidecar.rs:1259`](../../core/dr-pipeline/src/sidecar.rs#L1259), [`core/dr-pipeline/tests/mask_sidecar.rs:1347`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1347), [`core/dr-pipeline/tests/mask_sidecar.rs:1369`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1369), [`core/dr-pipeline/tests/mask_sidecar.rs:1395`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1395), [`ui/dr-ui/src/develop/masks.rs:431`](../../ui/dr-ui/src/develop/masks.rs#L431), [`ui/dr-ui/src/develop/masks.rs:492`](../../ui/dr-ui/src/develop/masks.rs#L492), [`ui/dr-ui/src/develop/masks.rs:511`](../../ui/dr-ui/src/develop/masks.rs#L511), [`ui/dr-ui/src/develop/masks.rs:546`](../../ui/dr-ui/src/develop/masks.rs#L546), [`ui/dr-ui/src/develop/session.rs:192`](../../ui/dr-ui/src/develop/session.rs#L192), [`ui/dr-ui/src/labels.rs:73`](../../ui/dr-ui/src/labels.rs#L73), [`ui/dr-ui/src/masks_ui.rs:1083`](../../ui/dr-ui/src/masks_ui.rs#L1083), [`ui/dr-ui/src/masks_ui.rs:1155`](../../ui/dr-ui/src/masks_ui.rs#L1155), [`ui/dr-ui/src/masks_ui.rs:1514`](../../ui/dr-ui/src/masks_ui.rs#L1514), [`ui/dr-ui/src/masks_ui.rs:1537`](../../ui/dr-ui/src/masks_ui.rs#L1537), [`ui/dr-ui/src/masks_ui.rs:270`](../../ui/dr-ui/src/masks_ui.rs#L270), [`ui/dr-ui/ui/masks.slint:151`](../../ui/dr-ui/ui/masks.slint#L151), [`ui/dr-ui/ui/masks.slint:176`](../../ui/dr-ui/ui/masks.slint#L176), [`ui/dr-ui/ui/masks.slint:338`](../../ui/dr-ui/ui/masks.slint#L338), [`ui/dr-ui/ui/masks.slint:375`](../../ui/dr-ui/ui/masks.slint#L375), [`ui/dr-ui/ui/masks.slint:417`](../../ui/dr-ui/ui/masks.slint#L417), [`ui/dr-ui/ui/masks.slint:463`](../../ui/dr-ui/ui/masks.slint#L463), [`ui/dr-ui/ui/masks.slint:791`](../../ui/dr-ui/ui/masks.slint#L791), [`ui/dr-ui/ui/masks.slint:876`](../../ui/dr-ui/ui/masks.slint#L876) | @@ -224,13 +224,14 @@ Defined in `requirements.md` and marked `(post-v1)` on the defining line. Not in ## Not yet tagged -31 of 189 requirements have no implementation tag. Expected while the codebase is young; each should gain one as it is built. +32 of 190 requirements have no implementation tag. Expected while the codebase is young; each should gain one as it is built.
Show untagged requirements - FR-CAT-14 - FR-CULL-6 - FR-CULL-7 +- FR-DEV-20 - FR-DEV-3g - FR-DSP-2 - FR-INF-2