「阶数 N」改称「迭代次数 N」;修复大文件放大后的平移卡顿与越界三角样式
一、命名(用户要求) - 实验性功能里的「阶数 N」全部改为「迭代次数 N」(面板滑块标签、均值滤波/中心轴 的数值框标签、构建提示语)。 - 相关标识符与函数参数统一改名:order → iterations(Lane::MeanFilterItem::iterations、 Lane::weakBoostIterations、ComputeWeakWaveBoost/ComputeMovingAverageIterated 的形参、 MeanFilterCurveFor/WeakBoostCurveFor/WeakBoostValueAt/EdgeCenterCountsFor、 各曲线缓存项的字段、EdgePanelLayout::rowIterations/sliderIterations、 PlotEditTarget::MEAN_FILTER_ITERATIONS/EDGE_CENTER_ITERATIONS、 PlotDragMode::BOOST_ITERATIONS、kWeakBoostIterationsMin/Max/Label、 DerivedSignalRequest::iterations 等)。网格拖拽重排里的局部 order 为避免歧义 改名为 laneOrder;`std::memory_order_*`、`rowOrder`→`rowIterations` 一并核对无误。 - 导出信号尾缀统一为「N次迭代」: `<原信号> (N点均值 M次迭代)`、`<原信号> (弱波增强 X% M次迭代)`; 弱波增强此前缺失该信息,现已补上(两种派生信号都恒定带迭代次数)。 状态提示语同步为「… M 次迭代信号。」。 二、越界三角与光标读数的样式统一(用户要求) - 新增 `kMarkerTriangleGap`:网格内数据点越界时,方向三角与数值标注之间**留出间隙** (此前三角与胶囊贴在一起,看起来像胶囊上多出的尖角);中心轴/均值滤波/弱波增强的 派生取值标注同样处理。 - 光标时间读数(以及双光标 Δt 读数)改用与网格内数据点**完全一致**的越界样式: 三角画在胶囊**外侧**、尖端朝外、与胶囊之间留出同样的间隙;为此把读数胶囊在越界一侧 向内让出「三角深度 + 间隙」。旧的"三角压在胶囊上沿"的画法以及为它额外留出的叠放 间距(kCursorTipStackGap)一并删除。 三、大文件放大后"平移 / 改配色非常卡"的根因与修复(用户要求,流畅性优先) 用离屏探针(`.preflight/perf3`)在 VERY_BIG_DATA(1.77GB、2580 万采样 × 5 信号、 1224×796 绘图区)上先量化,实测到的三个根因: 1. **包络带"梳状化"**:当信号的振荡周期与像素列宽度相当时(编码器方波在 2ms/大格下 约 3 个采样点一列),逐列包络会在"全高"与"极窄"之间交替——实测 1224 列里有 988 处 全高跳变。这种多边形让 GDI+ 的扫描线填充耗时暴涨:同一条 2448 顶点的路径 **27.6ms → 1.1ms(±1 列极值扩展后快 25 倍)**。这正是"某些放大等级下平移特别卡" (实测 2ms/大格平移 87ms,其余等级 17~20ms)的原因。 → `EmitEnvelopeBand` 在拼装包络带时对列窗口做 ±1 列的极值扩展(纵向最多各多 1 像素, 肉眼不可辨),一次性消除该病理。 2. **派生预览曲线按折线逐段描边**:均值滤波/弱波增强曲线在可见采样数超过像素列数时 仍按"每 2 像素一个顶点"的抗锯齿折线绘制,而这类曲线常叠在方波上(大量近垂直跳变), 实测单条 12~42ms,5 个网格合计上百毫秒。 → 稠密时改用**逐像素列的包络带**(复用 `EmitEnvelopeBand`)一次 FillPath,实测 0.56ms / 1.53ms(分别快 22 倍 / 28 倍),视觉与细折线一致(列宽就是 1 像素)。 3. **悬停光晕用宽笔描整条折线**:实测悬停一帧多花 35ms。 → 包络带模式下改为"把带整体外扩后填充一次"(`PaintBandHalo`),悬停帧恢复正常。 另外修掉两个相关的固定开销: - `UiMeasureTextWidth` 增加 (字体, 文本) 记忆化缓存:它是布局代码的热点(浮动面板几何 按「网格数 × 面板种类」重复计算,每帧重复测量同一批字符串成百上千次),实测单个面板 的绘制因此从 3.2ms 降到 1ms 量级。字体重建(DPI 变化)时由 `UiClearMeasureCache` 作废。 实测(VERY_BIG_DATA 全选 5 信号,绘图区全重绘 = 平移一帧): - 20ms/大格(用户报告的场景):平移 20.1ms → **11.3ms**; - 2ms/大格(此前最糟):平移 86.7ms → **12.3ms**; - 网格 1 开弱波增强:63.9ms → **17.6ms**;5 个网格全开:136.6ms → **31.9ms**; - 悬停信号:整帧 49.6ms → **15.5ms**(与不悬停持平,光晕几乎免费)。 仍存的已知热点:0.5ms/大格附近(可见约 1000 个采样点、走**逐点描边**路径)平移约 28~39ms —— 该区间采样比像素还稀疏、无法用包络带替代,且用户明确要求保留抗锯齿, 本次未动。 四、验证 - 离屏 harness(窗口 SW_HIDE、不占用鼠标/键盘/屏幕)**355 项检查全部通过**, 新增 `[AD]`:越界读数胶囊向内让位、三角在外侧、三角与胶囊间有真实间隙、 胶囊上方不再有内容;取值标注与三角之间保留 `kMarkerTriangleGap` 的间隙(用 散点模式排除波形干扰后逐像素断言)。`[X]/[Y]/[AA]/[AB]/[Z]` 等既有用例同步通过。 - 性能结论来自 `.preflight/perf3`(离屏探针 + 两套微基准),已随任务清理。
This commit is contained in:
1 parent
8c8508e5f8
commit
b960b03cb5
8 files changed
+666
-301
No files matched your search
@@ -241,7 +241,7 @@ namespace jdi
|
||||
/**
|
||||
* @brief 应用绘图区提交的「实验性功能 → 构建为新信号」请求。
|
||||
*
|
||||
* 为指定网格内的每条被勾选信号各构建一条派生信号(多阶均值滤波或弱波增强),
|
||||
* 为指定网格内的每条被勾选信号各构建一条派生信号(多次迭代均值滤波或弱波增强),
|
||||
* 命名为 `<原信号名称> (N点均值…)` / `<原信号名称> (弱波增强 M%)`,
|
||||
* 插入到原信号所在组的原信号位置**下方**,并把新信号所在的网格移动到原信号网格的下方。
|
||||
*
|
||||
@@ -250,20 +250,20 @@ namespace jdi
|
||||
bool ApplyPendingDerivedBuild();
|
||||
|
||||
/**
|
||||
* @brief 派生信号构建请求(多阶均值滤波 / 弱波增强共用同一套插入流程)。
|
||||
* @brief 派生信号构建请求(多次迭代均值滤波 / 弱波增强共用同一套插入流程)。
|
||||
*/
|
||||
struct DerivedSignalRequest
|
||||
{
|
||||
int fileIndex = -1; /**< 原信号所属文件下标。 */
|
||||
int signalIndex = -1; /**< 原信号下标。 */
|
||||
int points = 5; /**< 多阶均值滤波:均值点数 X(滑平半径)。 */
|
||||
int order = 1; /**< 多阶均值滤波:阶数 N(迭代次数)。 */
|
||||
int points = 5; /**< 多次迭代均值滤波:均值点数 X(滑平半径)。 */
|
||||
int iterations = 1; /**< 多次迭代均值滤波:迭代次数 N(至少 1)。 */
|
||||
int levelPercent = 50; /**< 弱波增强:增强等级(0–100)。 */
|
||||
bool weakBoost = false; /**< true = 弱波增强,false = 多阶均值滤波。 */
|
||||
bool weakBoost = false; /**< true = 弱波增强,false = 多次迭代均值滤波。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 把一条派生信号(多阶均值滤波 / 弱波增强)插入数据层并同步各视图。
|
||||
* @brief 把一条派生信号(多次迭代均值滤波 / 弱波增强)插入数据层并同步各视图。
|
||||
* @param [IN] request 构建请求。
|
||||
* @param [IN] makeVisible 是否在当前标签页中勾选新信号。
|
||||
* @return 构建并插入成功返回 true。
|
||||
|
||||
@@ -1473,30 +1473,22 @@ namespace jdi
|
||||
const std::wstring baseName = source.Title();
|
||||
|
||||
// 1. 计算派生采样值(与网格内的预览曲线共用同一实现,因此逐位一致)。
|
||||
// 多阶均值滤波形如「<原信号名称> (N点均值×M阶)」,
|
||||
// 弱波增强形如「<原信号名称> (弱波增强 M%)」。
|
||||
// 多次迭代均值滤波形如「<原信号名称> (N点均值 M次迭代)」,
|
||||
// 弱波增强形如「<原信号名称> (弱波增强 M% N次迭代)」。
|
||||
std::vector<float> derived_values;
|
||||
SignalData derived;
|
||||
if (request.weakBoost)
|
||||
{
|
||||
ComputeWeakWaveBoost(source.values, static_cast<double>(request.levelPercent) / 100.0,
|
||||
request.order, derived_values);
|
||||
derived.name = baseName + L" (弱波增强 " + std::to_wstring(request.levelPercent) + L"%";
|
||||
if (request.order > 1)
|
||||
{
|
||||
derived.name += L"×" + std::to_wstring(request.order) + L"阶";
|
||||
}
|
||||
derived.name += L")";
|
||||
request.iterations, derived_values);
|
||||
derived.name = baseName + L" (弱波增强 " + std::to_wstring(request.levelPercent) + L"% " +
|
||||
std::to_wstring(request.iterations) + L"次迭代)";
|
||||
}
|
||||
else
|
||||
{
|
||||
ComputeMovingAverageIterated(source.values, request.points, request.order, derived_values);
|
||||
derived.name = baseName + L" (" + std::to_wstring(request.points) + L"点均值";
|
||||
if (request.order > 1)
|
||||
{
|
||||
derived.name += L"×" + std::to_wstring(request.order) + L"阶";
|
||||
}
|
||||
derived.name += L")";
|
||||
ComputeMovingAverageIterated(source.values, request.points, request.iterations, derived_values);
|
||||
derived.name = baseName + L" (" + std::to_wstring(request.points) + L"点均值 " +
|
||||
std::to_wstring(request.iterations) + L"次迭代)";
|
||||
}
|
||||
|
||||
// 2. 组装新信号。
|
||||
@@ -1551,7 +1543,7 @@ namespace jdi
|
||||
request.fileIndex = item.fileIndex;
|
||||
request.signalIndex = item.signalIndex;
|
||||
request.points = item.points;
|
||||
request.order = item.order;
|
||||
request.iterations = item.iterations;
|
||||
request.weakBoost = false;
|
||||
requests.push_back(request);
|
||||
}
|
||||
@@ -1568,7 +1560,7 @@ namespace jdi
|
||||
request.fileIndex = item.fileIndex;
|
||||
request.signalIndex = item.signalIndex;
|
||||
request.levelPercent = item.levelPercent;
|
||||
request.order = item.order;
|
||||
request.iterations = item.iterations;
|
||||
request.weakBoost = true;
|
||||
requests.push_back(request);
|
||||
}
|
||||
@@ -1611,17 +1603,13 @@ namespace jdi
|
||||
std::wstring text = L"已构建 " + std::to_wstring(built) + L" 条 ";
|
||||
if (last.weakBoost)
|
||||
{
|
||||
text += L"弱波增强 " + std::to_wstring(last.levelPercent) + L"%" +
|
||||
std::to_wstring(last.order) + L"阶信号。";
|
||||
text += L"弱波增强 " + std::to_wstring(last.levelPercent) + L"% " +
|
||||
std::to_wstring(last.iterations) + L"次迭代信号。";
|
||||
}
|
||||
else
|
||||
{
|
||||
text += std::to_wstring(last.points) + L"点均值";
|
||||
if (last.order > 1)
|
||||
{
|
||||
text += L"×" + std::to_wstring(last.order) + L"阶";
|
||||
}
|
||||
text += L"滤波信号。";
|
||||
text += std::to_wstring(last.points) + L"点均值 " +
|
||||
std::to_wstring(last.iterations) + L"次迭代滤波信号。";
|
||||
}
|
||||
SetStatusMessage(text, false);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user