@mark1russell7/highways 0.4.1 → 0.5.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 (60) hide show
  1. package/README.md +43 -1
  2. package/build/index.d.ts +1377 -5
  3. package/build/index.d.ts.map +1 -1
  4. package/build/index.js +8202 -1515
  5. package/build/index.js.map +1 -1
  6. package/package.json +3 -1
  7. package/src/bench/exact/index.ts +197 -0
  8. package/src/bench/measures/highways.ts +93 -0
  9. package/src/bench/measures/index.ts +2 -0
  10. package/src/bench/measures/lanes.ts +304 -0
  11. package/src/bench/measures/levels.ts +86 -2
  12. package/src/bench/screen/forms.ts +11 -5
  13. package/src/bench/screen/measures.ts +23 -0
  14. package/src/bench/screen/screen.ts +42 -0
  15. package/src/channels.ts +56 -0
  16. package/src/highways/base.ts +126 -0
  17. package/src/highways/diffusion/index.ts +103 -0
  18. package/src/highways/edge-paths/index.ts +155 -0
  19. package/src/highways/fixtures.test-util.ts +71 -0
  20. package/src/highways/flow-clusters/index.ts +143 -0
  21. package/src/highways/flow-field/index.ts +49 -0
  22. package/src/highways/gates/ambiguity/index.ts +110 -0
  23. package/src/highways/gates/breakeven/index.ts +62 -0
  24. package/src/highways/gates/hysteresis/index.ts +48 -0
  25. package/src/highways/gates/ids/index.ts +59 -0
  26. package/src/highways/gates/index.ts +6 -0
  27. package/src/highways/gates/model.ts +129 -0
  28. package/src/highways/gates/stretch/index.ts +39 -0
  29. package/src/highways/grouped.ts +123 -0
  30. package/src/highways/growth/index.ts +148 -0
  31. package/src/highways/hdbscan/index.ts +250 -0
  32. package/src/highways/hough/index.ts +182 -0
  33. package/src/highways/hub-arcs/index.ts +181 -0
  34. package/src/highways/index.ts +30 -0
  35. package/src/highways/lanes/index.ts +189 -0
  36. package/src/highways/level-links/index.ts +114 -0
  37. package/src/highways/meet/index.ts +84 -0
  38. package/src/highways/mingle/index.ts +171 -0
  39. package/src/highways/model.ts +5 -0
  40. package/src/highways/nested/index.ts +143 -0
  41. package/src/highways/od-cells/index.ts +50 -0
  42. package/src/highways/quickbundles/index.ts +117 -0
  43. package/src/highways/ridges/index.ts +328 -0
  44. package/src/highways/road-classes/index.ts +74 -0
  45. package/src/highways/router.ts +1 -1
  46. package/src/highways/select/index.ts +162 -0
  47. package/src/highways/snap.ts +110 -0
  48. package/src/highways/soft-keys/index.ts +114 -0
  49. package/src/highways/spiral/index.ts +205 -0
  50. package/src/highways/stretches.ts +141 -0
  51. package/src/highways/stubs/index.ts +117 -0
  52. package/src/highways/traclus/index.ts +296 -0
  53. package/src/highways/weiszfeld/index.ts +105 -0
  54. package/src/highways/wspd/index.ts +130 -0
  55. package/src/highways/zipper/index.ts +168 -0
  56. package/src/index.ts +1 -0
  57. package/src/routers/shared.ts +56 -3
  58. package/src/strategies/builtins.ts +303 -7
  59. package/src/strategies/schemas.ts +300 -0
  60. package/src/visibility.ts +5 -0
@@ -1,7 +1,34 @@
1
1
  import type { CutOptions } from "../groups/cut/index.ts";
2
2
  import type { KdOptions } from "../groups/kd/index.ts";
3
3
  import type { KeyOptions } from "../groups/keys/index.ts";
4
+ import type { HighwayBase } from "../highways/base.ts";
4
5
  import type { CorridorOptions } from "../highways/corridors/index.ts";
6
+ import type { DiffusionOptions } from "../highways/diffusion/index.ts";
7
+ import type { EdgePathOptions } from "../highways/edge-paths/index.ts";
8
+ import type { FlowClusterOptions } from "../highways/flow-clusters/index.ts";
9
+ import type { FlowFieldOptions } from "../highways/flow-field/index.ts";
10
+ import type { GrowthOptions } from "../highways/growth/index.ts";
11
+ import type { GroupSpine } from "../highways/grouped.ts";
12
+ import type { HdbscanOptions } from "../highways/hdbscan/index.ts";
13
+ import type { HoughOptions } from "../highways/hough/index.ts";
14
+ import type { HubArcOptions } from "../highways/hub-arcs/index.ts";
15
+ import type { LanesOptions } from "../highways/lanes/index.ts";
16
+ import type { LevelHighwayOptions } from "../highways/level-links/index.ts";
17
+ import type { MeetOptions } from "../highways/meet/index.ts";
18
+ import type { MingleOptions } from "../highways/mingle/index.ts";
19
+ import type { NestedOptions } from "../highways/nested/index.ts";
20
+ import type { OdCellOptions } from "../highways/od-cells/index.ts";
21
+ import type { QuickBundlesOptions } from "../highways/quickbundles/index.ts";
22
+ import type { RidgeOptions } from "../highways/ridges/index.ts";
23
+ import type { RoadClassOptions } from "../highways/road-classes/index.ts";
24
+ import type { SelectOptions } from "../highways/select/index.ts";
25
+ import type { SoftKeyOptions } from "../highways/soft-keys/index.ts";
26
+ import type { SpiralOptions } from "../highways/spiral/index.ts";
27
+ import type { StubOptions } from "../highways/stubs/index.ts";
28
+ import type { TraclusOptions } from "../highways/traclus/index.ts";
29
+ import type { WeiszfeldOptions } from "../highways/weiszfeld/index.ts";
30
+ import type { WspdOptions } from "../highways/wspd/index.ts";
31
+ import type { ZipperOptions } from "../highways/zipper/index.ts";
5
32
  import type { CornersOptions } from "../routers/corners.ts";
6
33
  import type { SectionsOptions } from "../routers/sections.ts";
7
34
  import type { SharedOptions } from "../routers/shared.ts";
@@ -108,6 +135,24 @@ export const SHARED_SCHEMA: OptionSchema<RouterPreset<SharedOptions>> = {
108
135
  default: "span",
109
136
  describe: "The order of the edges of a key: the longest first, the shortest first, the most edges between two sections first, or the input order (NAT-024).",
110
137
  },
138
+ reuse: {
139
+ type: "number",
140
+ min: 0,
141
+ max: 2,
142
+ step: 0.25,
143
+ default: 0,
144
+ describe: "With a value above 0, each later pass routes the edges again, and the busy links of the pass before cost less (HWY-005).",
145
+ },
146
+ reuseExponent: { type: "number", min: 0.5, max: 2, step: 0.25, default: 1, describe: "The exponent of the pull of the busy links of the option `reuse`." },
147
+ capacity: {
148
+ type: "number",
149
+ min: 0,
150
+ max: 10,
151
+ step: 0.5,
152
+ default: 0,
153
+ describe: "With a value above 0, a link costs more for each lane that does not fit in the free space across it (HWY-016).",
154
+ },
155
+ laneWidth: { type: "number", min: 2, max: 8, step: 1, default: 4, describe: "The width of one lane, for the option `capacity`." },
111
156
  merge: {
112
157
  type: "enum",
113
158
  values: ["corner", "snell"],
@@ -283,3 +328,258 @@ export const CUT_SCHEMA: OptionSchema<CutOptions> = {
283
328
  pull: { type: "number", min: 0, max: 4, step: 0.25, marks: [0, 0.5, 1, 2, 4], default: 0.5, describe: "The cost of a line grows with its distance from the middle of the cell, by this factor." },
284
329
  guard: { type: "boolean", default: true, describe: "With `true`, each section also tests the quadtree split, and keeps the split that cuts fewer edges." },
285
330
  };
331
+
332
+ /** The declaration of the plan that a post step of the step `highway` changes (BUILD-W2B). */
333
+ const HIGHWAY_BASE: EnumOption<HighwayBase> = {
334
+ type: "enum",
335
+ values: ["none", "shared-ways", "corridors"],
336
+ default: "shared-ways",
337
+ describe: "The plan that the strategy changes: no highway, the highways of `shared-ways`, or the highways of `corridors`.",
338
+ };
339
+
340
+ /** The declarations of the options of the highway strategy `meet` (HWY-050). */
341
+ export const MEET_SCHEMA: OptionSchema<MeetOptions> = {
342
+ from: HIGHWAY_BASE,
343
+ near: { type: "number", min: 2, max: 40, step: 2, default: 8, describe: "A first route meets the spine where it is this distance from the spine, or nearer." },
344
+ maxTurn: { type: "number", min: 10, max: 90, step: 5, default: 45, describe: "A first route meets the spine only where it runs at this angle to the spine, or less, in degrees." },
345
+ minRun: { type: "number", min: 0, max: 80, step: 5, default: 10, describe: "A member keeps its places when the stretch where its first route meets the spine is shorter than this length." },
346
+ };
347
+
348
+ /** The declarations of the options of the highway strategy `weiszfeld` (HWY-043). */
349
+ export const WEISZFELD_SCHEMA: OptionSchema<WeiszfeldOptions> = {
350
+ from: HIGHWAY_BASE,
351
+ alpha: { type: "number", min: 0, max: 1, step: 0.1, default: 0.5, describe: "The weight of the trunk is `k^alpha` for `k` members." },
352
+ steps: { type: "integer", min: 1, max: 50, step: 1, marks: [10, 20, 50], default: 20, describe: "The number of steps of Weiszfeld." },
353
+ };
354
+
355
+ /** The declarations of the options of the highway strategy `stubs` (HWY-015 with WILD-005). */
356
+ export const STUB_SCHEMA: OptionSchema<StubOptions> = {
357
+ from: HIGHWAY_BASE,
358
+ omega: { type: "number", min: 10, max: 60, step: 5, default: 30, describe: "The ends of one side of a box whose directions are in a window of this angle share a stub, in degrees." },
359
+ sigma: { type: "number", min: 0.1, max: 0.4, step: 0.05, default: 0.25, describe: "The length of a stub is this share of the distance to the nearest other end." },
360
+ ends: { type: "enum", values: ["source", "target", "both"], default: "both", describe: "The ends that get stubs." },
361
+ minSize: { type: "integer", min: 2, max: 8, step: 1, default: 2, describe: "A stub has this number of edges or more." },
362
+ };
363
+
364
+ /** The declarations of the options of the highway strategy `zipper` (NAT-022 with WILD-037). */
365
+ export const ZIPPER_SCHEMA: OptionSchema<ZipperOptions> = {
366
+ from: HIGHWAY_BASE,
367
+ near: { type: "number", min: 0.5, max: 3, step: 0.25, default: 1, describe: "Two legs zip when they are this distance apart or nearer, in units of the board." },
368
+ maxAngle: { type: "number", min: 5, max: 30, step: 5, default: 15, describe: "Two legs zip when the angle between them is this value or less, in degrees." },
369
+ adhesion: { type: "number", min: 0, max: 1, step: 0.1, default: 0.3, describe: "Two legs zip when this value times their overlap is more than the length that the zip adds." },
370
+ minOverlap: { type: "number", min: 1, max: 5, step: 0.5, default: 1, describe: "Two legs zip when they overlap along this length or more, in units of the board." },
371
+ passes: { type: "integer", min: 1, max: 5, step: 1, default: 1, describe: "The number of passes. Each pass routes the plan and zips the legs again." },
372
+ };
373
+
374
+ /** The declarations of the options of the highway strategy `level-links` (HWY-056 with WILD-034). */
375
+ export const LEVEL_HIGHWAY_SCHEMA: OptionSchema<LevelHighwayOptions> = {
376
+ from: HIGHWAY_BASE,
377
+ depth: { type: "integer", min: 1, max: 3, step: 1, default: 1, describe: "The depth of the level in the tree of sections." },
378
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A level link becomes a highway when this number of edges or more ride it." },
379
+ stretch: { type: "number", min: 1.2, max: 2, step: 0.1, default: 1.5, describe: "An edge rides the link only when its way along the link is this many times its first route, or shorter." },
380
+ };
381
+
382
+ /** The declaration of the spine of a group of edges: the shared ways of the group, or one trunk between two terminals. */
383
+ const GROUP_SPINE: EnumOption<GroupSpine> = {
384
+ type: "enum",
385
+ values: ["shared", "trunk"],
386
+ default: "shared",
387
+ describe: "With `shared`, the edges of a group share their ways through the corner graph. With `trunk`, a group gets one trunk between two terminals.",
388
+ };
389
+
390
+ /** The declarations of the options of the highway strategy `quickbundles` (HWY-026). */
391
+ export const QUICKBUNDLES_SCHEMA: OptionSchema<QuickBundlesOptions> = {
392
+ theta: { type: "number", min: 1, max: 10, step: 0.5, marks: [1.5, 3, 6], default: 3, describe: "An edge joins a cluster when its distance to the centroid is this value or less, in units of the board." },
393
+ points: { type: "integer", min: 6, max: 24, step: 2, default: 12, describe: "The number of points of each line after the resampling." },
394
+ line: { type: "enum", values: ["routes", "lines"], default: "routes", describe: "The line of each edge: its first route, or the straight line between its plugs." },
395
+ order: { type: "enum", values: ["input", "length"], default: "input", describe: "The order of the edges in the pass: the order of the graph, or the longest line first." },
396
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A cluster with this number of edges or more gets highways." },
397
+ spine: GROUP_SPINE,
398
+ };
399
+
400
+ /** The declarations of the options of the highway strategy `road-classes` (HWY-034 with EDA-050). */
401
+ export const ROAD_CLASS_SCHEMA: OptionSchema<RoadClassOptions> = {
402
+ margin: WAY_SCHEMA.margin,
403
+ k: WAY_SCHEMA.k,
404
+ quantile: { type: "number", min: 0.5, max: 0.99, step: 0.05, marks: [0.8, 0.9, 0.95], default: 0.9, describe: "A link is a highway link when its use is at this quantile of the use of the links, or higher." },
405
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A highway link and a highway have this number of edges or more." },
406
+ discount: { type: "number", min: 0.1, max: 0.8, step: 0.1, default: 0.5, describe: "The second pass gives each highway link this discount, as a share of its length." },
407
+ };
408
+
409
+ /** The declarations of the options of the highway strategy `flow-field` (EDA-046 with HWY-037). */
410
+ export const FLOW_FIELD_SCHEMA: OptionSchema<FlowFieldOptions> = {
411
+ margin: WAY_SCHEMA.margin,
412
+ k: WAY_SCHEMA.k,
413
+ minFanIn: { type: "integer", min: 2, max: 10, step: 1, default: 2, describe: "An end with this number of edges or more on one side of its box gets a field." },
414
+ end: { type: "enum", values: ["target", "source"], default: "target", describe: "The end that gets a field: the target of a fan-in, or the source of a fan-out." },
415
+ };
416
+
417
+ /** The declarations of the options of the highway strategy `wspd` (HWY-018). */
418
+ export const WSPD_SCHEMA: OptionSchema<WspdOptions> = {
419
+ separation: { type: "number", min: 1, max: 8, step: 0.5, marks: [1, 2, 4], default: 2, describe: "The gap between the two sets of a pair is at least this value times the radius of the larger set." },
420
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 3, describe: "A pair with this number of edges or more gets a highway." },
421
+ spine: { ...GROUP_SPINE, default: "trunk" },
422
+ };
423
+
424
+ /** The declarations of the options of the highway strategy `od-cells` (EDA-033 with WILD-032). */
425
+ export const OD_CELL_SCHEMA: OptionSchema<OdCellOptions> = {
426
+ level: { type: "integer", min: 1, max: 4, step: 1, default: 2, describe: "The depth of the cells in the tree of sections." },
427
+ minGroup: { type: "integer", min: 2, max: 8, step: 1, default: 3, describe: "A pair of cells with this number of edges or more gets a trunk." },
428
+ legMax: { type: "number", min: 0.1, max: 1, step: 0.05, marks: [0.2, 0.3, 0.4], default: 0.3, describe: "An edge rides the trunk only when each of its legs is this share of the span or shorter." },
429
+ spine: { ...GROUP_SPINE, default: "trunk" },
430
+ };
431
+
432
+ /** The declarations of the options of the highway strategy `select` (HWY-045). */
433
+ export const SELECT_SCHEMA: OptionSchema<SelectOptions> = {
434
+ generators: { type: "list", default: ["corridors", "quickbundles", "wspd", "road-classes"], describe: "The highway strategies that propose the candidates." },
435
+ lambda: { type: "number", min: 0, max: 4, step: 0.25, marks: [0.5, 1, 2], default: 1, describe: "The weight of the added length of the edges against the ink that a highway saves." },
436
+ swaps: { type: "integer", min: 0, max: 5, step: 1, default: 2, describe: "The number of passes of the local search with one swap." },
437
+ };
438
+
439
+ /** The declarations of the options of the highway strategy `mingle` (HWY-003). */
440
+ export const MINGLE_SCHEMA: OptionSchema<MingleOptions> = {
441
+ k: { type: "integer", min: 4, max: 16, step: 1, default: 8, describe: "Each bundle looks for a merge among this number of nearest bundles in 4D." },
442
+ maxTurn: { type: "number", min: 20, max: 60, step: 5, marks: [20, 40, 60], default: 40, describe: "The largest turn of an edge at a meeting point, in degrees." },
443
+ levels: { type: "integer", min: 1, max: 10, step: 1, default: 6, describe: "The number of levels of merges." },
444
+ weight: { type: "number", min: 0.5, max: 1, step: 0.05, default: 1, describe: "The weight of the trunk in the ink. With 1, the trunk costs its length one time." },
445
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A bundle with this number of edges or more gets highways." },
446
+ spine: { ...GROUP_SPINE, default: "trunk" },
447
+ };
448
+
449
+ /** The declarations of the options of the highway strategy `spiral` (HWY-017 with EDA-035). */
450
+ export const SPIRAL_SCHEMA: OptionSchema<SpiralOptions> = {
451
+ margin: WAY_SCHEMA.margin,
452
+ k: WAY_SCHEMA.k,
453
+ alpha: { type: "number", min: 10, max: 40, step: 5, marks: [15, 25, 35], default: 25, describe: "The spiral angle, in degrees: the largest angle between a branch and the line to the root." },
454
+ minTargets: { type: "integer", min: 3, max: 20, step: 1, default: 4, describe: "A node with this number of edges or more gets a spiral tree." },
455
+ arc: { type: "integer", min: 2, max: 8, step: 1, default: 4, describe: "The number of points of the arc of each branch." },
456
+ };
457
+
458
+ /** The declarations of the options of the highway strategy `flow-clusters` (HWY-023). */
459
+ export const FLOW_CLUSTER_SCHEMA: OptionSchema<FlowClusterOptions> = {
460
+ tau: { type: "number", min: 0.1, max: 0.6, step: 0.05, marks: [0.2, 0.3, 0.45], default: 0.3, describe: "Two clusters join while their distance is this share of the length of the shorter edge, or less." },
461
+ linkage: { type: "enum", values: ["average", "complete", "single"], default: "average", describe: "The distance of two clusters: the mean, the largest or the smallest distance of their edges." },
462
+ directed: { type: "boolean", default: false, describe: "With this option, the source of one edge only compares with the source of the other edge." },
463
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A cluster with this number of edges or more gets highways." },
464
+ spine: { ...GROUP_SPINE, default: "trunk" },
465
+ };
466
+
467
+ /** The declarations of the options of the highway strategy `traclus` (HWY-025). */
468
+ export const TRACLUS_SCHEMA: OptionSchema<TraclusOptions> = {
469
+ margin: WAY_SCHEMA.margin,
470
+ k: WAY_SCHEMA.k,
471
+ eps: { type: "number", min: 1, max: 6, step: 0.5, marks: [1, 2, 4], default: 2, describe: "Two segments are neighbours when their distance is this value or less, in units of the board." },
472
+ minLns: { type: "integer", min: 2, max: 16, step: 1, default: 3, describe: "A cluster has segments of this number of edges or more." },
473
+ wPerp: { type: "number", min: 0, max: 2, step: 0.25, default: 1, describe: "The weight of the perpendicular distance." },
474
+ wPar: { type: "number", min: 0, max: 2, step: 0.25, default: 1, describe: "The weight of the parallel distance." },
475
+ wTheta: { type: "number", min: 0, max: 2, step: 0.25, default: 1, describe: "The weight of the angle distance." },
476
+ mdl: { type: "number", min: 0.5, max: 2, step: 0.25, default: 1, describe: "A route keeps a corner when the cost without it is more than this value times the cost with it." },
477
+ };
478
+
479
+ /** The declarations of the options of the highway strategy `diffusion` (HWY-020). */
480
+ export const DIFFUSION_SCHEMA: OptionSchema<DiffusionOptions> = {
481
+ margin: WAY_SCHEMA.margin,
482
+ k: WAY_SCHEMA.k,
483
+ a: { type: "number", min: 0, max: 0.5, step: 0.05, default: 0.25, describe: "The share of the density that each step takes from the links next to a link." },
484
+ steps: { type: "integer", min: 0, max: 10, step: 1, default: 3, describe: "The number of steps of the diffusion." },
485
+ lambda: { type: "number", min: 0, max: 2, step: 0.25, marks: [0.5, 1, 2], default: 1, describe: "The weight of the density in the cost of a link." },
486
+ gamma: { type: "number", min: 0.5, max: 2, step: 0.25, default: 1, describe: "The power of the discount of a dense link." },
487
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A highway has this number of edges or more." },
488
+ };
489
+
490
+ /** The declarations of the options of the highway strategy `nested` (HWY-052). */
491
+ export const NESTED_SCHEMA: OptionSchema<NestedOptions> = {
492
+ theta: QUICKBUNDLES_SCHEMA.theta,
493
+ ratio: { type: "number", min: 1.5, max: 4, step: 0.5, default: 2, describe: "The scale of each level is this value times the scale of the next closer level." },
494
+ levels: { type: "integer", min: 1, max: 6, step: 1, default: 3, describe: "The number of levels." },
495
+ level: { type: "integer", min: 0, max: 5, step: 1, default: 0, describe: "The level of the plan. Level 0 is the closest level." },
496
+ points: QUICKBUNDLES_SCHEMA.points,
497
+ line: QUICKBUNDLES_SCHEMA.line,
498
+ order: QUICKBUNDLES_SCHEMA.order,
499
+ minSize: QUICKBUNDLES_SCHEMA.minSize,
500
+ spine: GROUP_SPINE,
501
+ };
502
+
503
+ /** The declarations of the options of the highway strategy `lanes` (HWY-051). */
504
+ export const LANES_SCHEMA: OptionSchema<LanesOptions> = {
505
+ margin: WAY_SCHEMA.margin,
506
+ k: WAY_SCHEMA.k,
507
+ from: HIGHWAY_BASE,
508
+ laneGap: { type: "number", min: 2, max: 8, step: 1, default: 4, describe: "The gap between two lanes." },
509
+ maxWidth: { type: "number", min: 8, max: 64, step: 4, default: 32, describe: "The largest width of a highway." },
510
+ depth: { type: "integer", min: 0, max: 5, step: 1, default: 3, describe: "The number of times that a highway can split, one half after the other." },
511
+ };
512
+
513
+ /** The declarations of the options of the highway strategy `growth` (HWY-055). */
514
+ export const GROWTH_SCHEMA: OptionSchema<GrowthOptions> = {
515
+ margin: WAY_SCHEMA.margin,
516
+ k: WAY_SCHEMA.k,
517
+ order: { type: "enum", values: ["length", "input"], default: "length", describe: "The order of the edges: the longest first route first, or the order of the graph." },
518
+ share: { type: "number", min: 0.1, max: 1, step: 0.05, marks: [0.5], default: 0.5, describe: "The cost of the part on a spine, as a share of its length." },
519
+ stretch: { type: "number", min: 1, max: 2, step: 0.05, marks: [1.3], default: 1.3, describe: "An edge joins a highway only when its way along it is this value times its first route or shorter." },
520
+ extendLanes: { type: "integer", min: 2, max: 8, step: 1, default: 3, describe: "A spine end extends when this number of its lanes or more go on together." },
521
+ extendRadius: { type: "number", min: 0.5, max: 6, step: 0.5, default: 2, describe: "The lanes go on together when their ends are this distance from their center or nearer, in units of the board." },
522
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A highway with this number of edges or more stays in the plan." },
523
+ };
524
+
525
+ /** The declarations of the options of the highway strategy `edge-paths` (HWY-012). */
526
+ export const EDGE_PATH_SCHEMA: OptionSchema<EdgePathOptions> = {
527
+ margin: WAY_SCHEMA.margin,
528
+ k: WAY_SCHEMA.k,
529
+ distortion: { type: "number", min: 1.1, max: 4, step: 0.1, marks: [1.5, 2, 3], default: 2, describe: "An edge takes a path of other edges only when the path is this many times its own length or less." },
530
+ power: { type: "number", min: 1, max: 4, step: 0.5, default: 2, describe: "The weight of a link in the search is its length to this power." },
531
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A highway has this number of edges or more." },
532
+ };
533
+
534
+ /** The declarations of the options of the highway strategy `soft-keys` (HWY-019). */
535
+ export const SOFT_KEY_SCHEMA: OptionSchema<SoftKeyOptions> = {
536
+ rule: { type: "function", describe: "The rule that gives the key of each edge. Two different keys add the distance `lambda`." },
537
+ lambda: { type: "number", min: 0, max: 2, step: 0.05, marks: [0, 0.25, 1], default: 0.25, describe: "The distance that two different keys add. A very large value keeps the keys apart." },
538
+ tau: { type: "number", min: 0.1, max: 1.5, step: 0.05, marks: [0.3, 0.5, 1], default: 0.5, describe: "Two clusters join while their distance is this value or less." },
539
+ attributes: { type: "list", default: [], describe: "The names of number fields of `data` that add a distance." },
540
+ weight: { type: "number", min: 0, max: 2, step: 0.25, default: 1, describe: "The weight of each field of `attributes`." },
541
+ linkage: { type: "enum", values: ["average", "complete", "single"], default: "average", describe: "The distance of two clusters: the mean, the largest or the smallest distance of their edges." },
542
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A cluster with this number of edges or more gets highways." },
543
+ spine: { ...GROUP_SPINE, default: "shared" },
544
+ };
545
+
546
+ /** The declarations of the options of the highway strategy `hough` (HWY-024). */
547
+ export const HOUGH_SCHEMA: OptionSchema<HoughOptions> = {
548
+ margin: WAY_SCHEMA.margin,
549
+ k: WAY_SCHEMA.k,
550
+ dTheta: { type: "number", min: 2, max: 20, step: 1, marks: [4, 8, 12], default: 8, describe: "The width of the votes in the angle, in degrees." },
551
+ dRho: { type: "number", min: 4, max: 40, step: 2, marks: [8, 12, 24], default: 12, describe: "The width of the votes in the offset, in units of the board." },
552
+ minVotes: { type: "integer", min: 2, max: 16, step: 1, default: 3, describe: "A peak with fewer edges than this number is not a corridor." },
553
+ orthogonal: { type: "boolean", default: false, describe: "With this option, the peaks are only horizontal or vertical lines." },
554
+ };
555
+
556
+ /** The declarations of the options of the highway strategy `ridges` (HWY-032). */
557
+ export const RIDGE_SCHEMA: OptionSchema<RidgeOptions> = {
558
+ margin: WAY_SCHEMA.margin,
559
+ k: WAY_SCHEMA.k,
560
+ source: { type: "enum", values: ["lines", "routes"], default: "lines", describe: "The lines of the density: the straight lines of the edges, or their first routes." },
561
+ cell: { type: "number", min: 2, max: 32, step: 1, marks: [4, 8, 16], default: 8, describe: "The size of a cell of the density image, in units of the board." },
562
+ bandwidth: { type: "number", min: 4, max: 64, step: 2, marks: [8, 16, 32], default: 16, describe: "The width of the blur of the density, in units of the board." },
563
+ strength: { type: "number", min: 0, max: 1, step: 0.05, default: 0.15, describe: "A cell is part of a ridge only when its strength is this share of the largest strength or more." },
564
+ minLength: { type: "number", min: 10, max: 300, step: 10, marks: [30, 60, 120], default: 60, describe: "A ridge has this length or more, in units of the board." },
565
+ snap: { type: "number", min: 2, max: 64, step: 2, marks: [8, 16, 32], default: 16, describe: "An edge snaps to a ridge where it is this distance from the ridge or nearer." },
566
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A ridge with this number of edges or more gets a highway." },
567
+ };
568
+
569
+ /** The declarations of the options of the highway strategy `hdbscan` (HWY-028). */
570
+ export const HDBSCAN_SCHEMA: OptionSchema<HdbscanOptions> = {
571
+ minClusterSize: { type: "integer", min: 2, max: 16, step: 1, default: 3, describe: "A cluster has this number of edges or more." },
572
+ minSamples: { type: "integer", min: 1, max: 16, step: 1, default: 3, describe: "The core distance of an edge is the distance to its neighbour of this rank." },
573
+ distance: { type: "enum", values: ["compatibility", "flow"], default: "compatibility", describe: "The distance of two edges: 1 less their compatibility, or the flow distance of the ends." },
574
+ spine: { ...GROUP_SPINE, default: "trunk" },
575
+ };
576
+
577
+ /** The declarations of the options of the highway strategy `hub-arcs` (HWY-042). */
578
+ export const HUB_ARC_SCHEMA: OptionSchema<HubArcOptions> = {
579
+ q: { type: "integer", min: 0, max: 64, step: 1, marks: [4, 12, 32], default: 12, describe: "The largest number of arcs." },
580
+ alpha: { type: "number", min: 0, max: 1, step: 0.05, marks: [0.3, 0.5, 0.8], default: 0.5, describe: "The cost of a length on an arc against a length off the arcs." },
581
+ stretch: { type: "number", min: 1, max: 2, step: 0.05, marks: [1.25], default: 1.25, describe: "An edge rides an arc only when its way is this many times its first route or less." },
582
+ swaps: { type: "integer", min: 0, max: 5, step: 1, default: 1, describe: "The number of passes of the local search with one swap." },
583
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "An arc with fewer edges than this number is not a highway." },
584
+ generators: { type: "list", default: ["runs", "corridors", "road-classes"], describe: "The generators of the candidate arcs." },
585
+ };
package/src/visibility.ts CHANGED
@@ -211,6 +211,11 @@ export class CornerGraph {
211
211
  return n / 2;
212
212
  }
213
213
 
214
+ /** This method gives the corners that link to the corner `i`, in the order of their indexes. A corner that is not in the graph gives an empty list. */
215
+ neighbours(i: number): readonly number[] {
216
+ return this.#adj[i] ?? [];
217
+ }
218
+
214
219
  /** This method gives the index of the corner nearest to `p`, seen or not, or -1 when the graph has no corner near it. */
215
220
  nearest(p: Point): number {
216
221
  for (let r = this.#cell; r <= this.#cell * 64; r *= 2) {