Files
Just-DataInspector/Utilities/Inc/CsvTable.hpp
T
DeepSeek V4.1 Flash 8801c8f019 修复缩放视界下拖拽与改色卡顿、加载字节进度、光标越界三角与中心轴均值滤波统一
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 项检查全部通过;验证过程不显示窗口、不移动鼠标键盘、不抓屏。
2026-10-10 16:47:05 +08:00

77 lines
2.8 KiB
C++

#ifndef __CSV_TABLE_HPP__
#define __CSV_TABLE_HPP__
#include <cstddef>
#include <functional>
#include <string>
#include <vector>
namespace jdi
{
/**
* @brief CSV 文件的解析结果,保存列名与**列优先**的数值矩阵。
*
* 采用列优先(每条信号一整块连续内存)而不是行优先的二维数组,原因有二:
* 1. 大型文件(百万行级)若按行存储会产生上百万次独立堆分配,
* 每行还要额外承担 vector 的控制块与容量对齐开销,实测内存放大接近 1.5 倍;
* 2. 后续构建信号时可以直接把整列**移动**进 SignalData,不再逐元素拷贝。
*/
struct CsvTable
{
std::vector<std::wstring> headers; /**< 列名(已去除引号与首尾空白)。 */
std::vector<std::vector<double>> columns; /**< 列优先数值矩阵:columns[列][行],缺失处为 NaN。 */
std::size_t rowCount = 0; /**< 有效数据行数。 */
wchar_t delimiter = L','; /**< 实际使用的分隔符。 */
unsigned long long fileBytes = 0; /**< 源文件字节数(用于按比例预留容量)。 */
/**
* @brief 判断解析结果是否包含可用的表格数据。
* @return 存在列名且存在数据行时返回 true。
*/
bool HasData() const
{
return !headers.empty() && (rowCount > 0);
}
};
/**
* @brief 加载进度信息。
*
* 解析阶段会携带真实的"已读 / 总字节数";列重组与统计阶段没有字节可计,
* 此时 `hasBytes` 为 false,界面应只展示百分比。
*/
struct CsvProgressInfo
{
double ratio = 0.0; /**< 0-1 总体完成比例。 */
unsigned long long bytesRead = 0; /**< 已读取字节数。 */
unsigned long long totalBytes = 0; /**< 文件总字节数。 */
bool hasBytes = false; /**< 上述字节数字段是否有效。 */
};
/**
* @brief 解析进度回调。
*
* 在解析过程中按块回调;返回 false 表示请求取消,解析会尽快停止并返回失败。
*/
using CsvProgress = std::function<bool(const CsvProgressInfo& info)>;
/**
* @brief 读取并解析一个 CSV 文件。
*
* 文件以分块流式方式读取(不把整个文件一次性读入内存),
* 因此内存占用只与解析结果相关,不会因文件体积成倍放大,也没有体积上限。
*
* @param [IN] filePath CSV 文件完整路径(宽字符,支持中文路径)。
* @param [OUT] table 解析结果输出。
* @param [OUT] error 失败原因描述(成功时清空)。
* @param [IN] progress 解析进度回调,可为空。
* @return 解析成功返回 true,否则返回 false。
*/
bool LoadCsvTable(const std::wstring& filePath, CsvTable& table, std::wstring& error,
const CsvProgress& progress = CsvProgress());
} // namespace jdi
#endif // __CSV_TABLE_HPP__