Add comprehensive tests for image processing and mask functionalities
- Introduced tests for color image handling, ensuring source preservation and premultiplied alpha usage. - Implemented tests for brush stroke operations, validating segment boundaries and brush anti-aliasing. - Added tests for frame anti-aliasing, confirming correct rendering behavior with various alpha values and depth settings. - Created tests for frame projection, ensuring accurate overlap calculations and half-plane clipping. - Developed tests for image premultiplied retention, verifying behavior during loading and packing processes. - Added undo functionality tests for mask operations, ensuring single transaction behavior during edits.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-03
|
||||
@@ -0,0 +1,66 @@
|
||||
## Context
|
||||
|
||||
`ImageGesture` 已在屏幕空间维护 Polyline 的已提交顶点与移动光标,并在三个顶点后允许点击起点 8 px 范围完成。当前闭合圈只在进入命中范围后以固定尺寸出现,缺少接近过程反馈;Modal 也不处理 `DOUBLE_CLICK`。Mask 使用单一 WorkspaceTool 承载 Lasso、Brush 与 Polyline,当前未声明工具光标。
|
||||
|
||||
Blender 的 Polyline Gesture 将实际点击半径与更大的视觉提示范围分开:实际命中半径为 `15 × UI Scale`,鼠标进入约为该半径平方的提示距离后,起点圈从 `1 × UI Scale` 平滑放大到实际命中半径。Polyline modal keymap 将左键双击作为 Confirm;Sculpt 的 Box、Lasso、Line 与 Polyline Mask/Hide 工具统一使用 `PAINT_CROSS`。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 让 Polyline 起点闭合提示具有与 Blender 一致的渐进接近反馈和命中范围。
|
||||
- 支持双击完成有效 Polyline,并保留现有完成、回退和取消方式。
|
||||
- 让统一 Mask Tool 使用适合区域编辑的十字光标。
|
||||
- 将距离、缩放与事件判定保持为易单测的屏幕空间逻辑。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不调用或包装 Blender 内建 Polyline Operator。
|
||||
- 不改变 Polyline 顶点投影、Selection 栅格化或 Alpha 合成。
|
||||
- 不加入起点吸附、自动修改最后一个顶点或新的用户设置。
|
||||
- 不拆分现有单一 Mask Tool。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 分离闭合命中半径与视觉提示距离
|
||||
|
||||
定义 15 px 基础闭合半径,并使用操作开始时读取的 UI Scale 得到实际命中半径。视觉提示距离沿用 Blender 的 `scaled_radius²`;只有已提交至少三个点且鼠标位于该范围内时才绘制起点圈。
|
||||
|
||||
提示圈半径使用 smoothstep 随距离插值:鼠标位于提示范围边缘时接近 `1 × UI Scale`,位于起点时等于实际闭合半径。绘制使用一明一暗的相邻轮廓,使提示在亮、暗图片上都可辨认。
|
||||
|
||||
选择独立的纯计算 Helper,而不是在 Draw Handler 内直接散落公式,以便精确测试边界、单调性和 UI Scale。
|
||||
|
||||
### 2. 点击只使用实际闭合半径
|
||||
|
||||
渐进提示范围只控制视觉反馈,不扩大可点击区域。普通左键按下仍先判断是否已有三个点且光标位于实际闭合半径内;命中时直接完成并且不提交新顶点,否则沿用现有最小点距规则添加顶点。
|
||||
|
||||
不使用整个提示范围作为命中范围,避免鼠标离起点较远时意外闭合。
|
||||
|
||||
### 3. Modal 同时处理原生双击与连续按下
|
||||
|
||||
`ImageGesture._modal_polyline()` 在普通左键按下分支之前处理 `LEFTMOUSE` 的 `DOUBLE_CLICK`。同时记录最近一次左键按下的位置与时间:当 Blender 只向 Python Modal 连续发送两个 `PRESS` 时,使用用户设置中的双击间隔和 `5 px × UI Scale` 位移范围识别第二击。当已提交至少三个点时复用 `_confirm_polyline()`;点数不足时保持 Modal,不应用 Selection。
|
||||
|
||||
Blender 内建 Gesture 依靠 Modal Keymap 将双击转换为 Confirm,但当前 Python Operator 没有该映射,因此不能只依赖 `DOUBLE_CLICK` 事件。不为 WorkspaceTool 增加第二个启动 keymap 项,因为双击发生时 Operator 已处于 Modal,连续按下判定可以避免再次启动 Operator 或复制完成逻辑。双击只完成现有已提交路径,第二击不得添加重复顶点。
|
||||
|
||||
### 4. 统一 Mask Tool 使用 PAINT_CROSS
|
||||
|
||||
在 `MaskTool` 上声明 `bl_cursor = "PAINT_CROSS"`。这会覆盖 Lasso、Brush 与 Polyline,符合 Blender 对 Sculpt Mask/Hide 区域手势的统一光标约定,也避免根据 Gesture 动态设置和恢复 Window cursor。
|
||||
|
||||
### 5. 保留当前项目已有控制
|
||||
|
||||
Enter、Numpad Enter、Backspace、RMB、Esc、工具切换取消和至少三个已提交点的完成门槛保持不变。状态文本补充双击完成,但不改变 Mode 或 Brush Radius 的展示。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [提示距离按半径平方后明显大于实际命中范围] → 圆圈在远处保持接近 1 px,并通过连续放大表达接近程度;点击仍严格限制在实际半径内。
|
||||
- [UI Scale 与 Region 坐标可能在不同平台产生取整差异] → 全程使用浮点屏幕坐标,只在比较和绘制中复用同一个缩放值,并对 1.0 与非 1.0 Scale 建立单测。
|
||||
- [Python Modal 可能收到原生 `DOUBLE_CLICK`,也可能只收到连续 `PRESS`] → 同时支持两种事件链;连续按下仅在用户双击时间和小范围位移内成立,第二击不追加点。
|
||||
- [`PAINT_CROSS` 同时影响非 Polyline Gesture] → Blender 的 Box、Lasso 与 Polyline Mask/Hide 本身采用同一光标,因此统一行为优先于引入动态 cursor 生命周期。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
先替换闭合提示计算与绘制,再加入双击事件和 Tool cursor,随后更新状态文本、测试与内部文档。此变更不迁移持久数据;回滚只需恢复旧的固定半径提示、事件分支与默认 cursor。
|
||||
|
||||
## Open Questions
|
||||
|
||||
无。交互常量、光标范围和双击完成语义均以 Blender 当前 Polyline Gesture 为准。
|
||||
@@ -0,0 +1,26 @@
|
||||
## Why
|
||||
|
||||
当前 Polyline 只有固定 8 px 起点命中圈,闭合目标出现突然、范围偏小,并且只能点击起点或按 Enter 完成。对齐 Blender Sculpt Polyline Gesture 的渐进起点提示、双击完成和十字光标,可以让闭合意图更清楚并减少精确回点操作。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 至少提交三个点后,在起点周围显示随鼠标距离平滑放大的闭合提示圈。
|
||||
- 使用与 Blender Polyline Gesture 一致的 15 px 起点点击范围,并按 UI Scale 调整屏幕尺寸。
|
||||
- 支持在已有有效 Polygon 时双击左键完成 Polyline,同时保留点击起点、Enter、Backspace、RMB 和 Esc 行为。
|
||||
- Mask Tool 使用 `PAINT_CROSS` 光标,让 Lasso、Brush 与 Polyline 保持统一的图片区域编辑指针。
|
||||
- 更新 Polyline 状态提示、交互测试和内部文档。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `polyline-gesture-interaction`: 定义 Polyline 的渐进闭合提示、起点命中、双击完成、键盘控制与工具光标。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
## Impact
|
||||
|
||||
- 影响 `common/viewport.py` 的 Polyline 屏幕空间提示、命中判断和 Modal 状态机。
|
||||
- 影响 `operators/image_edit_tool/mask.py` 的 Mask Tool 光标与状态文本。
|
||||
- 影响 Blender Add-on 交互测试与 Image Edit Tool 内部文档。
|
||||
- 不改变 SelectionPath、SelectionMask、Alpha 合成、图片尺寸、对象结构或 Server 协议,不增加依赖。
|
||||
@@ -0,0 +1,61 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Polyline exposes a progressive close target
|
||||
Polyline SHALL 在至少三个已提交点后,根据鼠标到起点的屏幕距离显示渐进闭合提示。实际闭合半径 MUST 为 `15 px × UI Scale`;提示距离 MUST 为实际闭合半径的平方。鼠标从提示范围边缘接近起点时,提示圈半径 MUST 通过平滑插值从 `1 px × UI Scale` 增长到实际闭合半径,并 MUST 使用明暗对比轮廓保持可见。
|
||||
|
||||
#### Scenario: Cursor approaches the start point
|
||||
- **WHEN** Polyline 已提交至少三个点,且鼠标从提示范围边缘向起点移动
|
||||
- **THEN** 起点提示圈连续放大,并在鼠标到达起点时显示为实际闭合半径
|
||||
|
||||
#### Scenario: Cursor remains outside the hint distance
|
||||
- **WHEN** Polyline 已提交至少三个点,但鼠标位于提示距离之外
|
||||
- **THEN** 系统不绘制起点闭合提示圈
|
||||
|
||||
#### Scenario: Polyline has fewer than three points
|
||||
- **WHEN** Polyline 尚未提交三个点
|
||||
- **THEN** 系统不绘制起点闭合提示圈且不允许点击起点完成
|
||||
|
||||
#### Scenario: UI Scale changes
|
||||
- **WHEN** Blender UI Scale 不是 1.0
|
||||
- **THEN** 闭合命中半径、提示距离与提示圈尺寸使用同一 UI Scale 计算
|
||||
|
||||
### Requirement: Polyline supports deliberate mouse completion
|
||||
Polyline SHALL 在至少三个已提交点后允许用户点击起点实际闭合半径内或双击左键完成。起点点击 MUST 不添加新顶点;双击的第二击 MUST 不添加重复顶点。点数不足时,点击或双击 MUST NOT 提交 Selection。
|
||||
|
||||
#### Scenario: User clicks inside the close target
|
||||
- **WHEN** Polyline 已提交至少三个点,且用户在起点实际闭合半径内按下左键
|
||||
- **THEN** 系统使用现有已提交顶点完成 Polyline,不添加点击位置为新顶点
|
||||
|
||||
#### Scenario: User double-clicks after three points
|
||||
- **WHEN** Polyline 已提交至少三个点,且用户双击左键
|
||||
- **THEN** 系统完成 Polyline,并且双击的第二击不产生重复顶点
|
||||
|
||||
#### Scenario: User double-clicks before three points
|
||||
- **WHEN** Polyline 的已提交点少于三个,且用户双击左键
|
||||
- **THEN** 系统保持 Polyline Modal 运行且不提交 Selection
|
||||
|
||||
#### Scenario: User clicks outside the close target
|
||||
- **WHEN** Polyline 已提交至少三个点,且用户在起点实际闭合半径外单击有效的新位置
|
||||
- **THEN** 系统提交该位置为下一个顶点并继续 Polyline
|
||||
|
||||
### Requirement: Polyline retains keyboard and cancellation controls
|
||||
Polyline MUST 保留 Enter 与 Numpad Enter 完成、Backspace 删除最后一点、RMB 与 Esc 取消以及工具切换取消的现有行为。状态文本 SHALL 同时说明点击起点、双击或 Enter 可以完成,并说明 Backspace 删除一点。
|
||||
|
||||
#### Scenario: User confirms with Enter
|
||||
- **WHEN** Polyline 已提交至少三个点,且用户按 Enter 或 Numpad Enter
|
||||
- **THEN** 系统完成 Polyline
|
||||
|
||||
#### Scenario: User removes the last point
|
||||
- **WHEN** Polyline 已提交两个或更多点,且用户按 Backspace
|
||||
- **THEN** 系统删除最后一个已提交点并继续预览
|
||||
|
||||
#### Scenario: User cancels the gesture
|
||||
- **WHEN** 用户按 RMB、Esc 或切换到其他工具
|
||||
- **THEN** 系统取消未完成的 Polyline 并移除 Overlay
|
||||
|
||||
### Requirement: Mask uses a cross painting cursor
|
||||
Mask Tool SHALL 为 Lasso、Brush 与 Polyline Gesture 统一使用 Blender 的 `PAINT_CROSS` cursor。
|
||||
|
||||
#### Scenario: User activates Mask
|
||||
- **WHEN** 用户在 3D Viewport 激活 Mask Tool
|
||||
- **THEN** 工具光标显示为 `PAINT_CROSS`,并在切换 Lasso、Brush 与 Polyline 时保持一致
|
||||
18
openspec/changes/match-polyline-gesture-interaction/tasks.md
Normal file
18
openspec/changes/match-polyline-gesture-interaction/tasks.md
Normal file
@@ -0,0 +1,18 @@
|
||||
## 1. 渐进闭合提示
|
||||
|
||||
- [x] 1.1 在 `common/viewport.py` 定义基于 15 px 与 UI Scale 的闭合命中半径、提示距离和 smoothstep 提示圈半径纯计算入口
|
||||
- [x] 1.2 让 Polyline Overlay 在至少三个点后按鼠标距离绘制明暗双层渐进起点圈,并让点击闭合复用同一实际命中半径
|
||||
|
||||
## 2. 完成交互与光标
|
||||
|
||||
- [x] 2.1 在 Polyline Modal 中优先处理左键 `DOUBLE_CLICK`,有效路径直接完成且不追加重复顶点,点数不足时继续运行
|
||||
- [x] 2.2 为统一 Mask Tool 设置 `PAINT_CROSS` cursor,并更新状态文本以说明点击起点、双击、Enter 与 Backspace 控制
|
||||
- [x] 2.3 兼容 Python Modal 只收到连续 `PRESS` 的双击事件链,并复用 Blender 用户双击间隔
|
||||
|
||||
## 3. 验证与文档
|
||||
|
||||
- [x] 3.1 补充渐进提示边界、半径单调性、UI Scale、15 px 点击命中和提示范围不参与命中的测试
|
||||
- [x] 3.2 补充双击有效与无效路径、无重复顶点、Mask cursor 和状态文本测试,并保持现有 Enter、Backspace 与取消测试通过
|
||||
- [x] 3.3 更新 Image Edit Tool 内部文档中的 Polyline 交互说明
|
||||
- [x] 3.4 运行相关交互测试与完整 `uv run pytest`,不构建文档或扩展产物
|
||||
- [x] 3.5 补充连续 `PRESS` 双击的回归测试并重新运行相关测试与完整测试
|
||||
Reference in New Issue
Block a user