using HalconDotNet;
using OpenCvSharp;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Collections.Concurrent;
using LB_VisionControl;
using LB_SmartVision.ProcessRun;
using LB_VisionProcesses;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Communicators;
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
public partial class ProcessPage : UserControl
{
///
/// 运行步骤(object为IProces或者object为ICamera)
///
public ProcessRunBll ProcessRunBll { get; set; }
public Action LogInfo;
private UserHSmartWindowControl UserHSmartWindowControl = new UserHSmartWindowControl();
public ProcessPage()
{
InitializeComponent();
}
public ProcessPage(string Name, ProcessRunBll ProcessRunBll)
{
InitializeComponent();
this.Text = "ProcessPage";
this.Name = Name;
this.ProcessRunBll = ProcessRunBll;
Name = ProcessRunBll.Name;
Text = ProcessRunBll.Name;
this.splitContainer1.Panel1.Controls.Add(UserHSmartWindowControl);
UserHSmartWindowControl.Dock = DockStyle.Fill;
this.panel1.Controls.Add(ProcessRunBll.nodesControl);
ProcessRunBll.nodesControl.Location = new System.Drawing.Point(0, 0);
ProcessRunBll.nodesControl.Size = new System.Drawing.Size(5000, 5000);
RemoveAllHandler();
ProcessRunBll.nodesControl.AddNodeAction += AddProcess;
ProcessRunBll.nodesControl.RenameNodeAction += RenameProcess;
ProcessRunBll.nodesControl.InAndOutNodeAction += InAndOutProcess;
ProcessRunBll.nodesControl.DeleteNodeAction += DeleteProcess;
ProcessRunBll.nodesControl.EditNodeAction += EditProcess;
ProcessRunBll.nodesControl.AddBranchAction += AddBranch;
ProcessRunBll.nodesControl.DeleteBranchAction += DeleteBranch;
}
private void ProcessPage_Paint(object sender, PaintEventArgs e)
{
if (ProcessRunBll.Result)
btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Success;
else
btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Danger;
if (ProcessRunBll.GetImage(out _, out HObject RecordImage))
UserHSmartWindowControl.ShowHoImage(RecordImage);
}
public void RemoveAllHandler()
{
ProcessRunBll.nodesControl.AddNodeAction -= AddProcess;
ProcessRunBll.nodesControl.RenameNodeAction -= RenameProcess;
ProcessRunBll.nodesControl.InAndOutNodeAction -= InAndOutProcess;
ProcessRunBll.nodesControl.DeleteNodeAction -= DeleteProcess;
ProcessRunBll.nodesControl.EditNodeAction -= EditProcess;
ProcessRunBll.nodesControl.AddBranchAction -= AddBranch;
ProcessRunBll.nodesControl.DeleteBranchAction -= DeleteBranch;
}
private void btn_Run_Click(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
UserHSmartWindowControl.ClearObj();
LogInfo?.Invoke(string.Format("流程[{0}]开始运行", this.ProcessRunBll.Name), LogInfoType.INFO);
bool result = this.ProcessRunBll.Run();
string msg = ProcessRunBll.Msg;
LogInfo?.Invoke(string.Format("流程[{0}]运行完成,结果:{1}", this.ProcessRunBll.Name, msg)
, result ? LogInfoType.PASS : LogInfoType.ERROR);
if (ProcessRunBll.GetImage(out _, out HObject RecordImage))
UserHSmartWindowControl.ShowHoImage(RecordImage);
if (result)
btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Success;
else
btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Danger;
}));
}
public void AddProcess(string ProcessName, string Descript)
{
string ClassName = ProcessRunBll.Node2ToolClassName(Descript);
string ProcessPath = GlobalVar.allProcessPath + ProcessRunBll.Name + "\\" + ProcessName + ".json";
if (ProcessRunBll.AddStep(ProcessRunBll.Name, ProcessName, ClassName, ProcessPath))
{
ProcessRunBll.SaveInputs();
ProcessRunBll.SaveOutputs();
ProcessRunBll.CompileMappings();
}
else
LogInfo?.Invoke(string.Format("流程[{0}]添加步骤\"{1}\"失败", this.Text, ProcessName), LogInfoType.ERROR);
}
private void InAndOutProcess(string ProcessName)
{
var dicSteps = ProcessRunBll.GetSteps();
if (!dicSteps.ContainsKey(ProcessName))
return;
ProcessInputsSelectForm inputsSelectForm = new ProcessInputsSelectForm(ProcessName, ProcessRunBll);
inputsSelectForm.ProcessName = ProcessName;
inputsSelectForm.ShowDialog();
ProcessRunBll.SaveInputs();
ProcessRunBll.SaveOutputs();
ProcessRunBll.CompileMappings();
string ProcessPath = GlobalVar.allProcessPath + ProcessRunBll.Name + "\\" + ProcessName + ".json";
((IProcess)dicSteps[ProcessName]).Load(ProcessPath);
}
public void DeleteProcess(string ProcessName)
{
try
{
var dicSteps = ProcessRunBll.GetSteps();
if (!dicSteps.ContainsKey(ProcessName))
return;
string ProcessPath = GlobalVar.allProcessPath + ProcessRunBll.Name + "\\" + ProcessName + ".json";
if (string.IsNullOrEmpty(ProcessName) || string.IsNullOrEmpty(ProcessPath))
return;
// 获取所有文件(不管后缀名是什么)并进行遍历
string directoryPath = Path.GetDirectoryName(ProcessPath);
string[] files = Directory.GetFiles(directoryPath, ProcessName + ".*"); // 匹配所有名称为aa的文件,后缀不限
foreach (var file in files)
{
try
{
if (File.Exists(file))
File.Delete(file);
}
catch (Exception ex)
{
Debug.WriteLine($"删除文件 {file} 时出错: {ex.Message}");
LogInfo?.Invoke(string.Format("流程[{0}]移除步骤\"{1}\"失败,原因是{2}", this.Text, ProcessName, ex.Message), LogInfoType.ERROR);
return;
}
}
if (Directory.Exists(directoryPath + "\\" + ProcessName))
Directory.Delete(directoryPath + "\\" + ProcessName, true);
if (!ProcessRunBll.Remove(ProcessName))
LogInfo?.Invoke(string.Format("流程[{0}]移除步骤\"{1}\"失败", this.Text, ProcessName), LogInfoType.ERROR);
}
catch (Exception ex) { Debug.WriteLine(ex.Message); }
}
private void RenameProcess(string ProcessName, string newProcessName)
{
ConcurrentDictionary dicSteps = ProcessRunBll.GetSteps();
if (!dicSteps.ContainsKey(ProcessName))
return;
ProcessRenameEvent(ProcessName, newProcessName);
}
private void ProcessRenameEvent(string oriName, string newName)
{
ConcurrentDictionary dicSteps = ProcessRunBll.GetSteps();
//更新后的步骤名仍然需要是唯一
if (dicSteps.ContainsKey(newName))
{
MessageBox.Show(string.Format("重命名失败,步骤名称[{0}]已存在!", newName), "异常");
return;
}
if (dicSteps.ContainsKey(oriName))
{
string oriPath = GlobalVar.allProcessPath + this.Text + "\\" + oriName + ".json";
string newPath = GlobalVar.allProcessPath + this.Text + "\\" + newName + ".json";
string directoryPath = Path.GetDirectoryName(oriPath);
string[] files = new string[] { };
// 重命名当前文件夹
files = Directory.GetFiles(directoryPath, oriName + ".*"); // 匹配所有名称为oriName的文件,后缀不限
foreach (var file in files)
{
try
{
// 获取文件的扩展名
string extension = Path.GetExtension(file);
// 构造新文件名
string newFileName = Path.Combine(directoryPath, newName + extension);
if (!File.Exists(newFileName))
{
// 重命名文件
File.Move(file, newFileName);
Debug.WriteLine($"文件已重命名: {file} -> {newFileName}");
}
else
{
LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"失败,原因是{3}", this.Text, oriName, newName, "命名重复"), LogInfoType.ERROR);
return;
}
}
catch (Exception ex)
{
Debug.WriteLine($"重命名文件 {file} 时出错: {ex.Message}");
LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"失败,原因是{3}", this.Text, oriName, newName, ex.Message), LogInfoType.ERROR);
return;
}
}
// 重命名当前文件夹
if (Directory.Exists(directoryPath + "\\" + oriName))
{
Directory.Move(directoryPath + "\\" + oriName, directoryPath + "\\" + newName);
// 重命名子文件夹
string newParentDirectory = Path.GetDirectoryName(GlobalVar.allProcessPath + this.Text + "\\" + newName + "\\" + oriName + ".json");
files = Directory.GetFiles(newParentDirectory, oriName + ".*"); // 匹配子文件夹内所有名称为oriName的文件,后缀不限(一般只有一个)
foreach (var file in files)
{
try
{
// 获取文件的扩展名
string extension = Path.GetExtension(file);
// 构造新文件名
string newFileName = Path.Combine(newParentDirectory, newName + extension);
if (!File.Exists(newFileName))
{
if (!Directory.Exists(newParentDirectory))
Directory.CreateDirectory(newParentDirectory);
// 重命名文件
File.Move(file, newFileName);
Debug.WriteLine($"文件已重命名: {file} -> {newFileName}");
}
else
{
LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"失败,原因是{3}", this.Text, oriName, newName, "命名重复"), LogInfoType.ERROR);
return;
}
}
catch (Exception ex)
{
Debug.WriteLine($"重命名文件 {file} 时出错: {ex.Message}");
LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"失败,原因是{3}", this.Text, oriName, newName, ex.Message), LogInfoType.ERROR);
return;
}
}
}
ProcessRunBll.Rename(oriName, newName);
LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"成功", this.Text, oriName, newName), LogInfoType.PASS);
//if (dicSteps[newName] is VisionProTool && Tool.ContainsChinese(newName))
// MessageBox.Show($"VisionPro工具不支持命名为中文:{newName}", "异常");
}
}
private void EditProcess(string ProcessName)
{
try
{
ConcurrentDictionary dicSteps = ProcessRunBll.GetSteps();
if (!dicSteps.ContainsKey(ProcessName))
return;
string ClassName = dicSteps[ProcessName].GetType().ToString();
string ProcessPath = GlobalVar.allProcessPath + ProcessRunBll.Name + "\\" + ProcessName + ".json";
if (string.IsNullOrEmpty(ProcessName) || string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(ProcessPath))
return;
//利用反射创建实例
Type type = IProcess.GetExecutingAssembly().GetType(ClassName);
if (type == null)
{
LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"打开失败了,类[{2}]不存在", this.Text, ProcessName, ClassName), LogInfoType.ERROR);
return;
}
IProcess process = ((IProcess)dicSteps[ProcessName]).Clone() as IProcess;
Object InputImage = new Object();
if (process.InputImage != null)
{
if (process.InputImage is HObject ho_image && ho_image.IsInitialized())
InputImage = ho_image.CopyObj(1, -1);
else if (process.InputImage is Mat mat && !mat.Empty())
InputImage = mat.Clone();
else if (process.InputImage is Bitmap bitmap)
InputImage = bitmap.Clone();
}
if (ClassName.Contains("CameraConfig") && process is CameraConfig)
{
LB_VisionProcesses.Cameras.CameraForm cameraForm
= new LB_VisionProcesses.Cameras.CameraForm(GlobalVar.dicCameras.Items, (CameraConfig)process, ProcessPath);
cameraForm.ShowDialog();
if (!(process.Load(ProcessPath)))
LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"加载失败了", this.Text, ProcessName), LogInfoType.ERROR);
process.strProcessName = ProcessName;
}
else if (process is LB_VisionProcesses.Processes.BarcodeReaderProcess)
{
LB_VisionProcesses.BarcodeReaders.BarcodeReaderForm barcodeForm
= new LB_VisionProcesses.BarcodeReaders.BarcodeReaderForm((LB_VisionProcesses.Processes.BarcodeReaderProcess)process, ProcessPath);
barcodeForm.ShowDialog();
if (!(process.Load(ProcessPath)))
LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"加载失败了", this.Text, ProcessName), LogInfoType.ERROR);
process.strProcessName = ProcessName;
}
else if (ClassName.Contains("CommunicatorConfig") && process is CommunicatorConfig)
{
LB_VisionProcesses.Communicators.CommunicatorForm communicatorForm
= new LB_VisionProcesses.Communicators.CommunicatorForm(GlobalVar.dicCommunicators.Items, (CommunicatorConfig)process, ProcessPath);
communicatorForm.ShowDialog();
if (!(process.Load(ProcessPath)))
LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"加载失败了", this.Text, ProcessName), LogInfoType.ERROR);
process.strProcessName = ProcessName;
}
else
{
ProcessEditForm processEditForm = new ProcessEditForm(process, ProcessPath);
processEditForm.ShowDialog();
//重新加载更新后的步骤
if (processEditForm.hasChanged)
LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"更新了", this.Text, ProcessName), LogInfoType.WARN);
if (!(process.Load(ProcessPath)))
LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"加载失败了", this.Text, ProcessName), LogInfoType.ERROR);
process.strProcessName = ProcessName;
}
if (InputImage != null)
{
if (InputImage is HObject ho_image && ho_image.IsInitialized())
process.InputImage = ho_image.CopyObj(1, -1);
else if (InputImage is Mat mat && !mat.Empty())
process.InputImage = mat.Clone();
else if (InputImage is Bitmap bitmap)
process.InputImage = bitmap.Clone();
}
dicSteps[ProcessName] = process;
ProcessRunBll.UpdataInputsAndOutputs(ProcessName, process);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
MessageBox.Show($"打开配置界面失败: {ex.Message}\n{ex.StackTrace}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void AddBranch(string ProcessName)
{
var dicSteps = ProcessRunBll.GetSteps();
if (!dicSteps.ContainsKey(ProcessName))
return;
// 多分支的本质为脚本工具,根据branchIndex来走对应的分支
if (dicSteps[ProcessName] is LB_VisionProcesses.Processes.ScriptTool.ScriptTool ScriptTool)
{
ScriptTool.Params.Outputs.Add($"Branch{ScriptTool.Params.Outputs.Count}", false);
Debug.WriteLine($"脚本工具[{ProcessName}]增加了Branch{ScriptTool.Params.Outputs.Count - 1}");
}
}
private void DeleteBranch(string ProcessName)
{
var dicSteps = ProcessRunBll.GetSteps();
if (!dicSteps.ContainsKey(ProcessName))
return;
// 多分支的本质为脚本工具,根据branchIndex来走对应的分支
if (dicSteps[ProcessName] is LB_VisionProcesses.Processes.ScriptTool.ScriptTool ScriptTool
&& ScriptTool.Params.Outputs.Remove($"Branch{ScriptTool.Params.Outputs.Count}"))
{
Debug.WriteLine($"脚本工具[{ProcessName}]移除了Branch{ScriptTool.Params.Outputs.Count + 1}");
}
}
}
}