@coldtea/pr-lens-renderer 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,14 +5,13 @@ import { DIAGRAM_MARGIN } from "../design.js";
5
5
  import { travellingPulses } from "./pulse.js";
6
6
  import { canvasFor, union } from "../bounds.js";
7
7
  import { coord } from "../geometry.js";
8
- import { placeLabelPills } from "../layout/labels.js";
9
8
  import { relieveCongestion } from "../layout/congestion.js";
10
9
  import { lines, tag, textNode, wrap } from "./primitives.js";
11
10
  import { curveBounds } from "../layout/edges.js";
12
11
  import { atlasBoxes, emptyAtlas } from "../atlas.js";
13
12
  import { markerFor, shifted, toneColour, toneFor } from "./document.js";
14
13
  import { badgeColours, cardAttributes, cardGroupAttributes, edgeAttributes, stylesFor, } from "./styles.js";
15
- import { badgeRow, badgeWidth, cardBadges, cardTextWidth, deltaBadgeText, laneHeaderText, } from "../layout/architecture.js";
14
+ import { badgeRow, badgeWidth, cardBadges, cardTextWidth, deltaBadgeText, laneHeaderText, occupiedBoxes, } from "../layout/architecture.js";
16
15
  import { BADGE_GAP, BADGE_HEIGHT, BADGE_RADIUS, BADGE_RISE, CARD_PADDING_X, CARD_RADIUS, HERO_PULSE_COUNT, ICON_CHIP_GAP, ICON_CHIP_RADIUS, ICON_CHIP_SIZE, LANE_HEADER_BASELINE, LANE_PADDING_X, LANE_RADIUS, SUBTITLE_SIZE, } from "../design.js";
17
16
  const badgeTone = (node, text) => text === deltaBadgeText(node.delta) ? toneFor(node.delta) : "neutral";
18
17
  /** The badge row, laid left to right across the strip the layout reserved. */
@@ -171,13 +170,9 @@ export const paintLabelPill = (text, box, tone, palette) => {
171
170
  }, text));
172
171
  };
173
172
  export const paintArchitecture = (graph, hints, palette) => {
174
- const { layout, routed } = relieveCongestion(graph, hints);
173
+ const { layout, routed, pills } = relieveCongestion(graph, hints);
175
174
  const styles = stylesFor(palette);
176
- const pills = placeLabelPills(routed);
177
- const drawn = layout.nodes.flatMap((node) => {
178
- const row = badgeRow(node);
179
- return row === undefined ? [node.box] : [node.box, row.box];
180
- });
175
+ const drawn = occupiedBoxes(layout.nodes);
181
176
  const edgeMarkup = [];
182
177
  const pillMarkup = [];
183
178
  for (const edge of routed) {
@@ -1 +1 @@
1
- {"version":3,"file":"architecture.js","sourceRoot":"","sources":["../../src/svg/architecture.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"architecture.js","sourceRoot":"","sources":["../../src/svg/architecture.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -5,5 +5,5 @@
5
5
  * not otherwise need.
6
6
  */
7
7
  export declare const RENDERER_NAME = "@coldtea/pr-lens-renderer";
8
- export declare const RENDERER_VERSION = "0.3.0";
8
+ export declare const RENDERER_VERSION = "0.3.2";
9
9
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -5,5 +5,5 @@
5
5
  * not otherwise need.
6
6
  */
7
7
  export const RENDERER_NAME = "@coldtea/pr-lens-renderer";
8
- export const RENDERER_VERSION = "0.3.0";
8
+ export const RENDERER_VERSION = "0.3.2";
9
9
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coldtea/pr-lens-renderer",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "The PR Lens renderer: a schema-valid graph document in, a self-contained animated SVG out.",
5
5
  "license": "MIT",
6
6
  "author": "Coldtea AI",
@@ -40,7 +40,7 @@
40
40
  "node": ">=20.11"
41
41
  },
42
42
  "dependencies": {
43
- "@coldtea/pr-lens-schema": "0.6.0"
43
+ "@coldtea/pr-lens-schema": "0.7.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^20.19.0",
package/src/bounds.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Box } from "./geometry.js";
1
+ import type { Box, Point } from "./geometry.js";
2
2
 
3
3
  /** The smallest box containing both of them. */
4
4
  export const covering = (a: Box, b: Box): Box => {
@@ -17,6 +17,34 @@ export const union = (boxes: readonly Box[]): Box | undefined =>
17
17
  undefined,
18
18
  );
19
19
 
20
+ /** Zero-sized at the origin when there are no points. */
21
+ export const boundsOf = (points: readonly Point[]): Box => {
22
+ const xs = points.map(({ x }) => x);
23
+ const ys = points.map(({ y }) => y);
24
+ const left = xs.length === 0 ? 0 : Math.min(...xs);
25
+ const top = ys.length === 0 ? 0 : Math.min(...ys);
26
+ return {
27
+ x: left,
28
+ y: top,
29
+ width: xs.length === 0 ? 0 : Math.max(...xs) - left,
30
+ height: ys.length === 0 ? 0 : Math.max(...ys) - top,
31
+ };
32
+ };
33
+
34
+ export const inflate = (box: Box, by: number): Box => ({
35
+ x: box.x - by,
36
+ y: box.y - by,
37
+ width: box.width + by * 2,
38
+ height: box.height + by * 2,
39
+ });
40
+
41
+ /** Zero when the boxes touch or overlap. */
42
+ export const gapBetween = (a: Box, b: Box): number =>
43
+ Math.hypot(
44
+ Math.max(b.x - (a.x + a.width), a.x - (b.x + b.width), 0),
45
+ Math.max(b.y - (a.y + a.height), a.y - (b.y + b.height), 0),
46
+ );
47
+
20
48
  export type Canvas = { width: number; height: number; shiftX: number; shiftY: number };
21
49
 
22
50
  /**
package/src/design.ts CHANGED
@@ -76,6 +76,11 @@ export const PILL_PADDING_X = 8;
76
76
  export const PILL_TEXT_SIZE = 9.5;
77
77
  /** Two label pills never sit closer than this, in either direction. */
78
78
  export const PILL_CLEARANCE = 2;
79
+ /**
80
+ * A pill never comes closer than this to a card or its badges: any nearer and
81
+ * the label reads as part of the card instead of the line it rides.
82
+ */
83
+ export const PILL_CARD_CLEARANCE = 6;
79
84
 
80
85
  /**
81
86
  * Routes travel in the gaps of the grid: vertical corridors beside lanes and
@@ -122,6 +122,13 @@ export const badgeRow = (placed: PlacedNode): { badges: string[]; box: Box } | u
122
122
  };
123
123
  };
124
124
 
125
+ /** Every card and badge strip: what a label pill must keep clear of. */
126
+ export const occupiedBoxes = (nodes: readonly PlacedNode[]): Box[] =>
127
+ nodes.flatMap((node) => {
128
+ const row = badgeRow(node);
129
+ return row === undefined ? [node.box] : [node.box, row.box];
130
+ });
131
+
125
132
  /**
126
133
  * The gaps of the grid, for the router: the vertical corridors beside each
127
134
  * lane's cards and the horizontal extents of every row. Corridor `i` runs to
@@ -7,14 +7,24 @@ import {
7
7
  TRACK_CLEARANCE,
8
8
  TRACK_PITCH_MIN,
9
9
  } from "../design.js";
10
+ import { union } from "../bounds.js";
11
+ import type { Box } from "../geometry.js";
10
12
  import type { ScopedGraph } from "../scope.js";
11
13
  import {
12
14
  layoutArchitecture,
15
+ occupiedBoxes,
13
16
  type ArchitectureLayout,
14
17
  type GapExpansions,
15
18
  type LayoutGrid,
16
19
  } from "./architecture.js";
17
- import { channelTraffic, routeEdges, type ChannelTraffic, type RoutedEdge } from "./edges.js";
20
+ import {
21
+ chooseRetiredRoutes,
22
+ routeAndCount,
23
+ routeEdges,
24
+ type ChannelTraffic,
25
+ type RoutedEdge,
26
+ } from "./edges.js";
27
+ import { placeLabelPills, type LabelPlacement } from "./labels.js";
18
28
 
19
29
  /**
20
30
  * Layout and routing with the pitch floor held: any gap whose traffic would
@@ -24,25 +34,68 @@ import { channelTraffic, routeEdges, type ChannelTraffic, type RoutedEdge } from
24
34
  * moves the lanes or rows beside a saturated gap by one pitch step — a small
25
35
  * change staying a small move — and an uncrowded document is laid out
26
36
  * exactly as if this pass did not exist.
37
+ *
38
+ * A corridor is also widened when a label has nowhere on or beside its line
39
+ * to sit — a straight line across a corridor has only its width for a pill.
27
40
  */
28
41
  export const relieveCongestion = (
29
42
  graph: ScopedGraph,
30
43
  hints: LayoutHints | undefined,
31
- ): { layout: ArchitectureLayout; routed: RoutedEdge[] } => {
44
+ ): { layout: ArchitectureLayout; routed: RoutedEdge[]; pills: Map<string, Box> } => {
32
45
  let expansions: GapExpansions = { corridors: new Map(), bands: new Map() };
46
+ let labelRoom = new Map<number, number>();
33
47
  let layout = layoutArchitecture(graph, hints, expansions);
48
+ const retired = chooseRetiredRoutes(graph.edges, layout);
49
+ let placed: { routed: RoutedEdge[]; labels: LabelPlacement } | undefined;
34
50
 
35
51
  // Widening never changes which gaps the routes choose — plans are made of
36
- // lane and row indices, and cards keep their in-lane positions — so the
37
- // second round sees the same traffic and settles. The bound is a backstop.
38
- for (let round = 0; round < 3; round += 1) {
39
- const needed = expansionsFor(channelTraffic(graph.edges, layout), layout.grid);
40
- if (sameExpansions(needed, expansions)) break;
41
- expansions = needed;
52
+ // lane and row indices — so traffic settles after one widening. Label room
53
+ // only grows, so that settles too. The bound is a backstop.
54
+ for (let round = 0; round < 6; round += 1) {
55
+ const { routed, traffic } = routeAndCount(graph.edges, layout, retired);
56
+ const needed = expansionsFor(traffic, layout.grid, labelRoom);
57
+ if (!sameExpansions(needed, expansions)) {
58
+ expansions = needed;
59
+ layout = layoutArchitecture(graph, hints, expansions);
60
+ placed = undefined;
61
+ continue;
62
+ }
63
+
64
+ placed = { routed, labels: labelsOn(layout, routed) };
65
+ const grown = grownRoom(labelRoom, placed.labels.cramped, traffic);
66
+ if (sameEntries(grown, labelRoom)) break;
67
+ labelRoom = grown;
68
+ expansions = expansionsFor(traffic, layout.grid, labelRoom);
42
69
  layout = layoutArchitecture(graph, hints, expansions);
70
+ placed = undefined;
71
+ }
72
+
73
+ if (placed === undefined) {
74
+ const routed = routeEdges(graph.edges, layout, retired);
75
+ placed = { routed, labels: labelsOn(layout, routed) };
43
76
  }
77
+ return { layout, routed: placed.routed, pills: placed.labels.boxes };
78
+ };
79
+
80
+ const labelsOn = (layout: ArchitectureLayout, routed: readonly RoutedEdge[]): LabelPlacement =>
81
+ placeLabelPills(routed, occupiedBoxes(layout.nodes), union(layout.lanes.map(({ box }) => box)));
44
82
 
45
- return { layout, routed: routeEdges(graph.edges, layout) };
83
+ /** Air either side of a corridor-filling pill, so the arrowheads still show. */
84
+ const LABEL_CORRIDOR_AIR = 12;
85
+
86
+ /** Only ever grows, which is what lets the loop settle. */
87
+ const grownRoom = (
88
+ room: ReadonlyMap<number, number>,
89
+ cramped: ReadonlyMap<string, number>,
90
+ traffic: ChannelTraffic,
91
+ ): Map<number, number> => {
92
+ const grown = new Map(room);
93
+ for (const [id, pillWidth] of cramped) {
94
+ const width = pillWidth + LABEL_CORRIDOR_AIR * 2;
95
+ for (const index of traffic.corridorsByEdge.get(id) ?? [])
96
+ grown.set(index, Math.max(grown.get(index) ?? 0, width));
97
+ }
98
+ return grown;
46
99
  };
47
100
 
48
101
  /** Room for this many tracks at the floor pitch, plus clearance to the cards. */
@@ -51,10 +104,16 @@ const widthNeeded = (traffic: number): number =>
51
104
 
52
105
  const CORRIDOR_WIDTH = LANE_PADDING_X * 2 + LANE_GAP;
53
106
 
54
- const expansionsFor = (traffic: ChannelTraffic, grid: LayoutGrid): GapExpansions => {
107
+ const expansionsFor = (
108
+ traffic: ChannelTraffic,
109
+ grid: LayoutGrid,
110
+ labelRoom: ReadonlyMap<number, number>,
111
+ ): GapExpansions => {
55
112
  const corridors = new Map<number, number>();
56
- for (const [index, count] of traffic.corridors) {
57
- const extra = widthNeeded(count) - CORRIDOR_WIDTH;
113
+ for (const index of new Set([...traffic.corridors.keys(), ...labelRoom.keys()])) {
114
+ const count = traffic.corridors.get(index) ?? 0;
115
+ const width = Math.max(count > 0 ? widthNeeded(count) : 0, labelRoom.get(index) ?? 0);
116
+ const extra = width - CORRIDOR_WIDTH;
58
117
  if (extra > 0) corridors.set(index, extra);
59
118
  }
60
119
 
@@ -2,13 +2,17 @@ import type { GraphEdge } from "@coldtea/pr-lens-schema";
2
2
  import { assertNever } from "@coldtea/pr-lens-schema";
3
3
  import {
4
4
  BEND_RADIUS_MAX,
5
+ CARD_HEIGHT,
6
+ PILL_CARD_CLEARANCE,
5
7
  PORT_INSET,
6
8
  PORT_PITCH,
9
+ ROW_GAP,
7
10
  TRACK_CLEARANCE,
8
11
  TRACK_PITCH_MAX,
9
12
  } from "../design.js";
10
13
  import { boxCentre, coord, type Box, type Point, type Side } from "../geometry.js";
11
14
  import type { ArchitectureLayout, LayoutGrid, PlacedLane, PlacedNode } from "./architecture.js";
15
+ import { pillSize } from "./labels.js";
12
16
 
13
17
  /**
14
18
  * A route, kept as its own segments rather than as a path string, because the
@@ -24,7 +28,7 @@ export type RoutedEdge = {
24
28
  edge: GraphEdge;
25
29
  path: string;
26
30
  curve: Curve;
27
- /** Centre of the longest straight run — where this edge's label pill sits. */
31
+ /** Centre of the longest straight run — where a pill with no room on its route starts looking. */
28
32
  labelAnchor: Point | undefined;
29
33
  };
30
34
 
@@ -154,12 +158,11 @@ type Route = {
154
158
  const isDead = (placed: PlacedNode): boolean => placed.node.delta === "removed";
155
159
 
156
160
  /**
157
- * A retired connection with a living end never threads the living graph: it
158
- * exits past the last lane and comes back. Only a connection wholly between
159
- * dead cards keeps its short run inside the dead band — that is the internal
160
- * structure of the retired path.
161
+ * A retired connection with a living end goes directly or into exile, out
162
+ * past the last lane and back.
163
+ * One wholly between dead cards always keeps its short run in the dead band.
161
164
  */
162
- const isExiled = (edge: GraphEdge, from: PlacedNode, to: PlacedNode): boolean =>
165
+ const isRetiredWithLivingEnd = (edge: GraphEdge, from: PlacedNode, to: PlacedNode): boolean =>
163
166
  !(isDead(from) && isDead(to)) && (edge.delta === "removed" || isDead(from) || isDead(to));
164
167
 
165
168
  const clampBand = (index: number, grid: LayoutGrid): number =>
@@ -600,14 +603,80 @@ const labelAnchorOf = (curve: Curve): Point => {
600
603
  return best?.middle ?? pointAt(curve, 0.5);
601
604
  };
602
605
 
606
+ export type RetiredRoutes = ReadonlyMap<string, "direct" | "exile">;
607
+
608
+ /** A crossing of a living line is worth one row's pitch of extra travel. */
609
+ const CROSSING_COST = CARD_HEIGHT + ROW_GAP;
610
+
611
+ /**
612
+ * Direct or exile for each retired connection, whichever costs less in
613
+ * length plus crossings. Exile keeps retired paths out of the living graph,
614
+ * but in a wide diagram it sends the reader around everything. Decided on
615
+ * the first layout and held, so widening a gap can never flip a route.
616
+ */
617
+ export const chooseRetiredRoutes = (
618
+ edges: readonly GraphEdge[],
619
+ layout: ArchitectureLayout,
620
+ ): RetiredRoutes => {
621
+ const nodes = new Map(layout.nodes.map((node) => [node.node.id, node]));
622
+ const retired = edges.filter((edge) => {
623
+ const from = nodes.get(edge.from);
624
+ const to = nodes.get(edge.to);
625
+ if (from === undefined || to === undefined || edge.from === edge.to) return false;
626
+ return isRetiredWithLivingEnd(edge, from, to);
627
+ });
628
+ if (retired.length === 0) return new Map();
629
+
630
+ const everyone = (way: "direct" | "exile"): RetiredRoutes =>
631
+ new Map(retired.map(({ id }) => [id, way]));
632
+ const retiredIds = new Set(retired.map(({ id }) => id));
633
+ const costs = (pass: Pass): Map<string, number> => {
634
+ const living = [...pass.waypoints]
635
+ .filter(([id]) => !retiredIds.has(id))
636
+ .map(([, points]) => points);
637
+ return new Map(
638
+ retired.map(({ id }) => {
639
+ const points = pass.waypoints.get(id) ?? [];
640
+ const crossings = living.reduce((sum, other) => sum + crossingCount(points, other), 0);
641
+ return [id, polylineLength(points) + crossings * CROSSING_COST];
642
+ }),
643
+ );
644
+ };
645
+
646
+ const directPass = finalPass(edges, layout, everyone("direct"));
647
+ const direct = costs(directPass);
648
+ const exile = costs(finalPass(edges, layout, everyone("exile")));
649
+ return new Map(
650
+ retired.map(({ id, label }) => {
651
+ const points = directPass.waypoints.get(id) ?? [];
652
+ const fits = label === undefined || holdsPill(points, pillSize(label));
653
+ const cheaper = (direct.get(id) ?? Number.POSITIVE_INFINITY) < (exile.get(id) ?? 0);
654
+ return [id, fits && cheaper ? "direct" : "exile"];
655
+ }),
656
+ );
657
+ };
658
+
659
+ /** No label fits on the direct line between a pair's halves; exile gives it room. */
660
+ const holdsPill = (points: readonly Point[], pill: { width: number; height: number }): boolean =>
661
+ points.some((point, index) => {
662
+ const previous = points[index - 1];
663
+ if (previous === undefined) return false;
664
+ const horizontal = Math.abs(point.y - previous.y) < EPSILON;
665
+ const length = Math.hypot(point.x - previous.x, point.y - previous.y);
666
+ return length >= (horizontal ? pill.width : pill.height) + PILL_CARD_CLEARANCE * 2;
667
+ });
668
+
603
669
  export const routeEdges = (
604
670
  edges: readonly GraphEdge[],
605
671
  layout: ArchitectureLayout,
606
- ): RoutedEdge[] => finalPass(edges, layout).routed;
672
+ retired: RetiredRoutes,
673
+ ): RoutedEdge[] => finalPass(edges, layout, retired).routed;
607
674
 
608
675
  export type ChannelTraffic = {
609
676
  corridors: ReadonlyMap<number, number>;
610
677
  bands: ReadonlyMap<number, number>;
678
+ /** Where room for each edge's label would have to come from. */
679
+ corridorsByEdge: ReadonlyMap<string, readonly number[]>;
611
680
  };
612
681
 
613
682
  /**
@@ -619,28 +688,46 @@ export type ChannelTraffic = {
619
688
  export const channelTraffic = (
620
689
  edges: readonly GraphEdge[],
621
690
  layout: ArchitectureLayout,
622
- ): ChannelTraffic => {
691
+ retired: RetiredRoutes,
692
+ ): ChannelTraffic => routeAndCount(edges, layout, retired).traffic;
693
+
694
+ /** One routing pass, shared by drawing and gap sizing. */
695
+ export const routeAndCount = (
696
+ edges: readonly GraphEdge[],
697
+ layout: ArchitectureLayout,
698
+ retired: RetiredRoutes,
699
+ ): { routed: RoutedEdge[]; traffic: ChannelTraffic } => {
700
+ const pass = finalPass(edges, layout, retired);
623
701
  const corridors = new Map<number, number>();
624
702
  const bands = new Map<number, number>();
625
- for (const route of finalPass(edges, layout).plans)
703
+ const corridorsByEdge = new Map<string, number[]>();
704
+ for (const route of pass.plans)
626
705
  for (const channel of route.channels)
627
706
  switch (channel.kind) {
628
- case "corridor":
707
+ case "corridor": {
629
708
  corridors.set(channel.index, (corridors.get(channel.index) ?? 0) + 1);
709
+ const through = corridorsByEdge.get(route.edge.id) ?? [];
710
+ through.push(channel.index);
711
+ corridorsByEdge.set(route.edge.id, through);
630
712
  break;
713
+ }
631
714
  case "band":
632
715
  bands.set(channel.index, (bands.get(channel.index) ?? 0) + 1);
633
716
  break;
634
717
  default:
635
718
  assertNever(channel, "Unhandled channel");
636
719
  }
637
- return { corridors, bands };
720
+ return { routed: pass.routed, traffic: { corridors, bands, corridorsByEdge } };
638
721
  };
639
722
 
640
- const finalPass = (edges: readonly GraphEdge[], layout: ArchitectureLayout): Pass => {
641
- const first = routePass(edges, layout, new Set());
723
+ const finalPass = (
724
+ edges: readonly GraphEdge[],
725
+ layout: ArchitectureLayout,
726
+ retired: RetiredRoutes,
727
+ ): Pass => {
728
+ const first = routePass(edges, layout, new Set(), retired);
642
729
  const braiding = braidingTrunks(first.branches);
643
- return braiding.size === 0 ? first : routePass(edges, layout, braiding);
730
+ return braiding.size === 0 ? first : routePass(edges, layout, braiding, retired);
644
731
  };
645
732
 
646
733
  type Pass = {
@@ -648,12 +735,15 @@ type Pass = {
648
735
  plans: Route[];
649
736
  /** Per trunk group, each member's waypoints minus the shared head segment. */
650
737
  branches: Map<string, Point[][]>;
738
+ /** Every planned route's waypoints, before its corners are rounded. */
739
+ waypoints: Map<string, Point[]>;
651
740
  };
652
741
 
653
742
  const routePass = (
654
743
  edges: readonly GraphEdge[],
655
744
  layout: ArchitectureLayout,
656
745
  blockedTrunks: ReadonlySet<string>,
746
+ retired: RetiredRoutes,
657
747
  ): Pass => {
658
748
  const nodes = new Map(layout.nodes.map((node) => [node.node.id, node]));
659
749
  const blocked = blockedFaces(layout.nodes);
@@ -671,7 +761,7 @@ const routePass = (
671
761
 
672
762
  const trunkCounts = new Map<string, number>();
673
763
  for (const { edge, from, to } of drawable) {
674
- if (loops.has(edge.id) || isExiled(edge, from, to) || isDead(from)) continue;
764
+ if (loops.has(edge.id) || isRetiredWithLivingEnd(edge, from, to) || isDead(from)) continue;
675
765
  const key = trunkKey(edge, from, to);
676
766
  if (key === undefined || blockedTrunks.has(key)) continue;
677
767
  trunkCounts.set(key, (trunkCounts.get(key) ?? 0) + 1);
@@ -680,14 +770,16 @@ const routePass = (
680
770
  const routes: Route[] = drawable
681
771
  .filter(({ edge }) => !loops.has(edge.id))
682
772
  .map(({ edge, order, from, to }) => {
683
- if (isExiled(edge, from, to))
773
+ if (isRetiredWithLivingEnd(edge, from, to))
684
774
  return {
685
775
  edge,
686
776
  order,
687
777
  from,
688
778
  to,
689
779
  trunk: undefined,
690
- ...planExile(from, to, grid, laneCount, blocked),
780
+ ...(retired.get(edge.id) === "direct"
781
+ ? planRoute(from, to, layout.lanes, grid, blocked)
782
+ : planExile(from, to, grid, laneCount, blocked)),
691
783
  };
692
784
 
693
785
  const key = isDead(from) ? undefined : trunkKey(edge, from, to);
@@ -703,6 +795,7 @@ const routePass = (
703
795
  const tracks = allocateTracks(routes, ports, grid);
704
796
 
705
797
  const branches = new Map<string, Point[][]>();
798
+ const waypoints = new Map<string, Point[]>();
706
799
  const routedById = new Map<string, RoutedEdge>();
707
800
 
708
801
  for (const route of routes) {
@@ -713,6 +806,7 @@ const routePass = (
713
806
  (index) => tracks.get(`${route.edge.id}#${index}`) ?? 0,
714
807
  );
715
808
 
809
+ waypoints.set(route.edge.id, points);
716
810
  if (route.trunk !== undefined) {
717
811
  const list = branches.get(route.trunk) ?? [];
718
812
  list.push(points.slice(1));
@@ -740,7 +834,7 @@ const routePass = (
740
834
  };
741
835
  });
742
836
 
743
- return { routed, plans: routes, branches };
837
+ return { routed, plans: routes, branches, waypoints };
744
838
  };
745
839
 
746
840
  type Port = { along: number };
@@ -1012,7 +1106,8 @@ const braidingTrunks = (branches: ReadonlyMap<string, Point[][]>): Set<string> =
1012
1106
  return braiding;
1013
1107
  };
1014
1108
 
1015
- const polylinesCross = (a: readonly Point[], b: readonly Point[]): boolean => {
1109
+ const crossingCount = (a: readonly Point[], b: readonly Point[]): number => {
1110
+ let count = 0;
1016
1111
  for (let i = 0; i + 1 < a.length; i += 1)
1017
1112
  for (let j = 0; j + 1 < b.length; j += 1) {
1018
1113
  const a1 = a[i];
@@ -1020,11 +1115,21 @@ const polylinesCross = (a: readonly Point[], b: readonly Point[]): boolean => {
1020
1115
  const b1 = b[j];
1021
1116
  const b2 = b[j + 1];
1022
1117
  if (a1 === undefined || a2 === undefined || b1 === undefined || b2 === undefined) continue;
1023
- if (segmentsCross(a1, a2, b1, b2)) return true;
1118
+ if (segmentsCross(a1, a2, b1, b2)) count += 1;
1024
1119
  }
1025
- return false;
1120
+ return count;
1026
1121
  };
1027
1122
 
1123
+ const polylineLength = (points: readonly Point[]): number =>
1124
+ points.reduce((sum, point, index) => {
1125
+ const previous = points[index - 1];
1126
+ if (previous === undefined) return sum;
1127
+ return sum + Math.hypot(point.x - previous.x, point.y - previous.y);
1128
+ }, 0);
1129
+
1130
+ const polylinesCross = (a: readonly Point[], b: readonly Point[]): boolean =>
1131
+ crossingCount(a, b) > 0;
1132
+
1028
1133
  const EPSILON = 0.01;
1029
1134
 
1030
1135
  /** Proper crossing or collinear overlap of two axis-aligned segments. */