@mark1russell7/highways 0.4.2 → 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.
- package/README.md +18 -2
- package/build/index.d.ts +799 -68
- package/build/index.d.ts.map +1 -1
- package/build/index.js +6235 -2128
- package/build/index.js.map +1 -1
- package/package.json +3 -1
- package/src/bench/exact/index.ts +197 -0
- package/src/bench/measures/index.ts +1 -0
- package/src/bench/measures/lanes.ts +304 -0
- package/src/bench/measures/levels.ts +86 -2
- package/src/bench/screen/forms.ts +11 -5
- package/src/bench/screen/measures.ts +18 -0
- package/src/bench/screen/screen.ts +28 -0
- package/src/channels.ts +56 -0
- package/src/highways/diffusion/index.ts +103 -0
- package/src/highways/edge-paths/index.ts +155 -0
- package/src/highways/fixtures.test-util.ts +71 -0
- package/src/highways/flow-clusters/index.ts +143 -0
- package/src/highways/growth/index.ts +148 -0
- package/src/highways/hdbscan/index.ts +250 -0
- package/src/highways/hough/index.ts +182 -0
- package/src/highways/hub-arcs/index.ts +181 -0
- package/src/highways/index.ts +15 -0
- package/src/highways/lanes/index.ts +189 -0
- package/src/highways/mingle/index.ts +171 -0
- package/src/highways/nested/index.ts +143 -0
- package/src/highways/ridges/index.ts +328 -0
- package/src/highways/snap.ts +110 -0
- package/src/highways/soft-keys/index.ts +114 -0
- package/src/highways/spiral/index.ts +205 -0
- package/src/highways/traclus/index.ts +296 -0
- package/src/index.ts +1 -0
- package/src/routers/shared.ts +56 -3
- package/src/strategies/builtins.ts +155 -1
- package/src/strategies/schemas.ts +180 -0
- package/src/visibility.ts +5 -0
package/src/routers/shared.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { center, dist, type Point } from "../geom.ts";
|
|
2
2
|
import { nodeIndex, type Edge, type Graph, type GroupRule, type Result, type Route, type Router, type SharedRun } from "../model.ts";
|
|
3
|
+
import { channelWidth } from "../channels.ts";
|
|
3
4
|
import { placePlug, type Plug } from "../plugs.ts";
|
|
4
5
|
import { buildSections, type Section } from "../sections.ts";
|
|
5
6
|
import { orderLanes, type RunOrder } from "../segments.ts";
|
|
@@ -44,6 +45,20 @@ export interface SharedOptions extends WayOptions {
|
|
|
44
45
|
* With `snell`, the route meets the run at the angle `acos(d)`, with `d` the cost share of the run for the route (NAT-035).
|
|
45
46
|
*/
|
|
46
47
|
readonly merge?: ShareMerge;
|
|
48
|
+
/**
|
|
49
|
+
* The pull of the busy links of the pass before (HWY-005, Winding Roads). With a value above 0 and two passes or more, each later pass routes each edge again from no ways.
|
|
50
|
+
* A link then costs `len / (1 + reuse * u)^reuseExponent`, with `u` the edges of the key on it in the pass before. The default is 0: the later passes are rip-up passes.
|
|
51
|
+
*/
|
|
52
|
+
readonly reuse?: number;
|
|
53
|
+
/** The exponent of the pull of `reuse`. The default is 1. */
|
|
54
|
+
readonly reuseExponent?: number;
|
|
55
|
+
/**
|
|
56
|
+
* The cost of a lane that does not fit in its channel (HWY-016). One more edge on a link with `f` edges of the key costs `capacity * max(0, (f + 1) * laneWidth - width)` more.
|
|
57
|
+
* `width` is the free space across the link (`channelWidth`). The default is 0: the router does not read the channels.
|
|
58
|
+
*/
|
|
59
|
+
readonly capacity?: number;
|
|
60
|
+
/** The width of one lane, for `capacity`. The default is 4. */
|
|
61
|
+
readonly laneWidth?: number;
|
|
47
62
|
/** The benchmark skips a fixture with more nodes. */
|
|
48
63
|
readonly maxNodes?: number;
|
|
49
64
|
}
|
|
@@ -94,6 +109,10 @@ export function sharedRouter(options: SharedOptions): Router {
|
|
|
94
109
|
// The cost share of a link for one more edge, when `f` edges of the key use it already. The share falls when `f` grows.
|
|
95
110
|
const share = (f: number): number => (f <= 0 ? 1 : flow ? (f + 1) ** alpha - f ** alpha : discount);
|
|
96
111
|
const passes = Math.max(1, Math.floor(options.passes ?? 1));
|
|
112
|
+
const reuse = Math.max(0, options.reuse ?? 0);
|
|
113
|
+
const reuseExponent = Math.max(0, options.reuseExponent ?? 1);
|
|
114
|
+
const capacity = Math.max(0, options.capacity ?? 0);
|
|
115
|
+
const laneWidth = Math.max(0, options.laneWidth ?? 4);
|
|
97
116
|
const keyOf = (e: Edge): string => {
|
|
98
117
|
if (!options.rule) return "*";
|
|
99
118
|
return options.rule(e) ?? `\u0000${e.id}`;
|
|
@@ -131,14 +150,34 @@ export function sharedRouter(options: SharedOptions): Router {
|
|
|
131
150
|
const order = orderWays(all, options.order ?? "span", graph);
|
|
132
151
|
// The largest number of edges on one link of each key. The cost share of that number is the floor of the search.
|
|
133
152
|
const top = new Map<string, number>();
|
|
134
|
-
|
|
153
|
+
// The width of the channel of each link, for the option `capacity`. Each link gets its width at its first use.
|
|
154
|
+
const widths = new Map<number, number>();
|
|
155
|
+
const widthOf = (i: number, j: number): number => {
|
|
156
|
+
const k = link(i, j);
|
|
157
|
+
let wd = widths.get(k);
|
|
158
|
+
if (wd === undefined) widths.set(k, (wd = channelWidth(ways.obstacles, corners.points[i]!, corners.points[j]!)));
|
|
159
|
+
return wd;
|
|
160
|
+
};
|
|
161
|
+
/** This function routes one way. `before` holds the edges of the key on each link in the pass before, for the option `reuse`. */
|
|
162
|
+
const route = (w: Way, before?: ReadonlyMap<number, number>): void => {
|
|
135
163
|
let used = discounted.get(w.key);
|
|
136
164
|
if (!used) discounted.set(w.key, (used = new Map()));
|
|
137
165
|
const mine = used;
|
|
138
|
-
|
|
139
|
-
|
|
166
|
+
let floor = flow ? share(top.get(w.key) ?? 0) : discount;
|
|
167
|
+
let cost = flow
|
|
140
168
|
? (i: number, j: number, d: number): number => d * share(mine.get(link(i, j))?.length ?? 0)
|
|
141
169
|
: (i: number, j: number, d: number): number => (mine.has(link(i, j)) ? d * discount : d);
|
|
170
|
+
if (capacity > 0) {
|
|
171
|
+
const plain = cost;
|
|
172
|
+
cost = (i, j, d) => plain(i, j, d) + capacity * Math.max(0, ((mine.get(link(i, j))?.length ?? 0) + 1) * laneWidth - widthOf(i, j));
|
|
173
|
+
}
|
|
174
|
+
if (before !== undefined) {
|
|
175
|
+
const plain = cost;
|
|
176
|
+
let most = 0;
|
|
177
|
+
for (const u of before.values()) most = Math.max(most, u);
|
|
178
|
+
cost = (i, j, d) => plain(i, j, d) / (1 + reuse * (before.get(link(i, j)) ?? 0)) ** reuseExponent;
|
|
179
|
+
floor /= (1 + reuse * most) ** reuseExponent;
|
|
180
|
+
}
|
|
142
181
|
const way = corners.path(ways.out(w.ps), ways.out(w.pt), cost, floor);
|
|
143
182
|
if (!way) return;
|
|
144
183
|
w.found = true;
|
|
@@ -157,6 +196,20 @@ export function sharedRouter(options: SharedOptions): Router {
|
|
|
157
196
|
for (const w of order) route(w);
|
|
158
197
|
// Each later pass takes each edge off its links and finds its way again, with the ways of the other edges fixed.
|
|
159
198
|
for (let pass = 1; pass < passes; pass++) {
|
|
199
|
+
if (reuse > 0) {
|
|
200
|
+
// Winding Roads (HWY-005): each edge finds its way again from no ways, and the busy links of the pass before pull it.
|
|
201
|
+
const before = new Map<string, Map<number, number>>();
|
|
202
|
+
for (const [key, links] of discounted) before.set(key, new Map([...links].map(([k, list]) => [k, list.length])));
|
|
203
|
+
discounted.clear();
|
|
204
|
+
top.clear();
|
|
205
|
+
for (const w of order) {
|
|
206
|
+
w.found = false;
|
|
207
|
+
w.seq = [];
|
|
208
|
+
w.ids = [];
|
|
209
|
+
}
|
|
210
|
+
for (const w of order) route(w, before.get(w.key) ?? new Map());
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
160
213
|
for (const w of order) {
|
|
161
214
|
if (!w.found) continue;
|
|
162
215
|
const mine = discounted.get(w.key)!;
|
|
@@ -18,17 +18,31 @@ import { hysteresisGate, type HysteresisOptions } from "../highways/gates/hyster
|
|
|
18
18
|
import { stableIdGate, type StableIdOptions } from "../highways/gates/ids/index.ts";
|
|
19
19
|
import { gateStrategy } from "../highways/gates/model.ts";
|
|
20
20
|
import { stretchGate, type StretchOptions } from "../highways/gates/stretch/index.ts";
|
|
21
|
+
import { DIFFUSION_DEFAULTS, diffusionPlan, type DiffusionOptions } from "../highways/diffusion/index.ts";
|
|
22
|
+
import { FLOW_CLUSTER_DEFAULTS, flowClusterPlan, type FlowClusterOptions } from "../highways/flow-clusters/index.ts";
|
|
23
|
+
import { EDGE_PATH_DEFAULTS, edgePathPlan, type EdgePathOptions } from "../highways/edge-paths/index.ts";
|
|
24
|
+
import { HDBSCAN_DEFAULTS, hdbscanPlan, type HdbscanOptions } from "../highways/hdbscan/index.ts";
|
|
25
|
+
import { HOUGH_DEFAULTS, houghPlan, type HoughOptions } from "../highways/hough/index.ts";
|
|
26
|
+
import { HUB_ARC_DEFAULTS, hubArcPlan, type HubArcOptions } from "../highways/hub-arcs/index.ts";
|
|
27
|
+
import { RIDGE_DEFAULTS, ridgePlan, type RidgeOptions } from "../highways/ridges/index.ts";
|
|
28
|
+
import { SOFT_KEY_DEFAULTS, softKeyPlan, type SoftKeyOptions } from "../highways/soft-keys/index.ts";
|
|
21
29
|
import { FLOW_FIELD_DEFAULTS, flowFieldPlan, type FlowFieldOptions } from "../highways/flow-field/index.ts";
|
|
22
30
|
import { keysPlan, type KeysOptions } from "../highways/keys/index.ts";
|
|
23
31
|
import { LEVEL_HIGHWAY_DEFAULTS, levelHighwayPlan, type LevelHighwayOptions } from "../highways/level-links/index.ts";
|
|
24
32
|
import { MEET_DEFAULTS, meetPlan, type MeetOptions } from "../highways/meet/index.ts";
|
|
33
|
+
import { MINGLE_DEFAULTS, minglePlan, type MingleOptions } from "../highways/mingle/index.ts";
|
|
25
34
|
import type { HighwayInput } from "../highways/model.ts";
|
|
26
35
|
import { OD_CELL_DEFAULTS, odCellPlan, type OdCellOptions } from "../highways/od-cells/index.ts";
|
|
27
36
|
import { QUICKBUNDLES_DEFAULTS, quickBundlesPlan, type QuickBundlesOptions } from "../highways/quickbundles/index.ts";
|
|
37
|
+
import { NESTED_DEFAULTS, nestedPlan, type NestedOptions } from "../highways/nested/index.ts";
|
|
38
|
+
import { LANES_DEFAULTS, lanesPlan, type LanesOptions } from "../highways/lanes/index.ts";
|
|
39
|
+
import { GROWTH_DEFAULTS, growthPlan, type GrowthOptions } from "../highways/growth/index.ts";
|
|
28
40
|
import { ROAD_CLASS_DEFAULTS, roadClassPlan, type RoadClassOptions } from "../highways/road-classes/index.ts";
|
|
29
41
|
import { SELECT_DEFAULTS, selectPlan, type SelectOptions } from "../highways/select/index.ts";
|
|
30
42
|
import { sharedWaysPlan, type SharedWaysOptions } from "../highways/shared-ways/index.ts";
|
|
43
|
+
import { SPIRAL_DEFAULTS, spiralPlan, type SpiralOptions } from "../highways/spiral/index.ts";
|
|
31
44
|
import { STUB_DEFAULTS, stubPlan, type StubOptions } from "../highways/stubs/index.ts";
|
|
45
|
+
import { TRACLUS_DEFAULTS, traclusPlan, type TraclusOptions } from "../highways/traclus/index.ts";
|
|
32
46
|
import { WEISZFELD_DEFAULTS, weiszfeldPlan, type WeiszfeldOptions } from "../highways/weiszfeld/index.ts";
|
|
33
47
|
import { WSPD_DEFAULTS, wspdPlan, type WspdOptions } from "../highways/wspd/index.ts";
|
|
34
48
|
import { ZIPPER_DEFAULTS, zipperPlan, type ZipperOptions } from "../highways/zipper/index.ts";
|
|
@@ -44,7 +58,7 @@ import { byCollection, trunksRouter, type TrunksOptions } from "../routers/trunk
|
|
|
44
58
|
import { buildSections, SECTION_DEFAULTS, type SectionOptions } from "../sections.ts";
|
|
45
59
|
import { createRegistry, defineStrategy, type AnyStrategy, type CurveInput, type LaneBoard, type Registry, type Strategy } from "./model.ts";
|
|
46
60
|
import type { OptionSchema } from "./options.ts";
|
|
47
|
-
import { CLOTHOID_SCHEMA, CORNERS_SCHEMA, CORRIDOR_SCHEMA, CUT_SCHEMA, FLOW_FIELD_SCHEMA, HIGHWAY_SCHEMA, KD_SCHEMA, KEY_SCHEMA, LEVEL_HIGHWAY_SCHEMA, LEVEL_ROOM_SCHEMA, MEET_SCHEMA, OD_CELL_SCHEMA, QUICKBUNDLES_SCHEMA, RADIUS_SCHEMA, ROAD_CLASS_SCHEMA, ROOM_SCHEMA, SECTION_SCHEMA, SELECT_SCHEMA, SECTIONS_SCHEMA, SHARED_SCHEMA, SMOOTH_SCHEMA, STUB_SCHEMA, TENSION_SCHEMA, TRUNKS_SCHEMA, WEISZFELD_SCHEMA, WSPD_SCHEMA, ZIPPER_SCHEMA } from "./schemas.ts";
|
|
61
|
+
import { CLOTHOID_SCHEMA, CORNERS_SCHEMA, CORRIDOR_SCHEMA, CUT_SCHEMA, DIFFUSION_SCHEMA, EDGE_PATH_SCHEMA, FLOW_CLUSTER_SCHEMA, FLOW_FIELD_SCHEMA, GROWTH_SCHEMA, HDBSCAN_SCHEMA, HIGHWAY_SCHEMA, HOUGH_SCHEMA, HUB_ARC_SCHEMA, KD_SCHEMA, KEY_SCHEMA, LANES_SCHEMA, LEVEL_HIGHWAY_SCHEMA, LEVEL_ROOM_SCHEMA, MEET_SCHEMA, MINGLE_SCHEMA, NESTED_SCHEMA, OD_CELL_SCHEMA, QUICKBUNDLES_SCHEMA, RADIUS_SCHEMA, RIDGE_SCHEMA, ROAD_CLASS_SCHEMA, ROOM_SCHEMA, SECTION_SCHEMA, SELECT_SCHEMA, SECTIONS_SCHEMA, SHARED_SCHEMA, SMOOTH_SCHEMA, SOFT_KEY_SCHEMA, SPIRAL_SCHEMA, STUB_SCHEMA, TENSION_SCHEMA, TRACLUS_SCHEMA, TRUNKS_SCHEMA, WEISZFELD_SCHEMA, WSPD_SCHEMA, ZIPPER_SCHEMA } from "./schemas.ts";
|
|
48
62
|
|
|
49
63
|
/** The options of a router strategy: the options of its router, without the name and the limit of the benchmark. */
|
|
50
64
|
export type RouterPreset<O> = Omit<O, "name" | "maxNodes">;
|
|
@@ -389,6 +403,20 @@ export const highwayStrategies: {
|
|
|
389
403
|
readonly wspd: Strategy<"highway", WspdOptions>;
|
|
390
404
|
readonly "od-cells": Strategy<"highway", OdCellOptions>;
|
|
391
405
|
readonly select: Strategy<"highway", SelectOptions>;
|
|
406
|
+
readonly mingle: Strategy<"highway", MingleOptions>;
|
|
407
|
+
readonly spiral: Strategy<"highway", SpiralOptions>;
|
|
408
|
+
readonly "flow-clusters": Strategy<"highway", FlowClusterOptions>;
|
|
409
|
+
readonly traclus: Strategy<"highway", TraclusOptions>;
|
|
410
|
+
readonly diffusion: Strategy<"highway", DiffusionOptions>;
|
|
411
|
+
readonly nested: Strategy<"highway", NestedOptions>;
|
|
412
|
+
readonly lanes: Strategy<"highway", LanesOptions>;
|
|
413
|
+
readonly growth: Strategy<"highway", GrowthOptions>;
|
|
414
|
+
readonly "edge-paths": Strategy<"highway", EdgePathOptions>;
|
|
415
|
+
readonly "soft-keys": Strategy<"highway", SoftKeyOptions>;
|
|
416
|
+
readonly hough: Strategy<"highway", HoughOptions>;
|
|
417
|
+
readonly ridges: Strategy<"highway", RidgeOptions>;
|
|
418
|
+
readonly hdbscan: Strategy<"highway", HdbscanOptions>;
|
|
419
|
+
readonly "hub-arcs": Strategy<"highway", HubArcOptions>;
|
|
392
420
|
readonly "corridors+breakeven": Strategy<"highway", CorridorOptions & BreakEvenOptions>;
|
|
393
421
|
readonly "corridors+stretch": Strategy<"highway", CorridorOptions & StretchOptions>;
|
|
394
422
|
readonly "corridors+ambiguity": Strategy<"highway", CorridorOptions & AmbiguityGuardOptions>;
|
|
@@ -513,6 +541,132 @@ export const highwayStrategies: {
|
|
|
513
541
|
maxNodes: 10_000,
|
|
514
542
|
run: (input: HighwayInput, o: Readonly<SelectOptions>) => selectPlan(input, o),
|
|
515
543
|
}),
|
|
544
|
+
mingle: defineStrategy({
|
|
545
|
+
step: "highway",
|
|
546
|
+
name: "mingle",
|
|
547
|
+
describe: "MINGLE (HWY-003). Edges are points in 4D. Near bundles merge level by level while the merge saves ink, and each bundle gets one trunk.",
|
|
548
|
+
defaults: { ...MINGLE_DEFAULTS } as MingleOptions,
|
|
549
|
+
schema: MINGLE_SCHEMA,
|
|
550
|
+
maxNodes: 10_000,
|
|
551
|
+
run: (input: HighwayInput, o: Readonly<MingleOptions>) => minglePlan(input, o),
|
|
552
|
+
}),
|
|
553
|
+
spiral: defineStrategy({
|
|
554
|
+
step: "highway",
|
|
555
|
+
name: "spiral",
|
|
556
|
+
describe: "Spiral trees (HWY-017, EDA-035). The edges of a node with many edges branch on arcs of spirals, and each branch with two edges is a highway.",
|
|
557
|
+
defaults: { ...SPIRAL_DEFAULTS } as SpiralOptions,
|
|
558
|
+
schema: SPIRAL_SCHEMA,
|
|
559
|
+
maxNodes: 10_000,
|
|
560
|
+
run: (input: HighwayInput, o: Readonly<SpiralOptions>) => spiralPlan(input, o),
|
|
561
|
+
}),
|
|
562
|
+
"flow-clusters": defineStrategy({
|
|
563
|
+
step: "highway",
|
|
564
|
+
name: "flow-clusters",
|
|
565
|
+
describe: "Flow clusters (HWY-023). A hierarchical clustering puts the edges with near sources and near targets together, and each cluster gets highways.",
|
|
566
|
+
defaults: { ...FLOW_CLUSTER_DEFAULTS } as FlowClusterOptions,
|
|
567
|
+
schema: FLOW_CLUSTER_SCHEMA,
|
|
568
|
+
maxNodes: 10_000,
|
|
569
|
+
run: (input: HighwayInput, o: Readonly<FlowClusterOptions>) => flowClusterPlan(input, o),
|
|
570
|
+
}),
|
|
571
|
+
traclus: defineStrategy({
|
|
572
|
+
step: "highway",
|
|
573
|
+
name: "traclus",
|
|
574
|
+
describe: "TRACLUS (HWY-025). The first routes break into segments, and the dense clusters of near segments become highways.",
|
|
575
|
+
defaults: { ...TRACLUS_DEFAULTS } as TraclusOptions,
|
|
576
|
+
schema: TRACLUS_SCHEMA,
|
|
577
|
+
maxNodes: 10_000,
|
|
578
|
+
run: (input: HighwayInput, o: Readonly<TraclusOptions>) => traclusPlan(input, o),
|
|
579
|
+
}),
|
|
580
|
+
diffusion: defineStrategy({
|
|
581
|
+
step: "highway",
|
|
582
|
+
name: "diffusion",
|
|
583
|
+
describe: "Route-aware bundling (HWY-020). The density of the first ways diffuses on the corner graph, and dense links cost less in a second pass.",
|
|
584
|
+
defaults: { ...DIFFUSION_DEFAULTS } as DiffusionOptions,
|
|
585
|
+
schema: DIFFUSION_SCHEMA,
|
|
586
|
+
maxNodes: 10_000,
|
|
587
|
+
run: (input: HighwayInput, o: Readonly<DiffusionOptions>) => diffusionPlan(input, o),
|
|
588
|
+
}),
|
|
589
|
+
nested: defineStrategy({
|
|
590
|
+
step: "highway",
|
|
591
|
+
name: "nested",
|
|
592
|
+
describe: "Highways for each zoom level that nest (HWY-052). Each level puts the edges of each cluster of the level above in finer clusters.",
|
|
593
|
+
defaults: { ...NESTED_DEFAULTS } as NestedOptions,
|
|
594
|
+
schema: NESTED_SCHEMA,
|
|
595
|
+
maxNodes: 10_000,
|
|
596
|
+
run: (input: HighwayInput, o: Readonly<NestedOptions>) => nestedPlan(input, o),
|
|
597
|
+
}),
|
|
598
|
+
lanes: defineStrategy({
|
|
599
|
+
step: "highway",
|
|
600
|
+
name: "lanes",
|
|
601
|
+
describe: "Width, lanes and capacity (HWY-051). A highway that does not fit in its channels splits into two highways by lane order.",
|
|
602
|
+
defaults: { ...LANES_DEFAULTS } as LanesOptions,
|
|
603
|
+
schema: LANES_SCHEMA,
|
|
604
|
+
maxNodes: 10_000,
|
|
605
|
+
run: (input: HighwayInput, o: Readonly<LanesOptions>) => lanesPlan(input, o),
|
|
606
|
+
}),
|
|
607
|
+
growth: defineStrategy({
|
|
608
|
+
step: "highway",
|
|
609
|
+
name: "growth",
|
|
610
|
+
describe: "Local growth (HWY-055). Each edge, the longest first, joins the highway with the largest saving, or starts a highway.",
|
|
611
|
+
defaults: { ...GROWTH_DEFAULTS } as GrowthOptions,
|
|
612
|
+
schema: GROWTH_SCHEMA,
|
|
613
|
+
maxNodes: 10_000,
|
|
614
|
+
run: (input: HighwayInput, o: Readonly<GrowthOptions>) => growthPlan(input, o),
|
|
615
|
+
}),
|
|
616
|
+
"edge-paths": defineStrategy({
|
|
617
|
+
step: "highway",
|
|
618
|
+
name: "edge-paths",
|
|
619
|
+
describe: "Edge-path bundling (HWY-012). An edge with a short path of other edges follows their ways, and the shared stretches become highways.",
|
|
620
|
+
defaults: { ...EDGE_PATH_DEFAULTS } as EdgePathOptions,
|
|
621
|
+
schema: EDGE_PATH_SCHEMA,
|
|
622
|
+
maxNodes: 10_000,
|
|
623
|
+
run: (input: HighwayInput, o: Readonly<EdgePathOptions>) => edgePathPlan(input, o),
|
|
624
|
+
}),
|
|
625
|
+
"soft-keys": defineStrategy({
|
|
626
|
+
step: "highway",
|
|
627
|
+
name: "soft-keys",
|
|
628
|
+
describe: "Soft keys (HWY-019). The key of an edge adds a distance to the flow distance, and a hierarchical clustering makes the highways.",
|
|
629
|
+
defaults: { ...SOFT_KEY_DEFAULTS } as SoftKeyOptions,
|
|
630
|
+
schema: SOFT_KEY_SCHEMA,
|
|
631
|
+
maxNodes: 10_000,
|
|
632
|
+
run: (input: HighwayInput, o: Readonly<SoftKeyOptions>) => softKeyPlan(input, o),
|
|
633
|
+
}),
|
|
634
|
+
hough: defineStrategy({
|
|
635
|
+
step: "highway",
|
|
636
|
+
name: "hough",
|
|
637
|
+
describe: "Hough votes (HWY-024). The straight lines of the edges vote for corridors, and each peak of the votes becomes a highway.",
|
|
638
|
+
defaults: { ...HOUGH_DEFAULTS } as HoughOptions,
|
|
639
|
+
schema: HOUGH_SCHEMA,
|
|
640
|
+
maxNodes: 10_000,
|
|
641
|
+
run: (input: HighwayInput, o: Readonly<HoughOptions>) => houghPlan(input, o),
|
|
642
|
+
}),
|
|
643
|
+
ridges: defineStrategy({
|
|
644
|
+
step: "highway",
|
|
645
|
+
name: "ridges",
|
|
646
|
+
describe: "Ridges of the line density (HWY-032). The ridges of the blurred density of the edges become highways, and near edges snap to them.",
|
|
647
|
+
defaults: { ...RIDGE_DEFAULTS } as RidgeOptions,
|
|
648
|
+
schema: RIDGE_SCHEMA,
|
|
649
|
+
maxNodes: 10_000,
|
|
650
|
+
run: (input: HighwayInput, o: Readonly<RidgeOptions>) => ridgePlan(input, o),
|
|
651
|
+
}),
|
|
652
|
+
hdbscan: defineStrategy({
|
|
653
|
+
step: "highway",
|
|
654
|
+
name: "hdbscan",
|
|
655
|
+
describe: "HDBSCAN on edges (HWY-028). The density clusters of the edges that live over a long range become highways.",
|
|
656
|
+
defaults: { ...HDBSCAN_DEFAULTS } as HdbscanOptions,
|
|
657
|
+
schema: HDBSCAN_SCHEMA,
|
|
658
|
+
maxNodes: 10_000,
|
|
659
|
+
run: (input: HighwayInput, o: Readonly<HdbscanOptions>) => hdbscanPlan(input, o),
|
|
660
|
+
}),
|
|
661
|
+
"hub-arcs": defineStrategy({
|
|
662
|
+
step: "highway",
|
|
663
|
+
name: "hub-arcs",
|
|
664
|
+
describe: "Hub arc location (HWY-042). A greedy pass with swaps chooses at most q arcs from the candidates, and each edge rides its best arc.",
|
|
665
|
+
defaults: { ...HUB_ARC_DEFAULTS } as HubArcOptions,
|
|
666
|
+
schema: HUB_ARC_SCHEMA,
|
|
667
|
+
maxNodes: 10_000,
|
|
668
|
+
run: (input: HighwayInput, o: Readonly<HubArcOptions>) => hubArcPlan(input, o),
|
|
669
|
+
}),
|
|
516
670
|
"corridors+breakeven": gateStrategy(corridors, breakEvenGate),
|
|
517
671
|
"corridors+stretch": gateStrategy(corridors, stretchGate),
|
|
518
672
|
"corridors+ambiguity": gateStrategy(corridors, ambiguityGate),
|
|
@@ -3,15 +3,29 @@ import type { KdOptions } from "../groups/kd/index.ts";
|
|
|
3
3
|
import type { KeyOptions } from "../groups/keys/index.ts";
|
|
4
4
|
import type { HighwayBase } from "../highways/base.ts";
|
|
5
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";
|
|
6
9
|
import type { FlowFieldOptions } from "../highways/flow-field/index.ts";
|
|
10
|
+
import type { GrowthOptions } from "../highways/growth/index.ts";
|
|
7
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";
|
|
8
16
|
import type { LevelHighwayOptions } from "../highways/level-links/index.ts";
|
|
9
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";
|
|
10
20
|
import type { OdCellOptions } from "../highways/od-cells/index.ts";
|
|
11
21
|
import type { QuickBundlesOptions } from "../highways/quickbundles/index.ts";
|
|
22
|
+
import type { RidgeOptions } from "../highways/ridges/index.ts";
|
|
12
23
|
import type { RoadClassOptions } from "../highways/road-classes/index.ts";
|
|
13
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";
|
|
14
27
|
import type { StubOptions } from "../highways/stubs/index.ts";
|
|
28
|
+
import type { TraclusOptions } from "../highways/traclus/index.ts";
|
|
15
29
|
import type { WeiszfeldOptions } from "../highways/weiszfeld/index.ts";
|
|
16
30
|
import type { WspdOptions } from "../highways/wspd/index.ts";
|
|
17
31
|
import type { ZipperOptions } from "../highways/zipper/index.ts";
|
|
@@ -121,6 +135,24 @@ export const SHARED_SCHEMA: OptionSchema<RouterPreset<SharedOptions>> = {
|
|
|
121
135
|
default: "span",
|
|
122
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).",
|
|
123
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`." },
|
|
124
156
|
merge: {
|
|
125
157
|
type: "enum",
|
|
126
158
|
values: ["corner", "snell"],
|
|
@@ -403,3 +435,151 @@ export const SELECT_SCHEMA: OptionSchema<SelectOptions> = {
|
|
|
403
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." },
|
|
404
436
|
swaps: { type: "integer", min: 0, max: 5, step: 1, default: 2, describe: "The number of passes of the local search with one swap." },
|
|
405
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) {
|