@mark1russell7/highways 0.9.0 → 0.9.1
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 +38 -0
- package/build/index.d.ts +286 -6
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2036 -453
- package/build/index.js.map +1 -1
- package/package.json +2 -2
- package/src/bench/screen/exercise.ts +5 -0
- package/src/bench/screen/forms.ts +5 -1
- package/src/highways/fixtures.test-util.ts +13 -0
- package/src/highways/follow.ts +3 -2
- package/src/highways/free-lines.ts +141 -0
- package/src/highways/gaps/index.ts +85 -0
- package/src/highways/index.ts +6 -0
- package/src/highways/interchanges/index.ts +231 -0
- package/src/highways/search/index.ts +170 -0
- package/src/highways/snap.ts +4 -2
- package/src/highways/steiner/index.ts +215 -0
- package/src/highways/streets/index.ts +78 -0
- package/src/model.ts +60 -4
- package/src/routers/attraction/index.ts +61 -0
- package/src/routers/corners.ts +4 -4
- package/src/routers/index.ts +2 -1
- package/src/routers/plugs.ts +3 -2
- package/src/routers/sections.ts +3 -2
- package/src/routers/shared.ts +70 -7
- package/src/routers/straight.ts +3 -2
- package/src/routers/trunks.ts +3 -2
- package/src/strategies/builtins.ts +56 -1
- package/src/strategies/schemas.ts +56 -0
package/src/routers/index.ts
CHANGED
|
@@ -9,7 +9,8 @@ import { byCollection, trunksRouter } from "./trunks.ts";
|
|
|
9
9
|
export { boxExit, straightRouter } from "./straight.ts";
|
|
10
10
|
export { plugsRouter } from "./plugs.ts";
|
|
11
11
|
export { cornersRouter, type CornersOptions } from "./corners.ts";
|
|
12
|
-
export { sharedRouter, type ShareCost, type SharedOptions, type ShareMerge, type ShareOrder } from "./shared.ts";
|
|
12
|
+
export { sharedRouter, type ShareCost, type SharedNegotiation, type SharedOptions, type ShareMerge, type ShareOrder } from "./shared.ts";
|
|
13
|
+
export { ATTRACTION_DEFAULTS, ATTRACTION_SCHEMA, attractionRouter, attractionStrategy, type AttractionOptions } from "./attraction/index.ts";
|
|
13
14
|
export { sectionsRouter, type SectionsOptions } from "./sections.ts";
|
|
14
15
|
export { byCollection, groupEdges, laneOrder, splitPoint, trunksRouter, type TrunkFan, type TrunkSplit, type TrunksOptions } from "./trunks.ts";
|
|
15
16
|
|
package/src/routers/plugs.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { inflectionCurve } from "../curves.ts";
|
|
2
2
|
import { center } from "../geom.ts";
|
|
3
|
-
import { nodeIndex, type Graph, type Result, type Route, type Router } from "../model.ts";
|
|
3
|
+
import { nodeIndex, resolvePorts, type Graph, type Result, type Route, type Router } from "../model.ts";
|
|
4
4
|
import { placePlug } from "../plugs.ts";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -9,7 +9,8 @@ import { placePlug } from "../plugs.ts";
|
|
|
9
9
|
*/
|
|
10
10
|
export const plugsRouter: Router = {
|
|
11
11
|
name: "plugs",
|
|
12
|
-
route(
|
|
12
|
+
route(input: Graph): Result {
|
|
13
|
+
const graph = resolvePorts(input);
|
|
13
14
|
const byId = nodeIndex(graph);
|
|
14
15
|
const routes: Route[] = [];
|
|
15
16
|
for (const e of graph.edges) {
|
package/src/routers/sections.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { BACKTRACK_MIN, goesOutAndBack } from "../bench/links.ts";
|
|
|
2
2
|
import { center, dist, pointSegmentDistance, polylineLength, type Point } from "../geom.ts";
|
|
3
3
|
import { LEVEL_LINK_DEFAULTS, type LevelLinkOptions } from "../levels.ts";
|
|
4
4
|
import { depthLevels, type DepthLevelOptions } from "../levels/depths/index.ts";
|
|
5
|
-
import { nodeIndex, type Graph, type Level, type Node, type Result, type Route, type Router, type SharedRun } from "../model.ts";
|
|
5
|
+
import { nodeIndex, resolvePorts, type Graph, type Level, type Node, type Result, type Route, type Router, type SharedRun } from "../model.ts";
|
|
6
6
|
import { placePlug } from "../plugs.ts";
|
|
7
7
|
import { allSections, buildSections, checkSections, SECTION_DEFAULTS, type Section, type SectionOptions } from "../sections.ts";
|
|
8
8
|
import { orderLanes, type RunOrder } from "../segments.ts";
|
|
@@ -91,7 +91,8 @@ const dedupe = (p: readonly Point[]): Point[] => p.filter((q, i) => i === 0 || d
|
|
|
91
91
|
export function sectionsRouter(options: SectionsOptions): Router {
|
|
92
92
|
const router: Router = {
|
|
93
93
|
name: options.name,
|
|
94
|
-
route(
|
|
94
|
+
route(input: Graph): Result {
|
|
95
|
+
const graph = resolvePorts(input);
|
|
95
96
|
const stretch = options.stretch ?? SECTIONS_DEFAULTS.stretch;
|
|
96
97
|
const stretchPad = options.stretchPad ?? SECTIONS_DEFAULTS.stretchPad;
|
|
97
98
|
const hubSlack = options.hubSlack ?? SECTIONS_DEFAULTS.hubSlack;
|
package/src/routers/shared.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { center, dist, type Point } from "../geom.ts";
|
|
2
|
-
import { nodeIndex, type Edge, type Graph, type GroupRule, type Result, type Route, type Router, type SharedRun } from "../model.ts";
|
|
2
|
+
import { nodeIndex, resolvePorts, type Edge, type Graph, type GroupRule, type Result, type Route, type Router, type SharedRun } from "../model.ts";
|
|
3
3
|
import { channelWidth } from "../channels.ts";
|
|
4
4
|
import { orderRun } from "../lane-order.ts";
|
|
5
5
|
import { stretchLaneOrders, type LaneStretchOrder } from "../lane-orders/stretch/index.ts";
|
|
@@ -77,6 +77,21 @@ export interface SharedOptions extends WayOptions {
|
|
|
77
77
|
readonly maxNodes?: number;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* The negotiation of the router `attraction` (HWY-044, PathFinder turned around). Each pass routes each edge again from no ways.
|
|
82
|
+
* A link costs `len (1 - attraction h) (1 + weight max(0, use - cap))` more than in `shared`, with `h` the history of the link.
|
|
83
|
+
*/
|
|
84
|
+
export interface SharedNegotiation {
|
|
85
|
+
/** The number of passes, 1 or more. */
|
|
86
|
+
readonly passes: number;
|
|
87
|
+
/** The pull of the history of a link, from 0 to 1. */
|
|
88
|
+
readonly attraction: number;
|
|
89
|
+
/** The cost weight of each edge over the capacity of a link, 0 or more. */
|
|
90
|
+
readonly capacityWeight: number;
|
|
91
|
+
/** The width of one lane. The capacity of a link is its free width divided by this width, and 1 or more. */
|
|
92
|
+
readonly laneWidth: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
80
95
|
/** A way of one edge through the corner graph. */
|
|
81
96
|
export interface Way {
|
|
82
97
|
readonly edge: Edge;
|
|
@@ -114,7 +129,7 @@ function turn(from: Point, base: Point, to: Point): number {
|
|
|
114
129
|
* Thus the edges of a key come together on common ways. Each stretch that several edges share has the same points in each route.
|
|
115
130
|
* The result gives each stretch as a run, with the order of its lanes.
|
|
116
131
|
*/
|
|
117
|
-
export function sharedRouter(options: SharedOptions): Router {
|
|
132
|
+
export function sharedRouter(options: SharedOptions, negotiation?: SharedNegotiation): Router {
|
|
118
133
|
const discount = Math.min(1, Math.max(0.05, options.discount ?? 0.5));
|
|
119
134
|
const flow = options.cost === "flow";
|
|
120
135
|
const alpha = Math.min(1, Math.max(0.1, options.alpha ?? 0.6));
|
|
@@ -133,7 +148,8 @@ export function sharedRouter(options: SharedOptions): Router {
|
|
|
133
148
|
};
|
|
134
149
|
const router: Router = {
|
|
135
150
|
name: options.name,
|
|
136
|
-
route(
|
|
151
|
+
route(input: Graph): Result {
|
|
152
|
+
const graph = resolvePorts(input);
|
|
137
153
|
const byId = nodeIndex(graph);
|
|
138
154
|
const ways = new WayFinder(graph.nodes, options);
|
|
139
155
|
const corners = ways.corners;
|
|
@@ -172,8 +188,11 @@ export function sharedRouter(options: SharedOptions): Router {
|
|
|
172
188
|
if (wd === undefined) widths.set(k, (wd = channelWidth(ways.obstacles, corners.points[i]!, corners.points[j]!)));
|
|
173
189
|
return wd;
|
|
174
190
|
};
|
|
175
|
-
/**
|
|
176
|
-
|
|
191
|
+
/**
|
|
192
|
+
* This function routes one way. `before` holds the edges of the key on each link in the pass before, for the option `reuse`.
|
|
193
|
+
* `history` holds the history of each link of the key, for the negotiation of `attraction`.
|
|
194
|
+
*/
|
|
195
|
+
const route = (w: Way, before?: ReadonlyMap<number, number>, history?: ReadonlyMap<number, number>): void => {
|
|
177
196
|
let used = discounted.get(w.key);
|
|
178
197
|
if (!used) discounted.set(w.key, (used = new Map()));
|
|
179
198
|
const mine = used;
|
|
@@ -192,6 +211,20 @@ export function sharedRouter(options: SharedOptions): Router {
|
|
|
192
211
|
cost = (i, j, d) => plain(i, j, d) / (1 + reuse * (before.get(link(i, j)) ?? 0)) ** reuseExponent;
|
|
193
212
|
floor /= (1 + reuse * most) ** reuseExponent;
|
|
194
213
|
}
|
|
214
|
+
if (negotiation !== undefined && history !== undefined) {
|
|
215
|
+
const plain = cost;
|
|
216
|
+
const a = negotiation.attraction;
|
|
217
|
+
const b = negotiation.capacityWeight;
|
|
218
|
+
let most = 0;
|
|
219
|
+
for (const h of history.values()) most = Math.max(most, h);
|
|
220
|
+
cost = (i, j, d) => {
|
|
221
|
+
const k = link(i, j);
|
|
222
|
+
const use = (mine.get(k)?.length ?? 0) + 1;
|
|
223
|
+
const cap = Math.max(1, Math.floor(widthOf(i, j) / negotiation.laneWidth));
|
|
224
|
+
return plain(i, j, d) * (1 - a * (history.get(k) ?? 0)) * (1 + b * Math.max(0, use - cap));
|
|
225
|
+
};
|
|
226
|
+
floor *= 1 - a * most;
|
|
227
|
+
}
|
|
195
228
|
const way = corners.path(ways.out(w.ps), ways.out(w.pt), cost, floor);
|
|
196
229
|
if (!way) return;
|
|
197
230
|
w.found = true;
|
|
@@ -207,9 +240,39 @@ export function sharedRouter(options: SharedOptions): Router {
|
|
|
207
240
|
if (flow) top.set(w.key, Math.max(top.get(w.key) ?? 0, mine.get(link(a, b))!.length));
|
|
208
241
|
}
|
|
209
242
|
};
|
|
210
|
-
|
|
243
|
+
/**
|
|
244
|
+
* This function gives the passes of the negotiation (HWY-044). After each pass, the history of each link grows by `use / m`,
|
|
245
|
+
* with `m` the edges of the key, up to `0.9 / attraction`. Each later pass routes each edge again from no ways.
|
|
246
|
+
*/
|
|
247
|
+
const negotiate = (list: readonly Way[]): void => {
|
|
248
|
+
const nego = negotiation!;
|
|
249
|
+
const histories = new Map<string, Map<number, number>>();
|
|
250
|
+
const size = new Map<string, number>();
|
|
251
|
+
for (const w of list) size.set(w.key, (size.get(w.key) ?? 0) + 1);
|
|
252
|
+
const most = nego.attraction > 0 ? 0.9 / nego.attraction : Infinity;
|
|
253
|
+
for (let pass = 0; pass < Math.max(1, Math.floor(nego.passes)); pass++) {
|
|
254
|
+
if (pass > 0) {
|
|
255
|
+
for (const [key, links] of discounted) {
|
|
256
|
+
let h = histories.get(key);
|
|
257
|
+
if (!h) histories.set(key, (h = new Map()));
|
|
258
|
+
const m = size.get(key) ?? 1;
|
|
259
|
+
for (const [k, users] of links) h.set(k, Math.min(most, (h.get(k) ?? 0) + users.length / m));
|
|
260
|
+
}
|
|
261
|
+
discounted.clear();
|
|
262
|
+
top.clear();
|
|
263
|
+
for (const w of list) {
|
|
264
|
+
w.found = false;
|
|
265
|
+
w.seq = [];
|
|
266
|
+
w.ids = [];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
for (const w of list) route(w, undefined, histories.get(w.key) ?? new Map());
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
if (negotiation !== undefined) negotiate(order);
|
|
273
|
+
else for (const w of order) route(w);
|
|
211
274
|
// Each later pass takes each edge off its links and finds its way again, with the ways of the other edges fixed.
|
|
212
|
-
for (let pass = 1; pass < passes; pass++) {
|
|
275
|
+
for (let pass = 1; negotiation === undefined && pass < passes; pass++) {
|
|
213
276
|
if (reuse > 0) {
|
|
214
277
|
// Winding Roads (HWY-005): each edge finds its way again from no ways, and the busy links of the pass before pull it.
|
|
215
278
|
const before = new Map<string, Map<number, number>>();
|
package/src/routers/straight.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { center, type Box, type Point } from "../geom.ts";
|
|
2
|
-
import { fixedPortPoint, nodeIndex, type Graph, type Result, type Route, type Router } from "../model.ts";
|
|
2
|
+
import { fixedPortPoint, nodeIndex, resolvePorts, type Graph, type Result, type Route, type Router } from "../model.ts";
|
|
3
3
|
|
|
4
4
|
/** This function gives the point where the ray from the center of the box to `toward` leaves the box. */
|
|
5
5
|
export function boxExit(box: Box, toward: Point): Point {
|
|
@@ -19,7 +19,8 @@ export function boxExit(box: Box, toward: Point): Point {
|
|
|
19
19
|
*/
|
|
20
20
|
export const straightRouter: Router = {
|
|
21
21
|
name: "straight",
|
|
22
|
-
route(
|
|
22
|
+
route(input: Graph): Result {
|
|
23
|
+
const graph = resolvePorts(input);
|
|
23
24
|
const byId = nodeIndex(graph);
|
|
24
25
|
const routes: Route[] = [];
|
|
25
26
|
for (const e of graph.edges) {
|
package/src/routers/trunks.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { center, dist, type Point } from "../geom.ts";
|
|
2
|
-
import { nodeIndex, type Bundle, type Edge, type Graph, type GroupRule, type Node, type Result, type Route, type Router, type SharedRun } from "../model.ts";
|
|
2
|
+
import { nodeIndex, resolvePorts, type Bundle, type Edge, type Graph, type GroupRule, type Node, type Result, type Route, type Router, type SharedRun } from "../model.ts";
|
|
3
3
|
import { placePlug, type Plug } from "../plugs.ts";
|
|
4
4
|
import { orderLanes, type RunOrder } from "../segments.ts";
|
|
5
5
|
import { WayFinder, type WayOptions } from "../ways.ts";
|
|
@@ -209,7 +209,8 @@ export function trunksRouter(options: TrunksOptions): Router {
|
|
|
209
209
|
const rule = groupRuleOf(options.rule);
|
|
210
210
|
const router: Router = {
|
|
211
211
|
name: options.name,
|
|
212
|
-
route(
|
|
212
|
+
route(input: Graph): Result {
|
|
213
|
+
const graph = resolvePorts(input);
|
|
213
214
|
const byId = nodeIndex(graph);
|
|
214
215
|
const ways = new WayFinder(graph.nodes, options);
|
|
215
216
|
const points = new Map<string, readonly Point[]>();
|
|
@@ -44,6 +44,11 @@ import { TERRITORY_DEFAULTS, territoryPlan, type TerritoryOptions } from "../hig
|
|
|
44
44
|
import { CONSENSUS_DEFAULTS, consensusPlan, type ConsensusOptions } from "../highways/consensus/index.ts";
|
|
45
45
|
import { P_HUB_DEFAULTS, pHubPlan, type PHubOptions } from "../highways/p-hub/index.ts";
|
|
46
46
|
import { SCALE_SPACE_DEFAULTS, scaleSpacePlan, type ScaleSpaceOptions } from "../highways/scale-space/index.ts";
|
|
47
|
+
import { GAP_DEFAULTS, gapPlan, type GapOptions } from "../highways/gaps/index.ts";
|
|
48
|
+
import { INTERCHANGE_DEFAULTS, interchangePlan, type InterchangeOptions } from "../highways/interchanges/index.ts";
|
|
49
|
+
import { SEARCH_DEFAULTS, searchPlan, type SearchOptions } from "../highways/search/index.ts";
|
|
50
|
+
import { STEINER_DEFAULTS, steinerPlan, type SteinerOptions } from "../highways/steiner/index.ts";
|
|
51
|
+
import { STREET_DEFAULTS, streetPlan, type StreetOptions } from "../highways/streets/index.ts";
|
|
47
52
|
import { RIDGE_DEFAULTS, ridgePlan, type RidgeOptions } from "../highways/ridges/index.ts";
|
|
48
53
|
import { SOFT_KEY_DEFAULTS, softKeyPlan, type SoftKeyOptions } from "../highways/soft-keys/index.ts";
|
|
49
54
|
import { FLOW_FIELD_DEFAULTS, flowFieldPlan, type FlowFieldOptions } from "../highways/flow-field/index.ts";
|
|
@@ -83,7 +88,7 @@ import { createRegistry, defineStrategy, type AnyStrategy, type CurveInput, type
|
|
|
83
88
|
import type { OptionSchema } from "./options.ts";
|
|
84
89
|
import { AREA_SCHEMA, CONFLUENT_SCHEMA, CROSSBAR_SCHEMA, FRECHET_SCHEMA, MLSEB_SCHEMA, POWER_SCHEMA, SBEB_SCHEMA } from "./schemas.ts";
|
|
85
90
|
import { DEPTHS_SCHEMA, PIPELINE_SCHEMA } from "./schemas.ts";
|
|
86
|
-
import { CLOTHOID_SCHEMA, CORNERS_SCHEMA, CORRIDOR_SCHEMA, CONSENSUS_SCHEMA, CUBU_SCHEMA, CUT_SCHEMA, DIFFUSION_SCHEMA, DIVIDED_SCHEMA, EDGE_PATH_SCHEMA, FDEB_SCHEMA, FLOW_CLUSTER_SCHEMA, FLOW_FIELD_SCHEMA, GROWTH_SCHEMA, HDBSCAN_SCHEMA, HIERARCHY_SCHEMA, HIGHWAY_SCHEMA, HOUGH_SCHEMA, HUB_ARC_SCHEMA, KD_SCHEMA, KDEEB_SCHEMA, KEY_SCHEMA, LANES_SCHEMA, LEVEL_HIGHWAY_SCHEMA, LEVEL_ROOM_SCHEMA, LINK_COMMUNITY_SCHEMA, MEET_SCHEMA, MESH_SCHEMA, MINGLE_SCHEMA, NESTED_SCHEMA, OD_CELL_SCHEMA, P_HUB_SCHEMA, QUICKBUNDLES_SCHEMA, RADIUS_SCHEMA, RESISTANCE_SCHEMA, RIDGE_SCHEMA, ROAD_CLASS_SCHEMA, ROOM_SCHEMA, SCALE_SPACE_SCHEMA, SECTION_SCHEMA, SELECT_SCHEMA, SECTIONS_SCHEMA, SHARED_ALL_SCHEMA, SHARED_SCHEMA, SMOOTH_SCHEMA, SOFT_KEY_SCHEMA, SPECTRAL_SCHEMA, SPIRAL_SCHEMA, STUB_SCHEMA, TENSION_SCHEMA, TERRITORY_SCHEMA, TRACLUS_SCHEMA, TRUNKS_SCHEMA, WEISZFELD_SCHEMA, WSPD_SCHEMA, ZIPPER_SCHEMA } from "./schemas.ts";
|
|
91
|
+
import { CLOTHOID_SCHEMA, CORNERS_SCHEMA, CORRIDOR_SCHEMA, CONSENSUS_SCHEMA, CUBU_SCHEMA, CUT_SCHEMA, DIFFUSION_SCHEMA, DIVIDED_SCHEMA, EDGE_PATH_SCHEMA, FDEB_SCHEMA, FLOW_CLUSTER_SCHEMA, FLOW_FIELD_SCHEMA, GROWTH_SCHEMA, HDBSCAN_SCHEMA, HIERARCHY_SCHEMA, HIGHWAY_SCHEMA, HOUGH_SCHEMA, HUB_ARC_SCHEMA, KD_SCHEMA, KDEEB_SCHEMA, KEY_SCHEMA, LANES_SCHEMA, LEVEL_HIGHWAY_SCHEMA, LEVEL_ROOM_SCHEMA, LINK_COMMUNITY_SCHEMA, MEET_SCHEMA, MESH_SCHEMA, MINGLE_SCHEMA, NESTED_SCHEMA, OD_CELL_SCHEMA, P_HUB_SCHEMA, QUICKBUNDLES_SCHEMA, RADIUS_SCHEMA, RESISTANCE_SCHEMA, RIDGE_SCHEMA, ROAD_CLASS_SCHEMA, ROOM_SCHEMA, SCALE_SPACE_SCHEMA, SECTION_SCHEMA, SELECT_SCHEMA, SECTIONS_SCHEMA, SHARED_ALL_SCHEMA, SHARED_SCHEMA, SMOOTH_SCHEMA, SOFT_KEY_SCHEMA, SPECTRAL_SCHEMA, SPIRAL_SCHEMA, STUB_SCHEMA, TENSION_SCHEMA, TERRITORY_SCHEMA, TRACLUS_SCHEMA, TRUNKS_SCHEMA, WEISZFELD_SCHEMA, WSPD_SCHEMA, ZIPPER_SCHEMA, STEINER_SCHEMA, GAP_SCHEMA, STREET_SCHEMA, SEARCH_SCHEMA, INTERCHANGE_SCHEMA } from "./schemas.ts";
|
|
87
92
|
|
|
88
93
|
/** The options of a router strategy: the options of its router, without the name and the limit of the benchmark. */
|
|
89
94
|
export type RouterPreset<O> = Omit<O, "name" | "maxNodes">;
|
|
@@ -462,6 +467,11 @@ export const highwayStrategies: {
|
|
|
462
467
|
readonly consensus: Strategy<"highway", ConsensusOptions>;
|
|
463
468
|
readonly "p-hub": Strategy<"highway", PHubOptions>;
|
|
464
469
|
readonly "scale-space": Strategy<"highway", ScaleSpaceOptions>;
|
|
470
|
+
readonly steiner: Strategy<"highway", SteinerOptions>;
|
|
471
|
+
readonly gaps: Strategy<"highway", GapOptions>;
|
|
472
|
+
readonly streets: Strategy<"highway", StreetOptions>;
|
|
473
|
+
readonly search: Strategy<"highway", SearchOptions>;
|
|
474
|
+
readonly interchanges: Strategy<"highway", InterchangeOptions>;
|
|
465
475
|
readonly "corridors+breakeven": Strategy<"highway", CorridorOptions & BreakEvenOptions>;
|
|
466
476
|
readonly "corridors+stretch": Strategy<"highway", CorridorOptions & StretchOptions>;
|
|
467
477
|
readonly "corridors+ambiguity": Strategy<"highway", CorridorOptions & AmbiguityGuardOptions>;
|
|
@@ -892,6 +902,51 @@ export const highwayStrategies: {
|
|
|
892
902
|
maxNodes: 10_000,
|
|
893
903
|
run: (input: HighwayInput, o: Readonly<ScaleSpaceOptions>) => scaleSpacePlan(input, o),
|
|
894
904
|
}),
|
|
905
|
+
steiner: defineStrategy({
|
|
906
|
+
step: "highway",
|
|
907
|
+
name: "steiner",
|
|
908
|
+
describe: "Obstacle-avoiding rectilinear Steiner trees (HWY-036 with EDA-015). Each group of edges gets one tree, and the stretches that edges share become highways.",
|
|
909
|
+
defaults: { ...STEINER_DEFAULTS } as SteinerOptions,
|
|
910
|
+
schema: STEINER_SCHEMA,
|
|
911
|
+
maxNodes: 10_000,
|
|
912
|
+
run: (input: HighwayInput, o: Readonly<SteinerOptions>) => steinerPlan(input, o),
|
|
913
|
+
}),
|
|
914
|
+
gaps: defineStrategy({
|
|
915
|
+
step: "highway",
|
|
916
|
+
name: "gaps",
|
|
917
|
+
describe: "Gap highways (HWY-057). The free middle lines of the gaps are streets, and a street that enough edges choose becomes a highway.",
|
|
918
|
+
defaults: { ...GAP_DEFAULTS } as GapOptions,
|
|
919
|
+
schema: GAP_SCHEMA,
|
|
920
|
+
maxNodes: 10_000,
|
|
921
|
+
run: (input: HighwayInput, o: Readonly<GapOptions>) => gapPlan(input, o),
|
|
922
|
+
}),
|
|
923
|
+
streets: defineStrategy({
|
|
924
|
+
step: "highway",
|
|
925
|
+
name: "streets",
|
|
926
|
+
describe: "Orthogonal streets by a greedy set cover (HWY-058). Each step takes the street that its new edges ride the most per unit of its length.",
|
|
927
|
+
defaults: { ...STREET_DEFAULTS } as StreetOptions,
|
|
928
|
+
schema: STREET_SCHEMA,
|
|
929
|
+
maxNodes: 10_000,
|
|
930
|
+
run: (input: HighwayInput, o: Readonly<StreetOptions>) => streetPlan(input, o),
|
|
931
|
+
}),
|
|
932
|
+
search: defineStrategy({
|
|
933
|
+
step: "highway",
|
|
934
|
+
name: "search",
|
|
935
|
+
describe: "A local search over the set of highways (HWY-059). The annealing adds, drops and moves highways, edges and points on a score of the bundle measures.",
|
|
936
|
+
defaults: { ...SEARCH_DEFAULTS } as SearchOptions,
|
|
937
|
+
schema: SEARCH_SCHEMA,
|
|
938
|
+
maxNodes: 10_000,
|
|
939
|
+
run: (input: HighwayInput, o: Readonly<SearchOptions>) => searchPlan(input, o),
|
|
940
|
+
}),
|
|
941
|
+
interchanges: defineStrategy({
|
|
942
|
+
step: "highway",
|
|
943
|
+
name: "interchanges",
|
|
944
|
+
describe: "A network of highways with interchanges (HWY-060). Each edge rides up to a number of highways, with a cost for each change.",
|
|
945
|
+
defaults: { ...INTERCHANGE_DEFAULTS } as InterchangeOptions,
|
|
946
|
+
schema: INTERCHANGE_SCHEMA,
|
|
947
|
+
maxNodes: 10_000,
|
|
948
|
+
run: (input: HighwayInput, o: Readonly<InterchangeOptions>) => interchangePlan(input, o),
|
|
949
|
+
}),
|
|
895
950
|
"corridors+breakeven": gateStrategy(corridors, breakEvenGate),
|
|
896
951
|
"corridors+stretch": gateStrategy(corridors, stretchGate),
|
|
897
952
|
"corridors+ambiguity": gateStrategy(corridors, ambiguityGate),
|
|
@@ -39,6 +39,11 @@ import type { ResistanceOptions } from "../highways/resistance/index.ts";
|
|
|
39
39
|
import type { RidgeOptions } from "../highways/ridges/index.ts";
|
|
40
40
|
import type { RoadClassOptions } from "../highways/road-classes/index.ts";
|
|
41
41
|
import type { ScaleSpaceOptions } from "../highways/scale-space/index.ts";
|
|
42
|
+
import type { GapOptions } from "../highways/gaps/index.ts";
|
|
43
|
+
import type { InterchangeOptions } from "../highways/interchanges/index.ts";
|
|
44
|
+
import type { SearchOptions } from "../highways/search/index.ts";
|
|
45
|
+
import type { SteinerOptions } from "../highways/steiner/index.ts";
|
|
46
|
+
import type { StreetOptions } from "../highways/streets/index.ts";
|
|
42
47
|
import type { SelectOptions } from "../highways/select/index.ts";
|
|
43
48
|
import type { SoftKeyOptions } from "../highways/soft-keys/index.ts";
|
|
44
49
|
import type { SpectralOptions } from "../highways/spectral/index.ts";
|
|
@@ -925,3 +930,54 @@ export const PIPELINE_SCHEMA: OptionSchema<PipelineOptions> = {
|
|
|
925
930
|
room: { type: "strategy", step: "room", describe: "The room strategy. With it, the gaps of the board open before the routes. Without it, the board stays." },
|
|
926
931
|
roomOptions: { type: "object", describe: "The options of the room strategy." },
|
|
927
932
|
};
|
|
933
|
+
|
|
934
|
+
/** The declarations of the options of the highway strategy `steiner` (HWY-036 with EDA-015). */
|
|
935
|
+
export const STEINER_SCHEMA: OptionSchema<SteinerOptions> = {
|
|
936
|
+
group: { type: "enum", values: ["source", "key"], default: "source", describe: "The groups of the trees: the edges from one source node, or the edges of one collection." },
|
|
937
|
+
method: { type: "enum", values: ["one-steiner", "spanning"], default: "one-steiner", describe: "The method of the tree: the iterated 1-Steiner method, or the spanning tree of the terminals." },
|
|
938
|
+
maxGroup: { type: "integer", min: 3, max: 32, step: 1, marks: [8, 12, 16], default: 12, describe: "A group with more terminals than this number gets the spanning tree alone." },
|
|
939
|
+
metric: { type: "enum", values: ["rectilinear", "octilinear"], default: "rectilinear", describe: "The metric of the tree: two directions or four directions." },
|
|
940
|
+
detour: { type: "number", min: 1, max: 3, step: 0.05, marks: [1.25, 1.5, 2], default: 1.5, describe: "An edge rides the tree only when its path in the tree is this many times its first route or less." },
|
|
941
|
+
minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A stretch of a tree with fewer edges than this number is not a highway." },
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
/** The declarations of the options of the highway strategy `gaps` (HWY-057). */
|
|
945
|
+
export const GAP_SCHEMA: OptionSchema<GapOptions> = {
|
|
946
|
+
minSize: { type: "integer", min: 2, max: 16, step: 1, marks: [2, 3, 6], default: 3, describe: "A street with fewer edges than this number (the demand) is not a highway." },
|
|
947
|
+
discount: { type: "number", min: 0.1, max: 0.8, step: 0.05, marks: [0.3, 0.5, 0.7], default: 0.5, describe: "The cost of a length on a street against a length off the streets." },
|
|
948
|
+
detour: { type: "number", min: 1, max: 2, step: 0.05, marks: [1.2, 1.3, 1.5], default: 1.3, describe: "An edge rides a street only when its way along the street is this many times its first route or less." },
|
|
949
|
+
source: { type: "enum", values: ["room", "corners"], default: "room", describe: "The source of the streets: the gaps of the room step, or the lines through the corners." },
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
/** The declarations of the options of the highway strategy `streets` (HWY-058). */
|
|
953
|
+
export const STREET_SCHEMA: OptionSchema<StreetOptions> = {
|
|
954
|
+
detour: { type: "number", min: 1, max: 1.5, step: 0.05, marks: [1.1, 1.2, 1.3], default: 1.2, describe: "A street covers an edge when the way of the edge along it is this many times its first route or less." },
|
|
955
|
+
minGain: { type: "number", min: 1, max: 8, step: 0.25, marks: [1.5, 2, 4], default: 2, describe: "The cover stops when the best street gives less gain: the length that its edges ride over its length." },
|
|
956
|
+
maxStreets: { type: "integer", min: 4, max: 64, step: 4, marks: [16, 32], default: 32, describe: "The largest number of streets." },
|
|
957
|
+
minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A street with fewer new edges than this number is not a highway." },
|
|
958
|
+
source: { type: "enum", values: ["room", "corners"], default: "corners", describe: "The source of the streets: the gaps of the room step, or the lines through the corners." },
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
/** The declarations of the options of the highway strategy `search` (HWY-059). */
|
|
962
|
+
export const SEARCH_SCHEMA: OptionSchema<SearchOptions> = {
|
|
963
|
+
from: { type: "enum", values: ["corridors", "quickbundles", "wspd", "road-classes", "flow-field", "od-cells", "shared-ways"], default: "corridors", describe: "The plan where the search starts." },
|
|
964
|
+
pool: { type: "list", default: ["quickbundles", "road-classes"], describe: "The generators of the highways that the move `add` takes." },
|
|
965
|
+
evaluations: { type: "integer", min: 0, max: 400, step: 4, marks: [0, 16, 64], default: 16, describe: "The number of plans that the search measures. The value 0 gives the start plan." },
|
|
966
|
+
temperature: { type: "number", min: 0, max: 0.2, step: 0.005, marks: [0, 0.02, 0.05], default: 0.02, describe: "The first temperature of the annealing, on the scale of the score." },
|
|
967
|
+
inkWeight: { type: "number", min: 0, max: 4, step: 0.25, marks: [1], default: 1, describe: "The weight of the ink that the routes save (B1)." },
|
|
968
|
+
stretchWeight: { type: "number", min: 0, max: 4, step: 0.25, marks: [0.5], default: 0.5, describe: "The weight of the 0.95 quantile of the stretch (B3)." },
|
|
969
|
+
ambiguityWeight: { type: "number", min: 0, max: 4, step: 0.25, marks: [0.5], default: 0.5, describe: "The weight of the ambiguity (B4)." },
|
|
970
|
+
angleWeight: { type: "number", min: 0, max: 4, step: 0.25, marks: [0.25], default: 0.25, describe: "The weight of the largest merge angle (B6), divided by 180 degrees." },
|
|
971
|
+
seed: { type: "integer", min: 0, max: 1000, step: 1, default: 1, describe: "The seed of the moves." },
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
/** The declarations of the options of the highway strategy `interchanges` (HWY-060). */
|
|
975
|
+
export const INTERCHANGE_SCHEMA: OptionSchema<InterchangeOptions> = {
|
|
976
|
+
from: { type: "enum", values: ["corridors", "shared-ways"], default: "corridors", describe: "The plan that gives the highways of the network." },
|
|
977
|
+
changeCost: { type: "number", min: 0, max: 8, step: 0.5, marks: [0, 2, 4], default: 2, describe: "The cost of a change between two highways, in units of the board." },
|
|
978
|
+
interchanges: { type: "integer", min: 1, max: 32, step: 1, marks: [4, 16], default: 16, describe: "The largest number of interchanges." },
|
|
979
|
+
perEdge: { type: "integer", min: 1, max: 3, step: 1, default: 2, describe: "The largest number of highways on the way of one edge." },
|
|
980
|
+
radius: { type: "number", min: 0.5, max: 8, step: 0.5, marks: [1, 2, 4], default: 2, describe: "Two highways get an interchange where they come this near, in units of the board." },
|
|
981
|
+
discount: { type: "number", min: 0.1, max: 1, step: 0.05, marks: [0.3, 0.5, 0.7], default: 0.5, describe: "The cost of a length on a highway against a length off the highways." },
|
|
982
|
+
detour: { type: "number", min: 1, max: 3, step: 0.05, marks: [1.25, 1.5, 2], default: 1.5, describe: "An edge rides the network only when its way is this many times its first route or less." },
|
|
983
|
+
};
|