适应视图:撤回旧策略并重做边界规则(单值散点让出半径 + 单点簇视图)
用户 2026-10-15 第五轮报告的两个问题与要求(详见 Documents/agent_mem.md §9.33):
1. 加载文件后不勾选任何信号、连点几次「适应视图」,再勾选一个单值信号时,
初次自适应没有发生、数据点既不居中也不在网格内。
根因:FitAll() 在没有任何可见信号时也把 Tab().ViewInitialized() 置为 true,
随后勾选第一个信号时 Application::SynchronizeView 认为"已经初始化",
于是跳过自适应,视界停在"无信号"那一次的整段范围上(实测 MF4 为 42.386s,
数据点被推到绘图区右边缘之外)。
修法:FitAll() 只有在存在可见信号时才置位 ViewInitialized();
并让"初次自适应"与工具栏「适应视图」共用 FitAll() 这一条实现
(不再先试 FitSinglePointSignal)。
2. 仅勾选 WIN_Motor_StallCurrentVolBrk(单值信号)与 m_MOT_Current_DCom[0](连续信号)
时点「适应视图」,单值信号的点被挤到显示区域外只剩半个;上一轮"为左右空出一小格"
的需求效果不佳。
修法(按用户要求先撤回旧策略、再重做规则):
* 撤回并删除 FitSinglePointLanes()(左右各留一小格)、TimeGridCellSeconds()、
LaneValueGridCell()、FitSinglePointSignal()(首个单值信号的时间跨度 1s 视图)。
* 新规则:常规全局适应后,任何一条边界(时间轴左/右、每个网格幅值上/下)
若被一个单值信号的数据点顶住,就把该边界向外让出该散点的半径(+1 像素),
使其完整显示在网格内;只在散点会被裁切时才扩展(内部散点使视界一点不动);
边界不是单值信号的数据点时就落在该信号点上(时间轴不留额外余量)。
判断依据用信号自身的数据点,而不是时间轴范围(MF4 里单值信号与连续信号
常共用同一条时间轴,用轴的范围会误判)。
* 特例:全部可见数据点都是单值信号且时刻完全相同时,时间轴以该时刻居中、
缩放到一大格 = 1s(视界 = kTimeTickTarget × 1s = 10s,此时 NiceStep(10,10) 恰为 1.0),
每个网格的幅值区间以"能完整画出该网格内的全部数据点"为准
(退化成单值时以跨度 1 居中)。
* 新增 FitContribution / CollectFitContributions / FitLaneHeight /
ApplySinglePointValueMargins / FitSinglePointCluster 五个成员承载上述规则。
验证(全部离屏,不占用鼠标 / 键盘 / 屏幕):
- .preflight/check(SW_HIDE + 只注入合成消息 + 进程/线程 BELOW_NORMAL)**62/62 通过**,
连跑 3 次稳定:[A] 初次自适应、[B] 时间边界(外扩量恰为半径 + 1px)、
[C] 幅值边界、[D] 单点簇特例(跨度 10、一大格 1s、每个点都在网格内)、
[E] 回归(普通信号视界 = 数据范围、网格保持自动自适应、§9.31 的
"适应视图 ↔ Y 轴自适应互不干扰"仍逐位成立)。
- [F] 真实文件 TestData/MF4-Record.MF4:WIN_Motor_StallCurrentVolBrk 确实只有 1 个有效点
(t = 0.005492),与 m_MOT_Current_DCom[0](8475 样点)复现用户场景 —— 点「适应视图」后
散点圆心离绘图区左边界 16.5px、半径 15px,完整可见(修复前它正好压在边界上、只剩半个)。
- A/B 判别:回退四处规则后 **20 项如实失败**,失败信息即用户症状
("the dot is horizontally centred (got 1697, want 1084.75)"、
"[F] initial view = one big cell per second (got 42.386313, want 10.000000)")。
- make release:全部源文件重新编译 **零警告**;链接用临时 `make release TARGET_FILE_NAME=Target_check` 通过。
同步记忆:Documents/agent_mem.md 新增 §9.33、§11.2 第 69–71 条硬约束(并把第 68 条与
§9.32 的第四小节显式标注为"已作废/被取代")、变更日志新行。
This commit is contained in:
1 parent
aee3a388b5
commit
73389f424c
4 files changed
+470
-282
No files matched your search
@@ -430,40 +430,68 @@ namespace jdi
|
||||
HCURSOR QueryCursor(int x, int y) const;
|
||||
|
||||
/**
|
||||
* @brief 时间轴与幅值轴同时自适应到可见信号范围。
|
||||
* @brief 「适应视图」:时间轴与幅值轴同时自适应到可见信号范围。
|
||||
*
|
||||
* 边界规则(用户 2026-10-15 第五轮**重新定义**,取代此前"左右各留一小格"的旧做法):
|
||||
* * 常规的全局适应后,若某条边界(时间轴的左 / 右、每个网格幅值的上 / 下)被一个
|
||||
* **单值信号的数据点**顶住,则该边界再向外让出**该散点的半径**,使它**完整地
|
||||
* 显示在网格内**;边界若不是单值信号的数据点,则边界就落在这个信号点上
|
||||
* (时间轴不留额外余量,幅值仍走 `PadValueRange` 的统一留白)。
|
||||
* * 唯一特例:**所有可见信号都是单值数据点、且时刻完全相同**时,时间轴以该时刻
|
||||
* 居中并缩放到"一大格 = 1s",每个网格的幅值区间保证其数据点都能完整画出。
|
||||
*
|
||||
* ⚠️ 没有任何可见信号时**不置位** `Tab().ViewInitialized()`:用户先连点几次
|
||||
* 「适应视图」后再勾选第一个信号,初次自适应仍必须发生。
|
||||
*/
|
||||
void FitAll();
|
||||
|
||||
/**
|
||||
* @brief 「单点信号」的初始视图:把唯一的数据点居中,时间跨度 1s、幅值跨度 1。
|
||||
*
|
||||
* 用户要求(2026-10-15):当前**没有任何信号被勾选**、而勾选的第一个信号
|
||||
* **只有一个有效数据点**时,整段自适应并不能把它的状态显示出来
|
||||
*(时间轴会覆盖整条时间列、幅值区间退化成几乎为 0)。
|
||||
* 因此这种情况改为:数据点居中放置,**时间轴跨度 = 一个大格 = 1s**、
|
||||
* **Y 轴跨度 = 一个大格 = 1**。
|
||||
*
|
||||
* @return 已按“单点信号”初始化返回 true(调用方无需再做 `FitAll`)。
|
||||
* @brief 一个**可见信号**在「适应视图」里提供的边界贡献(见 `FitAll` 的边界规则)。
|
||||
*/
|
||||
bool FitSinglePointSignal();
|
||||
struct FitContribution
|
||||
{
|
||||
SignalRef ref; /**< 信号引用。 */
|
||||
double minTime = 0.0; /**< 时间轴下限(源时刻,与 `ComputeVisibleTimeBounds` 同源)。 */
|
||||
double maxTime = 0.0; /**< 时间轴上限。 */
|
||||
bool singlePoint = false; /**< 是否只有一个有效数据点(画出来就是一个圆点)。 */
|
||||
double pointTime = 0.0; /**< 单值时:数据点的源时刻。 */
|
||||
double pointValue = 0.0; /**< 单值时:**绘制变换后**的取值。 */
|
||||
float dotRadius = 0.0f; /**< 单值时:散点半径(设备像素)。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 「网格内只显示单点信号」时的自适应(含多个网格各只有一个数据点)。
|
||||
*
|
||||
* 用户要求(2026-10-15):多网格、每个网格只有一个数据点时,适应视图必须保证
|
||||
* **所有散点都在屏幕内**:
|
||||
* * 时间轴左边界 = 所有点中最早的时刻 **再向左偏移一小格**(一小格 = 该视界下
|
||||
* 主刻度 / 五等分,与网格叠底同源);右边界同理向右偏移一小格;
|
||||
* * 若**所有点都在同一时刻**(最极端情况),按“首个网格加载为单点信号”的方式对齐
|
||||
* (时间跨度 1s、居中);
|
||||
* * 逐网格的 Y 轴:网格内若有**取值不同**的多个单点信号,纵向同样在各边界留出一小格
|
||||
* (`LaneValueGridCell`);只有一个取值时跨度 1、居中。
|
||||
*
|
||||
* 任一网格里存在非单点的可见信号时**不适用**(返回 false,交回常规整段自适应)。
|
||||
*
|
||||
* @return 已按单点规则完成自适应返回 true。
|
||||
* @brief 汇总全部可见信号的 `FitContribution`(按网格分组)。
|
||||
* @param [OUT] perLane 与 `Tab().Lanes()` 同序的分组结果。
|
||||
* @return 可见信号总数(0 表示当前没有任何可见信号)。
|
||||
*/
|
||||
bool FitSinglePointLanes();
|
||||
std::size_t CollectFitContributions(std::vector<std::vector<FitContribution>>& perLane) const;
|
||||
|
||||
/**
|
||||
* @brief 当前布局下**单个网格的高度**(设备像素)。
|
||||
*
|
||||
* 与 `BuildLaneVisuals()` 用同一公式(而不是读 `m_lanes[i].rect.Height`):
|
||||
* `FitAll` 可能在网格数量刚变化、布局尚未重建时被调用,公式给出"将要生效"的值。
|
||||
* @return 网格高度;无网格时返回 0。
|
||||
*/
|
||||
float FitLaneHeight() const;
|
||||
|
||||
/**
|
||||
* @brief 若该网格的**幅值上/下边界**被单值散点顶住,把区间向外让出散点半径。
|
||||
*
|
||||
* 只在散点**会被裁切**时才改动区间("散点本来就完整可见"不动它,保持自动自适应的
|
||||
* 语义);改动时把 `autoRange` 置 false 并写入显式区间。
|
||||
*/
|
||||
void ApplySinglePointValueMargins(int laneIndex, const std::vector<FitContribution>& items,
|
||||
float laneHeight);
|
||||
|
||||
/**
|
||||
* @brief 「所有可见数据点都是单值信号、且时刻完全相同」时的自适应。
|
||||
*
|
||||
* 时间轴以 `sharedTime` 居中、**一大格 = 1s**;每个网格的幅值区间保证其数据点
|
||||
* 完整显示(网格内只有一个取值时以跨度 1 居中)。
|
||||
*/
|
||||
void FitSinglePointCluster(const std::vector<std::vector<FitContribution>>& perLane,
|
||||
double sharedTime);
|
||||
|
||||
/**
|
||||
* @brief 取某信号**唯一的有效数据点**(时刻 + 原始取值)。
|
||||
@@ -478,21 +506,6 @@ namespace jdi
|
||||
bool SinglePointOfSignal(const SignalData& signal, const TimeAxis& axis, double& time,
|
||||
double& value) const;
|
||||
|
||||
/**
|
||||
* @brief 时间轴**一小格**对应的时间跨度(= 主刻 / 五等分,与网格叠底同源)。
|
||||
* @param [IN] span 参考跨度。
|
||||
* @return 一小格的时间跨度(无法判定时返回 0)。
|
||||
*/
|
||||
double TimeGridCellSeconds(double span) const;
|
||||
|
||||
/**
|
||||
* @brief 某网格**一小格**对应的幅值跨度(与网格叠底的横向刻度同一套算法)。
|
||||
* @param [IN] span 参考幅值跨度。
|
||||
* @param [IN] laneHeight 网格高度(像素,决定纵向刻度密度)。
|
||||
* @return 一小格的幅值跨度(无法判定时返回 0)。
|
||||
*/
|
||||
double LaneValueGridCell(double span, float laneHeight) const;
|
||||
|
||||
/**
|
||||
* @brief 以给定倍率缩放时间轴(以视图中心为锚点)。
|
||||
* @param [IN] factor 缩放倍率,大于 1 表示放大。
|
||||
|
||||
Reference in new issue
Block a user