164 lines
6.4 KiB
Plaintext
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,
|
|
}
|
|
}
|