using Hawkeye.VisionBuilder.Workflow.Configuration; using Hawkeye.VisionBuilder.Workflow.Links; using OpenCvSharp; using System.ComponentModel.Design.Serialization; using System.Diagnostics; using System.Drawing; using System.Reflection.PortableExecutable; using System.Xml; using VisionBuilder.UI.Common.RecipeProcessing; using Size = OpenCvSharp.Size; namespace Hawkeye.VisionBuilder.Workflow; public class WorkflowList { public IImageSource ImageSource { get; set; } public Mat? RecipeImage { get; set; } public WorkflowConfiguration Configuration { get; set; } = new WorkflowConfiguration(); public List Operations { get; set; } = new List(); public Context Context { get; set; } = new Context(); private int _executionCounter = 0; public void Execute() { Context.GraphicsElements.Clear(); UpdateConfigVariables(); long total = 0; foreach (BaseOperation operation in Operations) { if (Context.CancellationToken.IsCancellationRequested) break; operation.Interpret(Context); } _executionCounter++; if (_executionCounter % 10 == 0) GC.Collect(); } public BaseOperation GetById(Guid originId) { var operation = Operations.FirstOrDefault(x => x.Id == originId); if(operation==null)return NoOrigin.Instance; return operation as BaseOperation; } public IHaveOrigin GetOriginById(Guid originId) { return GetById(originId) as IHaveOrigin ?? NoOrigin.Instance; } public void ExecuteTill(BaseOperation op) { Context.GraphicsElements.Clear(); UpdateConfigVariables(); foreach (BaseOperation operation in Operations) { if(operation == op) break; operation.Interpret(Context); } } public void ExecuteOne(BaseOperation operation) { Context.GraphicsElements.Clear(); UpdateConfigVariables(); try { operation.Interpret(Context); } catch (Exception e) { operation.SetError(e.Message); } } void UpdateConfigVariables() { BaseOperation.SetScriptValue("config", Configuration); } public void Save(BinaryWriter bw) { Configuration.Save(bw); bw.Write(Operations.Count); foreach (BaseOperation operation in Operations) { bw.Write(operation.GetType().AssemblyQualifiedName); operation.Save(bw); } if (RecipeImage == null) { var mat = new Mat(128, 128, MatType.CV_8UC3, Scalar.Gray); var image = mat.ToBytes(); bw.Write(image.Length); bw.Write(image); } else { var mat = RecipeImage; var image = mat.Resize(new Size(128, 128)).ToBytes(); bw.Write(image.Length); bw.Write(image); } } public event Action PythonMissing=delegate { }; public void Load(BinaryReader br, OperationDiscoveryService operationDiscoveryService) { Configuration.Load(br); if (!File.Exists(Configuration.PythonPath)) PythonMissing(); int count = br.ReadInt32(); Operations.Clear(); for (int i = 0; i < count; i++) { string operationType = br.ReadString(); var type=Type.GetType(operationType); BaseOperation operation = operationDiscoveryService.CreateInstance(type); operation.Load(br); Operations.Add(operation); } int length = br.ReadInt32(); var image = br.ReadBytes(length); RecipeImage = Mat.FromImageData(image); } public static WorkflowList LoadFromFile(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) using (var br = new BinaryReader(fs)) { var workflowList = new WorkflowList(); workflowList.Load(br, new OperationDiscoveryService(workflowList)); return workflowList; } } public void SaveXML(XmlWriter writer) { writer.WriteStartElement("Workflow"); // Save Configuration writer.WriteStartElement("Configuration"); writer.WriteAttributeString("RuntimeCameraType", Configuration.RuntimeCameraType.ToString()); writer.WriteAttributeString("DevelopmentCameraType", Configuration.DevelopmentCameraType.ToString()); writer.WriteAttributeString("Outputs", Configuration.Outputs.ToString()); writer.WriteAttributeString("EmulationPath", Configuration.EmulationPath); writer.WriteAttributeString("PythonPath", Configuration.PythonPath); writer.WriteAttributeString("ResultPin", Configuration.ResultPin.ToString()); writer.WriteAttributeString("SerialPort", Configuration.SerialPort); writer.WriteAttributeString("Delay", Configuration.Delay.ToString()); writer.WriteEndElement(); // Configuration // Save Operations writer.WriteStartElement("Operations"); writer.WriteAttributeString("Count", Operations.Count.ToString()); foreach (BaseOperation operation in Operations) { writer.WriteStartElement("Operation"); writer.WriteAttributeString("Type", operation.GetType().AssemblyQualifiedName); operation.SaveXML(writer); writer.WriteEndElement(); // Operation } writer.WriteEndElement(); // Operations // Save Recipe Image writer.WriteStartElement("RecipeImage"); if (RecipeImage == null) { var mat = new Mat(128, 128, MatType.CV_8UC3, Scalar.Gray); var image = mat.ToBytes(); writer.WriteAttributeString("Length", image.Length.ToString()); writer.WriteBase64(image, 0, image.Length); } else { var mat = RecipeImage; var image = mat.Resize(new Size(128, 128)).ToBytes(); writer.WriteAttributeString("Length", image.Length.ToString()); writer.WriteBase64(image, 0, image.Length); } writer.WriteEndElement(); // RecipeImage writer.WriteEndElement(); // Workflow } public void LoadXML(XmlReader reader, OperationDiscoveryService operationDiscoveryService) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { switch (reader.Name) { case "Configuration": LoadConfigurationXML(reader); break; case "Operations": LoadOperationsXML(reader, operationDiscoveryService); break; case "RecipeImage": LoadRecipeImageXML(reader); break; } } } } private void LoadConfigurationXML(XmlReader reader) { if (reader.GetAttribute("RuntimeCameraType") != null) Configuration.RuntimeCameraType = Enum.Parse(reader.GetAttribute("RuntimeCameraType")); if (reader.GetAttribute("DevelopmentCameraType") != null) Configuration.DevelopmentCameraType = Enum.Parse(reader.GetAttribute("DevelopmentCameraType")); if (reader.GetAttribute("Outputs") != null) Configuration.Outputs = Enum.Parse(reader.GetAttribute("Outputs")); if (reader.GetAttribute("EmulationPath") != null) Configuration.EmulationPath = reader.GetAttribute("EmulationPath"); if (reader.GetAttribute("PythonPath") != null) Configuration.PythonPath = reader.GetAttribute("PythonPath"); if (reader.GetAttribute("ResultPin") != null) Configuration.ResultPin = int.Parse(reader.GetAttribute("ResultPin")); if (reader.GetAttribute("SerialPort") != null) Configuration.SerialPort = reader.GetAttribute("SerialPort"); if (reader.GetAttribute("Delay") != null) Configuration.Delay = int.Parse(reader.GetAttribute("Delay")); } private void LoadOperationsXML(XmlReader reader, OperationDiscoveryService operationDiscoveryService) { Operations.Clear(); while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element && reader.Name == "Operation") { string operationType = reader.GetAttribute("Type"); var type = Type.GetType(operationType); if (type != null) { BaseOperation operation = operationDiscoveryService.CreateInstance(type); // go to child elements of Operation operation.LoadXML(reader); Operations.Add(operation); } } else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Operations") { break; } } } private void LoadRecipeImageXML(XmlReader reader) { if (reader.GetAttribute("Length") != null) { int length = int.Parse(reader.GetAttribute("Length")); byte[] imageData = new byte[length]; int bytesRead = reader.ReadElementContentAsBase64(imageData, 0, length); if (bytesRead > 0) { RecipeImage = Mat.FromImageData(imageData); } } } }