using RobotApp.VDA5050.InstantAction; using RobotApp.VDA5050.Order; using System.Text.Json; using System.Text.Json.Serialization; using System.Xml.Linq; namespace RobotApp.Client.Services; // ====================================================== // EDGE UI // ====================================================== public class UiEdge { public string EdgeId { get; set; } = ""; public int SequenceId { get; set; } public bool Released { get; set; } = true; public string StartNodeId { get; set; } = ""; public string EndNodeId { get; set; } = ""; // ===== CURVE (EDITOR GENERATED) ===== public double Radius { get; set; } = 0; public Quadrant Quadrant { get; set; } // ===== IMPORTED TRAJECTORY ===== public bool HasTrajectory { get; set; } = false; public UiTrajectory? Trajectory { get; set; } // ===== UI STATE ===== public bool Expanded { get; private set; } = false; public void MarkExpanded() { Expanded = true; } } public class UiTrajectory { public int Degree { get; set; } public double[] KnotVector { get; set; } = Array.Empty(); public List ControlPoints { get; set; } = new(); } public enum Quadrant { I, II, III, IV } // ====================================================== // GEOMETRY MODELS // ====================================================== public record Point(double X, double Y); public record QuarterResult( Point EndPoint, object Trajectory ); // ====================================================== // GEOMETRY HELPER (QUARTER CIRCLE) // ====================================================== public static class QuarterGeometry { private const double K = 0.5522847498307936; public static QuarterResult BuildQuarterTrajectory( Point A, double r, Quadrant q ) { Point P1, P2, C; switch (q) { case Quadrant.I: P1 = new(A.X, A.Y + K * r); P2 = new(A.X + K * r, A.Y + r); C = new(A.X + r, A.Y + r); break; case Quadrant.II: P1 = new(A.X - K * r, A.Y); P2 = new(A.X - r, A.Y + K * r); C = new(A.X - r, A.Y + r); break; case Quadrant.III: P1 = new(A.X, A.Y - K * r); P2 = new(A.X - K * r, A.Y - r); C = new(A.X - r, A.Y - r); break; case Quadrant.IV: P1 = new(A.X + K * r, A.Y); P2 = new(A.X + r, A.Y - K * r); C = new(A.X + r, A.Y - r); break; default: throw new ArgumentOutOfRangeException(nameof(q)); } return new QuarterResult( C, new { degree = 3, knotVector = new[] { 0, 0, 0, 0, 1, 1, 1, 1 }, controlPoints = new[] { new { x = A.X, y = A.Y }, // P0 new { x = P1.X, y = P1.Y }, // P1 new { x = P2.X, y = P2.Y }, // P2 new { x = C.X, y = C.Y } // P3 } } ); } } // ====================================================== // ORDER MESSAGE // ====================================================== public class OrderMessage { public uint HeaderId { get; set; } public string Timestamp { get; set; } = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); public string Version { get; set; } = "2.1.0"; public string Manufacturer { get; set; } = "PhenikaaX"; public string SerialNumber { get; set; } = "T800-003"; public string OrderId { get; set; } = ""; public int OrderUpdateId { get; set; } public string? ZoneSetId { get; set; } public List Nodes { get; set; } = []; public List Edges { get; set; } = []; public OrderMsg ToSchemaObject() { // ================= SORT NODES BY UI SEQUENCE ================= var orderedNodes = Nodes .OrderBy(n => n.SequenceId) .ToList(); // ================= BUILD NODE OBJECTS ================= var nodeObjects = orderedNodes .Select((n, index) => new Node { NodeId = n.NodeId, SequenceId = index * 2, // ✅ NODE = EVEN Released = n.Released, NodePosition = new NodePosition { X = n.NodePosition.X, Y = n.NodePosition.Y, Theta = n.NodePosition.Theta, AllowedDeviationXY = n.NodePosition.AllowedDeviationXY, AllowedDeviationTheta = n.NodePosition.AllowedDeviationTheta, MapId = string.IsNullOrWhiteSpace(n.NodePosition.MapId) ? "MAP_01" : n.NodePosition.MapId }, Actions = n.Actions? .Select(a => new VDA5050.InstantAction.Action { ActionId = a.ActionId, ActionType = a.ActionType, BlockingType = a.BlockingType, ActionParameters = a.ActionParameters? .Select(p => new ActionParameter { Key = p.Key, Value = p.Value }) .ToArray() ?? [] }) .ToArray() ?? [] }) .ToArray(); // ================= BUILD EDGE OBJECTS ================= Edge[] edgeObjects = Edges .Select((e, index) => { int sequenceId = index * 2 + 1; // ✅ EDGE = ODD // ---------- BASE ---------- var baseEdge = new { edgeId = e.EdgeId, sequenceId, released = true, startNodeId = e.StartNodeId, endNodeId = e.EndNodeId }; // ================================================= // 1️⃣ IMPORTED TRAJECTORY // ================================================= if (e.Trajectory != null) { return new Edge { EdgeId = baseEdge.edgeId, SequenceId = baseEdge.sequenceId, Released= baseEdge.released, StartNodeId= baseEdge.startNodeId, EndNodeId= baseEdge.endNodeId, Trajectory = new Trajectory { Degree = e.Trajectory.Degree, KnotVector = e.Trajectory.KnotVector, ControlPoints = e.Trajectory.ControlPoints .Select(p => new ControlPoint { X = p.X, Y = p.Y , Weight = 1}) .ToArray() }, Actions = [] }; } return new Edge { EdgeId = baseEdge.edgeId, SequenceId = baseEdge.sequenceId, Released = baseEdge.released, StartNodeId = baseEdge.startNodeId, EndNodeId = baseEdge.endNodeId, Actions = [] }; }) .ToArray(); // ================= FINAL SCHEMA OBJECT ================= return new OrderMsg { HeaderId = (uint)HeaderId++, Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"), Version = Version, Manufacturer = Manufacturer, SerialNumber = SerialNumber, OrderId = OrderId= Guid.NewGuid().ToString(), OrderUpdateId = OrderUpdateId, ZoneSetId = string.IsNullOrWhiteSpace(ZoneSetId) ? null : ZoneSetId, Nodes = nodeObjects, Edges = edgeObjects, }; } public void Import(OrderMsg order) { HeaderId = order.HeaderId; Timestamp = order.Timestamp; Version = order.Version; Manufacturer = order.Manufacturer; SerialNumber = order.SerialNumber; OrderId = order.OrderId; ZoneSetId = order.ZoneSetId; OrderUpdateId = order.OrderUpdateId; Nodes = [.. order.Nodes]; Edges = [.. order.Edges]; } } // ====================================================== // UI ACTION PARAM // ====================================================== public class UiActionParameter : ActionParameter { [JsonIgnore] public string ValueString { get => Value?.ToString() ?? ""; set => Value = value; } }