修复缩放视界下拖拽与改色卡顿、加载字节进度、光标越界三角与中心轴均值滤波统一
1. 修复选区放大后的拖拽/改色卡顿(先实测再修,不猜)
- 用离屏探针量化:缩放视界下一帧要画约 250 条网格线,GDI+ DrawLine 每条 0.1~0.19ms,
整帧 26.4ms;而包络带填充本身只要 0.36ms,真正的瓶颈是逐条直线调用。
- 网格线、时间轴刻度、绘图区边框、网格分隔线全部改为 GDI 批量 1px 直线绘制
(一次 SaveDC/IntersectClipRect/创建画笔,逐段 MoveToEx/LineTo);
纵轴数值胶囊改为把所有圆角矩形合并成一个路径、只调用一次填充。
- 半透明网格线颜色先用底色预混成不透明色,否则 GDI 无法绘制透明度;
GDI 绘制不受 GDI+ 裁剪约束,批量绘制一律显式设置裁剪矩形。
- 实测:缩放视界下场景缓存失效帧 26.4 -> 8.25ms,改色应用 7.1 -> 3.15ms,
缓存命中帧 2.06 -> 0.30ms。
2. 读取文件时显示"已读取 / 总大小 百分比"
- 解析进度回调扩展为携带真实字节数(已读字节、文件总字节);
列重组等没有字节可计的阶段只显示百分比。
- 新增字节数格式化:单位在 GB / MB / KB 之间自适应,只输出数字与单位;
已读大小随进度自动切换单位。
- 进度浮层按"已读取 / 文件总大小 百分比"显示,两个大小与百分比都保留两位小数,
完全取代原来的整数百分比。
3. 网格编号拖拽重排的绘制修复
- GX 编号悬停时保持普通箭头光标(不再变成四向箭头),按下拖拽时才使用上下箭头。
- 拖拽时先把整幅静态场景(含主时间轴)贴回,再把目标槽位高亮、被拖网格的轮廓与
投影裁剪在绘图区内,因此拖到工具栏甚至更上方、或拖到时间轴及下方都不再出现
残留与错乱。
4. 网格 Y 轴数值只在完全移出可视区时才不绘制
- 原来只要碰到边界就整条不画;现在按可见范围裁剪胶囊与数值,
部分可见时绘制未被遮挡的部分。
5. 边沿计数横向光标的读数与越界指示
- 幅值读数右移,让开横线左端的三角把手,不再遮挡。
- 幅值超出视界时(横线贴边显示)在读数上方/下方绘制方向三角,
并且与读数水平居中对齐。
6. 常规光标读数越界与双光标叠放
- 光标滞留在视界之外时,时间读数同样绘制方向三角。
- 双光标读数重叠时按时间值排序:小值在上、大值在下(原来固定把第二个上移,
左右光标交换后会显示成大的在上)。
- 双光标同时越界到同一侧时,两条时间读数与时间差值读数在同一列垂直对齐,
并为差值读数绘制方向三角;叠放间距按三角深度放宽,三角不会再压在相邻读数上。
7. 中心轴边沿计数与均值滤波统一
- 参数由单一的"平滑点数 N"改为按信号的"均值点数 X + 阶数 N",与实验性功能中的
均值滤波完全同构(同样的命名、同样的作用、同样的曲线实现),
两条曲线逐位一致,光标处的取值标注规则也统一。
- 浮动面板改为自上而下的逐信号条目,每个条目三排:
第一排信号名与复选框,第二排均值点数与阶数输入框,第三排该信号的上升沿/下降沿统计;
取消勾选即不显示该信号的参数编辑与统计结果,启用时默认只勾选第一个可见信号。
- 网格重建继承、拆分网格、信号插入/删除的下标修正与场景缓存指纹都同步覆盖新条目。
测试:离屏自动验证套件新增一组检查(字节数格式化、解析进度字节、编号悬停/拖拽光标、
双光标读数排序与对齐、中心轴三排布局与参数、横向光标越界三角、加载浮层渲染等),
合计 241 项检查全部通过;验证过程不显示窗口、不移动鼠标键盘、不抓屏。
This commit is contained in:
1 parent
bc8db72f18
commit
8801c8f019
12 files changed
+951
-420
No files matched your search
+80
-23
@@ -122,7 +122,7 @@ namespace jdi
|
||||
double edgePanelX = -1.0;
|
||||
double edgePanelY = -1.0;
|
||||
bool edgeCenter = false;
|
||||
int edgeCenterSmooth = 5;
|
||||
std::vector<Lane::EdgeCenterItem> edgeCenterItems;
|
||||
bool edgeCenterPanelOpen = true;
|
||||
double edgeCenterPanelX = -1.0;
|
||||
double edgeCenterPanelY = -1.0;
|
||||
@@ -147,7 +147,7 @@ namespace jdi
|
||||
carry.edgePanelX = lane.edgePanelX;
|
||||
carry.edgePanelY = lane.edgePanelY;
|
||||
carry.edgeCenter = lane.edgeCenter;
|
||||
carry.edgeCenterSmooth = lane.edgeCenterSmooth;
|
||||
carry.edgeCenterItems = lane.edgeCenterItems;
|
||||
carry.edgeCenterPanelOpen = lane.edgeCenterPanelOpen;
|
||||
carry.edgeCenterPanelX = lane.edgeCenterPanelX;
|
||||
carry.edgeCenterPanelY = lane.edgeCenterPanelY;
|
||||
@@ -183,7 +183,7 @@ namespace jdi
|
||||
lane.edgePanelX = carry.edgePanelX;
|
||||
lane.edgePanelY = carry.edgePanelY;
|
||||
lane.edgeCenter = carry.edgeCenter;
|
||||
lane.edgeCenterSmooth = carry.edgeCenterSmooth;
|
||||
lane.edgeCenterItems = carry.edgeCenterItems;
|
||||
lane.edgeCenterPanelOpen = carry.edgeCenterPanelOpen;
|
||||
lane.edgeCenterPanelX = carry.edgeCenterPanelX;
|
||||
lane.edgeCenterPanelY = carry.edgeCenterPanelY;
|
||||
@@ -571,11 +571,15 @@ namespace jdi
|
||||
|
||||
file.signals.push_back(std::move(signal));
|
||||
|
||||
if (progress && !progress(0.75 + 0.25 * static_cast<double>(column + 1) /
|
||||
static_cast<double>(columnCount)))
|
||||
if (progress)
|
||||
{
|
||||
error = L"已取消加载。";
|
||||
return false;
|
||||
CsvProgressInfo info;
|
||||
info.ratio = 0.75 + 0.25 * static_cast<double>(column + 1) / static_cast<double>(columnCount);
|
||||
if (!progress(info))
|
||||
{
|
||||
error = L"已取消加载。";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,6 +1034,41 @@ namespace jdi
|
||||
meanFilterItems.end());
|
||||
}
|
||||
|
||||
const Lane::EdgeCenterItem* Lane::FindEdgeCenterItem(const SignalRef& ref) const
|
||||
{
|
||||
for (const EdgeCenterItem& item : edgeCenterItems)
|
||||
{
|
||||
if (item.ref == ref)
|
||||
{
|
||||
return &item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Lane::EdgeCenterItem& Lane::EnsureEdgeCenterItem(const SignalRef& ref)
|
||||
{
|
||||
for (EdgeCenterItem& item : edgeCenterItems)
|
||||
{
|
||||
if (item.ref == ref)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
EdgeCenterItem item;
|
||||
item.ref = ref;
|
||||
edgeCenterItems.push_back(item);
|
||||
return edgeCenterItems.back();
|
||||
}
|
||||
|
||||
void Lane::RemoveEdgeCenterItem(const SignalRef& ref)
|
||||
{
|
||||
edgeCenterItems.erase(
|
||||
std::remove_if(edgeCenterItems.begin(), edgeCenterItems.end(),
|
||||
[&ref](const EdgeCenterItem& item) { return item.ref == ref; }),
|
||||
edgeCenterItems.end());
|
||||
}
|
||||
|
||||
int FindNearestSample(const DataFile& file, double time)
|
||||
{
|
||||
const std::size_t count = file.time.size();
|
||||
@@ -1254,22 +1293,26 @@ namespace jdi
|
||||
}
|
||||
}
|
||||
|
||||
// 均值滤波条目同样持有信号引用,必须一起删除/前移。
|
||||
std::vector<Lane::MeanFilterItem>& items = lane.meanFilterItems;
|
||||
items.erase(std::remove_if(items.begin(), items.end(),
|
||||
[fileIndex, signalIndex](const Lane::MeanFilterItem& item)
|
||||
{
|
||||
return item.ref.fileIndex == fileIndex &&
|
||||
item.ref.signalIndex == signalIndex;
|
||||
}),
|
||||
items.end());
|
||||
for (Lane::MeanFilterItem& item : items)
|
||||
// 均值滤波 / 中心轴边沿计数的条目同样持有信号引用,必须一起删除/前移。
|
||||
const auto purgeRefs = [fileIndex, signalIndex](std::vector<Lane::MeanFilterItem>& items)
|
||||
{
|
||||
if (item.ref.fileIndex == fileIndex && item.ref.signalIndex > signalIndex)
|
||||
items.erase(std::remove_if(items.begin(), items.end(),
|
||||
[fileIndex, signalIndex](const Lane::MeanFilterItem& item)
|
||||
{
|
||||
return item.ref.fileIndex == fileIndex &&
|
||||
item.ref.signalIndex == signalIndex;
|
||||
}),
|
||||
items.end());
|
||||
for (Lane::MeanFilterItem& item : items)
|
||||
{
|
||||
--item.ref.signalIndex;
|
||||
if (item.ref.fileIndex == fileIndex && item.ref.signalIndex > signalIndex)
|
||||
{
|
||||
--item.ref.signalIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
purgeRefs(lane.meanFilterItems);
|
||||
purgeRefs(lane.edgeCenterItems);
|
||||
}
|
||||
// 被移除信号若独占了某个网格,该网格随之消失(与取消勾选的行为一致)。
|
||||
m_lanes.erase(std::remove_if(m_lanes.begin(), m_lanes.end(),
|
||||
@@ -1558,13 +1601,13 @@ namespace jdi
|
||||
lane.edgePanelX = source.edgePanelX;
|
||||
lane.edgePanelY = source.edgePanelY;
|
||||
lane.edgeCenter = source.edgeCenter;
|
||||
lane.edgeCenterSmooth = source.edgeCenterSmooth;
|
||||
lane.edgeCenterPanelOpen = source.edgeCenterPanelOpen;
|
||||
lane.edgeCenterPanelX = source.edgeCenterPanelX;
|
||||
lane.edgeCenterPanelY = source.edgeCenterPanelY;
|
||||
lane.meanFilter = source.meanFilter;
|
||||
// 拆分后每个子网格只保留自己那个信号的均值滤波条目。
|
||||
// 拆分后每个子网格只保留自己那个信号的均值滤波 / 中心轴条目。
|
||||
lane.meanFilterItems.clear();
|
||||
lane.edgeCenterItems.clear();
|
||||
for (const Lane::MeanFilterItem& item : source.meanFilterItems)
|
||||
{
|
||||
if (item.ref == ref)
|
||||
@@ -1572,6 +1615,13 @@ namespace jdi
|
||||
lane.meanFilterItems.push_back(item);
|
||||
}
|
||||
}
|
||||
for (const Lane::EdgeCenterItem& item : source.edgeCenterItems)
|
||||
{
|
||||
if (item.ref == ref)
|
||||
{
|
||||
lane.edgeCenterItems.push_back(item);
|
||||
}
|
||||
}
|
||||
lane.meanFilterPanelOpen = source.meanFilterPanelOpen;
|
||||
lane.meanFilterPanelX = source.meanFilterPanelX;
|
||||
lane.meanFilterPanelY = source.meanFilterPanelY;
|
||||
@@ -1615,7 +1665,7 @@ namespace jdi
|
||||
++ref.signalIndex;
|
||||
}
|
||||
}
|
||||
// 均值滤波条目同样持有信号引用,必须一起后移。
|
||||
// 均值滤波 / 中心轴条目同样持有信号引用,必须一起后移。
|
||||
for (Lane::MeanFilterItem& item : lane.meanFilterItems)
|
||||
{
|
||||
if (item.ref.fileIndex == fileIndex && item.ref.signalIndex >= insertPos)
|
||||
@@ -1623,6 +1673,13 @@ namespace jdi
|
||||
++item.ref.signalIndex;
|
||||
}
|
||||
}
|
||||
for (Lane::EdgeCenterItem& item : lane.edgeCenterItems)
|
||||
{
|
||||
if (item.ref.fileIndex == fileIndex && item.ref.signalIndex >= insertPos)
|
||||
{
|
||||
++item.ref.signalIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user