RobotApp/RobotApp.Client/Services/UiEdge.cs
Đăng Nguyễn 49c0c1ab39 update
2025-12-31 13:25:10 +07:00

297 lines
9.0 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<double>();
public List<Point> 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<Node> Nodes { get; set; } = [];
public List<Edge> 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;
}
}