修复色域拖拽回弹、网格 GX 拖拽重排、均值滤波多阶与逐信号条目
1. 自定义颜色面板:拖动时鼠标移出控件不再"弹回去"
- 根因是选点位置每帧都从 RGB 反推:色相 1 与 0 是同一个颜色(红),拖到色相条底部
下一帧反推回 0,指示条弹到顶部;拖到色域方块右下角之外时明度为 0(黑色),
黑色的饱和度无定义,反推得 0,选点弹到最左边。
- 现在把"选点位置(饱和度/明度)与色相"作为独立状态保存,只由对应控件与外部改色维护;
越界一律夹取到最近边界,因此鼠标离开控件后选点停在边界上。
- 统一色域方块、色相条、预览色块与色号框的圆角;RGB 滑块适当加粗;
色域选点去掉外圈深色描边(只保留白色描边),色相指示器改为白色描边的圆角长方条、
底色取该位置的颜色;色相条改用分段线性渐变绘制。
2. 网格 GX 编号支持拖拽重排
- 按住网格图例左侧的 GX 徽标即可上下拖动,整块网格(连同波形与标尺)跟随鼠标移动;
途经的网格保持自身大小、整体让出一格,目标槽位有吸附高亮提示。
- 松开后真正重排并从下到上/从上到下重新编号,信号列表徽标、图例徽标、菜单与浮动面板
中所有 GX 编号同步更新;手动排布后切换为自定义划分,后续重建网格不会打乱次序。
- 拖动期间复用静态场景缓存,按网格条带平移贴图,因此大文件下依然流畅。
3. 均值滤波升级为"均值点数 X + 阶数 N"
- 原"均值点数 N"更名"均值点数 X",新增"阶数 N":预览曲线以 X 点均值滤波的结果为蓝本,
再重复同样的滤波共 N 阶(1 阶即与原来的单次滤波逐位一致)。
- 浮动面板改为逐信号条目:第一排是信号名与复选框,第二排是均值点数与阶数输入;
只有勾选的信号才绘制预览曲线,未勾选时不显示第二排;启用功能时默认只勾选第一个信号。
- 参数按信号保存(同一网格内不同信号可用不同参数),「构建为新信号」按各自参数构建。
This commit is contained in:
1 parent
2d029fb09b
commit
bc8db72f18
8 files changed
+1138
-181
No files matched your search
@@ -250,14 +250,16 @@ namespace jdi
|
||||
bool ApplyPendingMeanFilterBuild();
|
||||
|
||||
/**
|
||||
* @brief 把一条均值滤波派生信号插入数据层并同步各视图。
|
||||
* @brief 把一条多阶均值滤波派生信号插入数据层并同步各视图。
|
||||
* @param [IN] fileIndex 原信号所属文件下标。
|
||||
* @param [IN] signalIndex 原信号下标。
|
||||
* @param [IN] radius 均值滤波半径 N。
|
||||
* @param [IN] points 均值点数 X(滑平半径)。
|
||||
* @param [IN] order 阶数 N(迭代次数)。
|
||||
* @param [IN] makeVisible 是否在当前标签页中勾选新信号。
|
||||
* @return 构建并插入成功返回 true。
|
||||
*/
|
||||
bool BuildMeanFilterSignal(int fileIndex, int signalIndex, int radius, bool makeVisible);
|
||||
bool BuildMeanFilterSignal(int fileIndex, int signalIndex, int points, int order,
|
||||
bool makeVisible);
|
||||
|
||||
/**
|
||||
* @brief 弹出文件选择对话框并加载所选文件。
|
||||
|
||||
@@ -1436,7 +1436,8 @@ namespace jdi
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::BuildMeanFilterSignal(int fileIndex, int signalIndex, int radius, bool makeVisible)
|
||||
bool Application::BuildMeanFilterSignal(int fileIndex, int signalIndex, int points, int order,
|
||||
bool makeVisible)
|
||||
{
|
||||
const DataFile* file = m_dataSet.FileAt(fileIndex);
|
||||
if (file == nullptr || signalIndex < 0 || signalIndex >= static_cast<int>(file->signals.size()))
|
||||
@@ -1446,13 +1447,18 @@ namespace jdi
|
||||
const SignalData& source = file->signals[static_cast<std::size_t>(signalIndex)];
|
||||
const std::wstring baseName = source.Title();
|
||||
|
||||
// 1. 计算均值滤波采样值(与预览曲线共用同一实现)。
|
||||
// 1. 计算多阶均值滤波采样值(与预览曲线共用同一实现)。
|
||||
std::vector<float> filtered;
|
||||
ComputeMovingAverage(source.values, radius, filtered);
|
||||
ComputeMovingAverageIterated(source.values, points, order, filtered);
|
||||
|
||||
// 2. 组装新信号:名称形如「<原信号名称> (N点均值)」。
|
||||
// 2. 组装新信号:名称形如「<原信号名称> (N点均值x阶)」。
|
||||
SignalData derived;
|
||||
derived.name = baseName + L" (" + std::to_wstring(radius) + L"点均值)";
|
||||
derived.name = baseName + L" (" + std::to_wstring(points) + L"点均值";
|
||||
if (order > 1)
|
||||
{
|
||||
derived.name += L"×" + std::to_wstring(order) + L"阶";
|
||||
}
|
||||
derived.name += L")";
|
||||
derived.rawHeader = derived.name;
|
||||
derived.unit = source.unit;
|
||||
derived.values.assign(filtered.begin(), filtered.end());
|
||||
@@ -1490,8 +1496,8 @@ namespace jdi
|
||||
bool Application::ApplyPendingMeanFilterBuild()
|
||||
{
|
||||
int laneIndex = -1;
|
||||
int radius = 0;
|
||||
if (!m_plot.TakePendingMeanFilterBuild(laneIndex, radius))
|
||||
std::vector<PlotView::MeanFilterBuild> items;
|
||||
if (!m_plot.TakePendingMeanFilterBuild(laneIndex, items))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1501,21 +1507,10 @@ namespace jdi
|
||||
return false;
|
||||
}
|
||||
|
||||
// 先收集该网格内的全部可见信号(插入过程中信号下标会变化,因此先取快照)。
|
||||
std::vector<SignalRef> targets;
|
||||
for (const SignalRef& ref : ActiveTab().Lanes()[static_cast<std::size_t>(laneIndex)].signals)
|
||||
{
|
||||
if (m_dataSet.Resolve(ref) == nullptr || !ActiveTab().IsVisible(ref))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
targets.push_back(ref);
|
||||
}
|
||||
|
||||
// **同一文件内必须按下标降序处理**:每次插入只让插入点之后的信号下标 +1,
|
||||
// 降序处理可保证尚未处理的信号下标始终有效(升序会把新插入的信号当成原信号)。
|
||||
std::sort(targets.begin(), targets.end(),
|
||||
[](const SignalRef& a, const SignalRef& b)
|
||||
std::sort(items.begin(), items.end(),
|
||||
[](const PlotView::MeanFilterBuild& a, const PlotView::MeanFilterBuild& b)
|
||||
{
|
||||
if (a.fileIndex != b.fileIndex)
|
||||
{
|
||||
@@ -1525,19 +1520,28 @@ namespace jdi
|
||||
});
|
||||
|
||||
int built = 0;
|
||||
for (const SignalRef& ref : targets)
|
||||
int lastPoints = 0;
|
||||
int lastOrder = 1;
|
||||
for (const PlotView::MeanFilterBuild& item : items)
|
||||
{
|
||||
if (BuildMeanFilterSignal(ref.fileIndex, ref.signalIndex, radius, true))
|
||||
if (BuildMeanFilterSignal(item.fileIndex, item.signalIndex, item.points, item.order, true))
|
||||
{
|
||||
++built;
|
||||
lastPoints = item.points;
|
||||
lastOrder = item.order;
|
||||
}
|
||||
}
|
||||
|
||||
if (built > 0)
|
||||
{
|
||||
SetStatusMessage(L"已构建 " + std::to_wstring(built) + L" 条 " + std::to_wstring(radius) +
|
||||
L"点均值滤波信号。",
|
||||
false);
|
||||
std::wstring text = L"已构建 " + std::to_wstring(built) + L" 条 " +
|
||||
std::to_wstring(lastPoints) + L"点均值";
|
||||
if (lastOrder > 1)
|
||||
{
|
||||
text += L"×" + std::to_wstring(lastOrder) + L"阶";
|
||||
}
|
||||
text += L"滤波信号。";
|
||||
SetStatusMessage(text, false);
|
||||
}
|
||||
return built > 0;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user