修复浮动面板事件穿透 / 自由标记总是预览最近信号 / 固定点位于GX与图例之下 / 预览曲线取值插值;体积红线放宽到900KB

1) 浮动面板不得被右键与中键穿透(用户报告:在面板上右键会弹出下面网格的右键菜单)
   - 新增 PlotView::OnRButtonDown:TopPanelAtPoint 命中即置顶并消费该次右键;
     Application::WM_RBUTTONDOWN 在「绘图区右键 → 网格菜单」之前调用它。
   - OnMButtonDown 开头同样判定面板:命中即消费,不再进入平移。

2) 「自由标记点选取」总是预览网格内离鼠标较近的信号(用户报告:单信号时也必须贴近曲线)
   - ProbeFreeMarker 删除 `if (!hitCurve) continue;`,改为两候选取更近:
     ① 鼠标到画出来的折线的垂直距离(阶跃竖直段只有它能命中);
     ② 同一时刻(鼠标时刻吸附最近采样)采样点的屏幕纵向距离。
   - 门槛 tolerance 只用于「已吸附」圆环;固定点仍恒吸附到真实采样时刻。

3) 固定标记点位于 GX 编号徽标与图例之下(用户要求:数据显示不得遮挡它们)
   - PaintFreeMarker 把 m_legendHits 托底矩形与 LaneBadgeRect 用 gd::Region::Exclude
     排除出绘制区;仅在确有固定点/预览时才计算。
   - PaintFreeMarkerCapsule 新增 vectorText:胶囊与遮挡矩形相交时文字改走 GDI+
     (GDI DrawTextW 不认 GDI+ 裁剪区)。

4) 预览曲线(中心轴/均值滤波/弱峰调整)的光标取值点落回曲线
   - paintDerivedCapsule 改为在光标准确时刻按时间线性插值,且先 ApplyDrawTransform 再插值
     (绝对值/垂直镜像非线性,先插值会偏离折线);双光标增量同样插值。

5) 产物体积红线由 800KB 放宽到 900KB(到达阈值时提醒,不是禁止超过)。

验证(全离屏,未占用鼠标/键盘/屏幕):仓库外临时探针 25/25(A 面板右键/中键不穿透且面板外仍生效;
B 远离曲线可预览与单击固定、两信号按纵向距离择优;C 图例与 GX 区域像素差 0、整幅差异 5 万像素;
D 阶跃区标注点与曲线差 0.0px,插值点与最近采样点相差 39px/197px);A/B 恢复旧门槛 ⇒ 5 项失败,
改回最近采样取值 ⇒ 均值/中心轴各偏 36px 失败。make release / make debug 零警告;
Target.exe 860,672 字节(840.5 KiB)。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-27 20:14:49 +08:00
1 parent 14b18d5c39
commit df715a035e
6 files changed
+442 -60

No files matched your search

+88
View File
@@ -3021,6 +3021,8 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
| 2026-10-23 | DeepSeek-V4.1-Flash(**本机**) | **目录规范化(Inc/Src)+「自由标记」常规模式回归普通鼠标 + 两个显示开关 + 序号列/列分隔线 + 行悬停压暗(详见 §12 末尾「2026-10-23 第五轮」与 §11.2 第 221–229 条)**。① **目录规范化**:四个 `*Internal.hpp` 从 `Src` 迁到 `Inc`(`DataModelInternal` / `ApplicationInternal` / `PlotViewInternal` / `SignalPanelInternal`),并在 `Makefile` 固化「`Inc` 只放头文件、`Src` 只放 `.cpp`」;因 include 全是扁平形式,无需改任何 include。② **常规模式 = 普通鼠标**:`ProbeFreeMarker` 在未开启「自由标记点选取」时直接早退(不预览/不画纵向光标/单击不固定),并补上 `if (!hitCurve) continue;`(否则纵向光标整列都在时 `probe.ref` 恒有效 ⇒ 任意位置都能固定);固定点仍恒吸附到真实采样时刻,但“已吸附”圆环只在稀疏判据成立时画。③ **两个显示开关**:「自由标记点选取」下方新增「显示增量 | 显示枚举文本」(默认关闭,半宽同行),只影响已固定点胶囊,预览胶囊恒为“值 = 枚举”。④ **面板六列**:新增恒存在的「序号」列(组内 1 起),枚举列存在时无枚举/对不上的点显示 `N/A`,列间画竖线;悬停某行时其它固定点(数据点 + 胶囊)封顶 50% 不透明度、移出恢复。⑤ **移除固定点 ✕ 的悬停浮动提示**(`PaintFreeMarkerTooltip` 实现与声明全部删除);开启选取模式的网格上信号悬停提示只显示信号名。⑥ **两处缓存键补齐**:`FreeMarkerContents` 混入枚举表指纹(旧键会让加上枚举表后仍显示 `N/A`)、`PanelSlotKey` 混入两个新按钮矩形与开关状态。验证:新增离屏 `.preflight/mark5check` **52/52**(含“预览胶囊像素差 = 0”“行悬停压暗 848px → 移出恢复 0”“选取模式气泡变窄 1023→830”);回归 `markcheck` 67/67、`mark4check` 40/40、`fixcheck` 37/37、`round3check` 31/31、`round4check` 34/34、`round5check` 5/5、`editcheck` 20/20、`convcheck` 18/18、`diag` 19/19,`check` 136/137(唯一失败项为该探针既有的不稳定项,`drift=15818` 与改动前逐位相同);`make release`/`make debug` 零警告;`TargetCheck.exe` **857,600 字节(837.5 KiB)**。 |
| 2026-10-27 | DeepSeek-V4.1-Flash(**本机**) | **浮动面板事件穿透 + 「自由标记」总是预览最近信号 + 固定点位于 GX/图例之下 + 预览曲线取值插值 + 体积红线 900KB(详见 §12 末尾「2026-10-27 第六轮」与 §11.2 第 230–234 条)**。① **面板右键/中键穿透**:新增 `PlotView::OnRButtonDown`(`TopPanelAtPoint` 命中即置顶并消费,宿主不再弹网格 Y 轴菜单);`OnMButtonDown` 在面板上不再进入平移。② **自由标记探测去掉“必须贴近曲线”的门槛**:两个候选(折线垂直距离 / 同一时刻采样点纵向距离)取更近者 ⇒ 网格内只有一条信号、鼠标离曲线很远时也能预览并单击固定(A/B:恢复旧门限 ⇒ 5 项断言失败)。③ **固定标记点必须位于 GX 徽标与图例之下**:用 `gd::Region::Exclude` 把图例托底与徽标矩形从 `PaintFreeMarker` 的绘制区里排除,胶囊文字在相交时改走 GDI+(GDI 文字不认裁剪);实测图例区域像素差 **0**(旧的“画完再重绘图例”方案残留 240px 抗锯齿差)。④ **预览曲线取值点悬空**:`paintDerivedCapsule` 改为在光标时刻对派生曲线**按时间插值**(先 `ApplyDrawTransform` 再线性插值,与折线逐点一致);阶跃区实测标注点与曲线差 **0.0px**(旧实现偏 36–39px),中心轴/均值滤波/弱峰调整共用同一段代码。⑤ **体积红线由 800KB 放宽到 900KB**(到达阈值时提醒用户即可,不是禁止超过)。验证:离屏临时探针 **25/25**(已删除,不留在仓库);`make release`/`make debug` 零警告;`Target.exe` **860,672 字节(840.5 KiB)**。 |
## 11. 跨设备协作须知(起源设备视角)
> **本文件是唯一权威记忆**。所有设备 / Agent 共用它,**不要再新建 `agent_mem_origin.md` 等旁支记忆文件**。
@@ -4057,6 +4059,27 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
229. ⚠️ **固定点必须落在真实采样时刻上**:`ProbeFreeMarker` 命中曲线时**始终**吸附到最近采样点
(`snapToNearestSample`);只有“已吸附”圆环(`probe.snapped`)仍只在稀疏判据 `sparse` 成立时才显示
(密采样时吸附量 < 1 像素,圆环常驻会像是画错了)。
230. ⚠️⚠️ **浮动面板必须消费右键 / 中键**:`PlotView::OnRButtonDown` 用 `TopPanelAtPoint` 判定,
命中即 `BringPanelToFront` 并返回 true(宿主**不得**再弹网格的 Y 轴菜单);`OnMButtonDown`
在面板上**不得**进入平移(`m_dragMode = NONE` 后消费)。层序与左键 / 双击完全一致。
⚠️ 任何“上层元素”都必须在宿主分发前判定,否则会“在面板上右键却弹出下面网格的菜单”。
231. ⚠️⚠️ **「自由标记点选取」的探测没有“必须贴近曲线”的门槛**(用户 2026-10-27 明确要求):
总是预览**网格内离鼠标较近的那个信号**的数据点(同一时刻下纵向更近者优先)。
实现 = 两个候选取更近:① 鼠标到画出来的折线的垂直距离(阶跃竖直段只有它能命中);
② 同一时刻(鼠标时刻吸附到最近采样)该采样点的**纵向距离**。旧实现 `if (!hitCurve) continue;`
⇒ 网格里只有一条信号且鼠标离曲线较远时既无预览也无法单击固定。
232. ⚠️⚠️ **固定标记点必须位于 GX 编号徽标与图例“之下”**:做法是把 `m_legendHits` 的托底矩形与
`LaneBadgeRect` 全部 `gd::Region::Exclude` 出绘制区(`PaintFreeMarker` 开头),
**不要**改用“画完标记点再把图例重画一遍”—— 重画的抗锯齿边缘与装饰缓存 `AlphaBlend`
的结果不完全一致(实测图例胶囊圆角处仍有 240 像素差)。
⚠️ **GDI 文字不认 GDI+ 裁剪**:胶囊文字与遮挡矩形相交时必须走 GDI+(`PaintFreeMarkerCapsule`
的 `vectorText` 参数),否则文字会“穿透”到图例上面。
233. ⚠️⚠️ **预览曲线的取值必须按时间在相邻采样点之间插值**,且插值要在**套用「调整」变换之后**
(`PaintDerivedCurve` 逐顶点 `ApplyDrawTransform` 后用直线连接;绝对值/垂直镜像不是线性的)。
只取“最近采样点”的曲线值会让标注点离开曲线(用户 2026-10-27 报的“预览曲线数值点悬空”,
实测阶跃区偏 36~39 像素)。`probe` / 中心轴 / 均值滤波 / 弱峰调整共用 `paintDerivedCapsule`。
234. ⚠️ **产物体积红线已放宽到 900KB**(用户 2026-10-27):**到达 900KB 必须提醒用户**,
以便确认功能带来的体积膨胀是否值得;这不是“不许超过”,旧 800KB 红线作废。
### 11.3 离屏验证方法学(本机偏好,强烈建议沿用)
@@ -7794,3 +7817,68 @@ DG3 data=0 cycle=0 (空组,一个字符串通道)
判断“是否命中曲线/是否有可固定的点”必须看 `probe.ref.IsValid()`;
在固定点上做像素 A/B 时,固定点若落在悬浮面板下方(绘图区右侧)像素永远不会变 ⇒ 固定点的时间要放在左侧。
## 本轮(2026-10-27 第六轮,本机):浮动面板事件穿透 + 自由标记“总是预览最近信号” + 固定点位于 GX/图例之下 + 预览曲线取值插值 + 体积红线 900KB
> 用户需求(逐条):
> ① 浮动面板上右键会触发下方网格的右键菜单;面板上的点击 / 右键 / 拖拽等操作不得穿透到下层。
> ② 「自由标记点选取」应**总是**预览网格内离鼠标较近的那条信号的数据点(同一时刻 A 比 B 更近 ⇒ 预览 A),
> 现状是“即使只有一个信号,也必须把鼠标贴到曲线附近才会出现预览点”,远离曲线时无法预览、也无法左键固定。
> ③ 固定数据标记点不得遮挡网格的 GX 标签与图例:数据点与数据显示应位于它们**下方**。
> ④ 预览曲线(均值滤波等)的光标数值点会“悬空”(光标落在两个采样点之间时不落在曲线上),要求在所有带预览曲线的功能中修好。
> ⑤ 产物体积红线由 800KB 放宽到 **900KB**(到达阈值提醒即可,不是禁止超过)。
### A. 浮动面板不得被右键 / 中键穿透(§11.2 第 230 条)
- 新增 `PlotView::OnRButtonDown(int x, int y)`:`TopPanelAtPoint` 命中即 `BringPanelToFront` + `m_dragMode = NONE`,
返回 true(该次右键被面板消费)。`Application::WM_RBUTTONDOWN` 在“绘图区右键 → 网格菜单”**之前**调用它。
- `PlotView::OnMButtonDown` 开头同样判定浮动面板:命中即消费,**不进入平移**(否则会在面板上按住中键拖走整个绘图区)。
- 左键 / 双击的层序原本就正确(`OnLButtonDown` 的面板分支、`OnDoubleClick` 的面板分支),本轮未改。
### B. 「自由标记」总是预览网格内离鼠标较近的信号(§11.2 第 231 条)
- `ProbeFreeMarker` 删掉 `if (!hitCurve) continue;`,改成**两个候选取更近**:
* 曲线候选 = 鼠标到画出来的折线的垂直距离(阶跃竖直段只有它能命中);
* 采样候选 = 鼠标时刻吸附到最近采样后,该采样点的**屏幕纵向距离**。
两者都不设“必须命中”的门槛,`tolerance` 只用于决定是否画“已吸附”圆环(`snapped = sparse`)。
- 逐信号的 `distance` 取两者的较小值,因此“同一时刻下谁离鼠标更近就预览谁”在单信号与多信号下都成立。
- `snapToNearestSample` 仍然对两个候选生效 ⇒ 固定点始终落在真实采样时刻上(第 229 条不变)。
### C. 固定标记点位于 GX 徽标与图例之下(§11.2 第 232 条)
- `PaintFreeMarker` 开头(在 `g.SetClip(m_plotRect, Intersect)` 之后)收集遮挡矩形:`m_legendHits` 的全部托底 +
每个网格的 `LaneBadgeRect`,逐个 `gd::Region::Exclude` 出当前裁剪区,再 `SetClip(..., CombineModeReplace)`。
标记点(圆点 / 胶囊 / ✕ / 预览胶囊)因此**完全画不进**这些区域,图例与徽标的像素(含胶囊圆角之外的抗锯齿边)保持原样。
- ⚠️ **GDI 文字不认 GDI+ 裁剪**:`PaintFreeMarkerCapsule` 新增 `vectorText` 参数,胶囊矩形与任一遮挡矩形相交时
强制走 GDI+(`DrawFreeMarkerAlphaText`),否则文字会盖到图例上面。
- ⚠️ 试过并放弃的替代方案:画完标记点后**把图例原样重画一遍**(`PaintLegendOverlay`)。
它与装饰缓存的 `AlphaBlend` 结果不完全一致,实测图例胶囊圆角处残留 **240 像素**差;纯裁剪方案为 **0**。
- 只在“本网格确实有固定点 / 探针正停在本网格”时才做区域运算,没有标记时零开销。
### D. 预览曲线取值点落回曲线(§11.2 第 233 条)
- `paintDerivedCapsule` 不再取“最近采样点”的曲线值,改为在光标准确时刻对派生曲线**按时间线性插值**:
`locate(displayTime)` 用二分求两侧采样下标与比例(非单调时间轴退回最近采样),
再**先 `ApplyDrawTransform` 后插值**(绝对值 / 垂直镜像不是线性变换,先插值会偏离折线)。
- 请求窗口由“用到的那些源下标”拼出(仍收窄,不会因光标远离视界而重算整条曲线)。
- 双光标增量(`(+Δ 中心轴)`)同样走插值;显示数值现在也是**变换后**的值(与画出来的曲线一致)。
- 中心轴 / 均值滤波 / 弱峰调整共用同一段代码,因此三处一起修好。
### E. 体积红线 900KB(§11.2 第 234 条)
- `Makefile` 的 `RELEASE_OPT` 注释更新:**到达 900KB 必须提醒用户**(不是禁止超过),旧 800KB 红线作废。
### F. 验证(全离屏,未占用鼠标 / 键盘 / 屏幕)
- 临时离屏探针(仓库外 `%TEMP%\jdi_probe`,链接 `Build/Release/*.o` 去掉 `Main.o`)**25/25**:
* [A] 面板上右键被 `PlotView` 消费且**不弹菜单**、面板外右键仍弹菜单;面板上中键不进入平移、面板外仍平移;
* [B] 单信号 + 鼠标远离曲线 ⇒ `probe.ref` 有效、单击可固定、时间吸附到采样;两信号同网格 ⇒ 视鼠标高度分别选中 hold / step;
* [C] 加一个会压在图例上的固定点前后两帧:图例托底 + GX 徽标矩形内像素差 **0**,同时整幅差异 > 5 万像素(证明标记点确实画了);
* [D] `SCATTER_TEST.csv` 的 step、视界 0.998056–1.00091、光标 0.999277、均值点数 2 / 迭代 1:
均值滤波 0.0px、中心轴 0.0px、弱峰调整 0.2px(与曲线逐像素贴合);插值点与最近采样点相差 39px / 197px。
- **A/B 判别力**:临时恢复 `if (!hitCurve) continue;` ⇒ [B] 5 项如实失败;临时把插值改回“最近采样点” ⇒ 均值/中心轴各自偏 36px 并如实失败。
- `make release` / `make debug` **零警告**;`Target.exe` **860,672 字节(840.5 KiB < 900KB)**,比上一轮 +3 KB。
- ⚠️ 探针坑:`CycleCursorMode()` 是**循环**(无→单→双→无),在多组用例里每组都调一次会让后几组“没有光标”而误判为失败;
面板 / `LaneVisual` / `LegendHit` / `EdgePanelLayout` 都是 `PlotView` 的嵌套类型,探针里必须写 `PlotView::` 前缀。
- ⚠️ 本轮开始前发现工作区里 `PlotViewPaint.cpp` 与 `Documents/agent_mem.md` 被**回退到 `8f735d5`**(丢失第四/五轮全部改动),
已 `git checkout --` 恢复到 `HEAD` 后再施工;提交前务必确认这两份文件与 HEAD 一致。