using HalconDotNet; using LB_SmartVision.Forms.Pages.SettingPage; using LB_SmartVision.Tool; using LB_VisionFlowNode; using LB_VisionProcesses; using LB_VisionProcesses.Cameras; using LB_VisionProcesses.Communicators; using LB_VisionProcesses.Processes.ScriptTool; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using OpenCvSharp; using System.Collections.Concurrent; using System.Data; using System.Diagnostics; using System.Reflection; using System.Text; namespace LB_SmartVision.ProcessRun { public class ProcessRunBll { private ProcessContext ProcessContext = null; public static string Node2ToolClassName(string NodeName) { foreach (var item in IProcess.dicProcesses) { if (NodeName.StartsWith(item.Key)) return item.Value.ToString(); } return string.Empty; } /// /// 流程名称 /// public string Name = string.Empty; /// /// 运行标记 /// public bool bPruning { set { if (ProcessContext == null) return; ProcessContext.bRuning = value; } get { if (ProcessContext == null) return false; return ProcessContext.bRuning; } } /// /// 运行完成 /// public bool bCompleted { set { if (ProcessContext == null) return; ProcessContext.bCompleted = value; } get { if (ProcessContext == null) return false; return ProcessContext.bCompleted; } } /// /// 运行结果 /// public bool Result { set { if (ProcessContext == null) return; ProcessContext.Result = value; } get { if (ProcessContext == null) return false; return ProcessContext.Result; } } /// /// 运行消息 /// public string Msg { set { if (ProcessContext == null) return; ProcessContext.Msg = value; } get { if (ProcessContext == null) return "运行失败"; return ProcessContext.Msg; } } /// /// 运行时间(ms) /// public double RunTime = 0; public bool GetImage(Forms.Pages.SettingPage.Layout layout, out HObject InputImage, out HObject RecordImage) { return ProcessContext.GetImage(layout, out InputImage, out RecordImage); } public bool GetImage(out HObject InputImage, out HObject RecordImage) { InputImage = null; RecordImage = null; foreach (var layout in GlobalVar.dicLayout) { if (layout.Value.ProcessName == Name) return ProcessContext.GetImage(layout.Value, out InputImage, out RecordImage); } return false; } public bool GetCsv(CsvSetting csv, out List DataTitle, out Dictionary ResultData) { return ProcessContext.GetCsv(csv, out DataTitle, out ResultData); } public bool GetOutput(string map, out object obj) { return ProcessContext.GetValue(map, out obj); } public bool GetStringOutput(string map, out string str) { bool res = GetOutput(map, out object obj); str = ProcessParams.ConvertToString(obj); return res; } public bool GetBooleanOutput(string map, out bool ret) { try { if (!GetOutput(map, out object obj)) { ret = false; return ret; } ret = Convert.ToBoolean(obj); return true; } catch { ret = false; return ret; } } public ConcurrentDictionary GetSteps() { if (ProcessContext.dicContext == null) return new ConcurrentDictionary(); return ProcessContext.dicContext; } /// /// 运行流程 /// public FlowPanel nodesControl = null; /// /// 通讯集合(Key:通讯名,Value:通讯句柄) /// public ObservableConcurrentDictionary dicCommunicators { get; set; } /// /// 相机集合(Key:相机SN,Value:相机句柄) /// public ObservableConcurrentDictionary dicCameras { get; set; } public Action LogInfo; public string allProcessPath { get { return GlobalVar.allProcessPath + Name + "\\default.nds"; } } public string allProcessInputsSettingPath { get { return GlobalVar.allProcessPath + Name + "\\A_ProcessInputs.json"; } } public string allProcessOutputsSettingPath { get { return GlobalVar.allProcessPath + Name + "\\A_ProcessOutputs.json"; } } public ConcurrentDictionary>> dicInputsMapping = new ConcurrentDictionary>>(); public ConcurrentDictionary> dicOutputsMapping = new ConcurrentDictionary>(); public ProcessRunBll() { } public ProcessRunBll(string Name , ObservableConcurrentDictionary dicCameras , ObservableConcurrentDictionary dicCommunicators) { this.Name = Name; this.dicCameras = dicCameras; this.dicCommunicators = dicCommunicators; } public bool Load(out string msg) { try { if (!LoadInputs()) { msg = "加载输入失败"; return false; } if (!LoadOutputs()) { msg = "加载输出失败"; return false; } if (!allProcessPath.Contains(".nds")) { msg = "文件路径不完整"; return false; } ProcessContext = new ProcessContext(dicCameras, dicCommunicators, dicInputsMapping, dicOutputsMapping); nodesControl = new FlowPanel(ProcessContext); if (!File.Exists(allProcessPath)) { Save(out msg); msg = "文件不存在,创建默认布局"; } else { byte[] bytes = File.ReadAllBytes(allProcessPath); try { nodesControl.Load(allProcessPath); } catch { msg = $"文件损坏,长度为{bytes.Length}"; return false; } } foreach (var node in nodesControl.GetAllNodes().Values) { string ProcessName = node.Text; string ClassDescription = node.Description; string ClassName = Node2ToolClassName(ClassDescription); string ProcessPath = GlobalVar.allProcessPath + Name + "\\" + ProcessName + ".json"; if (!AddStep(Name, ProcessName, ClassName, ProcessPath)) LogInfo?.Invoke(string.Format("流程[{0}]添加\"{1}\"失败", Name, ProcessName), LogInfoType.ERROR); } msg = "加载布局成功"; CompileMappings(); return true; } catch { msg = "加载布局失败"; return false; } } public bool Save(out string msg) { try { if (!SaveInputs()) { msg = "保存输入失败"; return false; } if (!SaveOutputs()) { msg = "保存输出失败"; return false; } var dicSteps = GetSteps(); if (nodesControl.Save(allProcessPath)) { msg = "保存布局成功"; return true; } else { msg = "保存布局失败"; return false; } } catch { msg = "保存布局失败"; return false; } } public bool LoadInputs() { try { if (!allProcessInputsSettingPath.Contains(".json")) { Debug.WriteLine("文件路径不完整"); return false; } if (!File.Exists(allProcessInputsSettingPath)) { Debug.WriteLine("文件不存在创建空文件"); // 获取不带文件名的目录路径 string directoryPath = Path.GetDirectoryName(allProcessInputsSettingPath); SaveInputs(); return true; } // 如果文件存在,则先移除隐藏属性 if (File.Exists(allProcessInputsSettingPath)) File.SetAttributes(allProcessInputsSettingPath, File.GetAttributes(allProcessInputsSettingPath) & ~FileAttributes.Hidden); string strJson = string.Empty; using (StreamReader streamReader = new StreamReader(allProcessInputsSettingPath, Encoding.UTF8)) { strJson = streamReader.ReadToEnd(); streamReader.Close(); } dicInputsMapping = JsonConvert.DeserializeObject>>>(strJson); if (File.Exists(allProcessInputsSettingPath)) { // 获取文件信息 FileInfo fileInfo = new FileInfo(allProcessInputsSettingPath); // 设置文件为隐藏 fileInfo.Attributes |= FileAttributes.Hidden; } if (dicInputsMapping == null) return false; SaveInputs(); return true; } catch { return false; } } public bool SaveInputs() { string strJson = string.Empty; var settings = new JsonSerializerSettings { Formatting = Newtonsoft.Json.Formatting.Indented, // 自定义缩进(4空格) ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() } }; strJson = JsonConvert.SerializeObject(dicInputsMapping, settings); //判断文件夹是否存在,防呆输入为文件名称 if (!Directory.Exists(Path.GetDirectoryName(allProcessInputsSettingPath))) { try { Directory.CreateDirectory(Path.GetDirectoryName(allProcessInputsSettingPath)); } catch (Exception) { } } // 如果文件存在,则先移除隐藏属性 if (File.Exists(allProcessInputsSettingPath)) File.SetAttributes(allProcessInputsSettingPath, File.GetAttributes(allProcessInputsSettingPath) & ~FileAttributes.Hidden); File.WriteAllText(allProcessInputsSettingPath, strJson, Encoding.UTF8); if (File.Exists(allProcessInputsSettingPath)) { // 获取文件信息 FileInfo fileInfo = new FileInfo(allProcessInputsSettingPath); // 设置文件为隐藏 fileInfo.Attributes |= FileAttributes.Hidden; } CompileMappings(); return true; } public bool LoadOutputs() { try { if (!allProcessOutputsSettingPath.Contains(".json")) { Debug.WriteLine("文件路径不完整"); return false; } if (!File.Exists(allProcessOutputsSettingPath)) { Debug.WriteLine("文件不存在创建空文件"); // 获取不带文件名的目录路径 string directoryPath = Path.GetDirectoryName(allProcessOutputsSettingPath); SaveInputs(); return true; } // 如果文件存在,则先移除隐藏属性 if (File.Exists(allProcessOutputsSettingPath)) File.SetAttributes(allProcessOutputsSettingPath, File.GetAttributes(allProcessOutputsSettingPath) & ~FileAttributes.Hidden); string strJson = string.Empty; using (StreamReader streamReader = new StreamReader(allProcessOutputsSettingPath, Encoding.UTF8)) { strJson = streamReader.ReadToEnd(); streamReader.Close(); } dicOutputsMapping = JsonConvert.DeserializeObject>>(strJson); if (File.Exists(allProcessOutputsSettingPath)) { // 获取文件信息 FileInfo fileInfo = new FileInfo(allProcessOutputsSettingPath); // 设置文件为隐藏 fileInfo.Attributes |= FileAttributes.Hidden; } if (dicOutputsMapping == null) return false; SaveOutputs(); return true; } catch { return false; } } public bool SaveOutputs() { string strJson = string.Empty; var settings = new JsonSerializerSettings { Formatting = Newtonsoft.Json.Formatting.Indented, // 自定义缩进(4空格) ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() } }; strJson = JsonConvert.SerializeObject(dicOutputsMapping, settings); //判断文件夹是否存在,防呆输入为文件名称 if (!Directory.Exists(Path.GetDirectoryName(allProcessOutputsSettingPath))) { try { Directory.CreateDirectory(Path.GetDirectoryName(allProcessOutputsSettingPath)); } catch (Exception) { } } // 如果文件存在,则先移除隐藏属性 if (File.Exists(allProcessOutputsSettingPath)) File.SetAttributes(allProcessOutputsSettingPath, File.GetAttributes(allProcessOutputsSettingPath) & ~FileAttributes.Hidden); File.WriteAllText(allProcessOutputsSettingPath, strJson, Encoding.UTF8); if (File.Exists(allProcessOutputsSettingPath)) { // 获取文件信息 FileInfo fileInfo = new FileInfo(allProcessOutputsSettingPath); // 设置文件为隐藏 fileInfo.Attributes |= FileAttributes.Hidden; } CompileMappings(); return true; } /// /// 添加单个步骤到流程队列中 /// /// /// /// /// /// public bool AddStep(string Name, string ProcessName, string ClassName, string ProcessPath) { try { if (nodesControl == null || !(nodesControl.Context is ProcessContext)) return false; if (((ProcessContext)nodesControl.Context).dicContext.ContainsKey(ProcessName)) { LogInfo?.Invoke(string.Format("流程[{0}]已存在步骤[{1}]添加失败", Name, ProcessName), LogInfoType.WARN); return false; } //利用反射进行创建 if (ClassName.Contains("Cameras")) { Type type = IProcess.GetExecutingAssembly().GetType(ClassName.Split(',')[0]); if (type == null) { Debug.WriteLine("Class not found."); return false; } CameraConfig CameraConfig = Activator.CreateInstance(type, new object[] { dicCameras.Items }) as CameraConfig; if (CameraConfig == null) { Debug.WriteLine("Cameras not found."); return false; } CameraConfig.Load(ProcessPath); CameraConfig.strProcessName = ProcessName; AddInputsAndOutputs(CameraConfig.strProcessName, CameraConfig); } else if (ClassName.Contains("Communicators")) { Type type = IProcess.GetExecutingAssembly().GetType(ClassName.Split(',')[0]); if (type == null) { Debug.WriteLine("Class not found."); return false; } CommunicatorConfig CommunicatorConfig = Activator.CreateInstance(type, new object[] { dicCommunicators.Items }) as CommunicatorConfig; if (CommunicatorConfig == null) { Debug.WriteLine("Communicators not found."); return false; } CommunicatorConfig.Load(ProcessPath); CommunicatorConfig.strProcessName = ProcessName; AddInputsAndOutputs(CommunicatorConfig.strProcessName, CommunicatorConfig); } else if (!string.IsNullOrEmpty(ClassName)) { //利用反射进行创建 Type type = IProcess.GetExecutingAssembly().GetType(ClassName.Split(',')[0]); if (type == null) { Debug.WriteLine("Class not found."); return false; } IProcess process = Activator.CreateInstance(type) as IProcess; if (process == null) { Debug.WriteLine("IProcess not found."); return false; } process.Load(ProcessPath); process.strProcessName = ProcessName; //if (process is VisionProTool && Tool.ContainsChinese(ProcessName)) // MessageBox.Show($"VisionPro工具不支持命名为中文:{ProcessName}", "异常"); if (process is ScriptTool script) { if (script.Params.Outputs.Count <= 0) script.Params.Outputs.Add("Branch0", true); if (script.Params.Outputs.Count <= 1) script.Params.Outputs.Add("Branch1", false); } AddInputsAndOutputs(process.strProcessName, process); } LogInfo?.Invoke(string.Format("流程[{0}]添加步骤[{1}]", Name, ProcessName), LogInfoType.INFO); return true; } catch (Exception ex) { Debug.WriteLine("AddProcessToList失败,原因是" + ex.Message.ToString()); return false; } } public void AddInputsAndOutputs(string name, IProcess obj) { try { if (obj == null) return; if (nodesControl.Context == null || !(nodesControl.Context is ProcessContext)) return; ((ProcessContext)nodesControl.Context).dicContext.TryAdd(name, obj); if (obj is IProcess process) { if (!dicInputsMapping.ContainsKey(name)) { dicInputsMapping.TryAdd(name, new List>()); dicInputsMapping[name].Add(new Tuple(name + ".Inputs.Image", "")); //dicInputsMapping[name].Add(new Tuple(name + ".Inputs.Fixture", "")); foreach (var item in process.Params.Inputs) dicInputsMapping[name].Add(new Tuple(name + ".Inputs." + item.Name, "")); } if (!dicOutputsMapping.ContainsKey(name)) { dicOutputsMapping.TryAdd(name, new List()); dicOutputsMapping[name].Add(name + ".Outputs.Image"); dicOutputsMapping[name].Add(name + ".Outputs.Record"); dicOutputsMapping[name].Add(name + ".Outputs.Result"); //dicOutputsMapping[name].Add(name + ".Outputs.Fixture"); foreach (var item in process.Params.Outputs) dicOutputsMapping[name].Add(name + ".Outputs." + item.Name); } CompileMappings(); } } catch { } } public void CompileMappings() { try { if (ProcessContext != null) { ProcessContext.CompileMappings(); } } catch { } } public void UpdataInputsAndOutputs(string name, IProcess obj) { if (obj == null) return; if (obj is IProcess process) { if (dicInputsMapping.ContainsKey(name)) { foreach (var item in process.Params.Inputs) { if (dicInputsMapping[name].Where(x => x.Item1 == name + ".Inputs." + item.Name).Count() == 0) dicInputsMapping[name].Add(new Tuple(name + ".Inputs." + item.Name, "")); } } if (dicOutputsMapping.ContainsKey(name)) { foreach (var item in process.Params.Outputs) { if (dicOutputsMapping[name].Where(x => x == name + ".Outputs." + item.Name).Count() == 0) dicOutputsMapping[name].Add(name + ".Outputs." + item.Name); } } CompileMappings(); } } public bool Remove(string ProcessName) { try { if (ProcessContext == null) return false; ConcurrentDictionary dicSteps = GetSteps(); if (!dicSteps.ContainsKey(ProcessName)) return false; Object obj = dicSteps[ProcessName]; if (obj == null) return false; string strProcessName = ((IProcess)obj).strProcessName; if (!string.IsNullOrEmpty(strProcessName)) { dicInputsMapping.TryRemove(strProcessName, out List> tempInputs); dicOutputsMapping.TryRemove(strProcessName, out List tempOutputs); if (dicSteps.TryRemove(strProcessName, out IProcess tempObj)) LogInfo?.Invoke(string.Format("流程[{0}]移除步骤[{1}]", Name, strProcessName), LogInfoType.INFO); else LogInfo?.Invoke(string.Format("流程[{0}]移除步骤[{1}]失败", Name, strProcessName), LogInfoType.WARN); SaveInputs(); SaveOutputs(); CompileMappings(); return true; } return false; } catch { return false; } } void Rename(IProcess obj, string newName) { if (obj == null) return; ((IProcess)obj).strProcessName = newName; LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤[{1}]", Name, newName), LogInfoType.INFO); } /// /// 重命名步骤(!不是重命名流程!) /// /// /// public void Rename(string oldName, string newName) { if (ProcessContext == null) return; var dicSteps = GetSteps(); if (!dicSteps.ContainsKey(oldName)) return; dicSteps.TryRemove(oldName, out IProcess process); dicSteps.TryAdd(newName, process); Rename(process, newName); ConcurrentDictionary>> dicInputsMapping = new ConcurrentDictionary>>(); foreach (var InputsMapping in this.dicInputsMapping) { if (InputsMapping.Key == oldName) { List> tempTuples = new List>(); foreach (var tuple in InputsMapping.Value) { string[] arrInputs = tuple.Item1.Split("."); string InputProcessName = arrInputs[0]; string strInput = arrInputs[1]; string InputValueName = arrInputs[2]; string Input = ""; if (InputProcessName == oldName) Input = newName + "." + strInput + "." + InputValueName; else Input = tuple.Item1; tempTuples.Add(Tuple.Create(Input, tuple.Item2)); } dicInputsMapping.TryAdd(newName, tempTuples); } else { List> tempTuples = new List>(); foreach (var tuple in InputsMapping.Value) { string[] arrInputs = tuple.Item1.Split("."); if (arrInputs.Length < 3) { tempTuples.Add(tuple); continue; } string InputProcessName = arrInputs[0]; string strInput = arrInputs[1]; string InputValueName = arrInputs[2]; string[] arrOutputs = tuple.Item2.Split("."); if (arrOutputs.Length < 3) { tempTuples.Add(tuple); continue; } string IndexProcessName = arrOutputs[0]; string IndexIsInputOrOutput = arrOutputs[1]; string IndexValueName = arrOutputs[2]; if (IndexProcessName == oldName) { tempTuples.Add(new Tuple(tuple.Item1 , string.Format("{0}.{1}.{2}", newName, IndexIsInputOrOutput, IndexValueName))); } else tempTuples.Add(tuple); } dicInputsMapping.TryAdd(InputsMapping.Key, tempTuples); } } this.dicInputsMapping = ProcessContext.dicInputsMapping = dicInputsMapping; ConcurrentDictionary> dicOutputsMapping = new ConcurrentDictionary>(); foreach (var OutputsMapping in this.dicOutputsMapping) { if (OutputsMapping.Key == oldName) { List listOutputs = new List(); foreach (string Output in OutputsMapping.Value) { string[] arrOutputs = Output.Split("."); if (arrOutputs.Length < 3) { listOutputs.Add(Output); continue; } string IndexProcessName = arrOutputs[0]; string IndexIsInputOrOutput = arrOutputs[1]; string IndexValueName = arrOutputs[2]; if (IndexProcessName == oldName) { listOutputs.Add(string.Format("{0}.{1}.{2}", newName, IndexIsInputOrOutput, IndexValueName)); } else listOutputs.Add(Output); } dicOutputsMapping.TryAdd(newName, listOutputs); } else dicOutputsMapping.TryAdd(OutputsMapping.Key, OutputsMapping.Value); } this.dicOutputsMapping = ProcessContext.dicOutputsMapping = dicOutputsMapping; SaveInputs(); SaveOutputs(); CompileMappings(); } double total_OK; double total_NG; public double total { get { return total_OK + total_NG; } } public double Rate_OK { get { if (total == 0) return 100; return (total_OK / total) * 100; } } public void ClearTotal() { total_OK = 0; total_NG = 0; } /// /// 调用Run必须是在Inovk中否则会报线程错误,该类的Run调用需要封装在UI内 /// /// /// public bool Run() { bPruning = true; bCompleted = false; DateTime StartTime = DateTime.Now; try { Result = true; if (!nodesControl.Run(out string msg) && !string.IsNullOrEmpty(msg)) { Msg += $"【{msg}】"; Result &= false; } } catch (Exception ex) { Result = false; Msg = string.Format("运行发送了意外{0}", ex.Message.Trim()); } RunTime = (DateTime.Now - StartTime).TotalMilliseconds; bPruning = false; bCompleted = true; if (Result) { total_OK++; Msg = "运行成功"; } else total_NG++; if (IProcess.dicGlobalVars.ContainsKey($"{Name}.Result")) IProcess.dicGlobalVars[$"{Name}.Result"] = Result; else IProcess.dicGlobalVars.TryAdd($"{Name}.Result", Result); if (IProcess.dicGlobalVars.ContainsKey($"{Name}.Msg")) IProcess.dicGlobalVars[$"{Name}.Msg"] = Msg; else IProcess.dicGlobalVars.TryAdd($"{Name}.Msg", Msg); // 手动触发垃圾回收 GC.Collect(); return Result; } public void LogoInfo(string info, LogInfoType logInfoType) { LogInfo?.Invoke(info, logInfoType); } } }