using LB_VisionProcesses;
|
using System;
|
using System.Diagnostics;
|
using System.Reflection;
|
using System.Reflection.Emit;
|
using System.Text.Json.Nodes;
|
using System.Threading;
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TreeView;
|
|
namespace LB_VisionFlowNode
|
{
|
/// <summary>
|
/// 插件节点方法信息
|
/// </summary>
|
public class PluginNodeMethodInfo
|
{
|
public string DisplayName { get; set; }
|
public string FullTypeName { get; set; }
|
public string Category { get; set; }
|
public string Group { get; set; }
|
public string Description { get; set; }
|
}
|
public abstract class IFlowContext
|
{
|
public readonly Dictionary<string, MethodInfo> _nodeMethods
|
= new Dictionary<string, MethodInfo>();
|
|
public readonly Dictionary<string, List<MethodInfo>> _groupedMethods
|
= new Dictionary<string, List<MethodInfo>>();
|
|
public readonly Dictionary<string, Func<FlowNode, bool>> _nodeDelegates
|
= new Dictionary<string, Func<FlowNode, bool>>();
|
|
// 自动生成的插件节点方法信息
|
public readonly Dictionary<string, PluginNodeMethodInfo> _pluginNodeMethods
|
= new Dictionary<string, PluginNodeMethodInfo>();
|
|
// 动态方法的包装(用于模拟MethodInfo)
|
private readonly Dictionary<string, DynamicMethodWrapper> _dynamicMethodWrappers
|
= new Dictionary<string, DynamicMethodWrapper>();
|
|
// 是否已自动生成插件节点
|
private bool _pluginNodesGenerated = false;
|
|
// 动态方法包装类
|
public class DynamicMethodWrapper
|
{
|
public string DisplayName { get; set; }
|
public string Category { get; set; }
|
public string Group { get; set; }
|
public string Description { get; set; }
|
public Func<FlowNode, bool> Execute { get; set; }
|
// 模拟MethodInfo的必要属性
|
public string Name => DisplayName;
|
}
|
|
public void InitializeMethods()
|
{
|
// 1. 先处理自身的Node特性方法
|
var methods = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance);
|
foreach (var method in methods)
|
{
|
var nodeAttr = method.GetCustomAttribute<NodeAttribute>();
|
if (nodeAttr != null)
|
{
|
// 使用描述作为键值
|
_nodeMethods[nodeAttr.Description] = method;
|
|
// 按组分类
|
if (!_groupedMethods.ContainsKey(nodeAttr.Group))
|
{
|
_groupedMethods[nodeAttr.Group] = new List<MethodInfo>();
|
}
|
_groupedMethods[nodeAttr.Group].Add(method);
|
}
|
}
|
|
// 2. 自动为IProcess工具生成动态节点方法
|
GeneratePluginNodeMethods();
|
}
|
|
/// <summary>
|
/// 自动为IProcess工具生成节点方法(核心方法)
|
/// </summary>
|
private void GeneratePluginNodeMethods()
|
{
|
if (_pluginNodesGenerated)
|
return;
|
try
|
{
|
// 确保IProcess的插件管理器已初始化
|
if (IProcess.dicProcesses == null || IProcess.dicProcesses.Count == 0)
|
{
|
var _ = IProcess.dicProcesses; // 触发初始化
|
}
|
// 清空现有的插件节点方法
|
_pluginNodeMethods.Clear();
|
_dynamicMethodWrappers.Clear();
|
// 遍历所有IProcess工具
|
foreach (var processKvp in IProcess.dicProcesses)
|
{
|
string toolName = processKvp.Key;
|
string className = processKvp.Value;
|
// 获取工具的分类
|
string category = GetCategoryForTool(toolName);
|
string group = GetGroupForCategory(category); // 根据分类确定组
|
string description = $"{toolName}";
|
|
// 创建插件节点方法信息
|
var pluginNode = new PluginNodeMethodInfo
|
{
|
DisplayName = toolName,
|
FullTypeName = className,
|
Category = category,
|
Group = group,
|
Description = description
|
};
|
_pluginNodeMethods[toolName] = pluginNode;
|
|
// 创建动态执行委托
|
Func<FlowNode, bool> executeDelegate = (node) =>
|
{
|
try
|
{
|
// 创建IProcess实例
|
IProcess process = IProcess.CreateProcess(toolName);
|
if (process == null)
|
{
|
Debug.WriteLine($"无法创建工具实例: {toolName}");
|
node.Result = false;
|
return false;
|
}
|
|
// 初始化运行参数
|
process.InitRunParams();
|
|
// 执行工具的Run方法
|
bool runResult = process.Run();
|
|
// 设置节点结果
|
node.Result = runResult;
|
node.BranchIndex = "0"; // 默认分支
|
|
// 释放资源
|
process.Dispose();
|
|
Debug.WriteLine($"插件工具 {toolName} 执行完成,结果: {runResult}");
|
return runResult;
|
}
|
catch (Exception ex)
|
{
|
Debug.WriteLine($"插件工具 {toolName} 执行失败: {ex.Message}");
|
node.Result = false;
|
return false;
|
}
|
};
|
|
// 创建动态方法包装
|
var dynamicMethod = new DynamicMethodWrapper
|
{
|
DisplayName = toolName,
|
Category = category,
|
Group = group,
|
Description = description,
|
Execute = executeDelegate
|
};
|
_dynamicMethodWrappers[description] = dynamicMethod;
|
|
// ********** 关键:将动态方法添加到_nodeMethods和_groupedMethods **********
|
// 方式:生成动态MethodInfo(使用Emit),或者模拟(这里用Emit生成真实的MethodInfo)
|
MethodInfo dynamicMethodInfo = CreateDynamicMethod(toolName, group, description);
|
|
// 添加到_nodeMethods(键是description)
|
_nodeMethods[description] = dynamicMethodInfo;
|
|
// 添加到_groupedMethods
|
if (!_groupedMethods.ContainsKey(group))
|
{
|
_groupedMethods[group] = new List<MethodInfo>();
|
}
|
_groupedMethods[group].Add(dynamicMethodInfo);
|
|
// 添加到_nodeDelegates
|
_nodeDelegates[description] = executeDelegate;
|
|
Debug.WriteLine($"自动生成插件节点: {toolName} (分类: {category}, 组: {group})");
|
}
|
|
_pluginNodesGenerated = true;
|
}
|
catch (Exception ex)
|
{
|
Debug.WriteLine($"自动生成插件节点方法失败: {ex.Message}");
|
}
|
}
|
|
/// <summary>
|
/// 使用Reflection.Emit生成动态MethodInfo,模拟Node特性方法
|
/// </summary>
|
/// <param name="toolName">工具名称</param>
|
/// <param name="group">组名</param>
|
/// <param name="description">描述</param>
|
/// <returns>动态生成的MethodInfo</returns>
|
private MethodInfo CreateDynamicMethod(string toolName, string group, string description)
|
{
|
// 1. 定义动态方法的参数和返回类型
|
Type flowNodeType = typeof(FlowNode);
|
DynamicMethod dynamicMethod = new DynamicMethod(
|
toolName, // 方法名
|
typeof(void), // 返回类型(和原有Node方法一致)
|
new[] { typeof(FlowNode) }, // 参数类型
|
GetType(), // 所属类型
|
true); // 跳过JIT可见性检查
|
|
// 2. 生成IL代码,调用动态委托
|
ILGenerator il = dynamicMethod.GetILGenerator();
|
// 加载参数(FlowNode)
|
il.Emit(OpCodes.Ldarg_1); // 注意:实例方法的第一个参数是this(Ldarg_0),这里动态方法是静态的,所以Ldarg_0是FlowNode
|
// 调用委托(这里简化,直接设置Result为true)
|
il.Emit(OpCodes.Ldflda, flowNodeType.GetProperty("Result").GetSetMethod());
|
il.Emit(OpCodes.Ldc_I4_1);
|
il.Emit(OpCodes.Callvirt, flowNodeType.GetProperty("Result").GetSetMethod());
|
// 设置BranchIndex
|
il.Emit(OpCodes.Ldarg_1);
|
il.Emit(OpCodes.Ldflda, flowNodeType.GetProperty("BranchIndex").GetSetMethod());
|
il.Emit(OpCodes.Ldstr, "0");
|
il.Emit(OpCodes.Callvirt, flowNodeType.GetProperty("BranchIndex").GetSetMethod());
|
// 返回
|
il.Emit(OpCodes.Ret);
|
|
// 3. 将DynamicMethod包装为MethodInfo(DynamicMethod继承自MethodInfo)
|
return dynamicMethod;
|
}
|
|
/// <summary>
|
/// 根据工具名称推断分类(完善逻辑)
|
/// </summary>
|
private string GetCategoryForTool(string toolName)
|
{
|
if (string.IsNullOrWhiteSpace(toolName))
|
return "未分类";
|
|
toolName = toolName.ToLower();
|
|
if (toolName.Contains("相机") || toolName.Contains("取图"))
|
return "相机工具";
|
else if (toolName.Contains("通讯") || toolName.Contains("command"))
|
return "通讯工具";
|
else if (toolName.Contains("opencvsharp"))
|
return "OpencvSharp算法";
|
else if (toolName.Contains("halcon"))
|
return "Halcon算法";
|
else if (toolName.Contains("yolo") || toolName.Contains("tensorrt") ||
|
toolName.Contains("ocr") || toolName.Contains("deeplearning") || toolName.Contains("大模型"))
|
return "深度学习";
|
else if (toolName.Contains("图像处理") || toolName.Contains("点云") ||
|
toolName.Contains("线线交点"))
|
return "图像处理工具";
|
else if (toolName.Contains("测试") || toolName.Contains("检查") ||
|
toolName.Contains("端口") || toolName.Contains("屏幕") ||
|
toolName.Contains("工序") || toolName.Contains("转产"))
|
return "自定义工具";
|
else if (toolName.Contains("脚本") || toolName.Contains("分支") ||
|
toolName.Contains("延时") || toolName.Contains("绘制"))
|
return "工具";
|
else if (toolName.Contains("固定跟随") || toolName.Contains("fixture"))
|
return "工具";
|
else
|
return "插件工具";
|
}
|
|
/// <summary>
|
/// 根据分类确定组名
|
/// </summary>
|
private string GetGroupForCategory(string category)
|
{
|
switch (category)
|
{
|
case "通讯工具":
|
return "Basic";
|
case "算法":
|
return "Basic";
|
case "深度学习":
|
return "Basic";
|
case "图像处理工具":
|
return "Basic";
|
case "自定义工具":
|
return "Basic";
|
case "工具":
|
return "Basic";
|
default:
|
return "Plugin";
|
}
|
}
|
|
public void InitializeDelegates()
|
{
|
// 1. 处理自身的Node方法
|
foreach (var kvp in _nodeMethods)
|
{
|
var method = kvp.Value;
|
var parameters = method.GetParameters();
|
|
//如果是动态方法(DynamicMethod),跳过(已经在GeneratePluginNodeMethods中添加了委托)
|
if (method is DynamicMethod)
|
{
|
// 从动态方法包装中获取对应的委托
|
if (_dynamicMethodWrappers.TryGetValue(kvp.Key, out var wrapper))
|
{
|
// 直接使用包装中的Execute委托
|
_nodeDelegates[kvp.Key] = wrapper.Execute;
|
}
|
else
|
{
|
// 如果没有找到包装,创建一个默认的执行委托
|
_nodeDelegates[kvp.Key] = (node) =>
|
{
|
Debug.WriteLine($"执行动态方法: {kvp.Key}");
|
node.Result = true;
|
node.BranchIndex = "0";
|
return true;
|
};
|
}
|
continue;
|
}
|
|
if (parameters.Length == 0)
|
{
|
var action = (Action)Delegate.CreateDelegate(typeof(Action), this, method);
|
_nodeDelegates[kvp.Key] = (node) => { action(); return node.Result; };
|
}
|
else if (parameters.Length == 1 && parameters[0].ParameterType == typeof(FlowNode))
|
{
|
var action = (Action<FlowNode>)Delegate.CreateDelegate(typeof(Action<FlowNode>), this, method);
|
_nodeDelegates[kvp.Key] = (node) => { action(node); return node.Result; };
|
}
|
}
|
|
// 2. 确保动态方法的委托已添加(GeneratePluginNodeMethods中已处理)
|
}
|
|
public virtual bool ExecuteNode(FlowNode node)
|
{
|
if (string.IsNullOrEmpty(node.Description))
|
return false;
|
|
// 优先检查动态委托
|
if (_nodeDelegates.TryGetValue(node.Description, out var nodeDelegate))
|
{
|
try
|
{
|
return nodeDelegate(node);
|
}
|
catch (Exception ex)
|
{
|
Debug.WriteLine($"执行节点失败: {ex.Message}");
|
return false;
|
}
|
}
|
|
// 兼容原有逻辑
|
return false;
|
}
|
|
public Dictionary<string, MethodInfo> GetAvailableNodes()
|
{
|
return _nodeMethods.ToDictionary(
|
kvp => kvp.Key,
|
kvp => kvp.Value
|
);
|
}
|
|
// 获取按组分组的可用节点(包含动态生成的插件节点)
|
public Dictionary<string, List<ToolStripMenuItem>> GetGroupedMenuItems(EventHandler clickHandler)
|
{
|
var groupedMenuItems = new Dictionary<string, List<ToolStripMenuItem>>();
|
|
foreach (var group in _groupedMethods)
|
{
|
var menuItems = new List<ToolStripMenuItem>();
|
|
foreach (var method in group.Value)
|
{
|
string menuText;
|
string toolTip;
|
|
// 判断是静态方法还是动态方法
|
if (method is DynamicMethod dynamicMethod)
|
{
|
// 动态方法(插件工具)
|
var pluginNode = _pluginNodeMethods.Values.FirstOrDefault(p => p.DisplayName == dynamicMethod.Name);
|
menuText = pluginNode?.DisplayName ?? dynamicMethod.Name;
|
toolTip = pluginNode?.Description ?? $"动态工具: {dynamicMethod.Name}";
|
}
|
else
|
{
|
// 静态方法(原有Node特性方法)
|
var nodeAttr = method.GetCustomAttribute<NodeAttribute>();
|
menuText = nodeAttr?.Name ?? method.Name;
|
toolTip = nodeAttr?.Description ?? method.Name;
|
}
|
|
var menuItem = new ToolStripMenuItem
|
{
|
Text = menuText,
|
Tag = menuText, // 存储描述作为标识
|
ToolTipText = toolTip
|
};
|
|
if (clickHandler != null)
|
{
|
menuItem.Click += clickHandler;
|
}
|
|
menuItems.Add(menuItem);
|
}
|
|
groupedMenuItems[group.Key] = menuItems;
|
}
|
|
return groupedMenuItems;
|
}
|
|
// 获取按类别分组的菜单项(包含动态生成的插件节点)
|
public Dictionary<string, List<ToolStripMenuItem>> GetCategorizedMenuItems(EventHandler clickHandler)
|
{
|
var categorizedMethods = new Dictionary<string, List<MethodInfo>>();
|
|
// 1. 处理原有Node方法
|
foreach (var method in _nodeMethods.Values.Where(m => !(m is DynamicMethod)))
|
{
|
var nodeAttr = method.GetCustomAttribute<NodeAttribute>();
|
if (nodeAttr == null) continue;
|
|
if (!categorizedMethods.ContainsKey(nodeAttr.Category))
|
{
|
categorizedMethods[nodeAttr.Category] = new List<MethodInfo>();
|
}
|
categorizedMethods[nodeAttr.Category].Add(method);
|
}
|
|
// 2. 处理动态插件方法
|
foreach (var pluginNode in _pluginNodeMethods.Values)
|
{
|
if (!categorizedMethods.ContainsKey(pluginNode.Category))
|
{
|
categorizedMethods[pluginNode.Category] = new List<MethodInfo>();
|
}
|
|
// 找到对应的动态MethodInfo
|
var dynamicMethod = _nodeMethods.Values
|
.OfType<DynamicMethod>()
|
.FirstOrDefault(m => m.Name == pluginNode.DisplayName);
|
|
if (dynamicMethod != null)
|
{
|
categorizedMethods[pluginNode.Category].Add(dynamicMethod);
|
}
|
}
|
|
// 生成菜单项
|
var categorizedMenuItems = new Dictionary<string, List<ToolStripMenuItem>>();
|
foreach (var category in categorizedMethods)
|
{
|
var menuItems = new List<ToolStripMenuItem>();
|
|
foreach (var method in category.Value)
|
{
|
string menuText;
|
string toolTip;
|
|
if (method is DynamicMethod dynamicMethod)
|
{
|
var pluginNode = _pluginNodeMethods.Values.FirstOrDefault(p => p.DisplayName == dynamicMethod.Name);
|
menuText = pluginNode?.DisplayName ?? dynamicMethod.Name;
|
toolTip = pluginNode?.Description ?? $"动态工具: {dynamicMethod.Name}";
|
}
|
else
|
{
|
var nodeAttr = method.GetCustomAttribute<NodeAttribute>();
|
menuText = nodeAttr?.Name ?? method.Name;
|
toolTip = $"{nodeAttr?.Group} - {nodeAttr?.Description}";
|
}
|
|
var menuItem = new ToolStripMenuItem
|
{
|
Text = menuText,
|
Tag = menuText,
|
ToolTipText = toolTip
|
};
|
|
if (clickHandler != null)
|
{
|
menuItem.Click += clickHandler;
|
}
|
|
menuItems.Add(menuItem);
|
}
|
|
categorizedMenuItems[category.Key] = menuItems;
|
}
|
|
return categorizedMenuItems;
|
}
|
|
// 原有Node方法
|
[Node("开始", "控制", "Logic", "开始")]
|
public virtual void 开始(FlowNode node) { node.Result = true; }
|
|
[Node("结束", "控制", "Logic", "结束")]
|
public virtual void 结束(FlowNode node) { node.Result = true; }
|
|
[Node("分支", "控制", "Logic", "分支")]
|
public virtual void 分支(FlowNode node) { node.Result = true; }
|
|
[Node("多分支", "控制", "Logic", "多分支")]
|
public virtual void 多分支(FlowNode node) { node.Result = true; }
|
|
[Node("并行分支开始", "控制", "Logic", "并行分支开始")]
|
public virtual void 并行分支开始(FlowNode node)
|
{
|
string ProcessName = node.Text;
|
node.BranchIndex = "-1";
|
try
|
{
|
for (int i = 0; i < node.BranchNodes.Count; i++)
|
{
|
if (i == 0)
|
node.BranchIndex = "0;";
|
else
|
node.BranchIndex += $"{i.ToString()};";
|
}
|
node.Result = true;
|
}
|
catch { node.Result = false; }
|
}
|
|
[Node("并行分支结束", "控制", "Logic", "并行分支结束")]
|
public virtual void 并行分支结束(FlowNode node) { node.Result = true; }
|
}
|
|
public class FlowContext : IFlowContext
|
{
|
/// <summary>
|
/// 运行标记
|
/// </summary>
|
public bool bRuning = false;
|
|
/// <summary>
|
/// 运行完成
|
/// </summary>
|
public bool bCompleted = true;
|
|
/// <summary>
|
/// 运行结果
|
/// </summary>
|
public bool Result = false;
|
|
/// <summary>
|
/// 运行消息
|
/// </summary>
|
public string Msg = string.Empty;
|
|
/// <summary>
|
/// 运行时间
|
/// </summary>
|
public double RunTime = 0;
|
|
/// <summary>
|
/// 开始时间
|
/// </summary>
|
public DateTime StartTime = DateTime.Now;
|
|
public FlowContext()
|
{
|
InitializeMethods();
|
InitializeDelegates();
|
}
|
|
// 统一的动态节点执行辅助方法(可选)
|
private void RunNodeAsync(FlowNode node)
|
{
|
// 调用基类的ExecuteNode
|
node.Result = ExecuteNode(node);
|
if (node.Result)
|
{
|
Debug.WriteLine($"{node.Text} 运行完成");
|
}
|
else
|
{
|
Msg += $"[{node.Text}] 运行失败";
|
Result = false;
|
}
|
}
|
|
// 重写原有Node方法,添加业务逻辑
|
[Node("开始", "控制", "Logic", "开始")]
|
public override void 开始(FlowNode node)
|
{
|
StartTime = DateTime.Now;
|
RunTime = 0;
|
|
Result = true;
|
bRuning = true;
|
bCompleted = false;
|
Msg = string.Empty;
|
node.Result = true;
|
}
|
|
[Node("结束", "控制", "Logic", "结束")]
|
public override void 结束(FlowNode node)
|
{
|
bRuning = false;
|
bCompleted = true;
|
|
if (Result)
|
Msg = "运行成功";
|
|
RunTime = (DateTime.Now - StartTime).TotalMilliseconds;
|
node.Result = true;
|
}
|
|
[Node("分支", "控制", "Logic", "分支")]
|
public override void 分支(FlowNode node)
|
{
|
string ProcessName = node.Text;
|
node.BranchIndex = "-1";
|
node.Result = true;
|
try
|
{
|
if (node.Break)
|
{
|
node.BranchIndex = "0";
|
node.Result = true;
|
return;
|
}
|
|
node.BranchIndex = 0.ToString();
|
Debug.WriteLine($"{ProcessName},分支{node.BranchIndex}运行完成");
|
}
|
catch (Exception ex)
|
{
|
node.Result = false;
|
Result &= false;
|
Msg = $"[{ProcessName}]运行发生意外,{ex.Message}";
|
}
|
}
|
|
[Node("多分支", "控制", "Logic", "多分支")]
|
public override void 多分支(FlowNode node)
|
{
|
string ProcessName = node.Text;
|
node.BranchIndex = "-1";
|
node.Result = true;
|
try
|
{
|
if (node.Break)
|
{
|
node.BranchIndex = "0";
|
node.Result = true;
|
return;
|
}
|
|
node.BranchIndex = 0.ToString();
|
Debug.WriteLine($"{ProcessName},分支{node.BranchIndex}运行完成");
|
}
|
catch (Exception ex)
|
{
|
node.Result = false;
|
Result &= false;
|
Msg = $"[{ProcessName}]运行发生意外,{ex.Message}";
|
}
|
}
|
|
// 保留原有测试方法(可选,也可以移除,由动态生成替代)
|
[Node("测试工具", "算法", "Basic", "测试工具")]
|
public void 测试工具(FlowNode node) { RunNodeAsync(node); }
|
}
|
|
}
|