@mark1russell7/highways 0.1.5 → 0.3.0

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.
Files changed (56) hide show
  1. package/README.md +293 -8
  2. package/build/index.d.ts +1774 -236
  3. package/build/index.d.ts.map +1 -1
  4. package/build/index.js +9307 -3090
  5. package/build/index.js.map +1 -1
  6. package/package.json +2 -1
  7. package/src/bench/compare.ts +145 -0
  8. package/src/bench/curves.ts +514 -2
  9. package/src/bench/links.ts +28 -6
  10. package/src/bench/measures/bundles.ts +119 -0
  11. package/src/bench/measures/curves.ts +211 -0
  12. package/src/bench/measures/groups.ts +122 -0
  13. package/src/bench/measures/index.ts +9 -0
  14. package/src/bench/measures/levels.ts +103 -0
  15. package/src/bench/measures/pareto.ts +37 -0
  16. package/src/bench/measures/room.ts +43 -0
  17. package/src/bench/measures/routes.ts +226 -0
  18. package/src/bench/measures/stability.ts +104 -0
  19. package/src/bench/measures/stats.ts +114 -0
  20. package/src/bench/properties.ts +18 -2
  21. package/src/bench/room.ts +209 -2
  22. package/src/bench/run.ts +86 -11
  23. package/src/bench/sections.ts +121 -0
  24. package/src/bench/suite.ts +781 -0
  25. package/src/cases.ts +41 -5
  26. package/src/curves/clothoid/index.ts +150 -0
  27. package/src/curves/corner.ts +116 -0
  28. package/src/curves/fit.ts +79 -0
  29. package/src/curves/highway/index.ts +636 -0
  30. package/src/curves/index.ts +16 -1
  31. package/src/curves/model.ts +4 -2
  32. package/src/curves/smooth/index.ts +50 -0
  33. package/src/curves/space.ts +76 -0
  34. package/src/groups/cut/index.ts +292 -0
  35. package/src/groups/index.ts +4 -0
  36. package/src/groups/kd/index.ts +207 -0
  37. package/src/groups/keys/index.ts +81 -0
  38. package/src/groups/quadtree/index.ts +10 -0
  39. package/src/index.ts +7 -0
  40. package/src/levels.ts +178 -9
  41. package/src/model.ts +2 -0
  42. package/src/pick.ts +36 -0
  43. package/src/room/bends.ts +203 -0
  44. package/src/room/index.ts +28 -0
  45. package/src/room/levels/index.ts +155 -0
  46. package/src/routers/sections.ts +78 -55
  47. package/src/routers/shared.ts +7 -2
  48. package/src/routers/trunks.ts +131 -6
  49. package/src/sections.ts +93 -4
  50. package/src/segments.ts +81 -31
  51. package/src/strategies/builtins.ts +153 -7
  52. package/src/strategies/index.ts +1 -0
  53. package/src/strategies/model.ts +29 -7
  54. package/src/strategies/options.ts +296 -0
  55. package/src/strategies/schemas.ts +221 -0
  56. package/src/visibility.ts +190 -1
package/build/index.d.ts CHANGED
@@ -96,6 +96,8 @@ export interface Node {
96
96
  readonly id: string;
97
97
  readonly box: Box;
98
98
  readonly ports?: readonly Port[];
99
+ /** This data is free for the grouping rules of the nodes. The rule `keys` reads the string `data.group` by default. */
100
+ readonly data?: Readonly<Record<string, unknown>>;
99
101
  }
100
102
  /** One end of an edge: a node, and optionally one plug of that node. */
101
103
  export interface End {
@@ -244,6 +246,17 @@ export declare function hubChainBoard(): Graph;
244
246
  * On a level with many groups, some level links go around the outer edge of the board.
245
247
  */
246
248
  export declare function manyGroupsBoard(): Graph;
249
+ /** The options of `packedGridBoard`. */
250
+ export interface PackedGridOptions {
251
+ /** The seed of the links. The default is 11. */
252
+ readonly seed?: number;
253
+ /** The number of columns. The default is 12. */
254
+ readonly cols?: number;
255
+ /** The number of rows. The default is 8. */
256
+ readonly rows?: number;
257
+ /** The number of long links between boxes far apart. The default is 48. */
258
+ readonly long?: number;
259
+ }
247
260
  /**
248
261
  * This function makes the far view of a board after a host layout packs it.
249
262
  * The board has 96 boxes of one size in a grid of 12 columns and 8 rows.
@@ -251,8 +264,17 @@ export declare function manyGroupsBoard(): Graph;
251
264
  * The links have no channel between the boxes. The roadmap item ROOM measures this board before and after `makeRoom`.
252
265
  *
253
266
  * The board is not in `CASES`, because the digests of the router fix the output on each board of `CASES`.
267
+ * The options make a family of such boards for the measure suite. Without options, the board does not change.
268
+ */
269
+ export declare function packedGridBoard(options?: PackedGridOptions): Graph;
270
+ /**
271
+ * This function makes a packed board with three zoom levels of groups. The board has 256 touching boxes in a grid of 16 columns and 16 rows.
272
+ * The quadtree of `buildSections` splits it into 4, 16 and 64 groups. Each box links to a box near it, and 64 long links join boxes far apart.
273
+ * At each level, the boxes of the groups touch, so the level links have no channel. The roadmap item ROOM2 measures this board.
274
+ *
275
+ * The board is not in `CASES`, because the digests of the router fix the output on each board of `CASES`.
254
276
  */
255
- export declare function packedGridBoard(): Graph;
277
+ export declare function nestedGridBoard(): Graph;
256
278
  /** The case boards of the benchmark. Each board has a few hundred nodes at most, so the benchmark races them on each run. */
257
279
  export declare const CASES: readonly CaseBoard[];
258
280
  /** A plug: the point where a route leaves or enters a node, and the outward normal of its side. */
@@ -312,8 +334,10 @@ export declare function roundCorners(p: readonly Point[], radius: number, steps?
312
334
  * - `rounded`: a quadratic Bezier curve at each corner, as `roundCorners` draws it.
313
335
  * - `spline`: a centripetal Catmull-Rom spline through the points. It does not overshoot or make loops.
314
336
  * - `arc`: a circular arc at each corner, tangent to the two legs.
337
+ * - `smooth`: a cubic spiral, an arc and a second cubic spiral at each corner, as the corner smoothing of Figma.
338
+ * - `clothoid`: a clothoid, an arc and a second clothoid at each corner, as a transition curve of a road.
315
339
  */
316
- export type CurveType = "straight" | "rounded" | "spline" | "arc";
340
+ export type CurveType = "straight" | "rounded" | "spline" | "arc" | "smooth" | "clothoid";
317
341
  /** The curve types, in the order of the benchmark. */
318
342
  export declare const CURVE_TYPES: readonly CurveType[];
319
343
  /** The start of a curve: the pen goes to `to` and draws nothing. */
@@ -367,6 +391,12 @@ interface CurveSpace {
367
391
  * A polyline goes through a box when a part of it longer than `TOLERANCE` is inside the box made smaller by `TOLERANCE`.
368
392
  */
369
393
  addsHit(q: readonly Point[], p: readonly Point[]): boolean;
394
+ /**
395
+ * This method tells if the triangle `(a, v, b)` overlaps a box that the polyline `(a, v, b)` does not go through.
396
+ * A convex corner from `a` to `b` stays in this triangle, so a clear triangle proves a clear corner with no samples.
397
+ * The method is optional. Without it, a corner samples its curve.
398
+ */
399
+ addsHitTriangle?(a: Point, v: Point, b: Point): boolean;
370
400
  }
371
401
  /**
372
402
  * This function makes the free space of a board from its boxes. The boxes are the nodes, or the items of a zoom level.
@@ -439,13 +469,191 @@ interface ArcOptions {
439
469
  * On a polyline with only horizontal and vertical legs, each arc is a quarter circle.
440
470
  */
441
471
  export declare function arcCurve(points: readonly Point[], options?: ArcOptions): CurveSegment[];
472
+ /** The options of `smoothCurve`. */
473
+ interface SmoothOptions {
474
+ /** The radius of the arc in the middle of each corner: the smallest radius of the corner. The default is 12. */
475
+ readonly radius?: number;
476
+ /** The share of the turn of a corner in its two spirals, from 0 (a circular arc) to 1 (no arc). The default is 0.6. */
477
+ readonly smoothing?: number;
478
+ /** The boxes that the curve must not go through. Without it, each corner gets the largest radius that fits on its legs. */
479
+ readonly space?: CurveSpace;
480
+ }
481
+ /**
482
+ * This function rounds each inner vertex of a polyline with a cubic spiral, a circular arc and a second cubic spiral.
483
+ * It is the shape of the corner smoothing of Figma (F7 of the note CURVES). The curvature rises from 0 on the leg to `1 / radius` on the arc,
484
+ * so the curve is G2: it has no jump of the curvature. Each spiral turns by `smoothing` times half of the turn, up to `MAX_SPIRAL_TURN`.
485
+ * The ends of each corner stay on the first half of each leg, so the ends of the polyline stay.
486
+ * With `space`, the radius of a corner shrinks until its corner triangle overlaps no box that the polyline avoids.
487
+ */
488
+ export declare function smoothCurve(points: readonly Point[], options?: SmoothOptions): CurveSegment[];
489
+ /** The options of `clothoidCurve`. */
490
+ interface ClothoidOptions {
491
+ /** The radius of the arc in the middle of each corner: the smallest radius of the corner. The default is 12. */
492
+ readonly radius?: number;
493
+ /** The share of the turn of a corner in its two clothoids, from 0 (a circular arc) to 1 (no arc). The default is 0.5. */
494
+ readonly spiral?: number;
495
+ /** The largest distance from the cubic pieces to the true clothoid, in units of the plane. The default is 0.25. */
496
+ readonly tolerance?: number;
497
+ /** The boxes that the curve must not go through. Without it, each corner gets the largest radius that fits on its legs. */
498
+ readonly space?: CurveSpace;
499
+ }
500
+ /**
501
+ * This function rounds each inner vertex of a polyline with a clothoid, a circular arc and a second clothoid (F6 of the note CURVES).
502
+ * The curvature of a clothoid grows linearly with its length, from 0 on the leg to `1 / radius` on the arc. This is the transition curve of roads and railways.
503
+ * Each clothoid turns by `spiral` times half of the turn. G2 cubic pieces draw it within `tolerance` of the true clothoid.
504
+ *
505
+ * The ends of each corner stay on the first half of each leg, so the ends of the polyline stay.
506
+ * With `space`, the radius of a corner shrinks until its corner triangle overlaps no box that the polyline avoids.
507
+ */
508
+ export declare function clothoidCurve(points: readonly Point[], options?: ClothoidOptions): CurveSegment[];
509
+ /** A piece of drawn way. A shared segment carries several edges, in lane order. A private segment carries one edge. */
510
+ export interface Segment {
511
+ readonly id: string;
512
+ readonly points: readonly Point[];
513
+ /** The edges in lane order. Lane 0 is on the left of the segment, from its first point to its last. The y axis points down. */
514
+ readonly edges: readonly string[];
515
+ /** The number of edges. A renderer shows it on a fat edge. */
516
+ readonly count: number;
517
+ }
518
+ /** One step of a path: a segment, the way through it, and the lane of the edge in it. */
519
+ export interface SegmentRef {
520
+ readonly segment: string;
521
+ /** This value is true when the edge goes from the last point of the segment to its first point. */
522
+ readonly reverse: boolean;
523
+ readonly lane: number;
524
+ }
525
+ /** The route of one edge as a list of segments. */
526
+ export interface Path {
527
+ readonly edge: string;
528
+ readonly segments: readonly SegmentRef[];
529
+ }
530
+ /** The routes of a result as shared geometry. A renderer can draw each segment one time, with a count. */
531
+ export interface SegmentGraph {
532
+ readonly segments: readonly Segment[];
533
+ readonly paths: readonly Path[];
534
+ }
535
+ /**
536
+ * This function breaks each route into segments. The runs and the trunks of the bundles become shared segments.
537
+ * The other parts of each route become private segments. The segments of a path, in order, give the points of its route again.
538
+ */
539
+ export declare function segmentsOf(result: Result): SegmentGraph;
540
+ /** This function gives the points of a path, with the segments in the order and the way of the path. */
541
+ export declare function pathPoints(graph: SegmentGraph, path: Path): Point[];
542
+ /**
543
+ * This function moves each point of a polyline by `d` to the left, in a frame with the y axis down.
544
+ * At an inner point, it moves along the bisector, at most 2 × `d` far.
545
+ */
546
+ export declare function offsetPolyline(p: readonly Point[], d: number): Point[];
547
+ /** The options of `pullApart`. */
548
+ export interface PullApartOptions {
549
+ /** The distance between two lanes. */
550
+ readonly spacing: number;
551
+ /** The largest width of a segment, from its outer lane on the left to its outer lane on the right. */
552
+ readonly maxWidth: number;
553
+ }
554
+ /**
555
+ * This function pulls the lanes of each shared segment apart, and gives a route for each edge.
556
+ * The lanes keep the lane order, so they do not cross in a segment. The two ends of each route stay at their plugs.
557
+ */
558
+ export declare function pullApart(graph: SegmentGraph, options: PullApartOptions): Route[];
559
+ /** This function gives the key of a shared run: the ids of its edges, sorted and joined with commas. */
560
+ export declare function runKey(edges: readonly string[]): string;
561
+ /**
562
+ * This function opens the shared segments whose key is in `open`: each edge of an open segment gets its own lane.
563
+ * The lanes are `laneWidth` apart, and an open segment is at most `maxWidth` wide. The other segments stay as one way.
564
+ *
565
+ * Lane 0 is on the left of the segment, from its first point to its last, with the y axis down.
566
+ * The function takes a result or its segments. It gives a route for each edge, with the ends at their plugs.
567
+ * The key of a segment is `runKey` of its edges.
568
+ */
569
+ export declare function laneRoutes(source: Result | SegmentGraph, open: ReadonlySet<string>, laneWidth: number, maxWidth?: number): Route[];
570
+ /**
571
+ * The lane order of the shared ways of a router.
572
+ * With `bundle`, two edges keep one order on all the shared ways of their common stretch.
573
+ * With `run`, each shared way gets its order alone. Two edges can change sides from one shared way to the next.
574
+ */
575
+ export type RunOrder = "bundle" | "run";
576
+ /**
577
+ * This function gives the lane order of the edges on a shared way `run` (metro-line order).
578
+ * The routes are polylines that hold the points of the run in a row, in either direction. A route that does not hold the run goes last.
579
+ *
580
+ * Two routes go on together past each end of the run until they part. The route that turns more to the left there gets the lane more to the left.
581
+ *
582
+ * With the order `run`, the default, the end after the last point of the run tells the side first.
583
+ * With the order `bundle`, two routes that part on one side at both ends keep that side.
584
+ * When the two ends disagree, the two routes must cross. The end with the smaller x, then the smaller y, tells the side.
585
+ * Thus each shared way of a common stretch gives two routes the same order, and the crossing is where they part.
586
+ */
587
+ export declare function orderLanes(run: readonly Point[], routes: readonly Route[], order?: RunOrder): string[];
588
+ /** The options of `highwayCurves`. */
589
+ interface HighwayOptions {
590
+ /** The radius at a bend of the center line of a bundle, at a lone corner, and at a merge or a split. The default is 12. */
591
+ readonly radius?: number;
592
+ /** The smallest radius of each lane at a bend, a merge or a split. A bend of a bundle grows to keep its inner lane at this radius. The default is 4. */
593
+ readonly minRadius?: number;
594
+ /** The largest width of an open segment, from its outer lane on the left to its outer lane on the right, as in `laneRoutes`. The default is `Infinity`. */
595
+ readonly maxWidth?: number;
596
+ /** The boxes that the lanes must not go through, from `curveSpace`. With it, no lane goes through a box that its lane of `laneRoutes` avoids. */
597
+ readonly space?: CurveSpace;
598
+ /** The shape of the S curve where a lane joins or leaves a bundle. The default is `biarc`. */
599
+ readonly jog?: JogStyle;
600
+ /** The number of cubic pieces of a `quintic` S curve, from 1 to 8. The default is 4. */
601
+ readonly jogPieces?: number;
602
+ }
603
+ /**
604
+ * The shape of the S curve where a lane changes its offset.
605
+ *
606
+ * - `biarc`: two circular arcs. The curvature jumps at each end and at the inflection.
607
+ * - `cubic`: one cubic Bezier curve with its handles along the leg. The curvature jumps at each end.
608
+ * - `quintic`: the quintic `y = d (10 t³ - 15 t⁴ + 6 t⁵)`, in G2 cubic pieces. The curvature is 0 at each end and has no jump.
609
+ *
610
+ * Each shape keeps its curvature at `1 / radius` or less. The polynomial shapes are longer than the biarc for this reason.
611
+ */
612
+ type JogStyle = "biarc" | "cubic" | "quintic";
613
+ /**
614
+ * The S curves of the lanes, by the order of `laneRoutes`. Each S curve has the first and the last index of its segments in the curve of its lane, and its shape.
615
+ * A polynomial S curve that does not fit on its leg is a biarc.
616
+ */
617
+ type JogTrace = (readonly [number, number, JogStyle])[][];
618
+ /** The curve of the lane of one edge: a list of segments for any renderer, as `curveOf` gives. */
619
+ interface LaneCurve {
620
+ readonly edge: string;
621
+ readonly segments: CurveSegment[];
622
+ }
623
+ /**
624
+ * This function gives the curve of one polyline as a lane alone: an arc at each corner, as `arcCurve` gives.
625
+ * A lane alone has no merge and no split, so the curve strategy `highway` gives this curve for one polyline.
626
+ */
627
+ export declare function highwayCurve(points: readonly Point[], options?: Pick<HighwayOptions, "radius" | "space">): CurveSegment[];
628
+ /**
629
+ * This function gives the curve of each lane of `laneRoutes`. The lanes of one open segment bend as one highway.
630
+ *
631
+ * At each bend of an open segment, the lanes are arcs with one center. The radius of a lane is the radius of the center line,
632
+ * plus or minus its offset. So the lanes stay at the lane spacing through the bend. The bend grows to keep the inner lane at `minRadius`,
633
+ * and it shrinks to fit on the legs and in the free space.
634
+ *
635
+ * A lane joins (merges) or leaves (splits) a bundle on an S curve on the leg with fewer lanes. The option `jog` gives its shape.
636
+ * The smallest radius of the S curve is `radius` or less.
637
+ * Each curve has no break of its tangent where each radius is more than 0.
638
+ * A lane that is in no open segment gets the curve of `arcCurve`.
639
+ *
640
+ * The function takes the same input as `laneRoutes`, and it gives the curves in the order of `laneRoutes`.
641
+ * The output is a list of segments for any renderer. `toSvgPath` writes it as SVG path data, and `sampleCurve` gives points.
642
+ */
643
+ export declare function highwayCurves(source: Result | SegmentGraph, open: ReadonlySet<string>, laneWidth: number, options?: HighwayOptions): LaneCurve[];
442
644
  /** The options of `curveOf`. Each type reads only the options that it uses. */
443
645
  export interface CurveOptions {
444
646
  readonly type: CurveType;
445
- /** The types `rounded` and `arc` read this radius of the corners. The default is 12. */
647
+ /** The types `rounded`, `arc`, `smooth` and `clothoid` read this radius of the corners. The default is 12. */
446
648
  readonly radius?: number;
447
649
  /** The type `spline` reads this tension, from 0 to 1. The default is 0. */
448
650
  readonly tension?: number;
651
+ /** The type `smooth` reads this share of the turn of a corner in its spirals, from 0 to 1. The default is 0.6. */
652
+ readonly smoothing?: number;
653
+ /** The type `clothoid` reads this share of the turn of a corner in its clothoids, from 0 to 1. The default is 0.5. */
654
+ readonly spiral?: number;
655
+ /** The type `clothoid` reads this largest distance from its cubic pieces to the true clothoid. The default is 0.25. */
656
+ readonly tolerance?: number;
449
657
  /** The type `spline` leaves the first point along this outward normal of its plug. */
450
658
  readonly startNormal?: Point;
451
659
  /** The type `spline` comes into the last point against this outward normal of its plug. */
@@ -473,6 +681,12 @@ export declare class Obstacles {
473
681
  hit(a: Point, b: Point, pad: number, skip?: ReadonlySet<Node>): Node | undefined;
474
682
  /** This method tells if the polyline stays out of each box, made larger by `pad`. The nodes in `skip` do not count. */
475
683
  clearPath(p: readonly Point[], pad: number, skip?: ReadonlySet<Node>): boolean;
684
+ /**
685
+ * This method gives each node whose box the segment `ab` goes through to `visit`, one time each.
686
+ * The segment goes through a box when a part of it longer than `TOLERANCE` is inside the box made smaller by `TOLERANCE`.
687
+ * The link measures (`measureLinks`) use the same test.
688
+ */
689
+ through(a: Point, b: Point, visit: (n: Node) => void): void;
476
690
  /** This method gives each node whose bucket the box touches to `visit`. A node can be outside the box. */
477
691
  query(box: Box, visit: (n: Node) => void): void;
478
692
  /** This method tells if the point is inside a box, made larger by `pad`. The node `skip` does not count. */
@@ -539,6 +753,36 @@ export declare class CornerGraph {
539
753
  /** This method removes the vertices that a later vertex makes needless: from each vertex, it goes to the farthest vertex in view. */
540
754
  pull(p: readonly Point[], lookahead?: number): Point[];
541
755
  }
756
+ /** The options of the soft graph. */
757
+ export interface SoftGraphOptions {
758
+ /** The distance from a box to its corners. */
759
+ readonly margin: number;
760
+ /** The number of nearest neighbours of each vertex. */
761
+ readonly k: number;
762
+ /**
763
+ * The spacing of a lattice of points in the bounding box of the boxes, in units of the mean node size. The default is 3, and 0 turns it off.
764
+ * The lattice links groups of boxes across empty space.
765
+ */
766
+ readonly lattice?: number;
767
+ }
768
+ /**
769
+ * A graph whose links can go through the boxes. Its vertices are the corners of the boxes, made larger by `margin`,
770
+ * and a lattice of points in the bounding box of the boxes. Each vertex links to its `k` nearest vertices, in view or not.
771
+ * The graph keeps the boxes that each link goes through (`Obstacles.through`).
772
+ * A search gives each box a cost, so a path goes through few boxes, and only through boxes of a low cost.
773
+ */
774
+ export declare class SoftGraph {
775
+ #private;
776
+ readonly points: Point[];
777
+ /** This constructor makes the graph of the nodes. */
778
+ constructor(nodes: readonly Node[], obstacles: Obstacles, options: SoftGraphOptions);
779
+ /**
780
+ * This method gives a path of least cost from `from` to `to` (A*), with the two points as its ends.
781
+ * The cost of a path is its length, plus `cost(n)` for each link of the path and each box `n` of that link.
782
+ * Each cost must be 0 or more. The straight line from `from` to `to` is a path too, so the method always gives a path.
783
+ */
784
+ path(from: Point, to: Point, cost: (n: Node) => number): Point[];
785
+ }
542
786
  /** The options of a way finder. */
543
787
  export interface WayOptions {
544
788
  /** The distance from a box to the corners of the graph. The default is 5. */
@@ -568,74 +812,6 @@ export declare class WayFinder {
568
812
  /** This method gives a way from a free point to a plug, or `undefined` when the graph has none. */
569
813
  toPlug(from: Point, pt: Plug): Point[] | undefined;
570
814
  }
571
- /** A piece of drawn way. A shared segment carries several edges, in lane order. A private segment carries one edge. */
572
- export interface Segment {
573
- readonly id: string;
574
- readonly points: readonly Point[];
575
- /** The edges in lane order. Lane 0 is on the left of the segment, from its first point to its last. The y axis points down. */
576
- readonly edges: readonly string[];
577
- /** The number of edges. A renderer shows it on a fat edge. */
578
- readonly count: number;
579
- }
580
- /** One step of a path: a segment, the way through it, and the lane of the edge in it. */
581
- export interface SegmentRef {
582
- readonly segment: string;
583
- /** This value is true when the edge goes from the last point of the segment to its first point. */
584
- readonly reverse: boolean;
585
- readonly lane: number;
586
- }
587
- /** The route of one edge as a list of segments. */
588
- export interface Path {
589
- readonly edge: string;
590
- readonly segments: readonly SegmentRef[];
591
- }
592
- /** The routes of a result as shared geometry. A renderer can draw each segment one time, with a count. */
593
- export interface SegmentGraph {
594
- readonly segments: readonly Segment[];
595
- readonly paths: readonly Path[];
596
- }
597
- /**
598
- * This function breaks each route into segments. The runs and the trunks of the bundles become shared segments.
599
- * The other parts of each route become private segments. The segments of a path, in order, give the points of its route again.
600
- */
601
- export declare function segmentsOf(result: Result): SegmentGraph;
602
- /** This function gives the points of a path, with the segments in the order and the way of the path. */
603
- export declare function pathPoints(graph: SegmentGraph, path: Path): Point[];
604
- /**
605
- * This function moves each point of a polyline by `d` to the left, in a frame with the y axis down.
606
- * At an inner point, it moves along the bisector, at most 2 × `d` far.
607
- */
608
- export declare function offsetPolyline(p: readonly Point[], d: number): Point[];
609
- /** The options of `pullApart`. */
610
- export interface PullApartOptions {
611
- /** The distance between two lanes. */
612
- readonly spacing: number;
613
- /** The largest width of a segment, from its outer lane on the left to its outer lane on the right. */
614
- readonly maxWidth: number;
615
- }
616
- /**
617
- * This function pulls the lanes of each shared segment apart, and gives a route for each edge.
618
- * The lanes keep the lane order, so they do not cross in a segment. The two ends of each route stay at their plugs.
619
- */
620
- export declare function pullApart(graph: SegmentGraph, options: PullApartOptions): Route[];
621
- /** This function gives the key of a shared run: the ids of its edges, sorted and joined with commas. */
622
- export declare function runKey(edges: readonly string[]): string;
623
- /**
624
- * This function opens the shared segments whose key is in `open`: each edge of an open segment gets its own lane.
625
- * The lanes are `laneWidth` apart, and an open segment is at most `maxWidth` wide. The other segments stay as one way.
626
- *
627
- * Lane 0 is on the left of the segment, from its first point to its last, with the y axis down.
628
- * The function takes a result or its segments. It gives a route for each edge, with the ends at their plugs.
629
- * The key of a segment is `runKey` of its edges.
630
- */
631
- export declare function laneRoutes(source: Result | SegmentGraph, open: ReadonlySet<string>, laneWidth: number, maxWidth?: number): Route[];
632
- /**
633
- * This function gives the lane order of the edges on a shared way `run` (metro-line order). Two routes go on together
634
- * past the last point of the run until they part. The route that turns more to the left there gets the lane more to the left.
635
- * Two routes can part only before the first point. Then the route that comes from more to the left gets the lane more to the left.
636
- * A route that does not hold the run goes last.
637
- */
638
- export declare function orderLanes(run: readonly Point[], routes: readonly Route[]): string[];
639
815
  /** A section of the plane: a cell of a quadtree, with the nodes whose centers are in it. */
640
816
  export interface Section {
641
817
  /** The path from the root: "s", then one digit from 0 to 3 for each step down. */
@@ -652,7 +828,11 @@ export interface SectionOptions {
652
828
  readonly cap?: number;
653
829
  /** The tree stops at this depth. The default is 16. */
654
830
  readonly maxDepth?: number;
831
+ /** A cell shrinks to one quarter at most this many times without a split. Then it stops. The default is 32. */
832
+ readonly collapse?: number;
655
833
  }
834
+ /** The default values of `SectionOptions`. */
835
+ export declare const SECTION_DEFAULTS: Readonly<Required<SectionOptions>>;
656
836
  /**
657
837
  * This function makes the tree of sections of the nodes. A cell with more than `cap` nodes splits in four.
658
838
  * When the nodes of a cell are all in one quarter, the cell becomes that quarter and does not make a level.
@@ -662,6 +842,135 @@ export declare function buildSections(nodes: readonly Node[], options?: SectionO
662
842
  export declare function allSections(root: Section): Section[];
663
843
  /** This function gives the depth of the deepest section. */
664
844
  export declare function treeDepth(root: Section): number;
845
+ /**
846
+ * This function examines a tree of sections from a grouping rule. It throws an error when the tree is not valid for `count` nodes.
847
+ * In a valid tree, each node is in exactly one leaf. The children of a section split its nodes, and a child is one level deeper than its parent.
848
+ */
849
+ export declare function checkSections(root: Section, count: number): void;
850
+ /** The items of one zoom level of a tree of sections, and the item of each node. */
851
+ export interface LevelCut {
852
+ /** The items of the level: a section of the depth of the level, or one node of a leaf above that depth. */
853
+ readonly items: LevelItem[];
854
+ /** The index in `items` of the item of each node, in the order of the nodes. */
855
+ readonly owner: readonly number[];
856
+ }
857
+ /**
858
+ * This function gives the items of the zoom level at `depth`. A section of that depth is one item, with the bounding box of its nodes.
859
+ * A node of a leaf above that depth is an item alone. The items come in the order of the walk of the tree, parents before children.
860
+ * A depth past the depth of the deepest section gives each node alone.
861
+ */
862
+ export declare function levelCut(nodes: readonly Pick<Node, "id" | "box">[], root: Section, depth: number): LevelCut;
863
+ /**
864
+ * This function gives the tree of sections of the grouping rule `quadtree`: the cells of a quadtree of the plane (`buildSections`).
865
+ * It is the default grouping rule of the router `sections`.
866
+ */
867
+ export declare function quadtreeGroups(graph: Graph, options?: SectionOptions): Section;
868
+ /** A key rule gives the key of the group of a node. A node without a key is a group alone. */
869
+ type NodeKey = (node: Node, index: number) => string | undefined;
870
+ /** The options of the grouping rule `keys`. */
871
+ interface KeyOptions {
872
+ /** This function gives the key of the group of each node. The default is `byDataGroup`. */
873
+ readonly key?: NodeKey;
874
+ /**
875
+ * With this value, a group with more nodes than its `cap` splits into the cells of a quadtree, as `buildSections` does.
876
+ * Without it, each group is one leaf. The default is no split.
877
+ */
878
+ readonly split?: SectionOptions;
879
+ }
880
+ /** This key rule gives the string `data.group` of the node, or `undefined` when the node has no such string. */
881
+ export declare const byDataGroup: NodeKey;
882
+ /**
883
+ * This function gives the tree of sections of the grouping rule `keys`. The root holds each node. Each child of the root holds the nodes of one key,
884
+ * in the order of their first node. The id of a group is `s:` and its key. A node without a key is a group alone, with the id `s#` and its index.
885
+ * Thus the far view of the router `sections` shows one item for each group.
886
+ */
887
+ export declare function keyedSections(nodes: readonly Node[], options?: KeyOptions): Section;
888
+ /** This function gives the tree of sections of the grouping rule `keys` for a graph. */
889
+ export declare function keyGroups(graph: Graph, options?: KeyOptions): Section;
890
+ /** The cost of a line of the rule `cut`, from the cut `c` and the parts `A` and `B` of the split. */
891
+ type CutObjective = "ratio" | "normalized" | "sparsest";
892
+ /** The options of the grouping rule `cut` (M1 of GRP-R, the guillotine cut). */
893
+ interface CutOptions {
894
+ /** A section with more nodes splits. The default is 8, as for the quadtree. */
895
+ readonly cap?: number;
896
+ /** The tree stops at this depth. The default is 16. */
897
+ readonly maxDepth?: number;
898
+ /** The number of children of a section: 2 or 4. With 4, a section splits two times on one level. The default is 4. */
899
+ readonly fanout?: number;
900
+ /** The smallest share of the nodes in each part of a split (`β`), from 0.05 to 0.5. The default is 0.25. */
901
+ readonly balance?: number;
902
+ /**
903
+ * The cost of a line. The value `ratio` is `c / min(|A|, |B|)`. The value `normalized` is `c / vol(A) + c / vol(B)`, with `vol` the sum of the degrees
904
+ * inside the section. The value `sparsest` is `c / (|A| · |B|)`. The default is `ratio`.
905
+ */
906
+ readonly objective?: CutObjective;
907
+ /**
908
+ * The cost of a line grows by the factor `1 + pull · d`. The value `d` is the distance of the line from the middle of the cell, as a share of the side.
909
+ * A large value prefers the middle line, as the quadtree does. The default is 0.5.
910
+ */
911
+ readonly pull?: number;
912
+ /**
913
+ * With `true`, each section also tests the split of the quadtree, and keeps the split that cuts fewer edges.
914
+ * Thus no section cuts more edges than the quadtree split of its cell. With the fan-out 2, the test uses each midline of the cell. The default is `true`.
915
+ */
916
+ readonly guard?: boolean;
917
+ }
918
+ /** The default values of `CutOptions`. */
919
+ export declare const CUT_DEFAULTS: Readonly<Required<CutOptions>>;
920
+ /**
921
+ * This function gives the tree of sections of the grouping rule `cut`: a guillotine cut that reads the edges (M1 of GRP-R).
922
+ * A section with more than `cap` nodes splits in two along the line with the lowest cost, on either axis. A line goes between two centers.
923
+ * Each part of a split holds at least the share `balance` of the nodes. With the fan-out 4, each half splits again on the same level.
924
+ *
925
+ * The cells nest and do not overlap. The option `guard` keeps the split of the quadtree when that split cuts fewer edges.
926
+ */
927
+ export declare function cutGroups(graph: Graph, options?: CutOptions): Section;
928
+ /** The place of the line of a split of the rule `kd`. */
929
+ type KdLine = "median" | "middle" | "slide";
930
+ /** The axis of each split of the rule `kd`. */
931
+ type KdAxis = "longer" | "alternate";
932
+ /** The options of the grouping rule `kd` (S3 of GRP-R). */
933
+ interface KdOptions {
934
+ /** A section with more nodes splits. The default is 8, as for the quadtree. */
935
+ readonly cap?: number;
936
+ /** The tree stops at this depth. The default is 16. */
937
+ readonly maxDepth?: number;
938
+ /**
939
+ * This value sets the place of the line in the cell. The value `median` puts half of the nodes on each side. The value `middle` cuts the cell in half,
940
+ * and an empty half makes the cell shrink to the other half. The value `slide` cuts the cell in half, and a line with an empty side slides to the nearest node.
941
+ * The default is `slide`.
942
+ */
943
+ readonly line?: KdLine;
944
+ /** The number of children of a section: 2 or 4. With 4, a section splits two times on one level. The default is 4. */
945
+ readonly fanout?: number;
946
+ /** The value `longer` cuts across the longer side of the cell. The value `alternate` cuts across x, then y, then x again. The default is `longer`. */
947
+ readonly axis?: KdAxis;
948
+ }
949
+ /** The default values of `KdOptions`. */
950
+ export declare const KD_DEFAULTS: Readonly<Required<KdOptions>>;
951
+ /**
952
+ * This function gives the tree of sections of the grouping rule `kd`: a k-d tree of the plane (S3 of GRP-R).
953
+ * A section with more than `cap` nodes splits in two with a line across one axis. With the fan-out 4, each half splits again on the same level.
954
+ * The cells nest and do not overlap. The line `median` gives halves of equal size.
955
+ */
956
+ export declare function kdGroups(graph: Graph, options?: KdOptions): Section;
957
+ /** This function gives the median width of the shown items of each level, in units of the plane. */
958
+ export declare function itemSizes(levels: readonly Level[]): number[];
959
+ /** The far-view thresholds of `pickLevel`, in pixels on the screen. */
960
+ export interface PickOptions {
961
+ /** When a node is at least this wide on the screen, the view shows each route. */
962
+ readonly routesAt: number;
963
+ /** A level is fine enough when its median item is at least this wide on the screen. */
964
+ readonly itemAt: number;
965
+ }
966
+ /** The default thresholds: a node of 22 pixels shows its routes, and a group of 120 pixels shows its parts. */
967
+ export declare const PICK: PickOptions;
968
+ /**
969
+ * This function picks the level that a camera shows at a scale, in pixels for each unit of the plane. The sizes come from `itemSizes`.
970
+ * The value `sizes.length` stands for the routes of each edge. The last level holds the nodes alone.
971
+ * Each threshold that `options` does not give gets its value from `PICK`.
972
+ */
973
+ export declare function pickLevel(sizes: readonly number[], scale: number, options?: Partial<PickOptions>): number;
665
974
  /** This function gives the point where the ray from the center of the box to `toward` leaves the box. */
666
975
  export declare function boxExit(box: Box, toward: Point): Point;
667
976
  /**
@@ -695,6 +1004,8 @@ interface SharedOptions extends WayOptions {
695
1004
  readonly rule?: GroupRule;
696
1005
  /** The cost of a link that an edge with the same key uses already, as a share of its length. The default is 0.5. */
697
1006
  readonly discount?: number;
1007
+ /** The lane order of the runs. With `bundle`, the default, two edges keep one order on each run of their common stretch. With `run`, each run gets its order alone. */
1008
+ readonly laneOrder?: RunOrder;
698
1009
  /** The benchmark skips a fixture with more nodes. */
699
1010
  readonly maxNodes?: number;
700
1011
  }
@@ -705,73 +1016,46 @@ interface SharedOptions extends WayOptions {
705
1016
  * The result gives each stretch as a run, with the order of its lanes.
706
1017
  */
707
1018
  export declare function sharedRouter(options: SharedOptions): Router;
708
- /** The options of the router with sections. */
709
- interface SectionsOptions extends WayOptions, SectionOptions {
710
- /** The name in the benchmark. */
711
- readonly name: string;
1019
+ /** Two items of a level that a link joins, and the count of the edges between them. */
1020
+ interface ItemPair {
1021
+ readonly source: string;
1022
+ readonly target: string;
1023
+ readonly count: number;
1024
+ }
1025
+ /** The options of the links of a level: the options of the ways, and two limits of the level links. */
1026
+ interface LevelLinkOptions extends WayOptions {
712
1027
  /**
713
- * The number of hubs on each side of the lowest common section that a way passes. A smaller number gives shorter ways
714
- * and fewer shared ways. Without it, a way passes each hub from its node up.
1028
+ * The margin of the second corner graph. A gap between two boxes wider than approximately 1.5 times this margin lets a link through.
1029
+ * The second graph uses the smaller of this value and `margin`. The default is 1.
715
1030
  */
716
- readonly hubs?: number;
717
- /** A way through the hubs can be at most this many times as long as the line between its plugs. Else the edge goes directly. The default is 2. */
718
- readonly stretch?: number;
719
- /** The benchmark skips a fixture with more nodes. */
720
- readonly maxNodes?: number;
1031
+ readonly tightMargin?: number;
1032
+ /** A plug stays at least this far from the corners of its side. The level links use the smaller of this value and `margin`. The default is 6. */
1033
+ readonly plugInset?: number;
1034
+ /**
1035
+ * The cost of a level link through a far box, in units of the mean box size. A far box overlaps neither end of the link.
1036
+ * A link through a far box gets a second way that can go through boxes (`SoftGraph`). The link keeps the way with fewer far boxes.
1037
+ * The value 0 turns the second way off and gives the links of version 0.1.5. The default is 8.
1038
+ */
1039
+ readonly throughCost?: number;
721
1040
  }
722
1041
  /**
723
- * This function makes a router with a tree of sections. Each section has a hub: the free corner nearest to the center of its nodes.
724
- * An edge goes from its node up the hubs of its sections to the lowest common section, across, and down to the other node.
725
- * Each way from hub to hub is found one time, so all the edges on it share its points.
726
- * The edges in one section of the lowest level go straight around the nodes.
727
- *
728
- * An edge skips a hub that takes it away from its target. A way that still goes out and back gives way to the direct way.
729
- *
730
- * The result gives one zoom level for each depth of the tree.
731
- * A link of a level goes from the boundary of one item to the boundary of the other, around the other items.
1042
+ * The options of the room for the bends of the bundles (HWC-D). With them, `roomDemand` also opens the gaps where a bundle bends.
1043
+ * The values agree with the options of `highwayCurves` that draw the bundles.
732
1044
  */
733
- export declare function sectionsRouter(options: SectionsOptions): Router;
734
- /** The options of the trunk router. */
735
- interface TrunksOptions extends WayOptions {
736
- /** The name in the benchmark. */
737
- readonly name: string;
738
- /** The grouping rule. The edges from one plug with one key share a trunk. */
739
- readonly rule: GroupRule;
740
- /** The split point is at this share of the way to the center of the targets. The default is 0.5. */
741
- readonly split?: number;
742
- /** A group with fewer edges stays unbundled. The default is 2. */
743
- readonly minSize?: number;
744
- /** The benchmark skips a fixture with more nodes. */
745
- readonly maxNodes?: number;
1045
+ interface RoomBends {
1046
+ /** The router that bundles the edges. Each segment of its routes with two or more edges is a bundle. */
1047
+ readonly router: Router;
1048
+ /** The edges that the router routes. Without them, each link gives `count` edges, with no data. */
1049
+ readonly edges?: readonly Edge[];
1050
+ /** The distance between two lanes of a bundle, as `laneWidth` of `highwayCurves`. The default is 4. */
1051
+ readonly spacing?: number;
1052
+ /** The largest width of a bundle, from its outer lane to its outer lane, as `maxWidth` of `highwayCurves`. The default is `Infinity`. */
1053
+ readonly maxWidth?: number;
1054
+ /** The smallest radius of each lane, as `minRadius` of `highwayCurves`. The default is 4. */
1055
+ readonly minRadius?: number;
1056
+ /** The number of passes of the demand of the bends. Each pass routes the board that the passes before it opened. The default is 1. */
1057
+ readonly passes?: number;
746
1058
  }
747
- /** The rule that groups the edges by the collection of their target, in `data.collection`. */
748
- export declare const byCollection: GroupRule;
749
- /**
750
- * This function groups the edges by their source plug and their key. Each group keeps the order of the edges.
751
- * A group with fewer than `minSize` edges does not appear.
752
- */
753
- export declare function groupEdges(edges: readonly Edge[], rule: GroupRule, minSize?: number): Map<string, Edge[]>;
754
- /**
755
- * This function gives the lane order of the branches that leave the split point `from`, with the trunk along `dir`.
756
- * Lane 0 turns most to the left, in a frame with the y axis down. Thus two lanes do not cross at the split.
757
- */
758
- export declare function laneOrder(dir: Point, from: Point, branches: readonly {
759
- readonly edge: string;
760
- readonly next: Point;
761
- }[]): string[];
762
- /**
763
- * This function gives the split point of a bundle, on the line from `start` to the center of the targets.
764
- * The point is at `split` of the way, but at most half of the way to the nearest target. It moves back toward `start` out of the boxes.
765
- */
766
- export declare function splitPoint(start: Point, targets: readonly Point[], split: number, free: (p: Point) => boolean, step: number): Point;
767
- /**
768
- * This function makes a router that bundles the edges by a rule. The edges of a group share one plug and one trunk
769
- * to a split point. From there, each edge goes its own way. The router gives the bundles with their lane order.
770
- * The edges outside the groups go as in the corner router.
771
- */
772
- export declare function trunksRouter(options: TrunksOptions): Router;
773
- /** The built-in routers. The registry `STRATEGIES` holds the same routers as strategies, and the benchmark races the routers of the registry. */
774
- export declare const ROUTERS: readonly Router[];
775
1059
  /** An item with a box: a node of a graph, an item of a level or a box of a host layout. */
776
1060
  export interface Boxed {
777
1061
  readonly id: string;
@@ -836,6 +1120,12 @@ export interface RoomOptions {
836
1120
  * The limit `maxGrowth` applies to the sum of the passes.
837
1121
  */
838
1122
  readonly passes?: number;
1123
+ /**
1124
+ * The room for the bends of the bundles (HWC-D). Without it, the default, the demand counts only the lanes of the links.
1125
+ * With it, the router of `bends` routes the open board. Each leg of a bundle that is too short for its arcs grows by a gap.
1126
+ * The limit `maxGrowth` applies to the sum of the growth of the links and of the bends.
1127
+ */
1128
+ readonly bends?: RoomBends;
839
1129
  }
840
1130
  /** The demand of a board and the board with its gaps open. */
841
1131
  export interface Room<T extends Boxed> {
@@ -858,10 +1148,365 @@ export declare function openGaps<T extends Boxed>(items: readonly T[], gaps: rea
858
1148
  * The lanes of a gap come from the `method` of the options. The need of a gap is `gutter + lanes × spacing`, and not less than its current width.
859
1149
  */
860
1150
  export declare function roomDemand(items: readonly Boxed[], links: readonly RoomLink[], options?: RoomOptions): Gap[];
1151
+ /**
1152
+ * This function adds the growth for the bends of the bundles to the need of each gap. Each pass routes the board with each gap open to its need.
1153
+ * The open board has the same gaps in the same order. So the growth of each gap adds to the need of that gap.
1154
+ */
1155
+ export declare function withBends(items: readonly Boxed[], links: readonly RoomLink[], gaps: readonly Gap[], bends: RoomBends, snap?: number): Gap[];
861
1156
  /** This function gives the demand of the board and the board with each gap open to its need. */
862
1157
  export declare function makeRoom<T extends Boxed>(items: readonly T[], links: readonly RoomLink[], options?: RoomOptions): Room<T>;
863
1158
  /** This function gives the links between the nodes of a graph, with the count of the edges of each pair. A loop does not count. */
864
1159
  export declare function roomLinks(graph: Graph): RoomLink[];
1160
+ /** The scale of a number option. A sweep on the scale `log` gives values with equal ratios, not with equal differences. */
1161
+ export type OptionScale = "linear" | "log";
1162
+ /** The fields of each option declaration. */
1163
+ interface OptionBase {
1164
+ /** One short sentence that tells what the option sets. The site and the documents show it. */
1165
+ readonly describe: string;
1166
+ }
1167
+ /**
1168
+ * The declaration of a number option. The range from `min` to `max` is the range of a control and of a sweep.
1169
+ * The strategy can take a value outside the range. `checkOptions` reports such a value, and `clampOptions` moves it into the range.
1170
+ */
1171
+ export interface NumberOption extends OptionBase {
1172
+ /** The type `integer` takes only whole numbers. */
1173
+ readonly type: "number" | "integer";
1174
+ readonly min: number;
1175
+ readonly max: number;
1176
+ /** The grain of a control and of a sweep. A value off the step is valid. Without it, the grain is free (or 1 for an integer). */
1177
+ readonly step?: number;
1178
+ /** The scale of a control and of a sweep. The default is `linear`. The scale `log` needs a `min` above 0. */
1179
+ readonly scale?: OptionScale;
1180
+ /** These values are valid outside the range. For example, `Infinity` sets no limit. */
1181
+ readonly special?: readonly number[];
1182
+ /** These values are the notable values of the option: the default and the values of the sweeps of the benchmark. */
1183
+ readonly marks?: readonly number[];
1184
+ /** The strategy uses this value when the caller and `defaults` give no value. */
1185
+ readonly default?: number;
1186
+ }
1187
+ /** The declaration of a boolean option. */
1188
+ export interface BooleanOption extends OptionBase {
1189
+ readonly type: "boolean";
1190
+ /** The strategy uses this value when the caller and `defaults` give no value. */
1191
+ readonly default?: boolean;
1192
+ }
1193
+ /** The declaration of an option with a fixed list of string values. */
1194
+ export interface EnumOption<V extends string = string> extends OptionBase {
1195
+ readonly type: "enum";
1196
+ /** The values of the option, in the order of a control. */
1197
+ readonly values: readonly V[];
1198
+ /** The strategy uses this value when the caller and `defaults` give no value. */
1199
+ readonly default?: V;
1200
+ }
1201
+ /**
1202
+ * The declaration of an option that a control or a sweep cannot set from a range.
1203
+ * The type `function` is a rule, `strategy` is a strategy of the step `step`, `list` is an array and `object` is any other object.
1204
+ */
1205
+ export interface ValueOption<V = unknown> extends OptionBase {
1206
+ readonly type: "function" | "strategy" | "list" | "object";
1207
+ /** The step of the strategy, for the type `strategy`. A control lists the strategies of this step of a registry. */
1208
+ readonly step?: Step;
1209
+ /** The strategy uses this value when the caller and `defaults` give no value. */
1210
+ readonly default?: V;
1211
+ }
1212
+ /** The declaration of one option of any type. */
1213
+ export type AnyOption = NumberOption | BooleanOption | EnumOption | ValueOption;
1214
+ /** The declaration that fits the type of an option value: numbers, booleans, string unions or other values. */
1215
+ export type OptionDeclaration<V> = [V] extends [number] ? NumberOption : [V] extends [boolean] ? BooleanOption : [V] extends [string] ? EnumOption<V> : ValueOption<V>;
1216
+ /** The declarations of the options of a strategy. The schema has one declaration for each key of the options type, and no other key. */
1217
+ export type OptionSchema<O> = { readonly [K in keyof O]-?: OptionDeclaration<NonNullable<O[K]>>; };
1218
+ /** One problem of an option value against its declaration. */
1219
+ export interface OptionIssue {
1220
+ /** The key of the option. */
1221
+ readonly key: string;
1222
+ readonly value: unknown;
1223
+ /** The kind of the problem: no declaration, the wrong type, out of the range, not a whole number or not one of the values. */
1224
+ readonly problem: "unknown" | "type" | "range" | "integer" | "value";
1225
+ /** One sentence that tells the problem. */
1226
+ readonly message: string;
1227
+ }
1228
+ /** One setting of a sweep: a name for the rows of a table, and the options of the strategy. */
1229
+ export interface OptionSetting<O extends object> {
1230
+ /** The key and the value of each option of the setting, for example `stretch 1.5`. */
1231
+ readonly name: string;
1232
+ readonly options: Partial<O>;
1233
+ }
1234
+ /** The options of `sweepValues`, `sweepOf` and `sweepGrid`. */
1235
+ export interface SweepOptions {
1236
+ /**
1237
+ * The number of values on the range of a number option. Without it, the sweep gives the `marks` of the declaration.
1238
+ * A declaration without `marks` gets 5 values.
1239
+ */
1240
+ readonly count?: number;
1241
+ /** With `true`, a sweep of a number option on the range also gives the `special` values. The default is `false`. */
1242
+ readonly special?: boolean;
1243
+ }
1244
+ /** This function gives the declared options of a strategy, in the order of its schema, with the effective default of each one. */
1245
+ export declare function listOptions<S extends Step, O extends object>(strategy: Strategy<S, O>): {
1246
+ readonly key: keyof O & string;
1247
+ readonly declaration: AnyOption;
1248
+ readonly value: unknown;
1249
+ }[];
1250
+ /**
1251
+ * This function gives the effective default of each declared option: the value of `defaults`, else the `default` of the declaration.
1252
+ * An option without either value stays out. The strategy gives the same output with this object as with no options.
1253
+ */
1254
+ export declare function optionDefaults<S extends Step, O extends object>(strategy: Strategy<S, O>): Partial<O>;
1255
+ /**
1256
+ * This function examines option values against the schema of a strategy. It gives one issue for each key without a declaration.
1257
+ * It also gives one issue for each value of the wrong type, out of the range, not whole or not one of the values.
1258
+ * It changes no value.
1259
+ * A strategy without a schema gives no issue.
1260
+ */
1261
+ export declare function checkOptions<S extends Step, O extends object>(strategy: Strategy<S, O>, options: Partial<O>): OptionIssue[];
1262
+ /**
1263
+ * This function moves each number option into the range of its declaration, for a control. An integer option gets the nearest whole number.
1264
+ * A special value stays. The function keeps each other value as it is. `checkOptions` reports the values that this function cannot correct.
1265
+ */
1266
+ export declare function clampOptions<S extends Step, O extends object>(strategy: Strategy<S, O>, options: Partial<O>): Partial<O>;
1267
+ /**
1268
+ * This function gives the values of a sweep of one option declaration.
1269
+ * A number option gives its `marks`, or `count` values on its range and its scale. A boolean gives `false` and `true`. An enum gives its values.
1270
+ * An option of another type has no sweep, so the function throws an error.
1271
+ */
1272
+ export declare function sweepValues(declaration: AnyOption, options?: SweepOptions): unknown[];
1273
+ /**
1274
+ * This function gives the settings of a sweep of one option of a strategy, from its declaration only.
1275
+ * The name of each setting is the key and the value, for example `stretch 1.5`.
1276
+ */
1277
+ export declare function sweepOf<S extends Step, O extends object>(strategy: Strategy<S, O>, key: keyof O & string, options?: SweepOptions): OptionSetting<O>[];
1278
+ /**
1279
+ * This function gives the settings of a grid of options: each combination of the values of the sweeps of the keys.
1280
+ * The name of a setting joins the names of its values with commas, in the order of the keys.
1281
+ */
1282
+ export declare function sweepGrid<S extends Step, O extends object>(strategy: Strategy<S, O>, keys: readonly (keyof O & string)[], options?: SweepOptions): OptionSetting<O>[];
1283
+ /**
1284
+ * This function examines the schema of a strategy. It gives one message for each option of `defaults` without a declaration.
1285
+ * It also gives one message for each bad declaration, and for each value of `defaults` that does not fit its declaration.
1286
+ * A good schema gives an empty list.
1287
+ */
1288
+ export declare function checkSchema(strategy: Strategy<Step, object>): string[];
1289
+ /** The input of a curve strategy: one polyline and the context of its route. */
1290
+ export interface CurveInput {
1291
+ /** These points are the polyline: a route of a router, a lane of `laneRoutes` or a link of a zoom level. */
1292
+ readonly points: readonly Point[];
1293
+ /** The curve leaves the first point along this outward normal of its plug, if the strategy reads it. */
1294
+ readonly startNormal?: Point;
1295
+ /** The curve comes into the last point against this outward normal of its plug, if the strategy reads it. */
1296
+ readonly endNormal?: Point;
1297
+ /** The boxes that the curve must not go through, from `curveSpace`. */
1298
+ readonly space?: CurveSpace;
1299
+ }
1300
+ /** The input of a room strategy: the boxes of a board and the links between them. */
1301
+ export interface RoomInput {
1302
+ readonly items: readonly Boxed[];
1303
+ readonly links: readonly RoomLink[];
1304
+ /**
1305
+ * The tree of sections of the items, for a strategy that gives room to each zoom level. The indices of its nodes are the indices of `items`.
1306
+ * Without it, such a strategy makes the quadtree of `buildSections`. The other strategies do not read it.
1307
+ */
1308
+ readonly sections?: Section;
1309
+ }
1310
+ /**
1311
+ * The steps that have strategies, with the fixed input and output type of each step.
1312
+ *
1313
+ * - `group`: a graph in, the tree of sections out. The router `sections` makes its hubs and its zoom levels from this tree.
1314
+ * - `router`: a graph in, the routes (and the `levels`, `bundles` and `runs`) out.
1315
+ * - `curve`: a polyline in, the segments of a curve out.
1316
+ * - `room`: the boxes and links of a board in, the gaps of the board with their need out.
1317
+ */
1318
+ export interface StepTypes {
1319
+ readonly group: {
1320
+ readonly input: Graph;
1321
+ readonly output: Section;
1322
+ };
1323
+ readonly router: {
1324
+ readonly input: Graph;
1325
+ readonly output: Result;
1326
+ };
1327
+ readonly curve: {
1328
+ readonly input: CurveInput;
1329
+ readonly output: CurveSegment[];
1330
+ };
1331
+ readonly room: {
1332
+ readonly input: RoomInput;
1333
+ readonly output: Gap[];
1334
+ };
1335
+ }
1336
+ /** The name of a step that has strategies. */
1337
+ export type Step = keyof StepTypes;
1338
+ /** The input type of a step. */
1339
+ export type StepInput<S extends Step> = StepTypes[S]["input"];
1340
+ /** The output type of a step. */
1341
+ export type StepOutput<S extends Step> = StepTypes[S]["output"];
1342
+ /** The steps that have strategies, in the order of the pipeline. */
1343
+ export declare const STEPS: readonly Step[];
1344
+ /**
1345
+ * A strategy: one way to do one step, with a name and a description.
1346
+ * The same input and the same options must give the same output.
1347
+ */
1348
+ export interface Strategy<S extends Step = Step, O extends object = object> {
1349
+ /** The step of the strategy. It fixes the input and the output type. */
1350
+ readonly step: S;
1351
+ /** The name of the strategy. Each name is unique in its step of a registry. */
1352
+ readonly name: string;
1353
+ /** One or two sentences that tell what the strategy does. The site and the documents show them. */
1354
+ readonly describe: string;
1355
+ /** The values of the options when the caller gives no value. */
1356
+ readonly defaults: Readonly<O>;
1357
+ /** The declarations of the options: the type, the range, the step and the meaning of each one. A strategy without it declares nothing. */
1358
+ readonly schema?: OptionSchema<O>;
1359
+ /** The benchmark skips an input with more nodes than this. Without it, the strategy takes each input. */
1360
+ readonly maxNodes?: number;
1361
+ /** This method does the step. Each option that `options` does not give gets its value from `defaults`. */
1362
+ run(input: StepInput<S>, options?: Partial<O>): StepOutput<S>;
1363
+ }
1364
+ /** A strategy of any step. A registry holds a list of these. */
1365
+ export type AnyStrategy = { [S in Step]: Strategy<S>; }[Step];
1366
+ /** The definition of a strategy, for `defineStrategy`. */
1367
+ export interface StrategyDefinition<S extends Step, O extends object> {
1368
+ readonly step: S;
1369
+ readonly name: string;
1370
+ readonly describe: string;
1371
+ /** These values are the options when the caller gives no value. Give `{}` for a strategy without options. */
1372
+ readonly defaults: O;
1373
+ /** These declarations tell the type, the range, the step and the meaning of each option. `checkSchema` examines them. */
1374
+ readonly schema?: NoInfer<OptionSchema<O>>;
1375
+ readonly maxNodes?: number;
1376
+ /** This function does the step. It gets each option, from the caller or from `defaults`. */
1377
+ run(input: StepInput<S>, options: Readonly<O>): StepOutput<S>;
1378
+ }
1379
+ /**
1380
+ * This function makes a strategy from its definition. The strategy fills the missing options from `defaults`.
1381
+ * When the caller gives no option, the definition gets the `defaults` object itself.
1382
+ */
1383
+ export declare function defineStrategy<S extends Step, O extends object>(definition: StrategyDefinition<S, O>): Strategy<S, O>;
1384
+ /**
1385
+ * A registry: the strategies of each step, in order. A registry is data. No import changes it.
1386
+ * A consumer makes its own registry with `createRegistry`, and adds a strategy with `register`.
1387
+ * The list `group` is optional in the type, so a registry from version 0.1.5 stays a registry. `createRegistry` always gives it.
1388
+ */
1389
+ export type Registry = { readonly [S in Exclude<Step, "group">]: readonly Strategy<S>[]; } & {
1390
+ readonly group?: readonly Strategy<"group">[];
1391
+ };
1392
+ /** This function makes a registry from a list of strategies. It keeps their order. Two strategies with one step and one name are an error. */
1393
+ export declare function createRegistry(strategies: readonly AnyStrategy[]): Registry;
1394
+ /** This function gives a new registry with the strategies of `registry` and then `strategies`. It does not change `registry`. */
1395
+ export declare function register(registry: Registry, ...strategies: readonly AnyStrategy[]): Registry;
1396
+ /** This function gives the strategies of one step of a registry, in order. */
1397
+ export declare function listStrategies<S extends Step>(registry: Registry, step: S): readonly Strategy<S>[];
1398
+ /** This function gives the strategy of one step with a name, or `undefined` when the registry has no such strategy. */
1399
+ export declare function findStrategy<S extends Step>(registry: Registry, step: S, name: string): Strategy<S> | undefined;
1400
+ /** This function gives the strategy of one step with a name. When the registry has no such strategy, the function throws an error. */
1401
+ export declare function getStrategy<S extends Step>(registry: Registry, step: S, name: string): Strategy<S>;
1402
+ /** This function gives a `Router` that runs a router strategy with the options. The router keeps the name and the `maxNodes` of the strategy. */
1403
+ export declare function asRouter<O extends object>(strategy: Strategy<"router", O>, options?: Partial<O>): Router;
1404
+ /** This function gives the router strategies of a registry as `Router` objects, in order. The benchmark races them. */
1405
+ export declare function routersOf(registry: Registry): Router[];
1406
+ /**
1407
+ * The options of the router with sections. Each option has a default, and the defaults give the output of version 0.1.5.
1408
+ * The options `cap`, `maxDepth` and `collapse` are the limits of the default grouping rule, the quadtree of `buildSections`.
1409
+ * The options `tightMargin`, `plugInset` and `throughCost` are the limits of the level links (`levelLinks`).
1410
+ */
1411
+ interface SectionsOptions extends LevelLinkOptions, SectionOptions {
1412
+ /** The name in the benchmark. */
1413
+ readonly name: string;
1414
+ /**
1415
+ * The number of hubs on each side of the lowest common section that a way passes. A smaller number gives shorter ways
1416
+ * and fewer shared ways. Without it, a way passes each hub from its node up.
1417
+ */
1418
+ readonly hubs?: number;
1419
+ /**
1420
+ * The hub limit. A way through the hubs can be at most this many times as long as the line between its plugs, plus `stretchPad` margins.
1421
+ * Else the edge goes directly. The default is 2. The value `Infinity` keeps each way through the hubs.
1422
+ */
1423
+ readonly stretch?: number;
1424
+ /** A way through the hubs can be this many margins longer than `stretch` times the line between its plugs. The default is 4. */
1425
+ readonly stretchPad?: number;
1426
+ /**
1427
+ * A way skips a hub that is more than this many units farther from the target than the nearest approach of the way before it.
1428
+ * The default is 80, two times `BACKTRACK_MIN`. The value `Infinity` keeps each hub.
1429
+ */
1430
+ readonly hubSlack?: number;
1431
+ /**
1432
+ * The grouping rule: a strategy of the step `group` that makes the tree of sections. The hubs and the zoom levels come from this tree.
1433
+ * Without it, the router uses the quadtree of `buildSections` with the options `cap`, `maxDepth` and `collapse`.
1434
+ */
1435
+ readonly group?: Strategy<"group">;
1436
+ /** The options of the strategy `group`. The strategy gets its `defaults` for each option that this object does not give. */
1437
+ readonly groupOptions?: object;
1438
+ /**
1439
+ * The depths of the tree that get a zoom level with groups. The last level, with each node alone, always comes after them.
1440
+ * The default is each depth, from 0 to the depth of the deepest section.
1441
+ */
1442
+ readonly levels?: readonly number[];
1443
+ /** The lane order of the runs. With `run`, the default, each run gets its order alone. With `bundle`, two edges keep one order on each run of their common stretch. */
1444
+ readonly laneOrder?: RunOrder;
1445
+ /** The benchmark skips a fixture with more nodes. */
1446
+ readonly maxNodes?: number;
1447
+ }
1448
+ /**
1449
+ * This function makes a router with a tree of sections. Each section has a hub: the free corner nearest to the center of its nodes.
1450
+ * An edge goes from its node up the hubs of its sections to the lowest common section, across, and down to the other node.
1451
+ * Each way from hub to hub is found one time, so all the edges on it share its points.
1452
+ * The edges in one section of the lowest level go straight around the nodes.
1453
+ *
1454
+ * An edge skips a hub that takes it away from its target. A way that still goes out and back gives way to the direct way.
1455
+ *
1456
+ * The result gives one zoom level for each depth of the tree.
1457
+ * A link of a level goes from the boundary of one item to the boundary of the other, around the other items.
1458
+ */
1459
+ export declare function sectionsRouter(options: SectionsOptions): Router;
1460
+ /** The options of the trunk router. */
1461
+ interface TrunksOptions extends WayOptions {
1462
+ /** The name in the benchmark. */
1463
+ readonly name: string;
1464
+ /** The grouping rule. The edges from one plug with one key share a trunk. */
1465
+ readonly rule: GroupRule;
1466
+ /** The split point is at this share of the way to the center of the targets. The default is 0.5. */
1467
+ readonly split?: number;
1468
+ /** A group with fewer edges stays unbundled. The default is 2. */
1469
+ readonly minSize?: number;
1470
+ /** The lane order of a trunk. With `bundle`, the default, the branches part in lane order. With `run`, the first leg of each branch tells the order. */
1471
+ readonly laneOrder?: RunOrder;
1472
+ /**
1473
+ * The place where each lane leaves the trunk. With `part`, the default, a lane leaves where its way parts from the ways of the other lanes.
1474
+ * A lane that turns back over the trunk leaves at an earlier point of the trunk. With `split`, each lane leaves at the split point, as in version 0.2.0.
1475
+ */
1476
+ readonly leave?: TrunkLeave;
1477
+ /** The benchmark skips a fixture with more nodes. */
1478
+ readonly maxNodes?: number;
1479
+ }
1480
+ /** The place where the lanes of a trunk leave it: where their ways part, or at the split point. */
1481
+ type TrunkLeave = "part" | "split";
1482
+ /** The rule that groups the edges by the collection of their target, in `data.collection`. */
1483
+ export declare const byCollection: GroupRule;
1484
+ /**
1485
+ * This function groups the edges by their source plug and their key. Each group keeps the order of the edges.
1486
+ * A group with fewer than `minSize` edges does not appear.
1487
+ */
1488
+ export declare function groupEdges(edges: readonly Edge[], rule: GroupRule, minSize?: number): Map<string, Edge[]>;
1489
+ /**
1490
+ * This function gives the lane order of the branches that leave the split point `from`, with the trunk along `dir`.
1491
+ * Lane 0 turns most to the left, in a frame with the y axis down. Thus two lanes do not cross at the split.
1492
+ */
1493
+ export declare function laneOrder(dir: Point, from: Point, branches: readonly {
1494
+ readonly edge: string;
1495
+ readonly next: Point;
1496
+ }[]): string[];
1497
+ /**
1498
+ * This function gives the split point of a bundle, on the line from `start` to the center of the targets.
1499
+ * The point is at `split` of the way, but at most half of the way to the nearest target. It moves back toward `start` out of the boxes.
1500
+ */
1501
+ export declare function splitPoint(start: Point, targets: readonly Point[], split: number, free: (p: Point) => boolean, step: number): Point;
1502
+ /**
1503
+ * This function makes a router that bundles the edges by a rule. The edges of a group share one plug and one trunk
1504
+ * to a split point. From there, each edge goes its own way. The router gives the bundles with their lane order.
1505
+ * The edges outside the groups go as in the corner router.
1506
+ */
1507
+ export declare function trunksRouter(options: TrunksOptions): Router;
1508
+ /** The built-in routers. The registry `STRATEGIES` holds the same routers as strategies, and the benchmark races the routers of the registry. */
1509
+ export declare const ROUTERS: readonly Router[];
865
1510
  /**
866
1511
  * The lane order of the pieces of the links in one gap.
867
1512
  *
@@ -887,6 +1532,58 @@ export interface GapLaneOptions {
887
1532
  * When a move puts a link through more boxes than before, the link keeps its points.
888
1533
  */
889
1534
  export declare function gapLanes(items: readonly Boxed[], links: readonly LevelLink[], options?: GapLaneOptions): LevelLink[];
1535
+ /**
1536
+ * The boards of the zoom levels of `levelRoom`.
1537
+ *
1538
+ * - `shared`: each level uses the board of the nearest level. No box moves between two levels. A far level gets the area of the nearest level.
1539
+ * - `each`: each level has its own board. A far level opens only the gaps of its own links, and a nearer level adds to them.
1540
+ * Thus the items of a far level are nearer together, but a box moves in its parent when the level changes.
1541
+ */
1542
+ export type LevelBoard = "each" | "shared";
1543
+ /** The options of `levelRoom`: the options of `roomDemand` for each level, and the levels that get room. */
1544
+ export interface LevelRoomOptions extends RoomOptions {
1545
+ /** The depths of the tree that get room for their links. The default is each depth from 1 to the depth of the deepest section. */
1546
+ readonly depths?: readonly number[];
1547
+ /** With `true`, the last level, with each node alone, also gets room for the links between the nodes. The default is `false`. */
1548
+ readonly nodes?: boolean;
1549
+ /** The board of each level. The default is `shared`. */
1550
+ readonly board?: LevelBoard;
1551
+ }
1552
+ /** One zoom level of `levelRoom`: its items at their open places, its links and its demand. */
1553
+ export interface RoomLevel<T extends Boxed> {
1554
+ readonly depth: number;
1555
+ /** The items of the level, with the bounding box of their nodes at the places of this level. */
1556
+ readonly items: LevelItem[];
1557
+ /** The links between the items of the level. A link counts the links of the nodes between its two items. */
1558
+ readonly pairs: ItemPair[];
1559
+ /** The demand of the level on the board that it gets from the level before it. A level without room has no gaps. */
1560
+ readonly gaps: Gap[];
1561
+ /** The nodes at the places of this level. */
1562
+ readonly nodes: T[];
1563
+ }
1564
+ /** The room of each zoom level, and the board of the nearest level. */
1565
+ export interface LevelRoom<T extends Boxed> {
1566
+ /** The levels from depth 0 to the level with each node alone, in order. */
1567
+ readonly levels: RoomLevel<T>[];
1568
+ /** The gaps of the board of the nodes. `openGaps(nodes, gaps)` gives the nodes of the nearest level. */
1569
+ readonly gaps: Gap[];
1570
+ /** The nodes of the nearest level. */
1571
+ readonly items: T[];
1572
+ }
1573
+ /**
1574
+ * This function gives the links between the items of a level. Each pair of items gets one link, in the order of the first link of the pair.
1575
+ * The count of a link is the sum of the counts of its node links. A link inside one item does not count.
1576
+ */
1577
+ export declare function levelPairs(items: readonly LevelItem[], owner: readonly number[], indexOf: ReadonlyMap<string, number>, links: readonly RoomLink[]): ItemPair[];
1578
+ /**
1579
+ * This function gives the room of each zoom level of a tree of sections. The indices of the nodes of the tree are the indices of `nodes`.
1580
+ * The far levels open first, and each nearer level keeps their growth.
1581
+ *
1582
+ * At each level, `roomDemand` measures the links of that level on the board of the level before it. Then the nodes move with `openGaps`.
1583
+ * The nodes move by one monotone shift on each axis, so each level keeps the order and the alignment of the boxes.
1584
+ * A nearer level only adds growth, so no gap of a far level gets narrower, and a box moves with its parent.
1585
+ */
1586
+ export declare function levelRoom<T extends Boxed>(nodes: readonly T[], links: readonly RoomLink[], root: Section, options?: LevelRoomOptions): LevelRoom<T>;
890
1587
  /** A broken hard rule. A correct router has none. */
891
1588
  export interface Violation {
892
1589
  readonly rule: "complete" | "ends-at-plugs" | "fixed-plugs" | "no-pass-through" | "counts-sum" | "link-ends" | "bundle-trunk" | "run-shared";
@@ -905,6 +1602,12 @@ export declare const TOLERANCE = .5;
905
1602
  * The function gives at most `limit` violations.
906
1603
  */
907
1604
  export declare function checkProperties(graph: Graph, result: Result, limit?: number): Violation[];
1605
+ /**
1606
+ * This function checks the hard rules of the zoom levels. The counts of each level add up (`counts-sum`).
1607
+ * Each link of a level starts on the box of its source and ends on the box of its target (`link-ends`).
1608
+ * The function gives at most `limit` violations.
1609
+ */
1610
+ export declare function checkLevels(graph: Graph, levels: readonly Level[], limit?: number): Violation[];
908
1611
  /** The quality of a result. Lower is better for each value except `clearance`. */
909
1612
  export interface Quality {
910
1613
  /** The length of all drawn lines. A segment that several routes share counts one time. */
@@ -961,6 +1664,13 @@ export interface LinkFaults {
961
1664
  * A segment goes through a box when a part of it longer than `TOLERANCE` is inside the box made smaller by `TOLERANCE`.
962
1665
  */
963
1666
  readonly through: number;
1667
+ /**
1668
+ * The number of links of `through` that no route can keep out of the other boxes.
1669
+ * Each box that such a link goes through overlaps the box of its source or of its target, as `countOverlaps` sees it.
1670
+ */
1671
+ readonly unavoidable: number;
1672
+ /** The number of links of `through` that go through at least one box that overlaps neither end. `through` is `unavoidable` plus `avoidable`. */
1673
+ readonly avoidable: number;
964
1674
  /**
965
1675
  * The number of links that go out and back. The distance from a point of the link to its last point grows after the nearest approach.
966
1676
  * A link goes out and back when this growth is more than `BACKTRACK_SHARE` of the distance between its ends, and more than `BACKTRACK_MIN` units.
@@ -1013,6 +1723,8 @@ export declare function goesOutAndBack(p: readonly Point[]): boolean;
1013
1723
  * The bounding box of `outside` is the bounding box of all the boxes of the map.
1014
1724
  */
1015
1725
  export declare function measureLinks(boxes: ReadonlyMap<string, Box>, links: readonly MeasuredLink[], options?: LinkFaultOptions): LinkFaults;
1726
+ /** This function tells if two boxes overlap by more than `TOLERANCE` on each axis, as `countOverlaps` counts them. */
1727
+ export declare function boxesOverlap(a: Box, b: Box): boolean;
1016
1728
  /** This function measures the faults of the routes of a result. The ends of a route are the nodes of its edge. */
1017
1729
  export declare function measureRouteFaults(graph: Graph, result: Result, options?: LinkFaultOptions): LinkFaults;
1018
1730
  /** This function counts the pairs of boxes that overlap by more than `TOLERANCE` on each axis. */
@@ -1044,11 +1756,26 @@ export interface BenchRow {
1044
1756
  readonly faults: LinkFaults;
1045
1757
  /** The faults of each zoom level with groups (`measureLevelFaults`). The list is empty for a router without levels. */
1046
1758
  readonly levelFaults: readonly LevelFaults[];
1759
+ /** The routes of this cell took longer than the cell limit. The cell did not start more routes. A row within the limit has no such field. */
1760
+ readonly overLimit?: OverLimit;
1761
+ }
1762
+ /** The record of a cell over its time limit. */
1763
+ export interface OverLimit {
1764
+ /** The cell limit, in milliseconds. */
1765
+ readonly limit: number;
1766
+ /** The number of routes that the cell finished. With one route, the cell did not check "same twice". */
1767
+ readonly runs: number;
1047
1768
  }
1048
1769
  /** The options of a benchmark run. */
1049
1770
  export interface BenchOptions {
1050
1771
  /** The number of timed routes of each fixture by each router. The default is 3. */
1051
1772
  readonly repeat?: number;
1773
+ /**
1774
+ * The time limit of one cell (one router on one fixture), in milliseconds. The default is no limit.
1775
+ * After the routes of a cell pass the limit, the cell starts no more routes, and its row gets `overLimit`.
1776
+ * A route that runs does not stop.
1777
+ */
1778
+ readonly cellLimit?: number;
1052
1779
  }
1053
1780
  /** This function routes each fixture with each router, checks the hard rules and measures the quality. */
1054
1781
  export declare function runBenchmark(routers: readonly Router[], fixtures: readonly FixtureSpec[], options?: BenchOptions): BenchRow[];
@@ -1057,115 +1784,39 @@ export declare function runBenchmark(routers: readonly Router[], fixtures: reado
1057
1784
  * because the result of a large graph can be longer than the longest string.
1058
1785
  */
1059
1786
  export declare function sameData(a: unknown, b: unknown): boolean;
1060
- /** This function routes one graph with one router and measures the result. */
1061
- export declare function benchOne(router: Router, fixture: string, graph: Graph, repeat?: number): BenchRow;
1062
- /** This function writes the rows as a Markdown table. */
1063
- export declare function formatTable(rows: readonly BenchRow[]): string;
1064
1787
  /**
1065
- * This function writes the faults of the rows as a Markdown table: the routes first, then the sum of the levels with groups.
1066
- * A router without such levels gets a dash in the columns of the levels.
1788
+ * This function routes one graph with one router and measures the result. It routes at least two times, for the rule "same twice".
1789
+ * After the routes pass `cellLimit` milliseconds, it starts no more routes and marks the row with `overLimit`.
1067
1790
  */
1068
- export declare function formatFaults(rows: readonly BenchRow[]): string;
1069
- /** The input of a curve strategy: one polyline and the context of its route. */
1070
- export interface CurveInput {
1071
- /** These points are the polyline: a route of a router, a lane of `laneRoutes` or a link of a zoom level. */
1072
- readonly points: readonly Point[];
1073
- /** The curve leaves the first point along this outward normal of its plug, if the strategy reads it. */
1074
- readonly startNormal?: Point;
1075
- /** The curve comes into the last point against this outward normal of its plug, if the strategy reads it. */
1076
- readonly endNormal?: Point;
1077
- /** The boxes that the curve must not go through, from `curveSpace`. */
1078
- readonly space?: CurveSpace;
1079
- }
1080
- /** The input of a room strategy: the boxes of a board and the links between them. */
1081
- export interface RoomInput {
1082
- readonly items: readonly Boxed[];
1083
- readonly links: readonly RoomLink[];
1791
+ export declare function benchOne(router: Router, fixture: string, graph: Graph, repeat?: number, cellLimit?: number): BenchRow;
1792
+ /** One run of `benchRun`: the row of the benchmark and the result that the row measures. */
1793
+ export interface BenchRun {
1794
+ readonly row: BenchRow;
1795
+ readonly result: Result;
1084
1796
  }
1797
+ /** This function does the work of `benchOne` and also gives the result, so more measures can read it without a second route. */
1798
+ export declare function benchRun(router: Router, fixture: string, graph: Graph, repeat?: number, cellLimit?: number): BenchRun;
1085
1799
  /**
1086
- * The steps that have strategies, with the fixed input and output type of each step.
1087
- *
1088
- * - `router`: a graph in, the routes (and the `levels`, `bundles` and `runs`) out.
1089
- * - `curve`: a polyline in, the segments of a curve out.
1090
- * - `room`: the boxes and links of a board in, the gaps of the board with their need out.
1800
+ * This function puts rows in the order of one benchmark run: by fixture, then by router, each in the order of its list.
1801
+ * A name that is not in its list goes after the names of the list. Rows with the same place keep their order.
1802
+ * The workflow `Bench` uses it to join the rows of its parts.
1091
1803
  */
1092
- export interface StepTypes {
1093
- readonly router: {
1094
- readonly input: Graph;
1095
- readonly output: Result;
1096
- };
1097
- readonly curve: {
1098
- readonly input: CurveInput;
1099
- readonly output: CurveSegment[];
1100
- };
1101
- readonly room: {
1102
- readonly input: RoomInput;
1103
- readonly output: Gap[];
1104
- };
1105
- }
1106
- /** The name of a step that has strategies. */
1107
- export type Step = keyof StepTypes;
1108
- /** The input type of a step. */
1109
- export type StepInput<S extends Step> = StepTypes[S]["input"];
1110
- /** The output type of a step. */
1111
- export type StepOutput<S extends Step> = StepTypes[S]["output"];
1112
- /** The steps that have strategies, in the order of the pipeline. */
1113
- export declare const STEPS: readonly Step[];
1804
+ export declare function orderRows(rows: readonly BenchRow[], routers: readonly string[], fixtures: readonly string[]): BenchRow[];
1805
+ /** This function writes the rows as a Markdown table. A cell over its limit shows "over the limit" after its time, and a dash for "same twice" when it did not check it. */
1806
+ export declare function formatTable(rows: readonly BenchRow[]): string;
1114
1807
  /**
1115
- * A strategy: one way to do one step, with a name and a description.
1116
- * The same input and the same options must give the same output.
1808
+ * This function writes the faults of the rows as a Markdown table: the routes first, then the sum of the levels with groups.
1809
+ * A router without such levels gets a dash in the columns of the levels.
1117
1810
  */
1118
- export interface Strategy<S extends Step = Step, O extends object = object> {
1119
- /** The step of the strategy. It fixes the input and the output type. */
1120
- readonly step: S;
1121
- /** The name of the strategy. Each name is unique in its step of a registry. */
1122
- readonly name: string;
1123
- /** One or two sentences that tell what the strategy does. The site and the documents show them. */
1124
- readonly describe: string;
1125
- /** The values of the options when the caller gives no value. */
1126
- readonly defaults: Readonly<O>;
1127
- /** The benchmark skips an input with more nodes than this. Without it, the strategy takes each input. */
1128
- readonly maxNodes?: number;
1129
- /** This method does the step. Each option that `options` does not give gets its value from `defaults`. */
1130
- run(input: StepInput<S>, options?: Partial<O>): StepOutput<S>;
1131
- }
1132
- /** A strategy of any step. A registry holds a list of these. */
1133
- export type AnyStrategy = { [S in Step]: Strategy<S>; }[Step];
1134
- /** The definition of a strategy, for `defineStrategy`. */
1135
- export interface StrategyDefinition<S extends Step, O extends object> {
1136
- readonly step: S;
1137
- readonly name: string;
1138
- readonly describe: string;
1139
- /** These values are the options when the caller gives no value. Give `{}` for a strategy without options. */
1140
- readonly defaults: O;
1141
- readonly maxNodes?: number;
1142
- /** This function does the step. It gets each option, from the caller or from `defaults`. */
1143
- run(input: StepInput<S>, options: Readonly<O>): StepOutput<S>;
1811
+ export declare function formatFaults(rows: readonly BenchRow[]): string;
1812
+ /** A row with the faults of each zoom level, as `formatLevels` reads it: a router or a setting on one fixture. */
1813
+ export interface LevelRow {
1814
+ readonly router: string;
1815
+ readonly fixture: string;
1816
+ readonly levelFaults: readonly LevelFaults[];
1144
1817
  }
1145
- /**
1146
- * This function makes a strategy from its definition. The strategy fills the missing options from `defaults`.
1147
- * When the caller gives no option, the definition gets the `defaults` object itself.
1148
- */
1149
- export declare function defineStrategy<S extends Step, O extends object>(definition: StrategyDefinition<S, O>): Strategy<S, O>;
1150
- /**
1151
- * A registry: the strategies of each step, in order. A registry is data. No import changes it.
1152
- * A consumer makes its own registry with `createRegistry`, and adds a strategy with `register`.
1153
- */
1154
- export type Registry = { readonly [S in Step]: readonly Strategy<S>[]; };
1155
- /** This function makes a registry from a list of strategies. It keeps their order. Two strategies with one step and one name are an error. */
1156
- export declare function createRegistry(strategies: readonly AnyStrategy[]): Registry;
1157
- /** This function gives a new registry with the strategies of `registry` and then `strategies`. It does not change `registry`. */
1158
- export declare function register(registry: Registry, ...strategies: readonly AnyStrategy[]): Registry;
1159
- /** This function gives the strategies of one step of a registry, in order. */
1160
- export declare function listStrategies<S extends Step>(registry: Registry, step: S): readonly Strategy<S>[];
1161
- /** This function gives the strategy of one step with a name, or `undefined` when the registry has no such strategy. */
1162
- export declare function findStrategy<S extends Step>(registry: Registry, step: S, name: string): Strategy<S> | undefined;
1163
- /** This function gives the strategy of one step with a name. When the registry has no such strategy, the function throws an error. */
1164
- export declare function getStrategy<S extends Step>(registry: Registry, step: S, name: string): Strategy<S>;
1165
- /** This function gives a `Router` that runs a router strategy with the options. The router keeps the name and the `maxNodes` of the strategy. */
1166
- export declare function asRouter<O extends object>(strategy: Strategy<"router", O>, options?: Partial<O>): Router;
1167
- /** This function gives the router strategies of a registry as `Router` objects, in order. The benchmark races them. */
1168
- export declare function routersOf(registry: Registry): Router[];
1818
+ /** This function writes the faults of each zoom level with groups as a Markdown table, one line for each level. */
1819
+ export declare function formatLevels(rows: readonly LevelRow[]): string;
1169
1820
  /**
1170
1821
  * One row of the benchmark of the curves: one curve type on the routes of one router on one fixture.
1171
1822
  * The type `T` of the name of the curve is `CurveType` for `benchCurves`, and `string` for `benchCurveStrategies`.
@@ -1207,6 +1858,127 @@ export declare function benchCurves(router: Router, fixture: string, graph: Grap
1207
1858
  export declare function benchCurveStrategies(router: Router, fixture: string, graph: Graph, curves: readonly Strategy<"curve">[], options?: CurveBenchOptions): CurveBenchRow<string>[];
1208
1859
  /** This function writes the rows of `benchCurves` as a Markdown table. */
1209
1860
  export declare function formatCurves(rows: readonly CurveBenchRow<string>[]): string;
1861
+ /** The options of `measureHighways`. */
1862
+ export interface HighwayMeasureOptions {
1863
+ /** The largest width of an open segment, as in `laneRoutes`. The default is 16. */
1864
+ readonly maxWidth?: number;
1865
+ /** A piece of a curve with a radius under this value counts in `underMin`. The default is 4. */
1866
+ readonly minRadius?: number;
1867
+ /** The length at each end of a segment that the spacing does not sample, for the merges and the splits. The default is 12. */
1868
+ readonly ends?: number;
1869
+ /** The free space of the board. With it, the measure counts the lanes that go through a box that their polyline avoids. */
1870
+ readonly space?: CurveSpace;
1871
+ }
1872
+ /**
1873
+ * The measures of the lanes of the open segments of a board, after a curve.
1874
+ * The spacing errors are shares of the spacing of the segment: 0.05 is 5% of the spacing.
1875
+ */
1876
+ export interface HighwayMeasures {
1877
+ /** The number of open segments with two lanes or more. */
1878
+ readonly bundles: number;
1879
+ /** The number of curves of edges in an open segment. */
1880
+ readonly lanes: number;
1881
+ /** The number of sample points of the spacing. */
1882
+ readonly samples: number;
1883
+ /** The largest spacing error at a sample point. */
1884
+ readonly worstSpacing: number;
1885
+ /** The mean spacing error of the sample points. */
1886
+ readonly meanSpacing: number;
1887
+ /** The share of the sample points with a spacing error over `SPACING_LIMIT`. */
1888
+ readonly overLimit: number;
1889
+ /** The number of points where two lanes of one open segment cross, in the body of the segment: its bends and its straight parts. */
1890
+ readonly crossings: number;
1891
+ /** The number of points where two lanes of one open segment cross near an end of the segment, in the option `ends`. These are the merges and splits. */
1892
+ readonly endCrossings: number;
1893
+ /** The number of breaks of the tangent (G1 faults) near the open segments, by more than `BREAK` radians. */
1894
+ readonly breaks: number;
1895
+ /** The smallest radius of an arc or a cubic piece near the open segments. It is `Infinity` when there is no such piece. */
1896
+ readonly minRadius: number;
1897
+ /** The number of arcs and cubic pieces near the open segments with a radius under the option `minRadius`. */
1898
+ readonly underMin: number;
1899
+ /** The number of lanes that go through a box that their polyline of `laneRoutes` avoids. */
1900
+ readonly through: number;
1901
+ }
1902
+ /** A break of the tangent larger than this angle, in radians, counts in `breaks`. */
1903
+ export declare const BREAK = .01;
1904
+ /** A spacing error over this share of the spacing counts in `overLimit`. */
1905
+ export declare const SPACING_LIMIT = .05;
1906
+ /**
1907
+ * This function measures the lanes of the open segments of a board after a curve. It measures the spacing, the crossings,
1908
+ * the breaks of the tangent, the radii and the lanes that go through a box.
1909
+ *
1910
+ * A lane is in a segment where it goes near the center line of the segment, in its direction along the segment.
1911
+ * The spacing samples each lane `spacing / 4` apart, from the middle of the first leg to the middle of the last leg.
1912
+ * It does not sample the lane in the option `ends`. The ends of a segment are for the merges and the splits.
1913
+ *
1914
+ * A sample compares the distance to the next lane with the spacing. It counts when the next lane is in the band of the segment.
1915
+ * The crossings, the breaks and the radii count along the full segment, and `ends` past each end of it.
1916
+ */
1917
+ export declare function measureHighways(graph: SegmentGraph, open: ReadonlySet<string>, laneWidth: number, curves: readonly LaneCurve[], options?: HighwayMeasureOptions): HighwayMeasures;
1918
+ /** One row of `benchHighways`: the measures of the lanes of one router on one board, after one way to curve them. */
1919
+ export interface HighwayBenchRow extends HighwayMeasures {
1920
+ readonly router: string;
1921
+ readonly fixture: string;
1922
+ /** The way to curve the lanes: `rounded` curves each lane alone, and `highway` curves the lanes of a bundle together. */
1923
+ readonly curve: "rounded" | "highway";
1924
+ /** The shape of the S curves of a row `highway`. */
1925
+ readonly jog?: JogStyle;
1926
+ /** The measures of the S curves of a row `highway`. */
1927
+ readonly jogs?: JogMeasures;
1928
+ /** The time to make all curves, in milliseconds. */
1929
+ readonly ms: number;
1930
+ }
1931
+ /** The measures of the S curves where the lanes join or leave a bundle. Each curvature is in 1 / units. */
1932
+ export interface JogMeasures {
1933
+ /** The number of S curves. */
1934
+ readonly count: number;
1935
+ /** The number of S curves that are a biarc. A polynomial S curve that does not fit on its leg is a biarc. */
1936
+ readonly biarcs: number;
1937
+ /** The median and the largest of the peak curvature of each S curve with the shape of the row. */
1938
+ readonly peakMedian: number;
1939
+ readonly peakMax: number;
1940
+ /** The median ratio of the peak curvature of each S curve of the row to the peak curvature of the same biarc S curve. */
1941
+ readonly peakRatio?: number;
1942
+ /** The largest curvature at an end of an S curve with the shape of the row. The straight leg next to it has the curvature 0, so it is the jump at the end. */
1943
+ readonly endJump: number;
1944
+ /** The largest jump of the curvature at a joint inside an S curve with the shape of the row. */
1945
+ readonly innerJump: number;
1946
+ }
1947
+ /** This function gives the peak curvature of each S curve, by lane. `jogs` has the first and the last index of each S curve in the segments of its lane. */
1948
+ export declare function jogPeaks(curves: readonly LaneCurve[], jogs: JogTrace): number[][];
1949
+ /**
1950
+ * This function gives the peak curvature of one curve, in 1 / units: the largest curvature of its lines, cubic pieces and arcs (C5 of MEAS0 as `1 / rmin`).
1951
+ * A joint with a tangent break of more than 0.5 degrees is a sharp corner, so such a curve gets `Infinity`. A curve of lines only gives 0.
1952
+ */
1953
+ export declare function peakCurvature(segments: readonly CurveSegment[]): number;
1954
+ /**
1955
+ * This function measures the S curves of the lanes that have the shape `style`. `jogs` has the first and the last index of each S curve in the segments of its lane.
1956
+ * With `biarcPeaks`, the peak curvatures of the same S curves as biarcs, it also gives the median ratio of the peaks.
1957
+ */
1958
+ export declare function measureJogs(curves: readonly LaneCurve[], jogs: JogTrace, style?: JogStyle, biarcPeaks?: readonly (readonly number[])[]): JogMeasures;
1959
+ /** The options of `benchHighways`. */
1960
+ export interface HighwayBenchOptions {
1961
+ /** The spacing of the lanes. The default is 4. */
1962
+ readonly spacing?: number;
1963
+ /** The largest width of an open segment. The default is 16. */
1964
+ readonly maxWidth?: number;
1965
+ /** The radius of each curve. The default is 12. */
1966
+ readonly radius?: number;
1967
+ /** The smallest radius of `highwayCurves`, and the limit of `underMin`. The default is 4. */
1968
+ readonly minRadius?: number;
1969
+ /** The shapes of the S curves. Each shape gives one row `highway`. The default is `["biarc"]`. */
1970
+ readonly jogs?: readonly JogStyle[];
1971
+ /** The number of cubic pieces of a `quintic` S curve. The default is 4. */
1972
+ readonly jogPieces?: number;
1973
+ }
1974
+ /**
1975
+ * This function routes a graph, opens each shared segment, and curves the lanes in two ways.
1976
+ * The row `rounded` curves each lane of `laneRoutes` alone with the curve `rounded`. Each row `highway` curves them with `highwayCurves` and one shape of S curve.
1977
+ * Both ways get the free space of the nodes.
1978
+ */
1979
+ export declare function benchHighways(router: Router, fixture: string, graph: Graph, options?: HighwayBenchOptions): HighwayBenchRow[];
1980
+ /** This function writes the rows of `benchHighways` as a Markdown table. The spacing errors are percents of the spacing. */
1981
+ export declare function formatHighways(rows: readonly HighwayBenchRow[]): string;
1210
1982
  /** One row of the benchmark of the room: one state of a board, packed or open, and the measures of its links. */
1211
1983
  export interface RoomBenchRow {
1212
1984
  readonly fixture: string;
@@ -1268,6 +2040,669 @@ export declare function laneSettings(spacings?: readonly number[], orders?: read
1268
2040
  export declare function passSettings(gutters?: readonly number[], passes?: readonly number[]): RoomSetting[];
1269
2041
  /** This function writes the rows of `benchRoom` as a Markdown table. */
1270
2042
  export declare function formatRoom(rows: readonly RoomBenchRow[]): string;
2043
+ /** One row of the benchmark of the room of the zoom levels: one level with groups of one board. */
2044
+ export interface LevelRoomRow {
2045
+ readonly fixture: string;
2046
+ /** The board: `packed`, `gutter` (each level open to the gutter only), `routes` (the room of the nodes alone), `levels` or `levels each`. */
2047
+ readonly board: string;
2048
+ readonly depth: number;
2049
+ /** The number of items of the level. */
2050
+ readonly items: number;
2051
+ /** The number of links of the level. */
2052
+ readonly links: number;
2053
+ /** The area of the bounding box of the items of the level, as a share of the area of the packed board. */
2054
+ readonly area: number;
2055
+ /** The number of level links that go through a box that is not one of their ends. */
2056
+ readonly through: number;
2057
+ /** The crossings of the level links, with a lane for each link in each gap (`gapLanes` with the order `crossings`). */
2058
+ readonly crossings: number;
2059
+ /** The crossings of the level links without lanes. The links of a gap share one line, so this count hides crossings. */
2060
+ readonly sharedCrossings: number;
2061
+ /** The mean detour of the level links. */
2062
+ readonly detour: number;
2063
+ /** The worst detour of the level links. */
2064
+ readonly worstDetour: number;
2065
+ /** The number of pairs of items of the level whose order or alignment on an axis is not the order of the packed board. */
2066
+ readonly order: number;
2067
+ /** The number of pairs of items of the level before whose order or alignment on an axis changes at this level. */
2068
+ readonly levelOrder: number;
2069
+ /**
2070
+ * The mean shift of an item against its parent from the level before, in gutters. The shift compares the place of the item in its parent
2071
+ * at this level with its place in its parent at the level before. The value 0 means that the item moves with its parent.
2072
+ */
2073
+ readonly shift: number;
2074
+ /** The largest shift of an item against its parent, in gutters. */
2075
+ readonly worstShift: number;
2076
+ /** The time to open the board of all levels, in milliseconds. It is 0 for the packed board. */
2077
+ readonly ms: number;
2078
+ }
2079
+ /**
2080
+ * This function counts the pairs of boxes whose order or alignment on an axis is not the same in `a` and in `b`.
2081
+ * The order of two boxes is the order of their left (or top) edges. The cost is quadratic in the number of boxes.
2082
+ */
2083
+ export declare function orderChanges(a: readonly Box[], b: readonly Box[], snap?: number): number;
2084
+ /**
2085
+ * This function measures the room of the zoom levels of a board. The rows of each board give each level with groups, from depth 1.
2086
+ * The boards are the packed board, the fair baseline with each level open to the gutter only, and the room of the nodes alone (`makeRoom`).
2087
+ * Then come two boards of `levelRoom` with the options. The board `levels` uses the board of the nearest level for each level.
2088
+ * The board `levels each` has a board for each level.
2089
+ *
2090
+ * The links of each level are `levelLinks` with their defaults. Each link gets a lane of `spacing` in each gap.
2091
+ */
2092
+ export declare function benchLevelRoom(fixture: string, graph: Graph, options?: LevelRoomOptions, sections?: SectionOptions): LevelRoomRow[];
2093
+ /** This function writes the rows of `benchLevelRoom` as a Markdown table. */
2094
+ export declare function formatLevelRoom(rows: readonly LevelRoomRow[]): string;
2095
+ /** One row of `benchBendRoom`: the lanes of the bundles of one router on one open board, after `highwayCurves`. */
2096
+ export interface BendRoomRow extends HighwayMeasures {
2097
+ readonly router: string;
2098
+ readonly fixture: string;
2099
+ /** The board: `room` opens the gaps for the links only, and `room + bends` also opens them for the bends of the bundles. */
2100
+ readonly board: "room" | "room + bends";
2101
+ /** The area of the bounding box of the boxes, as a share of the area of the board before the room. */
2102
+ readonly area: number;
2103
+ }
2104
+ /**
2105
+ * This function measures the room for the bends of the bundles (HWC-D). It opens the board two times with `makeRoom`, without and with the option `bends`.
2106
+ * The option `bends` gets the router and the lane options of the curves. Then the router routes each open board, and `benchHighways` curves its bundles with `highway`.
2107
+ */
2108
+ export declare function benchBendRoom(router: Router, fixture: string, graph: Graph, options?: RoomOptions): BendRoomRow[];
2109
+ /** This function writes the rows of `benchBendRoom` as a Markdown table. The spacing error is a percent of the spacing. */
2110
+ export declare function formatBendRoom(rows: readonly BendRoomRow[]): string;
2111
+ /** The options of one setting of the router `sections`, without the name. */
2112
+ export type SectionsSettingOptions = Omit<SectionsOptions, "name" | "maxNodes">;
2113
+ /** One setting of a sweep of the router `sections`. */
2114
+ export interface SectionsSetting {
2115
+ /** The name of the setting in the column `setting`. */
2116
+ readonly name: string;
2117
+ readonly options: SectionsSettingOptions;
2118
+ }
2119
+ /** One row of a sweep of the router `sections`: one setting on one board, and the measures of its routes and of its zoom levels. */
2120
+ export interface SectionsBenchRow {
2121
+ readonly fixture: string;
2122
+ readonly setting: string;
2123
+ /** The faults of the routes of the edges (`measureRouteFaults`). */
2124
+ readonly faults: LinkFaults;
2125
+ /** The sum of the faults of the levels with groups (`measureLevelFaults` and `sumFaults`). */
2126
+ readonly levelFaults: LinkFaults;
2127
+ /** The sum of the overlaps of the levels with groups. */
2128
+ readonly overlaps: number;
2129
+ /** The number of routes that go through hubs: the routes that are not the same as the direct route of their edge. */
2130
+ readonly hubRoutes: number;
2131
+ /** The number of shared stretches of way of the result (`runs`). */
2132
+ readonly runs: number;
2133
+ /** The number of zoom levels, with the last level of single nodes. */
2134
+ readonly levels: number;
2135
+ /** The number of items of the far view: the first level with more than one item. */
2136
+ readonly farItems: number;
2137
+ /** The time of one route, in milliseconds. */
2138
+ readonly ms: number;
2139
+ }
2140
+ /**
2141
+ * This function measures the router `sections` on one board with each setting. The first row is the fair baseline: the defaults, with no option.
2142
+ * The direct routes come from the hub limit 0, so `hubRoutes` counts the routes that use the hubs.
2143
+ */
2144
+ export declare function sweepSections(fixture: string, graph: Graph, settings: readonly SectionsSetting[]): SectionsBenchRow[];
2145
+ /** The values of the hub limit (`stretch`) of the sweep of CUSTOM. The default is 2. */
2146
+ export declare const STRETCH_SWEEP: readonly number[];
2147
+ /** This function gives the settings of the sweep of the hub limit: one setting for each value of `stretch`. */
2148
+ export declare function stretchSettings(values?: readonly number[]): SectionsSetting[];
2149
+ /** The values of `hubSlack` of the sweep of CUSTOM. The default is 80. */
2150
+ export declare const SLACK_SWEEP: readonly number[];
2151
+ /** This function gives the settings of the sweep of the slack of the hubs: one setting for each value of `hubSlack`. */
2152
+ export declare function slackSettings(values?: readonly number[]): SectionsSetting[];
2153
+ /** The values of the section limit (`cap`) of the sweep of CUSTOM. The default is 8. */
2154
+ export declare const CAP_SWEEP: readonly number[];
2155
+ /** This function gives the settings of the sweep of the section limit: one setting for each value of `cap`. */
2156
+ export declare function capSettings(values?: readonly number[]): SectionsSetting[];
2157
+ /**
2158
+ * This function gives one setting for each grouping rule: the router `sections` with the strategy as its option `group`.
2159
+ * The map `options` gives the options of a strategy by its name.
2160
+ */
2161
+ export declare function groupSettings(strategies?: readonly Strategy<"group">[], options?: Readonly<Record<string, object>>): SectionsSetting[];
2162
+ /** This function writes the rows of `sweepSections` as a Markdown table. */
2163
+ export declare function formatSections(rows: readonly SectionsBenchRow[]): string;
2164
+ /**
2165
+ * This function gives the `p` quantile of the values, with a linear step between two ranks (type 7 of Hyndman and Fan).
2166
+ * The result is `NaN` for an empty list.
2167
+ */
2168
+ export declare function quantile(values: readonly number[], p: number): number;
2169
+ /** The spread of a measure over the seeds of a fixture family. */
2170
+ export interface Spread {
2171
+ /** The number of values. */
2172
+ readonly n: number;
2173
+ readonly median: number;
2174
+ /** The `0.25` quantile. */
2175
+ readonly q1: number;
2176
+ /** The `0.75` quantile. */
2177
+ readonly q3: number;
2178
+ /** The interquartile range: `q3 - q1`. */
2179
+ readonly iqr: number;
2180
+ readonly min: number;
2181
+ readonly max: number;
2182
+ }
2183
+ /** This function gives the median, the quartiles, the interquartile range, the smallest and the largest value of a list. */
2184
+ export declare function summarize(values: readonly number[]): Spread;
2185
+ /** The largest number of values for which `kendallTau` examines each pair. Above it, the function examines a seeded sample of pairs. */
2186
+ export declare const KENDALL_EXACT = 1500;
2187
+ /**
2188
+ * This function gives the Kendall tau-b of two lists of the same length (Kendall, 1938).
2189
+ * The value is from -1 to 1. A value of 1 means the same order. A pair with a tie in both lists does not count.
2190
+ * When one list has only ties, the value is 1. Above `KENDALL_EXACT` values, a seeded sample of 200 000 pairs gives an estimate.
2191
+ */
2192
+ export declare function kendallTau(a: readonly number[], b: readonly number[], seed?: number): number;
2193
+ /**
2194
+ * This function gives the adjusted Rand index of two groupings of the same items (Hubert and Arabie, 1985).
2195
+ * The item `i` is in the group `a[i]` of the first grouping and in the group `b[i]` of the second grouping.
2196
+ * The value is 1 for the same grouping, and near 0 for a random grouping. Two groupings with one group each give 1.
2197
+ */
2198
+ export declare function adjustedRandIndex(a: readonly (string | number)[], b: readonly (string | number)[]): number;
2199
+ /** A drawn segment: a pair of points. */
2200
+ export type DrawnSegment = readonly [Point, Point];
2201
+ /**
2202
+ * This function gives the drawn segments of the routes: one segment for each distinct pair of ends.
2203
+ * A segment that several routes share is one drawn segment, as in `measureQuality`.
2204
+ */
2205
+ export declare function drawnSegments(routes: readonly Route[]): DrawnSegment[];
2206
+ /** This function gives the key of the drawn segment between two points. Two routes share a segment when they give the same key. */
2207
+ export declare function segmentKey(a: Point, b: Point): string | undefined;
2208
+ /**
2209
+ * This function gives the unit of length of a board: the median of the short sides of the boxes of the nodes.
2210
+ * A length divided by the unit has no unit, so boards of different sizes compare. The unit of a board without nodes is 1.
2211
+ */
2212
+ export declare function boardUnit(graph: Graph): number;
2213
+ /** The crossings of a set of drawn segments and their angles (R1 and R2 of MEAS0). */
2214
+ export interface CrossingAngles {
2215
+ /** The number of crossings (R1). It is the same value as `crossings` of `measureQuality`. */
2216
+ readonly crossings: number;
2217
+ /** This value is true when the values come from a sample of the segments. */
2218
+ readonly estimated: boolean;
2219
+ /** The mean angle of a crossing, divided by 90 degrees (R2). The scale is 0 to 1, and higher is better. A set without crossings gives 1. */
2220
+ readonly mean: number;
2221
+ /** The smallest angle of a crossing, in degrees from 0 to 90 (R2). Higher is better. A set without crossings gives 90. */
2222
+ readonly min: number;
2223
+ }
2224
+ /** This function gives the angle between two segments, in degrees from 0 to 90. */
2225
+ export declare function crossingAngle(a: Point, b: Point, c: Point, d: Point): number;
2226
+ /**
2227
+ * This function measures the crossings of a set of segments and their angles (R1 and R2 of MEAS0).
2228
+ * It uses the grid and the sample of `countCrossings`. Above 20 000 segments, a seeded sample of 2 000 segments gives an estimate.
2229
+ * The cost is `n log n`.
2230
+ */
2231
+ export declare function crossingAngles(segs: readonly DrawnSegment[]): CrossingAngles;
2232
+ /** The total turn of the routes (R4 of MEAS0). */
2233
+ export interface TotalTurn {
2234
+ /** The mean over the routes of `T(r) = Σ abs(φ_i) / π`, in half turns. Lower is better. */
2235
+ readonly mean: number;
2236
+ /** The largest turn at one vertex of a route, in degrees from 0 to 180. Lower is better. */
2237
+ readonly max: number;
2238
+ }
2239
+ /** This function measures the total turn of the routes (R4 of MEAS0). A path that goes straight on has 0. The cost is linear. */
2240
+ export declare function totalTurn(routes: readonly Route[]): TotalTurn;
2241
+ /** The spread of the detour of the routes (R5 of MEAS0). */
2242
+ export interface DetourSpread {
2243
+ /** The median of `δ(e) = L(r_e) / span(e)`. */
2244
+ readonly median: number;
2245
+ /** The `0.95` quantile of `δ(e)`: the tail of bad routes. */
2246
+ readonly q95: number;
2247
+ readonly mean: number;
2248
+ }
2249
+ /**
2250
+ * This function measures the spread of the detour `δ(e) = L(r_e) / span(e)` of the routes (R5 of MEAS0).
2251
+ * A route with ends nearer than 1 unit does not count. Each value is 1 or more, and lower is better. The cost is linear.
2252
+ */
2253
+ export declare function detourSpread(routes: readonly Route[]): DetourSpread;
2254
+ /** The spacing of the plugs on the sides of the boxes (R11 of MEAS0). */
2255
+ export interface PlugSpacing {
2256
+ /** The smallest spacing of a side. The scale is 0 to 1, and higher is better. A value of 1 is even spacing. */
2257
+ readonly min: number;
2258
+ /** The `0.05` quantile of the spacing of the sides. */
2259
+ readonly q05: number;
2260
+ /** The number of sides with two plugs or more. */
2261
+ readonly sides: number;
2262
+ }
2263
+ /**
2264
+ * This function measures the spacing of the plugs on each side of each box (R11 of MEAS0), the angular resolution of a box.
2265
+ * For a side with `k` distinct plugs, `ps = min gap / (side / (k + 1))`, with a limit of 1.
2266
+ * Two ends nearer than `TOLERANCE` are one plug, because a bundle shares its plug. An end farther than 1 unit from the side does not count.
2267
+ * Without a side with two plugs, each value is 1. The cost is `n log n`.
2268
+ */
2269
+ export declare function plugSpacing(graph: Graph, routes: readonly Route[]): PlugSpacing;
2270
+ /**
2271
+ * This function gives the share of the ink that shared segments save (B1 of MEAS0): `inkSaved = 1 - ink(S) / Σ_e L(r_e)`.
2272
+ * `ink(S)` counts a shared segment one time, as `measureQuality` does. The scale is 0 to 1, and higher is better. The cost is `n log n`.
2273
+ */
2274
+ export declare function inkSaved(routes: readonly Route[]): number;
2275
+ /** The ambiguity of a result (B4 of MEAS0). */
2276
+ export interface Ambiguity {
2277
+ /** The share of false neighbours, from 0 to 1. Lower is better. */
2278
+ readonly value: number;
2279
+ /** This value is true when the value comes from a sample of the nodes. */
2280
+ readonly estimated: boolean;
2281
+ }
2282
+ /** The options of `ambiguity`. */
2283
+ export interface AmbiguityOptions {
2284
+ /** Up to this number of nodes, the function examines each node. The default is 1000. */
2285
+ readonly exact?: number;
2286
+ /** Above `exact` nodes, the function examines this number of nodes from a seeded sample. The default is 2000. */
2287
+ readonly sample?: number;
2288
+ /** The seed of the sample. The default is 1. */
2289
+ readonly seed?: number;
2290
+ }
2291
+ /**
2292
+ * This function measures the ambiguity of the routes (B4 of MEAS0), with one step of neighbours.
2293
+ * `N(v)` holds the nodes whose routes share a drawn segment with a route of `v`.
2294
+ * `amb = Σ_v count(w in N(v) : no edge v-w) / Σ_v count(N(v))`. The cost is quadratic, so a seeded sample serves above `exact` nodes.
2295
+ */
2296
+ export declare function ambiguity(graph: Graph, routes: readonly Route[], options?: AmbiguityOptions): Ambiguity;
2297
+ /** A joint of a curve: the end of one drawn segment and the start of the next drawn segment. */
2298
+ export interface CurveJoint {
2299
+ readonly at: Point;
2300
+ /** The angle between the tangent at the end of the first segment and the tangent at the start of the second segment, in degrees. */
2301
+ readonly angle: number;
2302
+ /** The jump of the curvature at the joint, `abs(κ^- - κ^+)`, in 1 / units. */
2303
+ readonly jump: number;
2304
+ /** The unit tangent at the end of the first segment. */
2305
+ readonly before: Point;
2306
+ /** The unit tangent at the start of the second segment. */
2307
+ readonly after: Point;
2308
+ }
2309
+ /**
2310
+ * This function gives the joints of a curve: each point where one drawn segment ends and the next one starts.
2311
+ * A segment of length 0 has no tangent, so the joint skips it. The analytic tangents and curvatures of lines, cubic curves and arcs give the values.
2312
+ */
2313
+ export declare function curveJoints(segments: readonly CurveSegment[]): CurveJoint[];
2314
+ /**
2315
+ * This function gives the G1 defect of a curve (C1 of MEAS0): `g1 = max_j angle(T_j^-, T_j^+)` over the joints, in degrees.
2316
+ * Lower is better. A curve is G1 when `g1` is 0.5 degrees or less. The cost is linear.
2317
+ */
2318
+ export declare function g1Defect(segments: readonly CurveSegment[]): number;
2319
+ /**
2320
+ * This function gives the G2 defect of a curve (C2 of MEAS0): `g2 = max_j abs(κ_j^- - κ_j^+) · u` over the joints.
2321
+ * The value has no unit, and lower is better. `u` is the unit of the board (`boardUnit`). The cost is linear.
2322
+ */
2323
+ export declare function g2Defect(segments: readonly CurveSegment[], u: number): number;
2324
+ /**
2325
+ * This function gives the bending energy of a sampled curve (C3 of MEAS0): `E = L · ∫ κ(s)^2 ds`.
2326
+ * At each inner sample, `κ = φ / l`, so `E = L · Σ φ_i^2 / l_i`. The length `l_i` is the mean of the two legs, with a limit of `8τ / φ_i`.
2327
+ * Thus a sharp corner counts as an arc with a sagitta of `τ`, the tolerance of the samples.
2328
+ *
2329
+ * The value has no unit, and lower is better. A full circle gives `4π^2`. The cost is linear.
2330
+ */
2331
+ export declare function bendingEnergy(points: readonly Point[], tolerance?: number): number;
2332
+ /** This function tells if a polyline crosses itself. Two legs next to each other do not count. The cost is `n log n`. */
2333
+ export declare function crossesItself(p: readonly Point[]): boolean;
2334
+ /** This function tells if a polyline turns back on itself at a vertex: a turn of more than 179 degrees, as at a cusp. */
2335
+ export declare function hasCusp(p: readonly Point[]): boolean;
2336
+ /** The input of `curveFaults`: one curve and the polyline that it draws. */
2337
+ export interface CurveCheck {
2338
+ /** The polyline of the route. */
2339
+ readonly polyline: readonly Point[];
2340
+ /** The segments of the curve. */
2341
+ readonly segments: readonly CurveSegment[];
2342
+ /** The samples of the curve (`sampleCurve`). */
2343
+ readonly samples: readonly Point[];
2344
+ /** The free space of the board. Without it, the check `clear` gives false. */
2345
+ readonly space?: CurveSpace;
2346
+ /** With these normals, the check `ends` also examines the direction of the curve at its two ends. */
2347
+ readonly startNormal?: Point;
2348
+ readonly endNormal?: Point;
2349
+ /** With this value, the check `g1` examines the joints. Give it for a curve type that is G1 by its design. */
2350
+ readonly smooth?: boolean;
2351
+ }
2352
+ /** The faults of one curve: one value for each proposed hard rule of the curves in MEAS0. */
2353
+ export interface CurveFaults {
2354
+ /** `curve-clear`: the curve goes through a box that its polyline avoids (C7). */
2355
+ readonly clear: boolean;
2356
+ /** `curve-ends`: the curve misses an end of its polyline, or an end tangent is more than 1 degree off its normal (C10). */
2357
+ readonly ends: boolean;
2358
+ /** `curve-g1`: a joint has a G1 defect of more than 0.5 degrees, and it is not a corner that the free space keeps sharp (C1). */
2359
+ readonly g1: boolean;
2360
+ /** `curve-simple`: the curve crosses itself or turns back at a cusp, and its polyline does not (C9). */
2361
+ readonly simple: boolean;
2362
+ }
2363
+ /** This function checks one curve against the proposed hard rules of the curves of MEAS0. The cost is `n log n` for each curve. */
2364
+ export declare function curveFaults(c: CurveCheck): CurveFaults;
2365
+ /**
2366
+ * This function counts the faults of the nesting of the levels (Z6 of MEAS0, the proposed rule `level-nesting`).
2367
+ * It counts the items of each level whose nodes are in more than one item of the level before it. Lower is better, and 0 is correct.
2368
+ * The cost is linear.
2369
+ */
2370
+ export declare function nestingFaults(levels: readonly Level[]): number;
2371
+ /**
2372
+ * This function measures the position stability of the levels (Z7 of MEAS0).
2373
+ * `ps = mean_(v,d) dist(center(item_d(v)), center(item_(d+1)(v))) / size(item_d(v))`, with `size` the longer side of the box.
2374
+ * The value has no unit, and lower is better. A result with one level gives 0. The cost is linear.
2375
+ */
2376
+ export declare function positionStability(levels: readonly Level[]): number;
2377
+ /**
2378
+ * This function measures the order stability of the levels with groups (Z8 of MEAS0).
2379
+ * For each level, `τ_x` and `τ_y` are the Kendall tau between the item centers and the centroids of their nodes on each axis.
2380
+ * The value is the mean of `(τ_x + τ_y) / 2` over the levels with groups and two items or more. The scale is -1 to 1, and higher is better.
2381
+ * A result without such a level gives 1. The cost is `n log n`, with a sample above 1500 items.
2382
+ */
2383
+ export declare function orderStability(graph: Graph, levels: readonly Level[]): number;
2384
+ /** A grouping of the nodes: a map from the id of each node to the id of its group. */
2385
+ export type Grouping = ReadonlyMap<string, string>;
2386
+ /** This function gives the grouping of one level: each node goes to the id of its item. */
2387
+ export declare function levelGrouping(level: Level): Map<string, string>;
2388
+ /** This function gives the far view of a result: the first level with more than one item, in the order of depth. */
2389
+ export declare function farLevel(levels: readonly Level[]): Level | undefined;
2390
+ /**
2391
+ * This function gives the modularity of a grouping (G1 of MEAS0, Newman and Girvan, 2004).
2392
+ * `Q = Σ_c (e_c / m - (d_c / (2m))^2)`, with `e_c` the edges inside `c` and `d_c` the sum of the degrees in `c`.
2393
+ * The scale is -0.5 to 1, and higher is better. A node without a group is a group alone. The cost is linear.
2394
+ */
2395
+ export declare function modularity(graph: Graph, groups: Grouping): number;
2396
+ /**
2397
+ * This function gives the cut share of a grouping (G2 of MEAS0): the share of the edges between two groups.
2398
+ * For the grouping of a level, it is the sum of the counts of the links of the level, divided by `m`. The scale is 0 to 1, and lower is better.
2399
+ */
2400
+ export declare function cutShare(graph: Graph, groups: Grouping): number;
2401
+ /**
2402
+ * This function gives the balance of one level (G6 of MEAS0): `H(s) / log(k)`, with `s` the shares of the nodes of the `k` items and `H` the entropy.
2403
+ * The scale is 0 to 1, and higher is better. A value of 1 is items of equal size. A level with one item gives 1.
2404
+ */
2405
+ export declare function balance(level: Level): number;
2406
+ /**
2407
+ * This function gives the tree cost of the levels (G8 of MEAS0, Dasgupta, 2016): `D = Σ_(u,v) leaves(lca(u, v)) / (m n)`.
2408
+ * The levels make the tree. `leaves(lca(u, v))` is the number of nodes of the deepest item that holds both ends.
2409
+ * Without such an item, the value is `n`. The scale is 0 to 1, and lower is better. The cost is linear times the depth.
2410
+ */
2411
+ export declare function treeCost(graph: Graph, levels: readonly Level[]): number;
2412
+ /** This function gives the leaf of each node in a tree of sections: the id of the leaf, by the index of the node. */
2413
+ export declare function leafGroups(root: Section, count: number): string[];
2414
+ /**
2415
+ * This function gives the group stability of two trees of the same nodes (G9 of MEAS0): the adjusted Rand index of their leaves.
2416
+ * The second tree comes from the graph after a small change (`changeGraph`). The scale is -1 to 1, and higher is better.
2417
+ */
2418
+ export declare function groupStability(before: Section, after: Section, count: number): number;
2419
+ /** A small change of a graph, for the stability measures Z10 and G9 of MEAS0. */
2420
+ export interface GraphChange {
2421
+ /** The graph after the change. It keeps the order of the nodes. */
2422
+ readonly graph: Graph;
2423
+ /** The node that moved by one unit, if a free place was found. */
2424
+ readonly moved?: string;
2425
+ /** The new edge, if the graph has two nodes without an edge between them. */
2426
+ readonly added?: string;
2427
+ /** The edge that the change removed. */
2428
+ readonly removed?: string;
2429
+ }
2430
+ /**
2431
+ * This function makes a seeded small change of a graph: one node moves by `boardUnit`, one edge goes and one new edge comes.
2432
+ * The moved box keeps a gap of 4 units to the other boxes. The same graph and the same seed give the same change.
2433
+ */
2434
+ export declare function changeGraph(graph: Graph, seed: number): GraphChange;
2435
+ /** The route stability of a router (Z10 of MEAS0). */
2436
+ export interface RouteStability {
2437
+ /** The mean Fréchet distance between the two routes of an edge, divided by the unit of the board. */
2438
+ readonly mean: number;
2439
+ /** The largest Fréchet distance, divided by the unit of the board. */
2440
+ readonly max: number;
2441
+ /** The share of the routes that moved more than 1 unit of length. */
2442
+ readonly moved: number;
2443
+ }
2444
+ /** The options of `routeStability`. */
2445
+ export interface RouteStabilityOptions {
2446
+ /** Above this number of routes, a seeded sample of this size serves. The default is 2000. */
2447
+ readonly sample?: number;
2448
+ readonly seed?: number;
2449
+ }
2450
+ /**
2451
+ * This function measures the route stability of a router (Z10 of MEAS0) with `measureStability`.
2452
+ * It compares the routes of the edges that both results have. Each distance is divided by the unit of the board.
2453
+ * The cost is quadratic for each route, so a seeded sample serves above `sample` routes.
2454
+ */
2455
+ export declare function routeStability(graph: Graph, before: Result, after: Result, options?: RouteStabilityOptions): RouteStability;
2456
+ /**
2457
+ * This function counts the pairs of boxes whose order or alignment changes on an axis (M2 of MEAS0, the proposed rule `room-order`).
2458
+ * On each axis, it compares the order of the low edges, the order of the high edges, and the relation "a ends before b starts".
2459
+ * Two values nearer than `snap` are equal. Lower is better, and 0 is correct. Above 2000 boxes, a seeded sample of pairs gives an estimate.
2460
+ */
2461
+ export declare function roomOrderFaults(before: readonly Boxed[], after: readonly Boxed[], snap?: number): number;
2462
+ /** One axis of a Pareto front: the key of a measure and the direction that is better. */
2463
+ export interface Objective {
2464
+ readonly key: string;
2465
+ /** `min`: lower is better. `max`: higher is better. */
2466
+ readonly better: "min" | "max";
2467
+ }
2468
+ /**
2469
+ * This function tells if the values `a` dominate the values `b`: `a` is no worse on each objective and better on one objective.
2470
+ * A missing value or `NaN` is the worst value.
2471
+ */
2472
+ export declare function dominates(a: Readonly<Record<string, number>>, b: Readonly<Record<string, number>>, objectives: readonly Objective[]): boolean;
2473
+ /**
2474
+ * This function gives the Pareto front of a list: the items that no other item dominates (MEAS0, "Pareto fronts").
2475
+ * The function `values` gives the measures of an item. The front keeps the order of the list. The cost is quadratic in the items.
2476
+ */
2477
+ export declare function paretoFront<T>(items: readonly T[], values: (item: T) => Readonly<Record<string, number>>, objectives: readonly Objective[]): T[];
2478
+ /** The names of the proposed hard rules of MEAS0. The suite counts them. It does not apply them as rules yet. */
2479
+ export declare const PROPOSED_RULES: readonly string[];
2480
+ /** The options of `runSuite`. */
2481
+ export interface SuiteOptions {
2482
+ /** The largest fixture, in nodes. The default is 1000. */
2483
+ readonly max?: number;
2484
+ /** The number of seeds of each fixture family. The default is 5. The first seed is the seed of the fixture. */
2485
+ readonly seeds?: number;
2486
+ /** A fixture family or a room family with more nodes than this number gets one seed only. The default is 1000. */
2487
+ readonly seedsMaxNodes?: number;
2488
+ /** The number of timed routes of the first seed. The other seeds route two times, for the rule "same twice". The default is 3. */
2489
+ readonly repeat?: number;
2490
+ /** The route stability (Z10) routes a changed graph again, so the suite measures it only up to this number of nodes. The default is 1000. */
2491
+ readonly stabilityMax?: number;
2492
+ /** The step `curve` draws the routes of the fixtures up to this number of nodes. The default is 1000. */
2493
+ readonly curveMax?: number;
2494
+ /** The router whose routes the step `curve` draws. The default is `corners`. */
2495
+ readonly curveRouter?: string;
2496
+ /** The curve strategies that are G1 by their design. The rule `curve-g1` examines them. The default is `rounded`, `arc`, `spline`, `smooth`, `clothoid` and `highway`. */
2497
+ readonly smoothCurves?: readonly string[];
2498
+ /** The curve strategies that read the normals of the plugs. The rule `curve-ends` examines their end tangents. The default is `spline`. */
2499
+ readonly normalCurves?: readonly string[];
2500
+ /** The strategies of each step. The default is the registry of the built-in strategies. */
2501
+ readonly registry?: Registry;
2502
+ /** The fixtures of the families of the steps `router`, `curve` and `group`. The default is `FIXTURES`. */
2503
+ readonly fixtures?: readonly FixtureSpec[];
2504
+ /** The families of the step `room`. The default is `ROOM_FAMILIES`. */
2505
+ readonly roomFamilies?: readonly RoomFamily[];
2506
+ /** The names of the routers of the step `router`. The default is each router of the registry. */
2507
+ readonly routers?: readonly string[];
2508
+ /** The steps that the suite runs. The default is each step. Each part of the workflow `Bench` runs some steps only. The step `curve` needs the step `router`. */
2509
+ readonly steps?: readonly Step[];
2510
+ /** The time limit of one cell of the step `router`, in milliseconds, as `BenchOptions.cellLimit` gives it. The default is no limit. */
2511
+ readonly cellLimit?: number;
2512
+ /** This function gets one line of progress for each fixture and seed. */
2513
+ readonly log?: (line: string) => void;
2514
+ }
2515
+ /** A family of packed boards for the step `room`: `packedGridBoard` with a seed for each member. */
2516
+ export interface RoomFamily {
2517
+ readonly name: string;
2518
+ readonly cols: number;
2519
+ readonly rows: number;
2520
+ /** The number of long links. */
2521
+ readonly long: number;
2522
+ }
2523
+ /** The families of the step `room`: the board of ROOM, and a board of 1000 boxes. */
2524
+ export declare const ROOM_FAMILIES: readonly RoomFamily[];
2525
+ /** One row of the suite: one strategy of one step on one member of a fixture family. */
2526
+ export interface SuiteRow {
2527
+ readonly step: Step;
2528
+ /** The name of the fixture family. */
2529
+ readonly fixture: string;
2530
+ /** The index of the seed in the family, from 0. */
2531
+ readonly seed: number;
2532
+ readonly strategy: string;
2533
+ readonly nodes: number;
2534
+ readonly edges: number;
2535
+ /**
2536
+ * The violations of the hard rules of today. The step `router` checks `checkProperties` and "same twice".
2537
+ * The step `group` checks `checkSections` and the rules of the levels (`checkLevels`).
2538
+ */
2539
+ readonly violations: number;
2540
+ /** The time of the step and of the measures of today, in milliseconds. */
2541
+ readonly ms: number;
2542
+ /** The time of the new measures of MEAS1, without the extra runs, in milliseconds. */
2543
+ readonly measureMs: number;
2544
+ /** The time of the extra routes of the stability measures (Z10 and G9), in milliseconds. */
2545
+ readonly extraMs: number;
2546
+ /** The time of the grouping rule alone, without the router, in milliseconds. Only the rows of the step `group` have it. */
2547
+ readonly treeMs?: number;
2548
+ /** The measures, by a key that starts with the id of MEAS0, or the name of a proposed rule. */
2549
+ readonly values: Readonly<Record<string, number>>;
2550
+ }
2551
+ /** The spread of each measure of one strategy on one fixture family, over the seeds. */
2552
+ export interface SuiteSummary {
2553
+ readonly step: Step;
2554
+ readonly fixture: string;
2555
+ readonly strategy: string;
2556
+ readonly nodes: number;
2557
+ readonly seeds: number;
2558
+ /** The sum of the violations over the seeds. */
2559
+ readonly violations: number;
2560
+ readonly measures: Readonly<Record<string, Spread>>;
2561
+ }
2562
+ /** The Pareto front of one step on one fixture family, over the medians of the seeds. */
2563
+ export interface SuiteFront {
2564
+ readonly step: Step;
2565
+ readonly fixture: string;
2566
+ readonly nodes: number;
2567
+ readonly objectives: readonly Objective[];
2568
+ /** The strategies on the front, in the order of the registry. */
2569
+ readonly front: readonly string[];
2570
+ /** The strategies with a violation of a hard rule. They do not enter the front. */
2571
+ readonly excluded: readonly string[];
2572
+ /** Each strategy that the front compares. */
2573
+ readonly strategies: readonly string[];
2574
+ }
2575
+ /** The count of one proposed hard rule for one strategy, over each fixture and each seed. */
2576
+ export interface RuleCount {
2577
+ readonly step: Step;
2578
+ readonly strategy: string;
2579
+ readonly rule: string;
2580
+ readonly count: number;
2581
+ }
2582
+ /** The report of the suite. The workflow `Bench` keeps it as an artifact. */
2583
+ export interface SuiteReport {
2584
+ readonly options: {
2585
+ readonly max: number;
2586
+ readonly seeds: number;
2587
+ readonly seedsMaxNodes: number;
2588
+ readonly repeat: number;
2589
+ readonly stabilityMax: number;
2590
+ readonly curveMax: number;
2591
+ readonly curveRouter: string;
2592
+ };
2593
+ readonly rows: readonly SuiteRow[];
2594
+ readonly summaries: readonly SuiteSummary[];
2595
+ readonly fronts: readonly SuiteFront[];
2596
+ readonly rules: readonly RuleCount[];
2597
+ }
2598
+ /** The axes of the Pareto front of each step. The note MEAS0 asks for two to four scores. */
2599
+ export declare const FRONT_OBJECTIVES: Readonly<Record<Step, readonly Objective[]>>;
2600
+ /** This function gives the seed of the member `k` of the family of a fixture. The member 0 is the fixture itself. */
2601
+ export declare function familySeed(spec: FixtureSpec, k: number): number;
2602
+ /** This function gives the measures of the levels of a result: Z6, Z7, Z8, and G1, G2 and G8 of the far view. A result without groups gives none. */
2603
+ export declare function levelMeasures(graph: Graph, result: Result): Record<string, number>;
2604
+ /** This function gives the new measures of the routes of a result (MEAS1). The row of `benchRun` gives the values of today. */
2605
+ export declare function routeMeasures(graph: Graph, result: Result, row: BenchRow): Record<string, number>;
2606
+ /** The options of `curveRuns`. */
2607
+ export interface CurveRunOptions {
2608
+ /** The name of the fixture family, for the rows. */
2609
+ readonly fixture: string;
2610
+ /** The index of the seed in the family, for the rows. */
2611
+ readonly seed: number;
2612
+ /** The curve strategies that are G1 by their design. The rule `curve-g1` examines them. */
2613
+ readonly smooth: ReadonlySet<string>;
2614
+ /** The curve strategies that read the normals of the plugs. The rule `curve-ends` examines their end tangents. */
2615
+ readonly normals: ReadonlySet<string>;
2616
+ /** The options of each curve strategy, by its name. A strategy without an entry gets its defaults. */
2617
+ readonly curveOptions?: Readonly<Record<string, object>>;
2618
+ }
2619
+ /** One curve strategy on the routes of one result: the row of the suite and the drawn curves. */
2620
+ export interface CurveRun {
2621
+ readonly row: SuiteRow;
2622
+ /** The segments of each curve, in the order of the routes that have two points or more. */
2623
+ readonly drawn: readonly CurveSegment[][];
2624
+ /** The edge of each curve of `drawn`. */
2625
+ readonly edges: readonly string[];
2626
+ }
2627
+ /** This function draws the routes of a result with each curve strategy and measures the curves (C1, C2, C3, C6 and the curve rules). */
2628
+ export declare function curveRuns(graph: Graph, result: Result, curves: readonly Strategy<"curve">[], options: CurveRunOptions): CurveRun[];
2629
+ /** One grouping rule on one graph: the row of the suite, the tree of the rule and the result of `sections` on that tree. */
2630
+ export interface GroupRun {
2631
+ readonly row: SuiteRow;
2632
+ readonly tree: Section;
2633
+ /** The result of the router `sections` with the tree of the rule. A tree that `checkSections` refuses gives no result. */
2634
+ readonly result?: Result;
2635
+ }
2636
+ /**
2637
+ * This function groups one graph with one grouping rule, routes it with the router `sections` on that tree, and measures the levels.
2638
+ * The grouping of the changed graph gives the group stability (G9). `options` are the options of the rule on `graph`.
2639
+ */
2640
+ export declare function groupRun(graph: Graph, strategy: Strategy<"group">, options: object, change: {
2641
+ readonly graph: Graph;
2642
+ readonly options: object;
2643
+ }, at: {
2644
+ readonly fixture: string;
2645
+ readonly seed: number;
2646
+ }): GroupRun;
2647
+ /**
2648
+ * This function gives the options of a grouping rule on a fixture. The rule `keys` gets a key from the data of the edges:
2649
+ * the collection of the first edge into the node. A node without such an edge is a group alone.
2650
+ */
2651
+ export declare function fixtureGroupOptions(strategy: string, graph: Graph): object;
2652
+ /**
2653
+ * This function starts the measure suite of MEAS1. The suite measures each strategy of each step on each seed of each fixture family.
2654
+ * The step `router` keeps the rows of today in `bench` for the first seed, so the tables of the benchmark stay the same.
2655
+ */
2656
+ export declare function runSuite(options?: SuiteOptions): {
2657
+ report: SuiteReport;
2658
+ bench: BenchRow[];
2659
+ };
2660
+ /**
2661
+ * This function puts the rows of the suite in the order of one run. It sorts them by fixture family, then by seed.
2662
+ * In one seed, the routers come first, and the curves come after the router of the curves. The grouping rules and the room come last.
2663
+ * A name that is not in its list goes after the names of the list.
2664
+ * The workflow `Bench` uses it to join the reports of its parts.
2665
+ */
2666
+ export declare function orderSuiteRows(rows: readonly SuiteRow[], options?: {
2667
+ registry?: Registry;
2668
+ fixtures?: readonly FixtureSpec[];
2669
+ roomFamilies?: readonly RoomFamily[];
2670
+ curveRouter?: string;
2671
+ }): SuiteRow[];
2672
+ /**
2673
+ * This function joins the reports of the parts of one benchmark into one report. It puts the rows in the order of one run.
2674
+ * Then it calculates the summaries, the fronts and the rule counts again from all the rows.
2675
+ */
2676
+ export declare function joinReports(reports: readonly SuiteReport[], options?: {
2677
+ registry?: Registry;
2678
+ fixtures?: readonly FixtureSpec[];
2679
+ roomFamilies?: readonly RoomFamily[];
2680
+ }): SuiteReport;
2681
+ /** This function gives the spread of each measure of each strategy on each fixture family, over the seeds. It keeps the order of the rows. */
2682
+ export declare function summarizeRows(rows: readonly SuiteRow[]): SuiteSummary[];
2683
+ /**
2684
+ * This function gives the Pareto front of each step on each fixture family, over the medians of the seeds.
2685
+ * A strategy with a violation of a hard rule does not enter the front, as MEAS0 asks.
2686
+ */
2687
+ export declare function suiteFronts(summaries: readonly SuiteSummary[], objectives?: Readonly<Record<Step, readonly Objective[]>>): SuiteFront[];
2688
+ /** This function sums each proposed hard rule of MEAS0 for each strategy of each step, over each fixture and each seed. */
2689
+ export declare function ruleCounts(rows: readonly SuiteRow[]): RuleCount[];
2690
+ /** The columns of the tables of `formatSuite`: the keys of the measures of each step. */
2691
+ export declare const SUITE_COLUMNS: Readonly<Record<Step, readonly string[]>>;
2692
+ /**
2693
+ * This function writes the summaries of one step as a Markdown table. Each cell is the median over the seeds, with the interquartile range in brackets.
2694
+ * The column `R1 IQR/median` gives the spread of the crossings.
2695
+ */
2696
+ export declare function formatSummaries(summaries: readonly SuiteSummary[], step: Step, columns?: readonly string[]): string;
2697
+ /** This function writes the Pareto fronts as a Markdown table. */
2698
+ export declare function formatFronts(fronts: readonly SuiteFront[]): string;
2699
+ /** This function writes the counts of the proposed hard rules as a Markdown table: one row for each step and strategy. */
2700
+ export declare function formatRules(rules: readonly RuleCount[]): string;
2701
+ /**
2702
+ * This function compares the time of the new measures with the time of the step and the measures of today.
2703
+ * It gives one row for each fixture family of a step. The extra routes of the stability measures have their own column.
2704
+ */
2705
+ export declare function formatMeasureTime(rows: readonly SuiteRow[], step?: Step): string;
1271
2706
  /** The options of a router strategy: the options of its router, without the name and the limit of the benchmark. */
1272
2707
  export type RouterPreset<O> = Omit<O, "name" | "maxNodes">;
1273
2708
  /** The built-in router strategies, in the order of the benchmark. They route as the routers of `ROUTERS`. */
@@ -1292,23 +2727,126 @@ export interface TensionOptions {
1292
2727
  /** The tension of the spline, from 0 (the spline) to 1 (the polyline). The default is 0. */
1293
2728
  readonly tension: number;
1294
2729
  }
1295
- /** The built-in curve strategies, in the order of `CURVE_TYPES`. Each one gives the same segments as `curveOf` with its type. */
2730
+ /** The options of the curve strategy `highway`. */
2731
+ export interface HighwayStrategyOptions {
2732
+ /** The radius of the center line of a bundle at a bend, and of each lone corner. The default is 12. */
2733
+ readonly radius: number;
2734
+ /** The smallest radius of a lane at a bend of a bundle. The default is 4. */
2735
+ readonly minRadius: number;
2736
+ /** The shape of the S curve where a lane changes its offset. The default is `biarc`. */
2737
+ readonly jog: JogStyle;
2738
+ /** The number of cubic pieces of a `quintic` S curve. The default is 4. */
2739
+ readonly jogPieces: number;
2740
+ }
2741
+ /** The options of the curve strategy `smooth`. */
2742
+ export interface SmoothStrategyOptions {
2743
+ /** The radius of the arc of each corner. The default is 12. */
2744
+ readonly radius: number;
2745
+ /** The share of the turn of a corner in its two spirals, from 0 to 1. The default is 0.6. */
2746
+ readonly smoothing: number;
2747
+ }
2748
+ /** The options of the curve strategy `clothoid`. */
2749
+ export interface ClothoidStrategyOptions {
2750
+ /** The radius of the arc of each corner. The default is 12. */
2751
+ readonly radius: number;
2752
+ /** The share of the turn of a corner in its two clothoids, from 0 to 1. The default is 0.5. */
2753
+ readonly spiral: number;
2754
+ /** The largest distance from the cubic pieces to the true clothoid. The default is 0.25. */
2755
+ readonly tolerance: number;
2756
+ }
2757
+ /**
2758
+ * The built-in curve strategies. The first six are in the order of `CURVE_TYPES`, and each one gives the same segments as `curveOf` with its type.
2759
+ * The strategy `highway` gives the curve of `arc` for one polyline. `highwayCurves` bends the lanes of a bundle as one.
2760
+ */
1296
2761
  export declare const curveStrategies: {
1297
2762
  readonly straight: Strategy<"curve", object>;
1298
2763
  readonly rounded: Strategy<"curve", RadiusOptions>;
1299
2764
  readonly spline: Strategy<"curve", TensionOptions>;
1300
2765
  readonly arc: Strategy<"curve", RadiusOptions>;
2766
+ readonly smooth: Strategy<"curve", SmoothStrategyOptions>;
2767
+ readonly clothoid: Strategy<"curve", ClothoidStrategyOptions>;
2768
+ readonly highway: Strategy<"curve", HighwayStrategyOptions>;
1301
2769
  };
1302
2770
  /** The options of a room strategy: the options of `roomDemand`, without the method. */
1303
2771
  export type RoomPreset = Omit<RoomOptions, "method">;
1304
- /** The built-in room strategies: the methods of `roomDemand`. */
2772
+ /** The options of the room strategy `levels`: the options of `levelRoom` without the method, and the limits of the quadtree. */
2773
+ export type LevelRoomPreset = Omit<LevelRoomOptions, "method"> & SectionOptions;
2774
+ /** The built-in room strategies: the methods of `roomDemand`, and the room of each zoom level (`levelRoom`). */
1305
2775
  export declare const roomStrategies: {
1306
2776
  readonly routes: Strategy<"room", RoomPreset>;
1307
2777
  readonly lines: Strategy<"room", RoomPreset>;
2778
+ readonly levels: Strategy<"room", LevelRoomPreset>;
2779
+ };
2780
+ /** The built-in grouping rules: the strategies of the step `group`. The router `sections` makes its hubs and its zoom levels from their tree. */
2781
+ export declare const groupStrategies: {
2782
+ readonly quadtree: Strategy<"group", Required<SectionOptions>>;
2783
+ readonly keys: Strategy<"group", KeyOptions>;
2784
+ readonly kd: Strategy<"group", Required<KdOptions>>;
2785
+ readonly cut: Strategy<"group", Required<CutOptions>>;
1308
2786
  };
1309
2787
  /** The built-in strategies of each step, in order. A consumer adds its own: `createRegistry([...BUILT_IN_STRATEGIES, mine])`. */
1310
2788
  export declare const BUILT_IN_STRATEGIES: readonly AnyStrategy[];
1311
2789
  /** The registry of the built-in strategies. The benchmark and the site take their lists from it. */
1312
2790
  export declare const STRATEGIES: Registry;
1313
- export type { ArcOptions, CornersOptions, CurveSpace, RoundedOptions, SectionsOptions, SharedOptions, SplineOptions, TrunksOptions };
2791
+ /** The steps that `compareStep` compares. The step `room` takes a packed board, not a graph, so it is not in the list. */
2792
+ export type CompareStep = Exclude<Step, "room">;
2793
+ /** The steps that `compareStep` compares, in the order of the pipeline. */
2794
+ export declare const COMPARE_STEPS: readonly CompareStep[];
2795
+ /** The options of `compareStep`. */
2796
+ export interface CompareOptions {
2797
+ /** The strategies of each step. The default is the registry of the built-in strategies. */
2798
+ readonly registry?: Registry;
2799
+ /** The options of each strategy of the step, by its name. A strategy without an entry gets its defaults. */
2800
+ readonly options?: Readonly<Record<string, object>>;
2801
+ /** The router whose routes the step `curve` draws. The default is `corners`, as in `runSuite`. */
2802
+ readonly curveRouter?: string;
2803
+ /** The seed of the small change of the graph for the stability measures (Z10 and G9). The default is 1. */
2804
+ readonly seed?: number;
2805
+ /** The route stability (Z10) routes a changed graph again, so the function measures it only up to this number of nodes. The default is 1000. */
2806
+ readonly stabilityMax?: number;
2807
+ /** The name of the graph in the rows. The default is `board`. */
2808
+ readonly name?: string;
2809
+ }
2810
+ /** One strategy of one step on one graph: its measures and its output. */
2811
+ export interface CompareRow {
2812
+ readonly step: CompareStep;
2813
+ readonly strategy: string;
2814
+ /** The violations of the hard rules, as `runSuite` counts them. A strategy with a violation does not enter the front. */
2815
+ readonly violations: number;
2816
+ /** The time of the step, in milliseconds. For the step `router`, it is the median of two routes. */
2817
+ readonly ms: number;
2818
+ /** The measures, by the keys of `runSuite`, and `ms`. The step `router` adds `ink`, and the step `curve` adds `C5.peak`. */
2819
+ readonly values: Readonly<Record<string, number>>;
2820
+ /** The reason when the strategy did not run, for example a graph over its `maxNodes`. */
2821
+ readonly skipped?: string;
2822
+ /** The result of the router, for the steps `router` and `group`. The step `group` routes with `sections` on the tree of the rule. */
2823
+ readonly result?: Result;
2824
+ /** The tree of the grouping rule, for the step `group`. */
2825
+ readonly tree?: Section;
2826
+ /** The segments of each curve, for the step `curve`, in the order of `edges`. */
2827
+ readonly curves?: readonly CurveSegment[][];
2828
+ /** The edge of each curve of `curves`. */
2829
+ readonly edges?: readonly string[];
2830
+ }
2831
+ /** The comparison of the strategies of one step on one graph. */
2832
+ export interface StepComparison {
2833
+ readonly step: CompareStep;
2834
+ /** One row for each strategy of the step, in the order of the registry. */
2835
+ readonly rows: readonly CompareRow[];
2836
+ /** The axes of the Pareto front: `FRONT_OBJECTIVES` of the step. */
2837
+ readonly objectives: readonly Objective[];
2838
+ /** The strategies on the Pareto front, in the order of the registry. */
2839
+ readonly front: readonly string[];
2840
+ /** The strategies with a violation of a hard rule, or that did not run. They do not enter the front. */
2841
+ readonly excluded: readonly string[];
2842
+ }
2843
+ /**
2844
+ * This function runs each strategy of one step on one graph and measures it with the measures of `runSuite`. Then it gives the Pareto front.
2845
+ * The step `router` routes the graph with each router. The step `curve` draws the routes of `curveRouter` with each curve.
2846
+ * The step `group` routes the graph with `sections` on the tree of each grouping rule.
2847
+ *
2848
+ * The same graph and the same options give the same measures. Only the times change.
2849
+ */
2850
+ export declare function compareStep(step: CompareStep, graph: Graph, options?: CompareOptions): StepComparison;
2851
+ export type { ArcOptions, ClothoidOptions, CornersOptions, CurveSpace, CutObjective, CutOptions, HighwayOptions, JogStyle, KdAxis, KdLine, KdOptions, KeyOptions, LaneCurve, NodeKey, RoomBends, RoundedOptions, SectionsOptions, SharedOptions, SmoothOptions, SplineOptions, TrunksOptions };
1314
2852
  //# sourceMappingURL=index.d.ts.map