using System.Collections.Concurrent; using System.Diagnostics; using System.Globalization; namespace StellaOps.ElkSharp; internal static partial class ElkEdgeRouterIterative { private static bool ShouldPreferFastTerminalOnlyHardRuleClosure(RoutingRetryState retryState) { return retryState.RemainingShortHighways == 0 && retryState.RepeatCollectorCorridorViolations == 0 && retryState.RepeatCollectorNodeClearanceViolations == 0 && retryState.TargetApproachBacktrackingViolations == 0 && retryState.ExcessiveDetourViolations == 0 && retryState.BoundarySlotViolations == 0 && retryState.BelowGraphViolations == 0 && retryState.UnderNodeViolations == 0 && retryState.LongDiagonalViolations == 0 && retryState.SharedLaneViolations <= 2 && (retryState.TargetApproachJoinViolations > 0 || retryState.EntryAngleViolations > 0 || retryState.GatewaySourceExitViolations > 0 || retryState.SharedLaneViolations > 0); } private static ElkRoutedEdge[] BuildFastTerminalOnlyHardRuleCandidate( ElkRoutedEdge[] edges, ElkPositionedNode[] nodes, ElkLayoutDirection direction, double minLineClearance, IReadOnlyCollection restrictedEdgeIds) { var candidate = edges; candidate = ChoosePreferredHardRuleLayout( candidate, ElkEdgePostProcessor.SeparateSharedLaneConflicts( candidate, nodes, minLineClearance, restrictedEdgeIds), nodes); candidate = ChoosePreferredHardRuleLayout( candidate, ElkEdgePostProcessor.SpreadSourceDepartureJoins( candidate, nodes, minLineClearance, restrictedEdgeIds), nodes); candidate = ChoosePreferredHardRuleLayout( candidate, ElkEdgePostProcessor.RepairBoundaryAnglesAndTargetApproaches( candidate, nodes, minLineClearance, restrictedEdgeIds), nodes); candidate = ChoosePreferredHardRuleLayout( candidate, ElkEdgePostProcessor.SpreadTargetApproachJoins( candidate, nodes, minLineClearance, restrictedEdgeIds, forceOutwardAxisSpacing: true), nodes); candidate = ChoosePreferredHardRuleLayout( candidate, ElkEdgePostProcessor.NormalizeBoundaryAngles(candidate, nodes), nodes); candidate = ChoosePreferredHardRuleLayout( candidate, ElkEdgePostProcessor.NormalizeSourceExitAngles(candidate, nodes), nodes); candidate = ChoosePreferredHardRuleLayout( candidate, ElkEdgePostProcessor.SeparateSharedLaneConflicts( candidate, nodes, minLineClearance, restrictedEdgeIds), nodes); return candidate; } private static bool ShouldPreferCompactFocusedTerminalClosure( RoutingRetryState retryState, int focusEdgeCount) { return focusEdgeCount <= 4 && retryState.BoundarySlotViolations == 0 && retryState.BelowGraphViolations == 0 && retryState.UnderNodeViolations == 0 && retryState.GatewaySourceExitViolations == 0 && retryState.EntryAngleViolations == 0 && retryState.TargetApproachBacktrackingViolations == 0 && retryState.ExcessiveDetourViolations == 0 && retryState.TargetApproachJoinViolations <= 1 && retryState.SharedLaneViolations <= 1 && (retryState.TargetApproachJoinViolations > 0 || retryState.SharedLaneViolations > 0); } private static ElkRoutedEdge[] ApplyCompactFocusedTerminalClosure( ElkRoutedEdge[] edges, ElkPositionedNode[] nodes, ElkLayoutDirection direction, double minLineClearance, IReadOnlyCollection focusedEdgeIds) { var candidate = edges; candidate = ApplyGuardedFocusedHardRulePass( candidate, nodes, current => ElkEdgePostProcessor.SeparateSharedLaneConflicts(current, nodes, minLineClearance, focusedEdgeIds)); candidate = ApplyGuardedFocusedHardRulePass( candidate, nodes, current => ElkEdgePostProcessor.SpreadSourceDepartureJoins(current, nodes, minLineClearance, focusedEdgeIds)); candidate = ApplyGuardedFocusedHardRulePass( candidate, nodes, current => ElkEdgePostProcessor.RepairBoundaryAnglesAndTargetApproaches(current, nodes, minLineClearance, focusedEdgeIds)); candidate = ApplyGuardedFocusedHardRulePass( candidate, nodes, current => ElkEdgePostProcessor.SpreadTargetApproachJoins( current, nodes, minLineClearance, focusedEdgeIds, forceOutwardAxisSpacing: true)); candidate = ApplyGuardedFocusedHardRulePass( candidate, nodes, current => ElkEdgePostProcessor.SeparateSharedLaneConflicts(current, nodes, minLineClearance, focusedEdgeIds)); candidate = ApplyGuardedFocusedHardRulePass( candidate, nodes, current => ElkEdgePostProcessor.NormalizeBoundaryAngles(current, nodes)); candidate = ApplyGuardedFocusedHardRulePass( candidate, nodes, current => ElkEdgePostProcessor.NormalizeSourceExitAngles(current, nodes)); return candidate; } }