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);
}
}
}