using RobotApp.VDA5050.InstantAction; using RobotApp.VDA5050.Order; using System.Text.Json.Serialization; namespace RobotApp.Client.Services; // ====================================================== // EDGE UI // ====================================================== public class UiEdge : VDA5050.Order.Edge { public double Radius { get; set; } = 0.0; public Quadrant Quadrant { get; set; } = Quadrant.I; // Đánh dấu đã expand chưa public bool Expanded { get; set; } = false; } 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 int HeaderId { get; set; } public string Timestamp { get; set; } = ""; public string Version { get; set; } = "v1"; public string Manufacturer { get; set; } = "PNKX"; public string SerialNumber { get; set; } = "T800-002"; public string OrderId { get; set; } = Guid.NewGuid().ToString(); public int OrderUpdateId { get; set; } public string? ZoneSetId { get; set; } public List Nodes { get; set; } = new(); public List Edges { get; set; } = new(); public static Node CreateCurveNode(Node startNode, UiEdge edge) { var A = new Point( startNode.NodePosition.X, startNode.NodePosition.Y ); var result = QuarterGeometry.BuildQuarterTrajectory( A, edge.Radius, edge.Quadrant ); return new Node { NodeId = $"NODE_C{Guid.NewGuid():N}".Substring(0, 12), Released = true, NodePosition = new NodePosition { X = result.EndPoint.X, Y = result.EndPoint.Y, Theta = startNode.NodePosition.Theta, MapId = startNode.NodePosition.MapId } }; } public object ToSchemaObject() { int seq = 0; return new { headerId = HeaderId++, timestamp = string.IsNullOrWhiteSpace(Timestamp) ? DateTime.UtcNow.ToString("O") : Timestamp, version = Version, manufacturer = Manufacturer, serialNumber = SerialNumber, orderId = OrderId, orderUpdateId = OrderUpdateId, zoneSetId = string.IsNullOrWhiteSpace(ZoneSetId) ? null : ZoneSetId, // ================= NODES ================= nodes = Nodes.Select(n => new { nodeId = n.NodeId, sequenceId = seq++, released = n.Released, nodePosition = new { 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 { actionId = a.ActionId, actionType = a.ActionType, blockingType = a.BlockingType, actionParameters = a.ActionParameters != null ? a.ActionParameters .Select(p => new { key = p.Key, value = p.Value }) .ToArray() : Array.Empty() }).ToArray() }).ToArray(), // ================= EDGES ================= edges = Edges.Select(e => { // ---------- ĐƯỜNG THẲNG ---------- if (e.Radius <= 0) { return new { edgeId = e.EdgeId, sequenceId = seq++, released = true, startNodeId = e.StartNodeId, endNodeId = e.EndNodeId, actions = Array.Empty() }; } // ---------- ĐƯỜNG CONG 1/4 ---------- var startNode = Nodes.First(n => n.NodeId == e.StartNodeId); var A = new Point( startNode.NodePosition.X, startNode.NodePosition.Y ); var result = QuarterGeometry.BuildQuarterTrajectory( A, e.Radius, e.Quadrant ); return new { edgeId = e.EdgeId, sequenceId = seq++, released = true, startNodeId = e.StartNodeId, endNodeId = e.EndNodeId, trajectory = result.Trajectory, actions = Array.Empty() }; }).ToArray() }; } } // ====================================================== // UI ACTION PARAM // ====================================================== public class UiActionParameter : ActionParameter { [JsonIgnore] public string ValueString { get => Value?.ToString() ?? ""; set => Value = value; } }