Refactor ElkSharp hybrid routing and document speed path
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
namespace StellaOps.ElkSharp;
|
||||
|
||||
internal static partial class ElkShapeBoundaries
|
||||
{
|
||||
private static double DistanceToSegment(ElkPoint point, ElkPoint start, ElkPoint end)
|
||||
{
|
||||
var deltaX = end.X - start.X;
|
||||
var deltaY = end.Y - start.Y;
|
||||
var lengthSquared = (deltaX * deltaX) + (deltaY * deltaY);
|
||||
if (lengthSquared <= 0.001d)
|
||||
{
|
||||
return Math.Sqrt(((point.X - start.X) * (point.X - start.X)) + ((point.Y - start.Y) * (point.Y - start.Y)));
|
||||
}
|
||||
|
||||
var t = (((point.X - start.X) * deltaX) + ((point.Y - start.Y) * deltaY)) / lengthSquared;
|
||||
t = Math.Max(0d, Math.Min(1d, t));
|
||||
var projectionX = start.X + (t * deltaX);
|
||||
var projectionY = start.Y + (t * deltaY);
|
||||
var distanceX = point.X - projectionX;
|
||||
var distanceY = point.Y - projectionY;
|
||||
return Math.Sqrt((distanceX * distanceX) + (distanceY * distanceY));
|
||||
}
|
||||
|
||||
private static bool TryGetGatewayBoundaryFace(
|
||||
ElkPositionedNode node,
|
||||
ElkPoint boundaryPoint,
|
||||
out ElkPoint faceStart,
|
||||
out ElkPoint faceEnd)
|
||||
{
|
||||
faceStart = default!;
|
||||
faceEnd = default!;
|
||||
|
||||
var polygon = BuildGatewayBoundaryPoints(node);
|
||||
var bestDistance = double.PositiveInfinity;
|
||||
var bestIndex = -1;
|
||||
for (var index = 0; index < polygon.Count; index++)
|
||||
{
|
||||
var start = polygon[index];
|
||||
var end = polygon[(index + 1) % polygon.Count];
|
||||
var distance = DistanceToSegment(boundaryPoint, start, end);
|
||||
if (distance > 2d || distance >= bestDistance)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bestDistance = distance;
|
||||
bestIndex = index;
|
||||
}
|
||||
|
||||
if (bestIndex < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
faceStart = polygon[bestIndex];
|
||||
faceEnd = polygon[(bestIndex + 1) % polygon.Count];
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsDisallowedGatewayVertex(
|
||||
ElkPositionedNode node,
|
||||
ElkPoint boundaryPoint)
|
||||
{
|
||||
return IsNearGatewayVertex(node, boundaryPoint, GatewayVertexTolerance)
|
||||
&& !IsAllowedGatewayTipVertex(node, boundaryPoint, GatewayVertexTolerance);
|
||||
}
|
||||
|
||||
private static (double X, double Y) BuildGatewayFaceNormal(
|
||||
ElkPositionedNode node,
|
||||
ElkPoint faceStart,
|
||||
ElkPoint faceEnd,
|
||||
ElkPoint boundaryPoint)
|
||||
{
|
||||
var deltaX = faceEnd.X - faceStart.X;
|
||||
var deltaY = faceEnd.Y - faceStart.Y;
|
||||
var length = Math.Sqrt((deltaX * deltaX) + (deltaY * deltaY));
|
||||
if (length <= 0.001d)
|
||||
{
|
||||
return (0d, -1d);
|
||||
}
|
||||
|
||||
var normalAX = deltaY / length;
|
||||
var normalAY = -deltaX / length;
|
||||
var normalBX = -normalAX;
|
||||
var normalBY = -normalAY;
|
||||
var centerX = node.X + (node.Width / 2d);
|
||||
var centerY = node.Y + (node.Height / 2d);
|
||||
var centerToBoundaryX = boundaryPoint.X - centerX;
|
||||
var centerToBoundaryY = boundaryPoint.Y - centerY;
|
||||
var dotA = (normalAX * centerToBoundaryX) + (normalAY * centerToBoundaryY);
|
||||
var dotB = (normalBX * centerToBoundaryX) + (normalBY * centerToBoundaryY);
|
||||
return dotA >= dotB
|
||||
? (normalAX, normalAY)
|
||||
: (normalBX, normalBY);
|
||||
}
|
||||
|
||||
private static double ComputeRayExitDistanceFromBoundingBox(
|
||||
ElkPositionedNode node,
|
||||
ElkPoint origin,
|
||||
double directionX,
|
||||
double directionY)
|
||||
{
|
||||
const double epsilon = 0.0001d;
|
||||
var bestDistance = double.PositiveInfinity;
|
||||
|
||||
if (directionX > epsilon)
|
||||
{
|
||||
bestDistance = Math.Min(bestDistance, (node.X + node.Width - origin.X) / directionX);
|
||||
}
|
||||
else if (directionX < -epsilon)
|
||||
{
|
||||
bestDistance = Math.Min(bestDistance, (node.X - origin.X) / directionX);
|
||||
}
|
||||
|
||||
if (directionY > epsilon)
|
||||
{
|
||||
bestDistance = Math.Min(bestDistance, (node.Y + node.Height - origin.Y) / directionY);
|
||||
}
|
||||
else if (directionY < -epsilon)
|
||||
{
|
||||
bestDistance = Math.Min(bestDistance, (node.Y - origin.Y) / directionY);
|
||||
}
|
||||
|
||||
if (double.IsInfinity(bestDistance) || bestDistance < 0d)
|
||||
{
|
||||
return 0d;
|
||||
}
|
||||
|
||||
return bestDistance;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user