This commit is contained in:
Đăng Nguyễn 2025-12-31 13:25:10 +07:00
parent 8362713dcc
commit 49c0c1ab39
6 changed files with 43 additions and 213 deletions

View File

@ -141,8 +141,7 @@
[Parameter] public OrderMessage Order { get; set; } = default!; [Parameter] public OrderMessage Order { get; set; } = default!;
[Parameter] public EventCallback OnAddEdge { get; set; } [Parameter] public EventCallback OnAddEdge { get; set; }
[Parameter] public EventCallback<UiEdge> OnRemoveEdge { get; set; } [Parameter] public EventCallback<VDA5050.Order.Edge> OnRemoveEdge { get; set; }
[Parameter] public EventCallback<UiEdge> OnApplyCurve { get; set; }
[Parameter] public EventCallback OnOrderChanged { get; set; } [Parameter] public EventCallback OnOrderChanged { get; set; }
@ -158,15 +157,9 @@
await OnOrderChanged.InvokeAsync(); await OnOrderChanged.InvokeAsync();
} }
private async Task RemoveEdgeAsync(UiEdge edge) private async Task RemoveEdgeAsync(VDA5050.Order.Edge edge)
{ {
await OnRemoveEdge.InvokeAsync(edge); await OnRemoveEdge.InvokeAsync(edge);
await OnOrderChanged.InvokeAsync(); await OnOrderChanged.InvokeAsync();
} }
private async Task ApplyCurveAsync(UiEdge edge)
{
await OnApplyCurve.InvokeAsync(edge);
await OnOrderChanged.InvokeAsync();
}
} }

View File

@ -132,17 +132,17 @@
try try
{ {
using var doc = JsonDocument.Parse(JsonText); var order = JsonSerializer.Deserialize<OrderMsg>(JsonText, new JsonSerializerOptions
var root = doc.RootElement;
// ===== BASIC STRUCTURE CHECK =====
if (!root.TryGetProperty("nodes", out _) ||
!root.TryGetProperty("edges", out _))
{ {
throw new Exception("Missing 'nodes' or 'edges' field."); WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
});
if(order is null)
{
ShowWarning = true;
ErrorMessage = "Can not convert file to Order message";
return;
} }
var order = OrderMessage.FromSchemaObject(root);
ValidateOrder(order); ValidateOrder(order);
MudDialog.Close(DialogResult.Ok(order)); MudDialog.Close(DialogResult.Ok(order));
@ -160,15 +160,15 @@
} }
// ================= DOMAIN VALIDATION ================= // ================= DOMAIN VALIDATION =================
private void ValidateOrder(OrderMessage order) private void ValidateOrder(OrderMsg order)
{ {
if (order.Nodes.Count == 0) if (order.Nodes.Length == 0)
throw new Exception("Order must contain at least one node."); throw new Exception("Order must contain at least one node.");
if (order.Nodes.Count != order.Edges.Count + 1) if (order.Nodes.Length != order.Edges.Length + 1)
throw new Exception( throw new Exception(
$"Invalid path structure: Nodes count ({order.Nodes.Count}) " + $"Invalid path structure: Nodes count ({order.Nodes.Length}) " +
$"must equal Edges count + 1 ({order.Edges.Count + 1})." $"must equal Edges count + 1 ({order.Edges.Length + 1})."
); );
var nodeIds = order.Nodes var nodeIds = order.Nodes

View File

@ -6,14 +6,14 @@
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<!-- IMPORT --> <!-- IMPORT -->
@* <MudButton Variant="Variant.Outlined" <MudButton Variant="Variant.Outlined"
Color="Color.Secondary" Color="Color.Secondary"
Size="Size.Small" Size="Size.Small"
StartIcon="@Icons.Material.Filled.UploadFile" StartIcon="@Icons.Material.Filled.UploadFile"
OnClick="OnImport"> OnClick="OnImport">
Import JSON Import JSON
</MudButton> </MudButton>
*@
<!-- CANCEL --> <!-- CANCEL -->
<MudButton Variant="Variant.Filled" <MudButton Variant="Variant.Filled"
Color="@CancelButtonColor" Color="@CancelButtonColor"

View File

@ -37,7 +37,6 @@
<EdgesPanel Order="Order" <EdgesPanel Order="Order"
OnAddEdge="AddEdge" OnAddEdge="AddEdge"
OnRemoveEdge="RemoveEdge" OnRemoveEdge="RemoveEdge"
OnApplyCurve="ApplyCurve"
OnOrderChanged="OnOrderChanged" /> OnOrderChanged="OnOrderChanged" />
</MudItem> </MudItem>
@ -99,9 +98,9 @@
var result = await dialog.Result; var result = await dialog.Result;
if (!result.Canceled && result.Data is OrderMessage imported) if (result is not null && !result.Canceled && result.Data is OrderMsg imported)
{ {
Order = imported; Order.Import(imported);
RebuildOrderJson(); RebuildOrderJson();
StateHasChanged(); StateHasChanged();
} }
@ -149,7 +148,7 @@
? Order.Nodes[1].NodeId ? Order.Nodes[1].NodeId
: start; // 👈 1 node thì start = end : start; // 👈 1 node thì start = end
Order.Edges.Add(new UiEdge Order.Edges.Add(new VDA5050.Order.Edge
{ {
EdgeId = $"EDGE_{Order.Edges.Count + 1}", EdgeId = $"EDGE_{Order.Edges.Count + 1}",
StartNodeId = start, StartNodeId = start,
@ -158,25 +157,10 @@
} }
void RemoveEdge(UiEdge edge) void RemoveEdge(VDA5050.Order.Edge edge)
{ {
Order.Edges.Remove(edge); Order.Edges.Remove(edge);
} }
void ApplyCurve(UiEdge edge)
{
if (edge.Radius <= 0 || edge.Expanded) return;
var startNode = Order.Nodes.First(n => n.NodeId == edge.StartNodeId);
var newNode = OrderMessage.CreateCurveNode(startNode, edge);
Order.Nodes.Add(newNode);
edge.EndNodeId = newNode.NodeId;
edge.MarkExpanded(); // ✅
ResequenceNodes();
}
// ================= ACTION ================= // ================= ACTION =================
void AddAction(Node node) void AddAction(Node node)
{ {

View File

@ -2,6 +2,7 @@
using RobotApp.VDA5050.Order; using RobotApp.VDA5050.Order;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Xml.Linq;
namespace RobotApp.Client.Services; namespace RobotApp.Client.Services;
@ -126,7 +127,7 @@ public static class QuarterGeometry
// ====================================================== // ======================================================
public class OrderMessage public class OrderMessage
{ {
public int HeaderId { get; set; } public uint HeaderId { get; set; }
public string Timestamp { get; set; } = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); public string Timestamp { get; set; } = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
public string Version { get; set; } = "2.1.0"; public string Version { get; set; } = "2.1.0";
public string Manufacturer { get; set; } = "PhenikaaX"; public string Manufacturer { get; set; } = "PhenikaaX";
@ -135,139 +136,9 @@ public class OrderMessage
public int OrderUpdateId { get; set; } public int OrderUpdateId { get; set; }
public string? ZoneSetId { get; set; } public string? ZoneSetId { get; set; }
public List<Node> Nodes { get; set; } = new(); public List<Node> Nodes { get; set; } = [];
public List<UiEdge> Edges { get; set; } = new(); public List<Edge> Edges { get; set; } = [];
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 static OrderMessage FromSchemaObject(JsonElement root)
{
var order = new OrderMessage
{
HeaderId = root.GetProperty("headerId").GetInt32(),
Timestamp = root.GetProperty("timestamp").GetString(),
Version = root.GetProperty("version").GetString(),
Manufacturer = root.GetProperty("manufacturer").GetString(),
SerialNumber = root.GetProperty("serialNumber").GetString(),
OrderId = root.GetProperty("orderId").GetString(),
OrderUpdateId = root.GetProperty("orderUpdateId").GetInt32()
};
// ================= NODES =================
foreach (var n in root.GetProperty("nodes").EnumerateArray())
{
var node = new Node
{
NodeId = n.GetProperty("nodeId").GetString()!,
SequenceId = n.GetProperty("sequenceId").GetInt32(),
Released = n.GetProperty("released").GetBoolean(),
NodePosition = new NodePosition
{
X = n.GetProperty("nodePosition").GetProperty("x").GetDouble(),
Y = n.GetProperty("nodePosition").GetProperty("y").GetDouble(),
Theta = n.GetProperty("nodePosition").GetProperty("theta").GetDouble(),
AllowedDeviationXY = n.GetProperty("nodePosition").GetProperty("allowedDeviationXY").GetDouble(),
AllowedDeviationTheta = n.GetProperty("nodePosition").GetProperty("allowedDeviationTheta").GetDouble(),
MapId = n.GetProperty("nodePosition").GetProperty("mapId").GetString()
},
Actions = ParseActions(n)
};
order.Nodes.Add(node);
}
foreach (var e in root.GetProperty("edges").EnumerateArray())
{
var edge = new UiEdge
{
EdgeId = e.GetProperty("edgeId").GetString()!,
SequenceId = e.GetProperty("sequenceId").GetInt32(),
Released = e.GetProperty("released").GetBoolean(),
StartNodeId = e.GetProperty("startNodeId").GetString()!,
EndNodeId = e.GetProperty("endNodeId").GetString()!,
};
// ===== IMPORT TRAJECTORY =====
if (e.TryGetProperty("trajectory", out var traj))
{
edge.HasTrajectory = true;
edge.Trajectory = new UiTrajectory
{
Degree = traj.GetProperty("degree").GetInt32(),
KnotVector = traj.GetProperty("knotVector")
.EnumerateArray()
.Select(x => x.GetDouble())
.ToArray(),
ControlPoints = traj.GetProperty("controlPoints")
.EnumerateArray()
.Select(p => new Point(
p.GetProperty("x").GetDouble(),
p.GetProperty("y").GetDouble()
))
.ToList()
};
// 🔥 IMPORTED CURVE → LOCK APPLY
edge.MarkExpanded();
}
order.Edges.Add(edge);
}
return order;
}
// ================= ACTION PARSER =================
private static VDA5050.InstantAction.Action[] ParseActions(JsonElement parent)
{
if (!parent.TryGetProperty("actions", out var acts))
return Array.Empty<VDA5050.InstantAction.Action>();
return acts.EnumerateArray().Select(a =>
new VDA5050.InstantAction.Action
{
ActionId = a.GetProperty("actionId").GetString(),
ActionType = a.GetProperty("actionType").GetString(),
BlockingType = a.GetProperty("blockingType").GetString(),
ActionParameters = a.TryGetProperty("actionParameters", out var ps)
? ps.EnumerateArray()
.Select(p => new ActionParameter
{
Key = p.GetProperty("key").GetString(),
Value = p.GetProperty("value").GetString()
})
.ToArray()
: Array.Empty<ActionParameter>()
}
).ToArray();
}
public OrderMsg ToSchemaObject() public OrderMsg ToSchemaObject()
{ {
// ================= SORT NODES BY UI SEQUENCE ================= // ================= SORT NODES BY UI SEQUENCE =================
@ -337,7 +208,7 @@ public class OrderMessage
// ================================================= // =================================================
// 1⃣ IMPORTED TRAJECTORY // 1⃣ IMPORTED TRAJECTORY
// ================================================= // =================================================
if (e.HasTrajectory && e.Trajectory != null) if (e.Trajectory != null)
{ {
return new Edge return new Edge
{ {
@ -360,39 +231,6 @@ public class OrderMessage
}; };
} }
// =================================================
// 2⃣ STRAIGHT EDGE
// =================================================
if (e.Radius <= 0)
{
return new Edge
{
EdgeId = baseEdge.edgeId,
SequenceId = baseEdge.sequenceId,
Released = baseEdge.released,
StartNodeId = baseEdge.startNodeId,
EndNodeId = baseEdge.endNodeId,
Actions = []
};
}
// =================================================
// 3⃣ GENERATED CURVE (EDITOR)
// =================================================
var startNode = orderedNodes.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 Edge return new Edge
{ {
EdgeId = baseEdge.edgeId, EdgeId = baseEdge.edgeId,
@ -428,6 +266,20 @@ public class OrderMessage
Edges = edgeObjects, 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];
}
} }
// ====================================================== // ======================================================

View File

@ -479,6 +479,7 @@ public class RobotOrderController(INavigation NavigationManager,
var edges = NewOrderEdges.ToList().GetRange(lastNodeIndex + 1, nodes.Count - 1); var edges = NewOrderEdges.ToList().GetRange(lastNodeIndex + 1, nodes.Count - 1);
for (int i = 0; i < nodes.Count - 1; i++) for (int i = 0; i < nodes.Count - 1; i++)
{ {
if (edges[i] is null) return (NodeStates, [.. pathEdges]);
pathEdges.Add(new() pathEdges.Add(new()
{ {
StartX = nodes[i].NodePosition.X, StartX = nodes[i].NodePosition.X,
@ -489,7 +490,7 @@ public class RobotOrderController(INavigation NavigationManager,
ControlPoint1Y = edges[i].Trajectory is not null && edges[i].Trajectory.ControlPoints.Length > 2 ? edges[i].Trajectory.ControlPoints[1].Y : 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, 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, ControlPoint2Y = edges[i].Trajectory is not null && edges[i].Trajectory.ControlPoints.Length > 3 ? edges[i].Trajectory.ControlPoints[2].Y : 0,
Degree = edges[i].Trajectory.Degree, Degree = edges[i].Trajectory is null ? 1 : edges[i].Trajectory.Degree,
}); });
} }
} }