RobotApp/RobotApp.Client/Services/UiEdge.cs
2025-12-21 16:50:37 +07:00

258 lines
7.5 KiB
C#

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<Node> Nodes { get; set; } = new();
public List<UiEdge> 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<object>()
}).ToArray()
}).ToArray(),
// ================= EDGES =================
edges = Edges.Select<UiEdge, object>(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<object>()
};
}
// ---------- ĐƯỜ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<object>()
};
}).ToArray()
};
}
}
// ======================================================
// UI ACTION PARAM
// ======================================================
public class UiActionParameter : ActionParameter
{
[JsonIgnore]
public string ValueString
{
get => Value?.ToString() ?? "";
set => Value = value;
}
}