using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using Plugins.Halcon.Models;
using Plugins.Halcon.Views;
using TeamAAS.FlowEditor.Execution;
using TeamAAS.FlowEditor.Models;
using TeamAAS.FlowEditor.Plugins;
namespace Plugins.Halcon
{
///
/// HALCON 图像显示节点(主流程节点,与 VP图像显示/VM图像显示 对等):把 HALCON 流程容器输出的
/// 图像/区域显示到主页画面框(视觉窗体 UCDispHalcon),每项可独立链接叠加区域与 OK/NG 结果驱动状态圆点。
/// 放在主流程调用:图像来源绑定上游「Halcon流程」容器的输出(或任意前序节点的图像/GenImage)。
/// 画面框是主页单例、独立于编辑器——正常运行只往里推图,不由编辑器控制。
///
[Serializable]
[Plugin("Halcon图像显示", PluginCategory.Halocn模块, typeof(HalconDisplayModel), "Monitor",
NodeShape = NodeCategory.Normal,
Description = "主流程节点:把 HALCON 图像/区域显示到主页画面框;每项可独立链接叠加区域与 OK/NG 结果驱动状态圆点")]
public class HalconDisplayPlugin : BasePlugin
{
public override List DeclareOutputs()
{
var list = new List
{
new OutputField("显示画面数", typeof(int)),
new OutputField("结果", typeof(bool)),
};
foreach (var kv in BuildItemKeys(Model))
list.Add(new OutputField(kv.Key, typeof(object)));
return list;
}
///
/// 依据显示项列表生成稳定的「输出键 → 显示项」映射:键优先取目标画面名,重名/空名追加序号去重。
/// 与 共用,保证键一致。
///
private static List> BuildItemKeys(HalconDisplayModel model)
{
var map = new List>();
if (model?.DisplayItems == null) return map;
var used = new HashSet();
for (int i = 0; i < model.DisplayItems.Count; i++)
{
var item = model.DisplayItems[i];
if (item == null) continue;
string key = item.FrameName;
if (string.IsNullOrWhiteSpace(key)) key = $"画面{item.FrameNo}";
string unique = key;
int dup = 2;
while (!used.Add(unique)) unique = $"{key}({dup++})";
map.Add(new KeyValuePair(unique, item));
}
return map;
}
public override NodeRunStatus PluginRun(CancellationToken token, out Dictionary results)
{
var res = new Dictionary();
results = res;
try
{
var windows = UCDispHalcon.Instance.halconWindow;
int displayed = 0;
Log(3, $"开始显示,显示项 {Model.DisplayItems?.Count ?? 0} 个,主页画面框 {windows?.Count ?? 0} 个");
foreach (var kv in BuildItemKeys(Model))
{
var item = kv.Value;
res[kv.Key] = null;
object image = GetResolve(item.Source);
object overlay = string.IsNullOrWhiteSpace(item.OverlaySource?.Formula) ? null : GetResolve(item.OverlaySource);
res[kv.Key] = image;
if (image == null)
{
Log(2, $"显示项[{kv.Key}] 未解析到图像,已跳过", TeamAAS.LogLevel.Warning);
continue;
}
if (item.FrameNo < 1 || windows == null || windows.Count < item.FrameNo)
{
Log(2, $"显示项[{kv.Key}] 目标画面序号 {item.FrameNo} 无效或主页画面框不足,已跳过", TeamAAS.LogLevel.Warning);
continue;
}
var win = windows[item.FrameNo - 1];
if (win == null) continue;
bool hasOk = !string.IsNullOrWhiteSpace(item.OkNgBinding?.Formula);
bool ok = hasOk && GetValue(item.OkNgBinding);
Application.Current?.Dispatcher.Invoke(() =>
{
win.RefreshImage(image, overlay);
if (hasOk) win.SetLable(ok ? HalconResultType.OK : HalconResultType.NG);
});
displayed++;
Log(4, $"显示项[{kv.Key}] → 画面{item.FrameNo},图像类型 {(image?.GetType().Name ?? "null")},叠加 {(overlay != null ? "有" : "无")}{(hasOk ? $",OK/NG={(ok ? "OK" : "NG")}" : "")}");
}
res["显示画面数"] = displayed;
res["结果"] = true;
Log(2, $"显示完成,共刷新 {displayed} 个画面");
return NodeRunStatus.Success;
}
catch (Exception ex)
{
res["Error"] = ex.Message;
res["结果"] = false;
Log(1, $"HALCON 图像显示异常: {ex.Message}", TeamAAS.LogLevel.Error);
return NodeRunStatus.Failed;
}
}
}
}