优化百万级采样文件的绘制性能,Esc 改为取消拖拽选区
性能(BIG_DATA.csv 128 万采样 × 10 信号全显示,实测): - 折线抽稀改为按像素列取上下包络(min/max),顶点数由固定 20000 降到像素量级; 既保住尖峰(等间隔抽样会整段漏掉),又不再把大量顶点堆在同一像素列上。 - 新增折线顶点缓存:以“构建折线实际读取的全部输入”(信号、时间轴范围、绘图区横向 几何、网格纵向几何)为键,视图未变化时直接复用,重复绘制不再重算全量采样。 - 悬停命中检测先按 x 二分裁剪到容差范围内的一小段(点到线段距离必不小于横向距离), 鼠标移动不再遍历上万个顶点。 - 结果:整帧渲染 1309ms -> 103~127ms(10 网格);折线构建 25ms -> 0ms(缓存命中); 单条折线绘制 1255ms -> 45~53ms;悬停命中 ~0ms。两文件 6 网格场景约 52ms。 - 未引入多线程:耗时集中在 GDI+ 单线程绘制调用与一次性 O(N) 包络扫描, 并行化的收益上限仅约 25ms,不值得引入线程与同步复杂度。 - 空闲(无交互)CPU 占用实测 0.00%,消息循环阻塞在 GetMessage, 无需重绘时不再产生任何计算。 Esc 行为: - 缩放拖拽(时间轴/幅值轴框选)按住左键时按 Esc:立即放弃选区并清空拖拽状态, 随后松开左键也不会把选区应用到视图(已验证:时间轴保持原范围,对照组正常缩放)。 - Esc 不再关闭时间光标(原先 Esc 会调用 DisableCursor);关闭光标只走工具栏「光标」按钮, 避免顺手按 Esc 时意外关掉指针。 - 数据层结构变化(加载/移除文件、切换上下文)后清空折线缓存, 防止旧几何键与新信号重合而取到过期顶点。
This commit is contained in:
1 parent
12b3531485
commit
d6a81839bb
3 files changed
+312
-20
No files matched your search
@@ -5,6 +5,7 @@
|
||||
#include <objidl.h>
|
||||
#include <gdiplus.h>
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -229,6 +230,18 @@ namespace jdi
|
||||
void DisableCursor();
|
||||
|
||||
/**
|
||||
* @brief 放弃当前正在进行的拖拽(缩放选区/平移/信号拖动),不改变视图范围。
|
||||
* @return 确实取消了某个拖拽返回 true。
|
||||
*/
|
||||
bool CancelDrag();
|
||||
|
||||
/**
|
||||
* @brief 清空折线顶点缓存。
|
||||
*
|
||||
* 数据层结构变化(加载/移除文件、信号增删)后信号引用与文件地址都可能改变,
|
||||
* 必须清空缓存,避免旧几何键与新的信号意外重合而取到过期顶点。
|
||||
*/
|
||||
void InvalidatePolylineCache(); /**
|
||||
* @brief 切换时间光标:启用时置于当前视图中心,再调用则关闭。
|
||||
* @return 状态发生变化返回 true。
|
||||
*/
|
||||
@@ -742,6 +755,43 @@ namespace jdi
|
||||
|
||||
std::vector<LegendHit> m_legendHits; /**< 最近一次绘制时记录的图例条目矩形。 */
|
||||
|
||||
/**
|
||||
* @brief 折线顶点缓存条目。
|
||||
*
|
||||
* 折线抽稀是 O(采样点数) 的(百万级采样约 2~3ms/条),
|
||||
* 而绘制、悬停命中检测每帧都要用到同一批顶点。
|
||||
* 用“构建折线时读取的全部输入”作为键缓存顶点,
|
||||
* 视图/网格几何未变化时可直接复用,避免重复扫描全量采样。
|
||||
*/
|
||||
struct PolylineCacheEntry
|
||||
{
|
||||
SignalRef ref; /**< 信号引用。 */
|
||||
const DataFile* file = nullptr; /**< 所属文件(内容不可变)。 */
|
||||
std::size_t sampleCount = 0; /**< 采样点数(数据变化时改变)。 */
|
||||
double viewMin = 0.0; /**< 时间轴显示下界。 */
|
||||
double viewMax = 0.0; /**< 时间轴显示上界。 */
|
||||
float plotX = 0.0f; /**< 绘图区左边界。 */
|
||||
float plotWidth = 0.0f; /**< 绘图区宽度。 */
|
||||
float laneY = 0.0f; /**< 网格上边界。 */
|
||||
float laneHeight = 0.0f; /**< 网格高度。 */
|
||||
double laneYMin = 0.0; /**< 网格幅值下界。 */
|
||||
double laneYMax = 0.0; /**< 网格幅值上界。 */
|
||||
std::vector<gd::PointF> points; /**< 折线顶点。 */
|
||||
std::vector<std::size_t> breaks; /**< 每段折线在 points 中的起始下标。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 取得(必要时重建)指定信号在当前几何下的折线顶点。
|
||||
* @param [IN] ref 信号引用(缓存键的一部分)。
|
||||
* @param [IN] resolved 已解析的信号。
|
||||
* @param [IN] lane 网格绘制信息。
|
||||
* @return 缓存条目指针,无法构建时返回 nullptr。
|
||||
*/
|
||||
const PolylineCacheEntry* AcquirePolyline(const SignalRef& ref, const ResolvedSignal& resolved,
|
||||
const LaneVisual& lane) const;
|
||||
|
||||
mutable std::deque<PolylineCacheEntry> m_polylineCache; /**< 折线顶点缓存(按几何键复用)。 */
|
||||
|
||||
/**
|
||||
* @brief 查询坐标命中的图例条目。
|
||||
* @param [IN] x 客户区横坐标。
|
||||
|
||||
Reference in new issue
Block a user