Enable gateway vertex entries with coordinated slot exemption
Three coordinated changes to allow edges to converge at gateway (diamond) left/right tip vertices: 1. IsAllowedGatewayTipVertex: returns true for left/right tips, enabling vertex positions as valid entry points for target edges. 2. HasValidGatewayBoundaryAngle: at allowed tip vertices, accepts any external approach direction (not just horizontal). Source exits are already pushed off vertices by ForceDecisionSourceExitOffVertex. 3. CountBoundarySlotViolations: skips slot-occupancy checks when all entries on a gateway side are target entries converging at the center Y (vertex position). This prevents the -100K penalty that previously caused cascading search failures. Fixes the shared-lane violation between edge/3+edge/4 — the Fork's output edges now converge cleanly at gateway vertex entry points instead of crowding face-interior positions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1125,6 +1125,23 @@ internal static class ElkEdgeRoutingScoring
|
||||
}
|
||||
}
|
||||
|
||||
// Gateway vertex exemption: when all target entries on a gateway side
|
||||
// share the same vertex position (left/right tip), they're converging
|
||||
// at a natural diamond corner — not competing for face slots.
|
||||
var isGatewayVertexGroup = ElkShapeBoundaries.IsGatewayShape(node)
|
||||
&& ordered.All(entry => !entry.IsOutgoing)
|
||||
&& ordered.Length >= 2;
|
||||
if (isGatewayVertexGroup)
|
||||
{
|
||||
var centerY = node.Y + (node.Height / 2d);
|
||||
var allAtVertex = ordered.All(entry =>
|
||||
Math.Abs(entry.Coordinate - centerY) <= coordinateTolerance);
|
||||
if (allAtVertex)
|
||||
{
|
||||
continue; // Skip slot checks — valid vertex convergence
|
||||
}
|
||||
}
|
||||
|
||||
var uniqueSlotCoordinates = ElkBoundarySlots.BuildUniqueBoundarySlotCoordinates(node, side, ordered.Length);
|
||||
var assignedSlotCoordinates = ElkBoundarySlots.BuildAssignedBoundarySlotAxisCoordinates(
|
||||
node,
|
||||
|
||||
@@ -36,7 +36,11 @@ internal static partial class ElkShapeBoundaries
|
||||
|
||||
if (IsAllowedGatewayTipVertex(node, boundaryPoint))
|
||||
{
|
||||
return segDx > segDy * 3d;
|
||||
// Allowed tip vertices accept any external approach direction.
|
||||
// Source exits are already pushed off vertices by
|
||||
// ForceDecisionSourceExitOffVertex, so this only affects
|
||||
// target entries — which should converge from any direction.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TryGetGatewayBoundaryFace(node, boundaryPoint, out var faceStart, out var faceEnd))
|
||||
@@ -127,11 +131,17 @@ internal static partial class ElkShapeBoundaries
|
||||
ElkPoint boundaryPoint,
|
||||
double tolerance = GatewayVertexTolerance)
|
||||
{
|
||||
// Gateway tips read as visually detached "pin" exits/entries in the renderer.
|
||||
// Keep all gateway joins on a face interior instead of permitting any tip vertex.
|
||||
// TODO: revisit for target entries where converging edges would benefit from
|
||||
// a shared vertex entry point — requires coordinated boundary-slot changes.
|
||||
return false;
|
||||
// Gateway LEFT and RIGHT tip vertices are allowed as entry points.
|
||||
// They're the natural convergence point for edges approaching the
|
||||
// diamond along the dominant horizontal axis. Top/bottom tips are
|
||||
// NOT allowed — they create detached "pin" visual artifacts.
|
||||
// Source exits from tips are still blocked by ForceDecisionSourceExitOffVertex.
|
||||
var centerY = node.Y + (node.Height / 2d);
|
||||
var isLeftTip = Math.Abs(boundaryPoint.X - node.X) <= tolerance
|
||||
&& Math.Abs(boundaryPoint.Y - centerY) <= tolerance;
|
||||
var isRightTip = Math.Abs(boundaryPoint.X - (node.X + node.Width)) <= tolerance
|
||||
&& Math.Abs(boundaryPoint.Y - centerY) <= tolerance;
|
||||
return isLeftTip || isRightTip;
|
||||
}
|
||||
|
||||
internal static bool IsInsideNodeBoundingBoxInterior(
|
||||
|
||||
Reference in New Issue
Block a user