diff --git a/RobotApp.Client/Pages/Dashboard.razor b/RobotApp.Client/Pages/Dashboard.razor index ccb4971..1c1aa8b 100644 --- a/RobotApp.Client/Pages/Dashboard.razor +++ b/RobotApp.Client/Pages/Dashboard.razor @@ -270,7 +270,7 @@ - + @context.Description @@ -309,7 +309,7 @@ Status - @context.ActionType + @context.ActionType @context.ActionId + OnClick="@(() => RemoveEdgeAsync(edge))" /> @@ -88,47 +87,6 @@ } - - @* - - - - - - @if (edge.Radius > 0) - { - - - I - II - III - IV - - - } - - - @if (!edge.HasTrajectory && edge.Radius > 0 && !edge.Expanded) - { - - - Apply Curve (generate node) - - - } *@ - diff --git a/RobotApp.Client/Pages/Order/JsonOutputPanel.razor b/RobotApp.Client/Pages/Order/JsonOutputPanel.razor index fbd2f25..1437aa9 100644 --- a/RobotApp.Client/Pages/Order/JsonOutputPanel.razor +++ b/RobotApp.Client/Pages/Order/JsonOutputPanel.razor @@ -1,7 +1,7 @@  - 📄 JSON Output (/order) + Output (/order)
diff --git a/RobotApp.Client/Pages/Order/OrderMess.razor b/RobotApp.Client/Pages/Order/OrderMess.razor index 85e4f45..1d1a62f 100644 --- a/RobotApp.Client/Pages/Order/OrderMess.razor +++ b/RobotApp.Client/Pages/Order/OrderMess.razor @@ -86,6 +86,7 @@ PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }); } + private async Task OpenImportDialog() { var dialog = await DialogService.ShowAsync( @@ -177,22 +178,19 @@ void RemoveAction(Node node, VDA5050.InstantAction.Action action) { - node.Actions = node.Actions?.Where(a => a != action).ToArray() - ?? Array.Empty(); + node.Actions = node.Actions?.Where(a => a != action).ToArray() ?? []; } void AddActionParameter(VDA5050.InstantAction.Action act) { - var list = (act.ActionParameters ?? Array.Empty()).ToList(); + var list = (act.ActionParameters ?? []).ToList(); list.Add(new UiActionParameter()); act.ActionParameters = list.ToArray(); } void RemoveActionParameter(VDA5050.InstantAction.Action act, ActionParameter param) { - act.ActionParameters = - act.ActionParameters?.Where(p => p != param).ToArray() - ?? Array.Empty(); + act.ActionParameters = act.ActionParameters?.Where(p => p != param).ToArray() ?? []; } // ================= SEND / COPY ================= @@ -302,7 +300,7 @@ _copyCts?.Cancel(); _copyCts = new(); - await JS.InvokeVoidAsync("navigator.clipboard.writeText", OrderJson); + await JS.InvokeVoidAsync("copyToClipboardFallback", OrderJson); copied = true; StateHasChanged(); diff --git a/RobotApp.Client/Services/UiEdge.cs b/RobotApp.Client/Services/UiEdge.cs index 37fadd7..927384a 100644 --- a/RobotApp.Client/Services/UiEdge.cs +++ b/RobotApp.Client/Services/UiEdge.cs @@ -1,127 +1,9 @@ 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 // ====================================================== @@ -141,110 +23,6 @@ public class OrderMessage 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++, @@ -262,8 +40,8 @@ public class OrderMessage ? null : ZoneSetId, - Nodes = nodeObjects, - Edges = edgeObjects, + Nodes = [..Nodes], + Edges = [..Edges], }; } diff --git a/RobotApp.Client/wwwroot/js/app.js b/RobotApp.Client/wwwroot/js/app.js index 5f28270..c0e2497 100644 --- a/RobotApp.Client/wwwroot/js/app.js +++ b/RobotApp.Client/wwwroot/js/app.js @@ -1 +1,10 @@ - \ No newline at end of file +window.copyToClipboardFallback = function (text) { + const textarea = document.createElement('textarea'); + textarea.value = text; + textarea.style.position = 'fixed'; + textarea.style.opacity = '0'; + document.body.appendChild(textarea); + textarea.select(); + document.execCommand('copy'); + document.body.removeChild(textarea); +} \ No newline at end of file diff --git a/RobotApp.VDA5050/State/EdgeState.cs b/RobotApp.VDA5050/State/EdgeState.cs index 9382df6..90d29c6 100644 --- a/RobotApp.VDA5050/State/EdgeState.cs +++ b/RobotApp.VDA5050/State/EdgeState.cs @@ -13,5 +13,5 @@ public class EdgeState public string EdgeDescription { get; set; } = string.Empty; [Required] public bool Released { get; set; } - public Trajectory Trajectory { get; set; } = new(); + public Trajectory? Trajectory { get; set; } } diff --git a/RobotApp/Services/Robot/RobotOrderController.cs b/RobotApp/Services/Robot/RobotOrderController.cs index 64f24ef..bfd0aee 100644 --- a/RobotApp/Services/Robot/RobotOrderController.cs +++ b/RobotApp/Services/Robot/RobotOrderController.cs @@ -480,17 +480,22 @@ public class RobotOrderController(INavigation NavigationManager, for (int i = 0; i < nodes.Count - 1; i++) { if (edges[i] is null) return (NodeStates, [.. pathEdges]); + + var trajectory = edges[i].Trajectory; + var controlPoints = trajectory?.ControlPoints; + + pathEdges.Add(new() { StartX = nodes[i].NodePosition.X, StartY = nodes[i].NodePosition.Y, EndX = nodes[i + 1].NodePosition.X, EndY = nodes[i + 1].NodePosition.Y, - ControlPoint1X = edges[i].Trajectory is not null && edges[i].Trajectory.ControlPoints.Length > 2 ? edges[i].Trajectory.ControlPoints[1].X : 0, - ControlPoint1Y = edges[i].Trajectory is not null && edges[i].Trajectory.ControlPoints.Length > 2 ? edges[i].Trajectory.ControlPoints[1].Y : 0, - ControlPoint2X = edges[i].Trajectory is not null && edges[i].Trajectory.ControlPoints.Length > 3 ? edges[i].Trajectory.ControlPoints[2].X : 0, - ControlPoint2Y = edges[i].Trajectory is not null && edges[i].Trajectory.ControlPoints.Length > 3 ? edges[i].Trajectory.ControlPoints[2].Y : 0, - Degree = edges[i].Trajectory is null ? 1 : edges[i].Trajectory.Degree, + ControlPoint1X = controlPoints is { Length: > 2 } ? controlPoints[1].X : 0, + ControlPoint1Y = controlPoints is { Length: > 2 } ? controlPoints[1].Y : 0, + ControlPoint2X = controlPoints is { Length: > 3 } ? controlPoints[2].X : 0, + ControlPoint2Y = controlPoints is { Length: > 3 } ? controlPoints[2].Y : 0, + Degree = trajectory is null ? 1 : trajectory.Degree, }); } } diff --git a/RobotApp/Services/Robot/RobotPathPlanner.cs b/RobotApp/Services/Robot/RobotPathPlanner.cs index 33f7238..b7919fa 100644 --- a/RobotApp/Services/Robot/RobotPathPlanner.cs +++ b/RobotApp/Services/Robot/RobotPathPlanner.cs @@ -21,11 +21,11 @@ public class RobotPathPlanner(IConfiguration Configuration) Y1 = inNode.NodePosition.Y, X2 = futureNode.NodePosition.X, Y2 = futureNode.NodePosition.Y, - ControlPoint1X = edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].X : 0, - ControlPoint1Y = edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].Y : 0, - ControlPoint2X = edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].X : 0, - ControlPoint2Y = edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].Y : 0, - TrajectoryDegree = edge.Trajectory.Degree == 1 ? TrajectoryDegree.One : edge.Trajectory.Degree == 2 ? TrajectoryDegree.Two : TrajectoryDegree.Three, + ControlPoint1X = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].X : 0, + ControlPoint1Y = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].Y : 0, + ControlPoint2X = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].X : 0, + ControlPoint2Y = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].Y : 0, + TrajectoryDegree = edge.Trajectory is null ? TrajectoryDegree.One : edge.Trajectory.Degree == 1 ? TrajectoryDegree.One : edge.Trajectory.Degree == 2 ? TrajectoryDegree.Two : TrajectoryDegree.Three, }); (double robotx, double roboty) = ( @@ -61,30 +61,46 @@ public class RobotPathPlanner(IConfiguration Configuration) navigationNodes[0].Direction = GetDirectionInNode(currentTheta, nodes[0], nodes[1], edges[0]); for (int i = 1; i < nodes.Length - 1; i++) { + var trajectory = edges[i - 1].Trajectory; + var controlPoints = trajectory?.ControlPoints; (double lastx, double lasty) = MathExtensions.Curve(0.1, new() { X1 = nodes[i - 1].NodePosition.X, Y1 = nodes[i - 1].NodePosition.Y, X2 = nodes[i].NodePosition.X, Y2 = nodes[i].NodePosition.Y, - ControlPoint1X = edges[i - 1].Trajectory.ControlPoints.Length > 2 ? edges[i - 1].Trajectory.ControlPoints[1].X : 0, - ControlPoint1Y = edges[i - 1].Trajectory.ControlPoints.Length > 2 ? edges[i - 1].Trajectory.ControlPoints[1].Y : 0, - ControlPoint2X = edges[i - 1].Trajectory.ControlPoints.Length > 3 ? edges[i - 1].Trajectory.ControlPoints[2].X : 0, - ControlPoint2Y = edges[i - 1].Trajectory.ControlPoints.Length > 3 ? edges[i - 1].Trajectory.ControlPoints[2].Y : 0, - TrajectoryDegree = edges[i - 1].Trajectory.Degree == 1 ? TrajectoryDegree.One : edges[i - 1].Trajectory.Degree == 2 ? TrajectoryDegree.Two : TrajectoryDegree.Three, + ControlPoint1X = controlPoints is { Length: > 2 } ? controlPoints[1].X : 0, + ControlPoint1Y = controlPoints is { Length: > 2 } ? controlPoints[1].Y : 0, + ControlPoint2X = controlPoints is { Length: > 3 } ? controlPoints[2].X : 0, + ControlPoint2Y = controlPoints is { Length: > 3 } ? controlPoints[2].Y : 0, + TrajectoryDegree = trajectory?.Degree switch + { + 1 => TrajectoryDegree.One, + 2 => TrajectoryDegree.Two, + _ => TrajectoryDegree.Three + }, }); + + trajectory = edges[i].Trajectory; + controlPoints = trajectory?.ControlPoints; (double futurex, double futurey) = MathExtensions.Curve(0.1, new() { X1 = nodes[i].NodePosition.X, Y1 = nodes[i].NodePosition.Y, X2 = nodes[i + 1].NodePosition.X, Y2 = nodes[i + 1].NodePosition.Y, - ControlPoint1X = edges[i].Trajectory.ControlPoints.Length > 2 ? edges[i].Trajectory.ControlPoints[1].X : 0, - ControlPoint1Y = edges[i].Trajectory.ControlPoints.Length > 2 ? edges[i].Trajectory.ControlPoints[1].Y : 0, - ControlPoint2X = edges[i].Trajectory.ControlPoints.Length > 3 ? edges[i].Trajectory.ControlPoints[2].X : 0, - ControlPoint2Y = edges[i].Trajectory.ControlPoints.Length > 3 ? edges[i].Trajectory.ControlPoints[2].Y : 0, - TrajectoryDegree = edges[i].Trajectory.Degree == 1 ? TrajectoryDegree.One : edges[i].Trajectory.Degree == 2 ? TrajectoryDegree.Two : TrajectoryDegree.Three, + ControlPoint1X = controlPoints is { Length: > 2 } ? controlPoints[1].X : 0, + ControlPoint1Y = controlPoints is { Length: > 2 } ? controlPoints[1].Y : 0, + ControlPoint2X = controlPoints is { Length: > 3 } ? controlPoints[2].X : 0, + ControlPoint2Y = controlPoints is { Length: > 3 } ? controlPoints[2].Y : 0, + TrajectoryDegree = trajectory?.Degree switch + { + 1 => TrajectoryDegree.One, + 2 => TrajectoryDegree.Two, + _ => TrajectoryDegree.Three + }, }); + var angle = MathExtensions.GetVectorAngle( nodes[i].NodePosition.X, nodes[i].NodePosition.Y, @@ -128,11 +144,11 @@ public class RobotPathPlanner(IConfiguration Configuration) Y1 = startNode.Y, X2 = endNode.X, Y2 = endNode.Y, - ControlPoint1X = edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].X : 0, - ControlPoint1Y = edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].Y : 0, - ControlPoint2X = edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].X : 0, - ControlPoint2Y = edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].Y : 0, - TrajectoryDegree = edge.Trajectory.Degree == 1 ? TrajectoryDegree.One : edge.Trajectory.Degree == 2 ? TrajectoryDegree.Two : TrajectoryDegree.Three + ControlPoint1X = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].X : 0, + ControlPoint1Y = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].Y : 0, + ControlPoint2X = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].X : 0, + ControlPoint2Y = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].Y : 0, + TrajectoryDegree = edge.Trajectory is null ? TrajectoryDegree.One : edge.Trajectory.Degree == 1 ? TrajectoryDegree.One : edge.Trajectory.Degree == 2 ? TrajectoryDegree.Two : TrajectoryDegree.Three }; double length = EdgeCalculatorModel.GetEdgeLength(); @@ -194,11 +210,11 @@ public class RobotPathPlanner(IConfiguration Configuration) Y1 = startNode.NodePosition.Y, X2 = endNode.NodePosition.X, Y2 = endNode.NodePosition.Y, - ControlPoint1X = edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].X : 0, - ControlPoint1Y = edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].Y : 0, - ControlPoint2X = edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].X : 0, - ControlPoint2Y = edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].Y : 0, - TrajectoryDegree = edge.Trajectory.Degree == 1 ? TrajectoryDegree.One : edge.Trajectory.Degree == 2 ? TrajectoryDegree.Two : TrajectoryDegree.Three + ControlPoint1X = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].X : 0, + ControlPoint1Y = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 2 ? edge.Trajectory.ControlPoints[1].Y : 0, + ControlPoint2X = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].X : 0, + ControlPoint2Y = edge.Trajectory is not null && edge.Trajectory.ControlPoints.Length > 3 ? edge.Trajectory.ControlPoints[2].Y : 0, + TrajectoryDegree = edge.Trajectory is null ? TrajectoryDegree.One : edge.Trajectory.Degree == 1 ? TrajectoryDegree.One : edge.Trajectory.Degree == 2 ? TrajectoryDegree.Two : TrajectoryDegree.Three }; double length = EdgeCalculatorModel.GetEdgeLength();