实验性功能新增「均值滤波」+ 构建为新信号

- 「实验性功能」二级菜单新增带勾选的「均值滤波」:开启后为本网格每条信号叠加绘制
  一条 N 点滑动平均曲线,算法与「边沿计数(中心轴)」的中心平均值曲线**完全一致**
  (同一实现 ComputeMovingAverage),配色同样由信号色派生为高对比度颜色、透明度一致。
- 新增均值滤波浮动面板:标题栏可拖拽、✕ 关闭,面板内列出被处理的信号名、
  「均值点数 N」内联编辑行,以及底部的「构建为新信号」按钮(悬停高亮 + 手型光标)。
- 「构建为新信号」:把滤波后的曲线作为新信号插入,命名为「<原信号名称> (N点均值)」,
  归属到原信号所属组的原信号位置**下方**,成为独立的新信号;其所在网格也移动到
  原信号网格的下方。合并网格时一次按钮为该网格内每条可见信号各构建一条。
  为此新增 DataSet::InsertDerivedSignal / TabConfig::RemapAfterSignalInsert /
  TabConfig::MoveLaneOfSignalBelow / TabConfig::RenameLanes(插入位置之后的信号引用
  与可见性列同步重映射)。
- 光标交互与「边沿计数(中心轴)」同构:光标处标注均值滤波曲线的取值
  与双光标增量,文案为「值(均值滤波)」/「值(+增量 均值滤波)」;
  两条派生曲线的取值胶囊已抽成同一段绘制逻辑。
- 浮动面板种类由 bool centerAxis 改为 EdgePanelKind{COUNT,CENTER,MEAN},
  布局/宽度/命中测试/绘制统一走同一套几何。
- 以 VERY_BIG_DATA.CSV 验证:曲线预览、N 编辑、双光标取值标注、
  单信号与合并网格两种情况下的新信号命名与插入位置均正确。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-09 21:00:38 +08:00
1 parent 8ae8d7af4f
commit f5028b1e18
6 files changed
+885 -210

No files matched your search

+76 -1
View File
@@ -212,6 +212,22 @@ namespace jdi
*/
bool AddPreparedFile(DataFile&& file, int& fileIndex);
/**
* @brief 在指定文件的指定信号**下方**插入一条新信号(派生信号)。
*
* 新信号会占据 `afterSignalIndex + 1` 的位置,该位置及其后的信号下标整体后移一位;
* 调用方必须紧接着对每个标签页调用 `TabConfig::RemapAfterSignalInsert()` 修正引用。
* 采样值会被就地统计(min/max/finiteCount 与粗粒度包络层),显示外观按「全局信号序号」
* 取调色板颜色(与普通新信号一致)。
*
* @param [IN] fileIndex 目标文件下标。
* @param [IN] afterSignalIndex 插入位置的上一条信号下标。
* @param [IN,OUT] signal 待插入的信号(values 会被统计,其余字段原样使用)。
* @param [OUT] newSignalIndex 新信号在本文件内的下标。
* @return 插入成功返回 true。
*/
bool InsertDerivedSignal(int fileIndex, int afterSignalIndex, SignalData&& signal, int& newSignalIndex);
/**
* @brief 移除指定下标的文件,并立即释放其占用的全部采样内存。
* @param [IN] fileIndex 文件下标。
@@ -391,6 +407,27 @@ namespace jdi
/** 中心轴统计面板左上角纵坐标(<0 表示自动定位)。 */
double edgeCenterPanelY = -1.0;
/**
* @brief 「实验性功能 → 均值滤波」开关。
*
* 开启后为本网格内每条信号额外绘制一条 N 点滑动平均曲线(算法与「边沿计数(中心轴)」
* 的中心平均值曲线完全一致),并在浮动面板中提供参数 N 与「构建为新信号」按钮。
* 与其它实验性功能一样属于网格自身状态,重建网格时按信号继承。
*/
bool meanFilter = false;
/** 均值滤波半径 N(左右各取 N 个数据点,窗口大小 2N+1)。 */
int meanFilterRadius = 5;
/** 均值滤波浮动面板是否展开。 */
bool meanFilterPanelOpen = true;
/** 均值滤波面板左上角位置(客户区像素;<0 表示自动定位)。 */
double meanFilterPanelX = -1.0;
/** 均值滤波面板左上角纵坐标(<0 表示自动定位)。 */
double meanFilterPanelY = -1.0;
};
/**
@@ -404,6 +441,18 @@ namespace jdi
*/
bool SampleFileAt(const DataFile& file, const SignalData& signal, double time, bool interpolate, double& value);
/**
* @brief 计算 N 点滑动平均(窗口 = [i-N, i+N],边界按实际窗口长度)。
*
* 与「边沿计数(中心轴)」的中心平均值曲线**完全同一算法**:
* NaN 不参与平均;中心点本身为 NaN 时结果也为 NaN;窗口内无有效值时为 NaN。
*
* @param [IN] values 原始采样值。
* @param [IN] radius 平滑半径 N(0 表示原样返回)。
* @param [OUT] out 输出数组(长度与 values 相同)。
*/
void ComputeMovingAverage(const std::vector<double>& values, int radius, std::vector<float>& out);
/**
* @brief 在指定文件的时间轴上查找与给定时刻最接近的采样点。
* @param [IN] file 目标文件。
@@ -579,8 +628,34 @@ namespace jdi
*/
int SplitLane(int laneIndex);
/** * @brief 在数据层插入新信号之后,修正本页引用该文件的信号下标。
*
* 数据层在下标 `insertPos` 处插入了一条信号,因此本页可见性表需插入一列,
* 且所有指向该文件、下标不小于 `insertPos` 的信号引用都要后移一位。
*
* @param [IN] fileIndex 发生插入的文件下标。
* @param [IN] insertPos 新信号的下标。
*/
void RemapAfterSignalInsert(int fileIndex, int insertPos);
/**
* @brief 查询某文件的分组是否处于折叠状态。
* @brief 把某信号所在的网格移动到另一信号所在网格的下方(紧邻其后)。
*
* 用于「均值滤波 → 构建为新信号」:新信号所在的网格应紧跟在原信号网格的下方。
* 移动成功后会切换为自定义划分策略,避免后续重建网格时顺序被复原。
*
* @param [IN] moved 被移动网格内的任一信号。
* @param [IN] anchor 锚点信号(其所在网格之后即为目标位置)。
* @return 发生移动返回 true。
*/
bool MoveLaneOfSignalBelow(const SignalRef& moved, const SignalRef& anchor);
/**
* @brief 按当前位置统一重命名全部网格(GX 编号由位置推导,须保持一致)。
*/
void RenameLanes();
/** * @brief 查询某文件的分组是否处于折叠状态。
* @param [IN] fileIndex 文件下标。
* @return 折叠状态。
*/