「调整」数值符号规则 + 边沿统计按帧推进(含首帧公平分摊)+ 浮动面板排版与弱峰复位控件
一、「调整」类数值的符号(SignalPanel) 1. FormatSignedNumber:0 不再显示 `+`(旧实现恒带符号 → `+0.00`),Y 轴偏移默认值显示 0.00。 2. FormatGainText:非 0 正值带 `+`、负值带 `-`、0 不带符号;仅用于非编辑态显示, 进入编辑的初始文本仍为无符号纯数值。 3. 新增 FormatOffsetTimeText:`Δt:` 后按正负带符号(Δt:+5s 60ms / Δt:-5s 60ms / Δt:0s), 打开面板 / CMD_OFFSET_TIME 提交 / CMD_OFFSET_RESET 三处统一走它。 二、边沿统计:按帧预算 + 每状态公平配额 (用户报告:按住横向光标不动时统计停在“统计中…”不更新;改中心轴参数回车后不动鼠标时停在部分值) 根因:预算按 GetTickCount64() 分桶,而系统时钟粒度约 15.6ms;RequestEdgeScanFrame 的 PostMessage 自持重绘把帧率拉高 ⇒ 同一 tick 内连画多帧却完全不推进。 1. Paint 开头 ++m_edgeScanFrame; m_edgeScanBudget = kEdgeScanPairsPerFrame;(按帧重置), 删除 m_edgeScanTick。 2. 每个状态各自持有每帧配额(pumpedFrame/pumpedPairs):perState = max(60000, 1.2M/share), share = max(kEdgeScanFairShare=6, m_edgeScans.size())。 注意:不能直接用 size() 分摊 —— 状态在同一帧内逐个创建,第一个那一刻 size()==1 会独占整额, 同帧后面新建的状态全部被截断为 0 配额(即“只有第一条信号推进”)。 实测(合成 5 信号 × 200 万采样、同一网格):首帧 5 个状态全部推进;9 帧内全部扫完(期间不注入 任何鼠标消息);数值与独立参考实现逐位一致;阈值变化后就地重置、随后“停住不动”仍精确扫完。 三、浮动面板排版 1. 信号名宽度上限 kEdgePanelNameMaxWidth=150 逻辑像素:宽度计算与绘制都用 min(实测, 上限) + UiEllipsize(300 字符名字只比单字符宽 44px,旧实现要多 5100px)。 2. 统计信息两列等宽(新增 EdgeRisingText/EdgeFallingText/EdgeCountsPending):面板宽度按 2×max(两列文本宽)+kEdgePanelStatColumnGap 预留,绘制时两列各占 (可用宽−间距)/2 ⇒ 多条信号的 “上升沿/下降沿”列起点固定、严格垂直对齐。 3. 未完成时 rising 与 falling 两个数字后面都带 `…`(旧实现只在整行末尾追加一次, 视觉上只跟在“下降沿”的数字后面)。 四、弱峰调整面板 1. 每行滑块右侧新增复位控件(复用还原图标绘制 PaintPanelResetIcon):悬停高亮 + IDC_HAND + 一次性提示;点击恢复幅度 0 / 迭代 1 且 maxIterations 回到初始上限 10。 EdgePanelLayout 新增 rowLevelResets/rowIterResets(并进 PanelSlotKey),两行按钮共用同一 X。 2. 迭代次数上限输入框的空内容提示改为“输入上限(当前N)”。 3. 滑块标签去掉多余的 %/N(kWeakPeakLevelLabel=调整幅度;新增 kWeakPeakIterationsSliderLabel= 迭代次数;MEAN / CENTER 输入框的“迭代次数 N”保持不变)。 五、验证(全部离屏;进程/线程 BELOW_NORMAL、窗口 SW_HIDE、不注入真实鼠标键盘) - 新增 .preflight/perf/panelcheck_main.cpp:46/46 通过(符号规则走真实菜单路径;按帧推进 / 不饿死 / 精确性 / 自持驱动;两列等宽预留(含未完成时两处 …);名字上限; 弱峰复位控件位置 / 对齐 / 点击恢复默认值与上限)。 - 既有 verify_main.cpp:47/47(另 2 条为本机 .preflight 未随远端同步的旧规则断言)。 - make release 零警告。 规则同步:Documents/agent_mem.md 新增 §9.26,§11.2 新增第 43–48 条硬约束,变更日志补一行。
This commit is contained in:
1 parent
65f7625dce
commit
fba40ee1a2
4 files changed
+564
-80
No files matched your search
@@ -1234,6 +1234,14 @@ namespace jdi
|
||||
std::vector<gd::RectF> rowLevelValues;
|
||||
std::vector<gd::RectF> rowIterTracks;
|
||||
std::vector<gd::RectF> rowIterValues;
|
||||
/**
|
||||
* @brief 「弱峰调整」每行滑块右侧的**复位按钮**矩形(与 `rowLevelTracks` 同序)。
|
||||
*
|
||||
* 点击把该行参数恢复为默认值(幅度 0 / 迭代次数 1 且上限回到初始上限)。
|
||||
* 未勾选或非 PEAK 面板时对应元素为空矩形(数组也可能为空)。
|
||||
*/
|
||||
std::vector<gd::RectF> rowLevelResets;
|
||||
std::vector<gd::RectF> rowIterResets;
|
||||
std::vector<SignalRef> rowRefs;
|
||||
};
|
||||
|
||||
@@ -1663,9 +1671,11 @@ namespace jdi
|
||||
*
|
||||
* ⚠️ **本函数绝不长时间阻塞 UI 线程**(千万级信号整段扫描实测 ≈115ms/条,
|
||||
* 横向光标每一帧都会换阈值 → 拖动时每帧都要扫,5 条信号就是 ≈575ms/帧):
|
||||
* 扫描按「逐块累积」进行,每个 tick(约一帧)只消耗 `kEdgeScanPairsPerTick`
|
||||
* 个采样对的预算,未扫完时 `complete` 返回 false(界面显示上一个完整结果 + “…”)。
|
||||
* 拖动横向光标(`EDGE_MOVE`)期间阈值每帧都变,推进等于白做功 → 不推进。
|
||||
* 扫描按「逐块累积」进行,**每帧**只消耗 `kEdgeScanPairsPerFrame` 个采样对的预算
|
||||
*(且**每个状态各自持有配额**,多条信号不会互相饿死),未扫完时 `complete` 返回 false
|
||||
*(界面显示上一个完整结果 + “…”)。
|
||||
* 阈值变化(横向光标拖动中)就地把累积状态重置(不新建条目),且当帧不展示部分值
|
||||
*(`justReset`),避免“错误且不更新的数字”。
|
||||
*
|
||||
* @param [IN] file 信号所属文件。
|
||||
* @param [IN] signal 目标信号。
|
||||
@@ -1871,6 +1881,8 @@ namespace jdi
|
||||
* 因此必须单独记住这个状态才能触发重绘与取消高亮。
|
||||
*/
|
||||
int m_hoverBadge = -1;
|
||||
/** 「弱峰调整」每行滑块右侧的复位控件是否处于悬停态(用于“进入/离开”时只提示一次)。 */
|
||||
bool m_peakResetHover = false;
|
||||
int m_mouseX = 0; /**< 最近一次鼠标横坐标(用于悬停提示定位)。 */
|
||||
int m_mouseY = 0; /**< 最近一次鼠标纵坐标(用于悬停提示定位)。 */
|
||||
bool m_spanHover = false; /**< 鼠标是否悬停在双光标差值标签上。 */
|
||||
@@ -1915,6 +1927,15 @@ namespace jdi
|
||||
std::size_t falling = 0; /**< 已扫部分的下降沿总数。 */
|
||||
bool complete = false; /**< 整条信号是否已扫完。 */
|
||||
bool justReset = false; /**< 本 tick 刚因阈值/参数变化重新开始(不展示部分值)。 */
|
||||
/**
|
||||
* @brief 本状态**上一次推进所在的帧序号**与当时已消耗的配额。
|
||||
*
|
||||
* 每个状态**每帧各自持有配额**(而不是所有状态共享一个总额):旧实现下推进总是
|
||||
* 从列表第一个状态扫起,5 条信号同一网格时只有第一条有进展、其余长期显示“统计中…”
|
||||
*(用户报告“很多项都停在了统计中不更新”)。
|
||||
*/
|
||||
std::uint64_t pumpedFrame = 0; /**< 最近一次推进的帧序号(与 `m_edgeScanFrame` 比较)。 */
|
||||
std::size_t pumpedPairs = 0; /**< 本帧已消耗的采样对配额(新帧开始时重置)。 */
|
||||
/**
|
||||
* @brief 中心轴扫描**就地计算**的一小段均值滤波曲线(源下标空间)。
|
||||
*
|
||||
@@ -1932,8 +1953,15 @@ namespace jdi
|
||||
bool localValid = false; /**< 本地区间是否可用。 */
|
||||
};
|
||||
mutable std::vector<EdgeScanState> m_edgeScans; /**< 边沿统计累积状态(纯缓存)。 */
|
||||
mutable std::size_t m_edgeScanBudget = 0; /**< 本 tick 剩余可扫描的采样对数量(限制单帧总开销)。 */
|
||||
mutable std::uint64_t m_edgeScanTick = 0; /**< 最近一次重置扫描预算的 tick。 */
|
||||
mutable std::size_t m_edgeScanBudget = 0; /**< 本帧剩余可扫描的采样对数量(跨状态共享,限制单帧总开销)。 */
|
||||
/**
|
||||
* @brief 帧序号(`Paint` 每帧递增)。
|
||||
*
|
||||
* ⚠️ 预算必须**按帧**重置,不能按 `GetTickCount64()` 分桶:系统时钟粒度约 15.6ms,
|
||||
* 帧率一高(`PostMessage` 自持重绘会把它拉高)就会在同一 tick 内连画多帧而不推进,
|
||||
* 用户看到的就是“按住光标不动时统计卡住、要动鼠标才更新”。
|
||||
*/
|
||||
mutable std::uint64_t m_edgeScanFrame = 0;
|
||||
/** 诊断计数:中心轴本地曲线计算失败次数(内存不足等)。0 = 一切正常。 */
|
||||
mutable std::size_t m_edgeScanLocalCurveFails = 0;
|
||||
|
||||
|
||||
Reference in new issue
Block a user