RobotNet/RobotNet.WebApp/Maps/Components/Editor/Edge/EdgeCurveCreating.razor
2025-10-15 15:15:53 +07:00

164 lines
6.4 KiB
Plaintext

@inject IJSRuntime JSRuntime
<g @ref="Ref" visibility="hidden">
<defs>
<marker id="arrowhead" markerWidth="5" markerHeight="4" refX="5" refY="2" orient="auto">
<line x1="0" y1="0" x2="5" y2="2" style="stroke: #ff0000; stroke-width: 1px;" />
<line x1="5" y1="2" x2="0" y2="4" style="stroke: #ff0000; stroke-width: 1px;" />
</marker>
</defs>
<path @ref="PathRef" />
<line @ref="SubPath1Ref" x1="@StartNode.X" x2="@SubStartNode.X" y1="@StartNode.Y" y2="@SubStartNode.Y" stroke="#ff0000" stroke-width="0.05" marker-end="url(#arrowhead)" />
<line @ref="SubPath2Ref" x1="@EndNode.X" x2="@SubEndNode.X" y1="@EndNode.Y" y2="@SubEndNode.Y" stroke="#ff0000" stroke-width="0.05" marker-end="url(#arrowhead)" />
<circle cx="@StartNode.X" cy="@StartNode.Y" />
<circle cx="@EndNode.X" cy="@EndNode.Y" />
</g>
@code {
private ElementReference Ref;
private ElementReference PathRef;
private ElementReference SubPath1Ref;
private ElementReference SubPath2Ref;
private (double X, double Y) StartNode;
private (double X, double Y) SubStartNode;
private (double X, double Y) EndNode;
private (double X, double Y) SubEndNode;
private TrajectoryDegree Degree;
private (double X, double Y) ControlPoint1;
private (double X, double Y) ControlPoint2;
public CreateCurveEdgeStep CreateStep { get; set; } = CreateCurveEdgeStep.Hidden;
public async Task Update(double x, double y)
{
if (CreateStep == CreateCurveEdgeStep.CreateSubStartEdge)
{
SubStartNode.X = x;
SubStartNode.Y = y;
}
else if (CreateStep == CreateCurveEdgeStep.FinishCreateSubStartEdge)
{
EndNode.X = x;
EndNode.Y = y;
await CreateTangentPath();
}
else if (CreateStep == CreateCurveEdgeStep.CreateSubEndEdge)
{
SubEndNode.X = x;
SubEndNode.Y = y;
await CreateTangentPath();
}
StateHasChanged();
}
public async Task CreateSubEdgeAsync(double x, double y, TrajectoryDegree degree = TrajectoryDegree.Two)
{
Degree = degree;
if (CreateStep == CreateCurveEdgeStep.Hidden)
{
await Visible();
StartNode.X = x;
StartNode.Y = y;
SubStartNode.X = x;
SubStartNode.Y = y;
CreateStep = CreateCurveEdgeStep.CreateSubStartEdge;
}
else if (CreateStep == CreateCurveEdgeStep.FinishCreateSubStartEdge)
{
EndNode.X = x;
EndNode.Y = y;
SubEndNode.X = x;
SubEndNode.Y = y;
CreateStep = CreateCurveEdgeStep.CreateSubEndEdge;
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", SubPath2Ref, "visibility", "visible");
}
StateHasChanged();
}
public async Task FinishSubEdgeAsync(double x, double y)
{
if (CreateStep == CreateCurveEdgeStep.CreateSubStartEdge)
{
SubStartNode.X = x;
SubStartNode.Y = y;
EndNode.X = x;
EndNode.Y = y;
CreateStep = CreateCurveEdgeStep.FinishCreateSubStartEdge;
await CreateTangentPath();
}
else if (CreateStep == CreateCurveEdgeStep.CreateSubEndEdge) CreateStep = CreateCurveEdgeStep.Finish;
}
public EdgeCreateModel GetEdgeCreateModel()
{
return new()
{
X1 = StartNode.X,
Y1 = StartNode.Y,
X2 = EndNode.X,
Y2 = EndNode.Y,
ControlPoint1X = ControlPoint1.X,
ControlPoint1Y = ControlPoint1.Y,
ControlPoint2X = ControlPoint2.X,
ControlPoint2Y = ControlPoint2.Y,
TrajectoryDegree = Degree,
};
}
private async Task CreateTangentPath()
{
var data = $"M {StartNode.X} {StartNode.Y}";
if(Degree == TrajectoryDegree.Two)
{
var cp = MapEditorHelper.CaculateIntersectionPoint(SubStartNode.X, SubStartNode.Y, StartNode.X, StartNode.Y, EndNode.X, EndNode.Y, SubEndNode.X, SubEndNode.Y);
if (cp is null || CreateStep == CreateCurveEdgeStep.FinishCreateSubStartEdge) cp = MapEditorHelper.CaculateControlPoint(StartNode.X, StartNode.Y, EndNode.X, EndNode.Y, 45, 1 / Math.Sqrt(2));
data = $"{data} Q {cp.Value.X} {cp.Value.Y} {EndNode.X} {EndNode.Y}";
ControlPoint1 = (cp.Value.X, cp.Value.Y);
}
else if(Degree == TrajectoryDegree.Three)
{
if (CreateStep == CreateCurveEdgeStep.FinishCreateSubStartEdge)
{
ControlPoint1 = MapEditorHelper.CaculateControlPoint(StartNode.X, StartNode.Y, EndNode.X, EndNode.Y, 45, 1 / Math.Sqrt(2));
ControlPoint2 = MapEditorHelper.CaculateControlPoint(StartNode.X, StartNode.Y, EndNode.X, EndNode.Y, -45, 1 / Math.Sqrt(2));
}
else (ControlPoint1.X, ControlPoint1.Y, ControlPoint2.X, ControlPoint2.Y) = MapEditorHelper.CaculateDoubleControlPoint(SubStartNode.X, SubStartNode.Y, StartNode.X, StartNode.Y, EndNode.X, EndNode.Y, SubEndNode.X, SubEndNode.Y);
data = $"{data} C {ControlPoint1.X} {ControlPoint1.Y}, {ControlPoint2.X} {ControlPoint2.Y}, {EndNode.X} {EndNode.Y}";
}
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", PathRef, "d", data);
StateHasChanged();
}
public async Task Visible()
{
EndNode = (0, 0);
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", PathRef, "d", "");
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", SubPath1Ref, "visibility", "visible");
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", SubPath2Ref, "visibility", "hidden");
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", Ref, "visibility", "visible");
}
public async Task Hidden()
{
CreateStep = CreateCurveEdgeStep.Hidden;
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", SubPath1Ref, "visibility", "hidden");
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", SubPath2Ref, "visibility", "hidden");
await JSRuntime.InvokeVoidAsync("ElementSetAttribute", Ref, "visibility", "hidden");
}
public enum CreateCurveEdgeStep
{
Hidden,
CreateSubStartEdge,
FinishCreateSubStartEdge,
CreateSubEndEdge,
Finish,
}
}