实验性功能完善:面板交互修正 + 新增「边沿计数(中心轴)」
一、实验性功能浮动面板的交互修正(「边沿计数」与「边沿计数(中心轴)」共用) - 面板只有**标题栏**可以拖拽:鼠标在标题栏显示抓握光标(IDC_SIZEALL), 在面板主体(含统计行与底部编辑行)保持原始箭头,按下主体也不再拖动面板(仅消费点击, 不会穿透到底层的平移/选区/信号拖拽)。 - ✕ 关闭按钮:鼠标悬停时高亮(danger 色底 + danger 色叉),但**不改变鼠标光标样式**。 - 为此新增 `EdgePanelLayout`(panel / title / close / edit / rows)与 `EdgePanelLayoutFor(laneIndex, centerAxis)`,`QueryCursor`、`OnMouseMove`、`OnLButtonDown` 与绘制统一按该布局判定。 二、新增「实验性功能 → 边沿计数(中心轴)」(带 √ 的切换项,按网格独立) - 开启后为网格内**每条信号**叠加绘制一条"中心平均值曲线": 每个数据点 = 自身与左右各 N 个数据点(共 2N+1 点,边界处按实际窗口)的平均值。 用滑动窗口求和构建,整体 O(n),不额外占用前缀和内存;结果按 (信号, N) 缓存 (deque 保证引用有效),数据层变化或 N 改变时清空。 - 该曲线只是叠加显示,**不会**加入左侧信号列表; 为与波形区分,颜色按背景明暗把信号色向黑/白方向拉远(浅色主题加深、深色主题提亮), 线宽略粗于原信号。 - 纵向光标仍会标注这条曲线的取值:在原取值胶囊之外额外绘制一个「中 <值>」胶囊 (与曲线同色、半透明),并复用统一的避让逻辑(PlaceCursorLabel,已抽成函数)。 - 统计规则:**信号从下往上越过中心平均值曲线 → 上升沿;从上往下穿过 → 下降沿** (比较 `signal[i] - center[i]` 的符号变化,NaN 视为断点)。 - 浮动面板标题为「中心轴边沿计数」,样式与「边沿计数」面板一致(GX 徽标 + 标题 + ✕ + 每信号一行名称与「上升沿 N / 下降沿 M」,数字完整不省略、面板宽度按文本实测自适应); 面板**底部固定一行「平滑点数 N」内联编辑设置**(新增 EditFilter::NUMBER 编辑目标 PlotEditTarget::EDGE_CENTER_SMOOTH,夹在 0–1000000),始终位于面板最下方。 - 与双光标模式联动:双光标时标题追加「(光标区间内)」,只统计左右光标之间的区间; 区间端点恒取两光标时间的 min/max,因此把任一光标拖到另一侧(左右交换)后依然正确。 - ✕ 关闭面板的同时关闭该网格的「边沿计数(中心轴)」功能(面板与曲线一并消失)。 验证(TestData/VERY_BIG_DATA.CSV,编码器A相,125%、1725x996): - 面板光标形态探测:主体 = ARROW、标题栏 = SIZEALL、✕ = ARROW; 从主体拖动面板不发生位移(截图核对)。 - ✕ 悬停高亮可见。 - 「边沿计数(中心轴)」:面板标题「中心轴边沿计数」、底部「平滑点数 N = 5」; 中心平均值曲线(深蓝)清晰可见;把 N 改为 3000 后计数同步更新。 用独立脚本 .preflight/centerprobe.ps1 按同一规则复算,与界面**逐位一致**: N=5 → 上升沿 2712920 / 下降沿 2712913;N=1000 → 2373176 / 2373176。 - 双光标联动:区间 [48.0211, 64.4051](面板标题带「(光标区间内)」)→ 349220 / 349220; 把光标 1 的时间改到 100(越过光标 2 的 64.4051)后,区间变为 [64.4051, 100], 计数 778085 / 778084,与按该区间复算的结果一致(±2 为光标时间显示值取整导致的边界差)。 - 纵向光标读数:右光标显示 `4.9417 (-0.071945)` + `中 4.94199`, 左光标显示 `中 2.9165`(中心曲线取值单独标注)。 - 左侧信号列表仍只有原信号,未新增曲线条目。 - 回归:[1].CSV 上「边沿计数(光标区间内)」正常(Δt:151ms 200us); 「边沿计数(中心轴)」在 [1].CSV 上曲线清晰可见(上升沿 199 / 下降沿 199)。 - make clean && make all 无警告无错误。
This commit is contained in:
1 parent
b884e7ecb4
commit
5182bd8aa3
5 files changed
+996
-206
No files matched your search
@@ -1451,6 +1451,12 @@ namespace jdi
|
||||
edgeCount.id = PLOT_CMD_LANE_EDGE_COUNT;
|
||||
edgeCount.checked = m_plot.LaneEdgeCount(laneIndex);
|
||||
experimental.submenu.push_back(edgeCount);
|
||||
|
||||
MenuItem edgeCenter;
|
||||
edgeCenter.label = L"边沿计数(中心轴)";
|
||||
edgeCenter.id = PLOT_CMD_LANE_EDGE_CENTER;
|
||||
edgeCenter.checked = m_plot.LaneEdgeCenterCount(laneIndex);
|
||||
experimental.submenu.push_back(edgeCenter);
|
||||
}
|
||||
items.push_back(experimental);
|
||||
|
||||
@@ -1557,6 +1563,10 @@ namespace jdi
|
||||
// 「实验性功能 → 边沿计数」:切换本网格的横向光标与统计面板。
|
||||
m_plot.ToggleLaneEdgeCount(laneIndex);
|
||||
break;
|
||||
case PLOT_CMD_LANE_EDGE_CENTER:
|
||||
// 「实验性功能 → 边沿计数(中心轴)」:切换中心平均值曲线与统计面板。
|
||||
m_plot.ToggleLaneEdgeCenterCount(laneIndex);
|
||||
break;
|
||||
case PLOT_CMD_FIT_ALL:
|
||||
m_plot.FitAll();
|
||||
break;
|
||||
|
||||
@@ -52,7 +52,8 @@ namespace jdi
|
||||
CURSOR_SPAN, /**< 编辑双光标之间的时间差(前方光标不动,后方光标随之移动)。 */
|
||||
LANE_Y_MAX, /**< 编辑某网格的 Y 轴最大值。 */
|
||||
LANE_Y_MIN, /**< 编辑某网格的 Y 轴最小值。 */
|
||||
SIGNAL_NAME /**< 编辑图例中某信号的显示名称。 */
|
||||
SIGNAL_NAME, /**< 编辑图例中某信号的显示名称。 */
|
||||
EDGE_CENTER_SMOOTH /**< 编辑「中心轴边沿计数」的平滑点数 N。 */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -66,7 +67,8 @@ namespace jdi
|
||||
PLOT_CMD_FIT_ALL = 4, /**< 全部网格与时间轴自适应。 */
|
||||
PLOT_CMD_LANE_FIT_TIME = 5, /**< 时间轴自适应到本网格信号范围(按网格时间轴展开)。 */
|
||||
PLOT_CMD_LANE_AUTO_VIEW = 6, /**< 切换本网格的「选区 Y 轴自适应」开关。 */
|
||||
PLOT_CMD_LANE_EDGE_COUNT = 7 /**< 切换本网格的「实验性功能 → 边沿计数」开关。 */
|
||||
PLOT_CMD_LANE_EDGE_COUNT = 7, /**< 切换本网格的「实验性功能 → 边沿计数」开关。 */
|
||||
PLOT_CMD_LANE_EDGE_CENTER = 8 /**< 切换本网格的「实验性功能 → 边沿计数(中心轴)」开关。 */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -407,6 +409,28 @@ namespace jdi
|
||||
*/
|
||||
bool ToggleLaneEdgeCount(int laneIndex);
|
||||
|
||||
/**
|
||||
* @brief 判断某网格是否开启了「实验性功能 → 边沿计数(中心轴)」。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
* @return 开启返回 true。
|
||||
*/
|
||||
bool LaneEdgeCenterCount(int laneIndex) const;
|
||||
|
||||
/**
|
||||
* @brief 设置某网格的「边沿计数(中心轴)」开关。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
* @param [IN] enabled 目标状态。
|
||||
* @return 状态发生变化返回 true。
|
||||
*/
|
||||
bool SetLaneEdgeCenterCount(int laneIndex, bool enabled);
|
||||
|
||||
/**
|
||||
* @brief 切换某网格的「边沿计数(中心轴)」开关。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
* @return 切换后的状态。
|
||||
*/
|
||||
bool ToggleLaneEdgeCenterCount(int laneIndex);
|
||||
|
||||
/**
|
||||
* @brief 进入某网格 Y 轴上限/下限的内联输入状态。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
@@ -855,6 +879,90 @@ namespace jdi
|
||||
*/
|
||||
bool IsOnEdgeCursorLine(int x, int y, int& laneIndex) const;
|
||||
|
||||
/**
|
||||
* @brief 实验性功能浮动面板的几何布局(边沿计数 / 中心轴边沿计数共用同一套样式)。
|
||||
*/
|
||||
struct EdgePanelLayout
|
||||
{
|
||||
gd::RectF panel; /**< 面板整体矩形。 */
|
||||
gd::RectF title; /**< 标题栏(**唯一可拖拽区域**)。 */
|
||||
gd::RectF close; /**< ✕ 关闭按钮。 */
|
||||
gd::RectF edit; /**< 面板底部编辑行(无编辑内容时宽度为 0)。 */
|
||||
int rows = 0; /**< 统计行数(每条可见信号一行)。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 计算某个实验性功能面板的布局。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
* @param [IN] centerAxis 为 true 时取「边沿计数(中心轴)」面板,否则取「边沿计数」。
|
||||
* @return 布局;面板未展开时各项均为空矩形。
|
||||
*/
|
||||
EdgePanelLayout EdgePanelLayoutFor(int laneIndex, bool centerAxis) const;
|
||||
|
||||
/**
|
||||
* @brief 获取「边沿计数(中心轴)」浮动面板的矩形。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
* @return 面板矩形(未展开时为空矩形)。
|
||||
*/
|
||||
gd::RectF EdgeCenterPanelRect(int laneIndex) const;
|
||||
|
||||
/**
|
||||
* @brief 获取中心平均值曲线(每个数据点 = 自身与左右各 N 点的平均值),结果带缓存。
|
||||
* @param [IN] signal 目标信号。
|
||||
* @param [IN] smooth 平滑半径 N(0 表示不平滑)。
|
||||
* @return 曲线数值数组(长度与 `signal.values` 相同;缺失处为 NaN)。
|
||||
*/
|
||||
const std::vector<float>& CenterCurveFor(const SignalData& signal, int smooth) const;
|
||||
|
||||
/**
|
||||
* @brief 取某个时刻的中心平均值曲线取值(用于纵向光标的取值标注)。
|
||||
* @param [IN] file 信号所属文件。
|
||||
* @param [IN] signal 目标信号。
|
||||
* @param [IN] smooth 平滑半径 N。
|
||||
* @param [IN] time 采样时刻。
|
||||
* @param [OUT] value 输出取值。
|
||||
* @return 取到有效值返回 true。
|
||||
*/
|
||||
bool CenterValueAt(const DataFile& file, const SignalData& signal, int smooth, double time,
|
||||
double& value) const;
|
||||
|
||||
/**
|
||||
* @brief 统计信号穿越“中心平均值曲线”的上/下边沿数量,结果带缓存。
|
||||
* @param [IN] file 信号所属文件。
|
||||
* @param [IN] signal 目标信号。
|
||||
* @param [IN] smooth 平滑半径 N。
|
||||
* @param [IN] hasRange 是否只统计某个时间区间(双光标模式下为光标区间)。
|
||||
* @param [IN] rangeMin 区间左端点时间。
|
||||
* @param [IN] rangeMax 区间右端点时间。
|
||||
* @param [OUT] rising 上升沿数量(信号从下往上越过中心平均值曲线)。
|
||||
* @param [OUT] falling 下降沿数量(信号从上往下穿过中心平均值曲线)。
|
||||
*/
|
||||
void EdgeCenterCountsFor(const DataFile& file, const SignalData& signal, int smooth,
|
||||
bool hasRange, double rangeMin, double rangeMax, std::size_t& rising,
|
||||
std::size_t& falling) const;
|
||||
|
||||
/**
|
||||
* @brief 绘制某条信号的中心平均值曲线(叠加在原信号所在网格上)。
|
||||
* @param [IN,OUT] g 绘图上下文。
|
||||
* @param [IN] resolved 信号视图。
|
||||
* @param [IN] lane 网格绘制信息。
|
||||
* @param [IN] smooth 平滑半径 N。
|
||||
*/
|
||||
void PaintCenterCurve(gd::Graphics& g, const ResolvedSignal& resolved, const LaneVisual& lane,
|
||||
int smooth) const;
|
||||
|
||||
/**
|
||||
* @brief 放置一个光标取值胶囊:先夹到网格可见范围内,再向下(必要时向上)避让
|
||||
* 已占用的标注矩形,最后登记到 `m_cursorLabelRects`。
|
||||
* @param [IN,OUT] rect 胶囊矩形(Y 会被调整)。
|
||||
* @param [IN] preferredTop 期望的顶边纵坐标(避让前)。
|
||||
* @param [IN] textHeight 胶囊高度。
|
||||
* @param [IN] clipTop 网格可见区上边界。
|
||||
* @param [IN] clipBottom 网格可见区下边界。
|
||||
*/
|
||||
void PlaceCursorLabel(gd::RectF& rect, float preferredTop, float textHeight, float clipTop,
|
||||
float clipBottom);
|
||||
|
||||
/**
|
||||
* @brief 获取边沿统计面板的矩形(未展开时返回空矩形)。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
@@ -885,11 +993,12 @@ namespace jdi
|
||||
std::size_t& falling) const;
|
||||
|
||||
/**
|
||||
* @brief 计算边沿统计面板所需的宽度(排版与绘制共用,保证文字完整不被省略)。
|
||||
* @brief 计算实验性功能面板所需的宽度(排版与绘制共用,保证文字完整不被省略)。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
* @param [IN] centerAxis 为 true 时取「边沿计数(中心轴)」面板。
|
||||
* @return 面板宽度(像素)。
|
||||
*/
|
||||
float EdgePanelWidth(int laneIndex) const;
|
||||
float EdgePanelWidth(int laneIndex, bool centerAxis) const;
|
||||
|
||||
/**
|
||||
* @brief 判断边沿统计是否限定在双光标区间内(双光标模式)。
|
||||
@@ -1050,9 +1159,34 @@ namespace jdi
|
||||
};
|
||||
mutable std::vector<EdgeCountEntry> m_edgeCountCache; /**< 边沿统计缓存(纯缓存,逻辑上不影响对象状态)。 */
|
||||
|
||||
/** 中心平均值曲线缓存项(按「信号指针 + 平滑半径」标识)。 */
|
||||
struct CenterCurveEntry
|
||||
{
|
||||
const SignalData* signal = nullptr;
|
||||
int smooth = 0;
|
||||
std::vector<float> values; /**< 与 signal->values 等长;缺失处为 NaN。 */
|
||||
};
|
||||
/** 中心平均值曲线缓存:**deque** 保证 push_back 后已有元素引用仍然有效。 */
|
||||
mutable std::deque<CenterCurveEntry> m_centerCurveCache;
|
||||
|
||||
/** 中心轴边沿统计缓存项。 */
|
||||
struct EdgeCenterCountEntry
|
||||
{
|
||||
const DataFile* file = nullptr;
|
||||
const SignalData* signal = nullptr;
|
||||
int smooth = 0;
|
||||
bool hasRange = false;
|
||||
double rangeMin = 0.0;
|
||||
double rangeMax = 0.0;
|
||||
std::size_t rising = 0;
|
||||
std::size_t falling = 0;
|
||||
};
|
||||
mutable std::vector<EdgeCenterCountEntry> m_edgeCenterCountCache; /**< 中心轴边沿统计缓存。 */
|
||||
|
||||
// 「边沿计数」横向光标 / 面板的拖拽状态。
|
||||
int m_edgeDragLane = -1; /**< 正在拖动的横向光标所属网格。 */
|
||||
int m_edgePanelDragLane = -1; /**< 正在拖动的统计面板所属网格。 */
|
||||
bool m_edgePanelDragCenter = false; /**< 正在拖动的面板是否为「中心轴边沿计数」面板。 */
|
||||
gd::PointF m_edgePanelDragOffset; /**< 抓取面板时的相对偏移(保持不跳变)。 */
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -370,6 +370,27 @@ namespace jdi
|
||||
|
||||
/** 统计面板左上角纵坐标(<0 表示自动定位)。 */
|
||||
double edgePanelY = -1.0;
|
||||
|
||||
/**
|
||||
* @brief 「实验性功能 → 边沿计数(中心轴)」开关。
|
||||
*
|
||||
* 开启后为本网格内每条信号额外绘制一条"中心平均值曲线"(每个数据点取自身与左右各
|
||||
* `edgeCenterSmooth` 个点的平均值),并按“信号穿越中心平均值曲线”统计上/下边沿。
|
||||
* 这条曲线只是叠加显示,不会作为信号加入左侧列表。
|
||||
*/
|
||||
bool edgeCenter = false;
|
||||
|
||||
/** 中心平均值的平滑半径 N(左右各取 N 个数据点,窗口大小 2N+1)。 */
|
||||
int edgeCenterSmooth = 5;
|
||||
|
||||
/** 中心轴统计浮动面板是否展开。 */
|
||||
bool edgeCenterPanelOpen = true;
|
||||
|
||||
/** 中心轴统计面板左上角位置(客户区像素;<0 表示自动定位)。 */
|
||||
double edgeCenterPanelX = -1.0;
|
||||
|
||||
/** 中心轴统计面板左上角纵坐标(<0 表示自动定位)。 */
|
||||
double edgeCenterPanelY = -1.0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -121,6 +121,11 @@ namespace jdi
|
||||
bool edgePanelOpen = true;
|
||||
double edgePanelX = -1.0;
|
||||
double edgePanelY = -1.0;
|
||||
bool edgeCenter = false;
|
||||
int edgeCenterSmooth = 5;
|
||||
bool edgeCenterPanelOpen = true;
|
||||
double edgeCenterPanelX = -1.0;
|
||||
double edgeCenterPanelY = -1.0;
|
||||
};
|
||||
|
||||
// 先记下每个信号原来所在网格的网格自身状态:
|
||||
@@ -136,6 +141,11 @@ namespace jdi
|
||||
carry.edgePanelOpen = lane.edgePanelOpen;
|
||||
carry.edgePanelX = lane.edgePanelX;
|
||||
carry.edgePanelY = lane.edgePanelY;
|
||||
carry.edgeCenter = lane.edgeCenter;
|
||||
carry.edgeCenterSmooth = lane.edgeCenterSmooth;
|
||||
carry.edgeCenterPanelOpen = lane.edgeCenterPanelOpen;
|
||||
carry.edgeCenterPanelX = lane.edgeCenterPanelX;
|
||||
carry.edgeCenterPanelY = lane.edgeCenterPanelY;
|
||||
for (const SignalRef& ref : lane.signals)
|
||||
{
|
||||
previousCarry.emplace_back(ref, carry);
|
||||
@@ -162,6 +172,11 @@ namespace jdi
|
||||
lane.edgePanelOpen = carry.edgePanelOpen;
|
||||
lane.edgePanelX = carry.edgePanelX;
|
||||
lane.edgePanelY = carry.edgePanelY;
|
||||
lane.edgeCenter = carry.edgeCenter;
|
||||
lane.edgeCenterSmooth = carry.edgeCenterSmooth;
|
||||
lane.edgeCenterPanelOpen = carry.edgeCenterPanelOpen;
|
||||
lane.edgeCenterPanelX = carry.edgeCenterPanelX;
|
||||
lane.edgeCenterPanelY = carry.edgeCenterPanelY;
|
||||
};
|
||||
|
||||
// 收集全部可见信号引用。
|
||||
|
||||
Reference in new issue
Block a user