@mark1russell7/highways 0.9.5 → 0.9.7
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 +22 -1
- package/build/index.d.ts +110 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +995 -68
- package/build/index.js.map +1 -1
- package/package.json +2 -1
- package/src/bench/compare.ts +24 -1
- package/src/bench/measures/lanes.ts +95 -1
- package/src/bench/measures/stability.ts +47 -3
- package/src/bench/screen/measures.ts +8 -0
- package/src/bench/screen/screen.ts +4 -1
- package/src/index.ts +1 -0
- package/src/model.ts +21 -3
- package/src/plugs/assign/index.ts +494 -0
- package/src/plugs/fix.ts +55 -0
- package/src/plugs/justify.ts +39 -7
- package/src/plugs/range.ts +120 -0
- package/src/plugs/row-cards.ts +42 -0
- package/src/plugs/side.ts +7 -0
- package/src/plugs/spread/index.ts +28 -42
- package/src/plugs/walls.ts +47 -0
- package/src/plugs.ts +4 -2
- package/src/strategies/builtins.ts +11 -1
- package/src/strategies/schemas.ts +7 -0
package/build/index.js
CHANGED
|
@@ -351,10 +351,20 @@ function portOffset(box, port) {
|
|
|
351
351
|
along: port.along
|
|
352
352
|
});
|
|
353
353
|
}
|
|
354
|
-
/**
|
|
354
|
+
/**
|
|
355
|
+
* This function throws a `RangeError` when the `along` of a plug is bad: not finite, outside 0 to 1, without `side` or with `at`.
|
|
356
|
+
* It also throws a `RangeError` for a bad `range` of a plug. A bad range has a value that is not finite or is outside 0 to 1, or a start after its end.
|
|
357
|
+
*/
|
|
355
358
|
function checkPort(node, port) {
|
|
356
|
-
if (port.along === void 0) return;
|
|
357
359
|
const at = `The plug "${port.id}" of the node "${node.id}"`;
|
|
360
|
+
if (port.range !== void 0) {
|
|
361
|
+
const r = port.range;
|
|
362
|
+
if (!Array.isArray(r) || r.length !== 2 || !r.every((v) => typeof v === "number" && Number.isFinite(v))) throw new RangeError(`${at} has the range ${JSON.stringify(r)}. It must be two finite numbers.`);
|
|
363
|
+
const [lo, hi] = r;
|
|
364
|
+
if (lo < 0 || hi > 1) throw new RangeError(`${at} has the range [${lo}, ${hi}]. It must be in the side, from 0 to 1.`);
|
|
365
|
+
if (lo > hi) throw new RangeError(`${at} has the range [${lo}, ${hi}]. Its start must not be after its end.`);
|
|
366
|
+
}
|
|
367
|
+
if (port.along === void 0) return;
|
|
358
368
|
if (typeof port.along !== "number" || !Number.isFinite(port.along) || port.along < 0 || port.along > 1) throw new RangeError(`${at} has the along value ${String(port.along)}. It must be a finite number from 0 to 1.`);
|
|
359
369
|
if (port.side === void 0) throw new RangeError(`${at} has an along value and no side. A plug with along needs a side.`);
|
|
360
370
|
if (port.at !== void 0) throw new RangeError(`${at} has an along value and an at point. Give one of the two.`);
|
|
@@ -362,7 +372,7 @@ function checkPort(node, port) {
|
|
|
362
372
|
/**
|
|
363
373
|
* This function checks the plugs of a graph, and gives each plug with `side` and `along` a fixed `at`. The plug keeps its `side`.
|
|
364
374
|
* Each router calls it at the start of `route`, so all routers agree. A graph without `along` comes back as the same object.
|
|
365
|
-
* It throws a `RangeError` for a bad `along` (`checkPort`).
|
|
375
|
+
* It throws a `RangeError` for a bad `along` or a bad `range` (`checkPort`).
|
|
366
376
|
*/
|
|
367
377
|
function resolvePorts(graph) {
|
|
368
378
|
let found = false;
|
|
@@ -913,6 +923,115 @@ const CASES = [
|
|
|
913
923
|
make: () => manyGroupsBoard()
|
|
914
924
|
}
|
|
915
925
|
];
|
|
926
|
+
// src/plugs/range.ts
|
|
927
|
+
/** The tolerance of the comparisons of places along a side. */
|
|
928
|
+
const EPS$9 = 1e-9;
|
|
929
|
+
/** This function gives the axis along a side. */
|
|
930
|
+
function alongAxis(side) {
|
|
931
|
+
return side === "east" || side === "west" ? "y" : "x";
|
|
932
|
+
}
|
|
933
|
+
/** This function gives the port of an end, or `undefined` when the end has no port or the node has no such port. */
|
|
934
|
+
function portOfEnd(node, end) {
|
|
935
|
+
return end.port === void 0 ? void 0 : node.ports?.find((p) => p.id === end.port);
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* This function gives the interval of a plug with a range, on the axis along its side, or `undefined` for a port without a range.
|
|
939
|
+
* The interval is the range of the port, without the corner insets of the side.
|
|
940
|
+
* When the range is all in a corner inset, the interval is the range.
|
|
941
|
+
*/
|
|
942
|
+
function rangeInterval(box, side, port, inset = 6) {
|
|
943
|
+
const range = port?.range;
|
|
944
|
+
if (range === void 0) return void 0;
|
|
945
|
+
const along = alongAxis(side);
|
|
946
|
+
const start = along === "y" ? box.y : box.x;
|
|
947
|
+
const len = along === "y" ? box.h : box.w;
|
|
948
|
+
const m = Math.min(inset, len / 4);
|
|
949
|
+
const lo = start + range[0] * len;
|
|
950
|
+
const hi = start + range[1] * len;
|
|
951
|
+
const a = Math.max(lo, start + m);
|
|
952
|
+
const b = Math.min(hi, start + len - m);
|
|
953
|
+
return a <= b ? [a, b] : [lo, hi];
|
|
954
|
+
}
|
|
955
|
+
/** This function moves a point of a side into the interval of its range, on the axis along the side. A point of a port without a range stays. */
|
|
956
|
+
function clampToRange(box, side, port, point, inset = 6) {
|
|
957
|
+
const r = rangeInterval(box, side, port, inset);
|
|
958
|
+
if (!r) return point;
|
|
959
|
+
const along = alongAxis(side);
|
|
960
|
+
const v = Math.max(r[0], Math.min(r[1], point[along]));
|
|
961
|
+
return along === "y" ? {
|
|
962
|
+
x: point.x,
|
|
963
|
+
y: v
|
|
964
|
+
} : {
|
|
965
|
+
x: v,
|
|
966
|
+
y: point.y
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* This function places `ideal.length` plugs of one side in their given order. The plug `i` stays in the interval from `lo[i]` to `hi[i]`.
|
|
971
|
+
* Two neighbours are at least `gap` apart. When the intervals are too short for the gap, the gap shrinks evenly to the largest gap that they let.
|
|
972
|
+
* The sum of the squares of the moves from the ideal places is the least.
|
|
973
|
+
*
|
|
974
|
+
* When the order cannot keep each plug in its interval, the plugs take the order of their ideal places in their intervals. Thus the intervals win over the order.
|
|
975
|
+
* The result is in the order of `ideal`.
|
|
976
|
+
*/
|
|
977
|
+
function placeInIntervals(ideal, lo, hi, gap) {
|
|
978
|
+
const k = ideal.length;
|
|
979
|
+
if (k === 0) return [];
|
|
980
|
+
let order = ideal.map((_, i) => i);
|
|
981
|
+
let most = -Infinity;
|
|
982
|
+
let broken = false;
|
|
983
|
+
for (const i of order) {
|
|
984
|
+
if (hi[i] < most - EPS$9) broken = true;
|
|
985
|
+
most = Math.max(most, lo[i]);
|
|
986
|
+
}
|
|
987
|
+
if (broken) {
|
|
988
|
+
const c = order.map((i) => Math.max(lo[i], Math.min(hi[i], ideal[i])));
|
|
989
|
+
order = [...order].sort((a, b) => c[a] - c[b] || a - b);
|
|
990
|
+
}
|
|
991
|
+
let s = Math.max(0, gap);
|
|
992
|
+
for (let i = 1; i < k; i++) {
|
|
993
|
+
const hiI = hi[order[i]];
|
|
994
|
+
for (let j = 0; j < i; j++) s = Math.min(s, (hiI - lo[order[j]]) / (i - j));
|
|
995
|
+
}
|
|
996
|
+
s = Math.max(0, s);
|
|
997
|
+
const lower = new Array(k);
|
|
998
|
+
const upper = new Array(k);
|
|
999
|
+
let run = -Infinity;
|
|
1000
|
+
for (let i = 0; i < k; i++) lower[i] = run = Math.max(run, lo[order[i]] - i * s);
|
|
1001
|
+
run = Infinity;
|
|
1002
|
+
for (let i = k - 1; i >= 0; i--) upper[i] = run = Math.min(run, hi[order[i]] - i * s);
|
|
1003
|
+
const sum = [];
|
|
1004
|
+
const size = [];
|
|
1005
|
+
const blockLo = [];
|
|
1006
|
+
const blockHi = [];
|
|
1007
|
+
const value = [];
|
|
1008
|
+
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
1009
|
+
for (let i = 0; i < k; i++) {
|
|
1010
|
+
sum.push(ideal[order[i]] - i * s);
|
|
1011
|
+
size.push(1);
|
|
1012
|
+
blockLo.push(lower[i]);
|
|
1013
|
+
blockHi.push(upper[i]);
|
|
1014
|
+
value.push(clamp(sum[sum.length - 1], lower[i], upper[i]));
|
|
1015
|
+
while (value.length > 1 && value[value.length - 2] > value[value.length - 1]) {
|
|
1016
|
+
const t = value.length - 1;
|
|
1017
|
+
sum[t - 1] += sum[t];
|
|
1018
|
+
size[t - 1] += size[t];
|
|
1019
|
+
blockLo[t - 1] = blockLo[t];
|
|
1020
|
+
value[t - 1] = clamp(sum[t - 1] / size[t - 1], blockLo[t - 1], blockHi[t - 1]);
|
|
1021
|
+
sum.pop();
|
|
1022
|
+
size.pop();
|
|
1023
|
+
blockLo.pop();
|
|
1024
|
+
blockHi.pop();
|
|
1025
|
+
value.pop();
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
const out = new Array(k);
|
|
1029
|
+
let i = 0;
|
|
1030
|
+
value.forEach((v, b) => {
|
|
1031
|
+
for (let j = 0; j < size[b]; j++, i++) out[order[i]] = v + i * s;
|
|
1032
|
+
});
|
|
1033
|
+
return out;
|
|
1034
|
+
}
|
|
916
1035
|
// src/plugs.ts
|
|
917
1036
|
/** The outward normal of each side, in a frame with the y axis down. */
|
|
918
1037
|
const SIDE_NORMAL = {
|
|
@@ -983,7 +1102,7 @@ function pointOnSide(box, side, toward, inset = 6) {
|
|
|
983
1102
|
}
|
|
984
1103
|
/**
|
|
985
1104
|
* This function places the plug of one end of an edge. A fixed plug stays at its point. A plug with a side stays on that side.
|
|
986
|
-
* The router places a free plug on the side that faces `toward`.
|
|
1105
|
+
* The router places a free plug on the side that faces `toward`. A free plug of a port with a `range` stays in that range (`clampToRange`).
|
|
987
1106
|
*/
|
|
988
1107
|
function placePlug(node, end, toward) {
|
|
989
1108
|
const fixed = fixedPortPoint(node, end);
|
|
@@ -993,8 +1112,9 @@ function placePlug(node, end, toward) {
|
|
|
993
1112
|
normal: SIDE_NORMAL[port?.side ?? nearestSide(node.box, fixed)]
|
|
994
1113
|
};
|
|
995
1114
|
const side = port?.side ?? sideToward(node.box, toward);
|
|
1115
|
+
const point = pointOnSide(node.box, side, toward);
|
|
996
1116
|
return {
|
|
997
|
-
point:
|
|
1117
|
+
point: port?.range === void 0 ? point : clampToRange(node.box, side, port, point),
|
|
998
1118
|
normal: SIDE_NORMAL[side]
|
|
999
1119
|
};
|
|
1000
1120
|
}
|
|
@@ -4953,6 +5073,7 @@ function isotonic(v) {
|
|
|
4953
5073
|
* This function moves the free plugs of each side of each node, so that two of them are at least `gap` apart (`justifyPlugs`).
|
|
4954
5074
|
* The plugs keep their order on the side. Two plugs at one place take the order of their other ends. A fixed plug does not move.
|
|
4955
5075
|
* A plug stays `inset` from the corners of its side, or a quarter of the side when the side is short.
|
|
5076
|
+
* A plug of a port with a `range` stays in its range (PORT-RANGE), and the plugs keep their order and the gap (`placeInIntervals`).
|
|
4956
5077
|
*/
|
|
4957
5078
|
function spacePlugs(ends, gap, inset = 6) {
|
|
4958
5079
|
const sides = /* @__PURE__ */ new Map();
|
|
@@ -4985,18 +5106,21 @@ function spacePlugs(ends, gap, inset = 6) {
|
|
|
4985
5106
|
side.items.push([
|
|
4986
5107
|
i,
|
|
4987
5108
|
k,
|
|
4988
|
-
other.point
|
|
5109
|
+
other.point,
|
|
5110
|
+
portOfEnd(node, end)
|
|
4989
5111
|
]);
|
|
4990
5112
|
}
|
|
4991
5113
|
});
|
|
4992
5114
|
for (const { node, normal, items } of sides.values()) {
|
|
4993
|
-
|
|
5115
|
+
const ranged = items.some((x) => x[3]?.range !== void 0);
|
|
5116
|
+
if (items.length < 2 && !ranged) continue;
|
|
4994
5117
|
const along = normal.x !== 0 ? "y" : "x";
|
|
4995
5118
|
const b = node.box;
|
|
4996
5119
|
const start = along === "y" ? b.y : b.x;
|
|
4997
5120
|
const len = along === "y" ? b.h : b.w;
|
|
4998
5121
|
const m = Math.min(inset, len / 4);
|
|
4999
|
-
const
|
|
5122
|
+
const ideal = items.map(([i, k]) => ends[i][k].point[along]);
|
|
5123
|
+
const placed = ranged ? spaceInRanges(b, normal, items, ideal, start + m, start + len - m, gap, inset) : justifyPlugs(ideal, start + m, start + len - m, gap, (j) => items[j][2][along]);
|
|
5000
5124
|
items.forEach(([i, k], j) => {
|
|
5001
5125
|
const old = ends[i][k];
|
|
5002
5126
|
ends[i][k] = {
|
|
@@ -5013,6 +5137,28 @@ function spacePlugs(ends, gap, inset = 6) {
|
|
|
5013
5137
|
}
|
|
5014
5138
|
}
|
|
5015
5139
|
/**
|
|
5140
|
+
* This function places the free plugs of one side with ranges (PORT-RANGE). The order is the order of `justifyPlugs`.
|
|
5141
|
+
* Each plug stays in the interval of its range, or in the room of the side without a range.
|
|
5142
|
+
*/
|
|
5143
|
+
function spaceInRanges(box, normal, items, ideal, lo, hi, gap, inset) {
|
|
5144
|
+
const side = sideOfNormal(normal);
|
|
5145
|
+
const along = alongAxis(side);
|
|
5146
|
+
const order = ideal.map((_, i) => i).sort((a, b) => ideal[a] - ideal[b] || items[a][2][along] - items[b][2][along] || a - b);
|
|
5147
|
+
const span = order.map((j) => rangeInterval(box, side, items[j][3], inset) ?? [lo, hi]);
|
|
5148
|
+
const at = placeInIntervals(order.map((j) => ideal[j]), span.map((r) => r[0]), span.map((r) => r[1]), gap);
|
|
5149
|
+
const out = new Array(ideal.length);
|
|
5150
|
+
order.forEach((j, i) => {
|
|
5151
|
+
out[j] = at[i];
|
|
5152
|
+
});
|
|
5153
|
+
return out;
|
|
5154
|
+
}
|
|
5155
|
+
/** This function gives the side of an outward normal. */
|
|
5156
|
+
function sideOfNormal(n) {
|
|
5157
|
+
if (n.x > 0) return "east";
|
|
5158
|
+
if (n.x < 0) return "west";
|
|
5159
|
+
return n.y > 0 ? "south" : "north";
|
|
5160
|
+
}
|
|
5161
|
+
/**
|
|
5016
5162
|
* This function gives the plugs of the plug strategy `justify` (WILD-002): the plugs of `facing`, then the gaps of `spacePlugs`.
|
|
5017
5163
|
* The router `corners` with the option `plugGap` gives the same plugs.
|
|
5018
5164
|
*/
|
|
@@ -5048,7 +5194,8 @@ function justifyEnds(input, options = {}) {
|
|
|
5048
5194
|
/** This function gives the free side of an end, or `undefined` when the plug of the end is fixed. */
|
|
5049
5195
|
function freeSide(node, end, toward, inset) {
|
|
5050
5196
|
if (fixedPortPoint(node, end)) return void 0;
|
|
5051
|
-
const
|
|
5197
|
+
const port = end.port === void 0 ? void 0 : node.ports?.find((p) => p.id === end.port);
|
|
5198
|
+
const side = port?.side ?? sideToward(node.box, toward);
|
|
5052
5199
|
const b = node.box;
|
|
5053
5200
|
const along = side === "east" || side === "west" ? "y" : "x";
|
|
5054
5201
|
const start = along === "y" ? b.y : b.x;
|
|
@@ -5056,6 +5203,23 @@ function freeSide(node, end, toward, inset) {
|
|
|
5056
5203
|
const m = Math.min(inset, len / 4);
|
|
5057
5204
|
const at = side === "east" ? b.x + b.w : side === "west" ? b.x : side === "south" ? b.y + b.h : b.y;
|
|
5058
5205
|
const point = pointOnSide(b, side, toward, inset);
|
|
5206
|
+
const range = port?.range === void 0 ? void 0 : rangeInterval(b, side, port, inset);
|
|
5207
|
+
if (range) {
|
|
5208
|
+
const facing = clampToRange(b, side, port, point, inset);
|
|
5209
|
+
return {
|
|
5210
|
+
node,
|
|
5211
|
+
side,
|
|
5212
|
+
normal: SIDE_NORMAL[side],
|
|
5213
|
+
along,
|
|
5214
|
+
at,
|
|
5215
|
+
lo: range[0],
|
|
5216
|
+
hi: range[1],
|
|
5217
|
+
facing: {
|
|
5218
|
+
point: facing,
|
|
5219
|
+
normal: SIDE_NORMAL[side]
|
|
5220
|
+
}
|
|
5221
|
+
};
|
|
5222
|
+
}
|
|
5059
5223
|
return {
|
|
5060
5224
|
node,
|
|
5061
5225
|
side,
|
|
@@ -5215,7 +5379,7 @@ function sideEnds(input, options = {}) {
|
|
|
5215
5379
|
// src/routers/gutter.ts
|
|
5216
5380
|
/** The default cost of one bend of the gutter mode. */
|
|
5217
5381
|
const GUTTER_BEND_COST = 16;
|
|
5218
|
-
const EPS$
|
|
5382
|
+
const EPS$8 = 1e-6;
|
|
5219
5383
|
/** The directions of a step: east, south, west and north, with the y axis down. */
|
|
5220
5384
|
const DX = [
|
|
5221
5385
|
1,
|
|
@@ -5239,7 +5403,7 @@ const DY = [
|
|
|
5239
5403
|
*/
|
|
5240
5404
|
function gutterRoutes(frame, nodes, edges, options = {}) {
|
|
5241
5405
|
const bend = options.bendCost ?? 16;
|
|
5242
|
-
const boxes = nodes.map((n) => n.box).filter((b) => b.w > EPS$
|
|
5406
|
+
const boxes = nodes.map((n) => n.box).filter((b) => b.w > EPS$8 && b.h > EPS$8);
|
|
5243
5407
|
const entries = edges.map(entriesOf);
|
|
5244
5408
|
const xs = /* @__PURE__ */ new Set();
|
|
5245
5409
|
const ys = /* @__PURE__ */ new Set();
|
|
@@ -5257,7 +5421,7 @@ function gutterRoutes(frame, nodes, edges, options = {}) {
|
|
|
5257
5421
|
const cuts = [lo, lo + size];
|
|
5258
5422
|
for (const b of boxes) for (const v of key === "x" ? [b.x, b.x + b.w] : [b.y, b.y + b.h]) if (v > lo && v < lo + size) cuts.push(v);
|
|
5259
5423
|
cuts.sort((a, b) => a - b);
|
|
5260
|
-
for (let i = 1; i < cuts.length; i++) if (cuts[i] - cuts[i - 1] > EPS$
|
|
5424
|
+
for (let i = 1; i < cuts.length; i++) if (cuts[i] - cuts[i - 1] > EPS$8) lines.add((cuts[i] + cuts[i - 1]) / 2);
|
|
5261
5425
|
}
|
|
5262
5426
|
edges.forEach((e, i) => {
|
|
5263
5427
|
for (const { point, normal } of [{
|
|
@@ -5320,19 +5484,19 @@ function stubOnly(e, boxes) {
|
|
|
5320
5484
|
const n = e.plug.normal;
|
|
5321
5485
|
let q;
|
|
5322
5486
|
if (n.x !== 0) {
|
|
5323
|
-
if (!(p.y > b.y + EPS$
|
|
5487
|
+
if (!(p.y > b.y + EPS$8 && p.y < b.y + b.h - EPS$8)) return void 0;
|
|
5324
5488
|
q = {
|
|
5325
5489
|
x: n.x > 0 ? b.x + b.w : b.x,
|
|
5326
5490
|
y: p.y
|
|
5327
5491
|
};
|
|
5328
|
-
if ((q.x - p.x) * n.x > EPS$
|
|
5492
|
+
if ((q.x - p.x) * n.x > EPS$8) return void 0;
|
|
5329
5493
|
} else {
|
|
5330
|
-
if (!(p.x > b.x + EPS$
|
|
5494
|
+
if (!(p.x > b.x + EPS$8 && p.x < b.x + b.w - EPS$8)) return void 0;
|
|
5331
5495
|
q = {
|
|
5332
5496
|
x: p.x,
|
|
5333
5497
|
y: n.y > 0 ? b.y + b.h : b.y
|
|
5334
5498
|
};
|
|
5335
|
-
if ((q.y - p.y) * n.y > EPS$
|
|
5499
|
+
if ((q.y - p.y) * n.y > EPS$8) return void 0;
|
|
5336
5500
|
}
|
|
5337
5501
|
for (const o of boxes) if (o !== b && blocks(p, q, o)) return void 0;
|
|
5338
5502
|
return [p, q];
|
|
@@ -5340,11 +5504,11 @@ function stubOnly(e, boxes) {
|
|
|
5340
5504
|
/** This function tells if the axis-parallel segment `ab` meets the closed box `o` along a part longer than a tiny length. A segment along a side meets the box. */
|
|
5341
5505
|
function blocks(a, b, o) {
|
|
5342
5506
|
if (a.y === b.y) {
|
|
5343
|
-
if (a.y < o.y - EPS$
|
|
5344
|
-
return Math.min(Math.max(a.x, b.x), o.x + o.w) - Math.max(Math.min(a.x, b.x), o.x) > EPS$
|
|
5507
|
+
if (a.y < o.y - EPS$8 || a.y > o.y + o.h + EPS$8) return false;
|
|
5508
|
+
return Math.min(Math.max(a.x, b.x), o.x + o.w) - Math.max(Math.min(a.x, b.x), o.x) > EPS$8;
|
|
5345
5509
|
}
|
|
5346
|
-
if (a.x < o.x - EPS$
|
|
5347
|
-
return Math.min(Math.max(a.y, b.y), o.y + o.h) - Math.max(Math.min(a.y, b.y), o.y) > EPS$
|
|
5510
|
+
if (a.x < o.x - EPS$8 || a.x > o.x + o.w + EPS$8) return false;
|
|
5511
|
+
return Math.min(Math.max(a.y, b.y), o.y + o.h) - Math.max(Math.min(a.y, b.y), o.y) > EPS$8;
|
|
5348
5512
|
}
|
|
5349
5513
|
/** This function gives the direction index of a unit normal: 0 east, 1 south, 2 west, 3 north. */
|
|
5350
5514
|
function dirOf(n) {
|
|
@@ -5363,12 +5527,12 @@ var Grid$1 = class {
|
|
|
5363
5527
|
this.#free = new Uint8Array(xs.length * ys.length);
|
|
5364
5528
|
for (let i = 0; i < ys.length; i++) {
|
|
5365
5529
|
const y = ys[i];
|
|
5366
|
-
if (y <= frame.y + EPS$
|
|
5530
|
+
if (y <= frame.y + EPS$8 || y >= frame.y + frame.h - EPS$8) continue;
|
|
5367
5531
|
for (let j = 0; j < xs.length; j++) {
|
|
5368
5532
|
const x = xs[j];
|
|
5369
|
-
if (x <= frame.x + EPS$
|
|
5533
|
+
if (x <= frame.x + EPS$8 || x >= frame.x + frame.w - EPS$8) continue;
|
|
5370
5534
|
let free = true;
|
|
5371
|
-
for (const b of boxes) if (x >= b.x - EPS$
|
|
5535
|
+
for (const b of boxes) if (x >= b.x - EPS$8 && x <= b.x + b.w + EPS$8 && y >= b.y - EPS$8 && y <= b.y + b.h + EPS$8) {
|
|
5372
5536
|
free = false;
|
|
5373
5537
|
break;
|
|
5374
5538
|
}
|
|
@@ -5405,11 +5569,11 @@ var Grid$1 = class {
|
|
|
5405
5569
|
const sign = d < 2 ? 1 : -1;
|
|
5406
5570
|
let k = -1;
|
|
5407
5571
|
if (sign > 0) {
|
|
5408
|
-
for (let m = 0; m < list.length; m++) if (list[m] > v + EPS$
|
|
5572
|
+
for (let m = 0; m < list.length; m++) if (list[m] > v + EPS$8) {
|
|
5409
5573
|
k = m;
|
|
5410
5574
|
break;
|
|
5411
5575
|
}
|
|
5412
|
-
} else for (let m = list.length - 1; m >= 0; m--) if (list[m] < v - EPS$
|
|
5576
|
+
} else for (let m = list.length - 1; m >= 0; m--) if (list[m] < v - EPS$8) {
|
|
5413
5577
|
k = m;
|
|
5414
5578
|
break;
|
|
5415
5579
|
}
|
|
@@ -5608,7 +5772,7 @@ function lanes(frame, boxes, edges, entries, routes, laneGap) {
|
|
|
5608
5772
|
const b = legs[j];
|
|
5609
5773
|
if (a.route === b.route || a.horizontal !== b.horizontal) continue;
|
|
5610
5774
|
if (Math.min(a.s1, b.s1) - Math.max(a.s0, b.s0) <= -laneGap) continue;
|
|
5611
|
-
if (a.across < b.lo - EPS$
|
|
5775
|
+
if (a.across < b.lo - EPS$8 || a.across > b.hi + EPS$8 || b.across < a.lo - EPS$8 || b.across > a.hi + EPS$8) continue;
|
|
5612
5776
|
parent[root(i)] = root(j);
|
|
5613
5777
|
}
|
|
5614
5778
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -5648,9 +5812,9 @@ function free(frame, boxes, horizontal, across, s0, s1) {
|
|
|
5648
5812
|
b.x,
|
|
5649
5813
|
b.w
|
|
5650
5814
|
];
|
|
5651
|
-
if (Math.min(s1, bs + bl) - Math.max(s0, bs) <= EPS$
|
|
5652
|
-
if (cs + cl <= across + EPS$
|
|
5653
|
-
if (cs >= across - EPS$
|
|
5815
|
+
if (Math.min(s1, bs + bl) - Math.max(s0, bs) <= EPS$8) continue;
|
|
5816
|
+
if (cs + cl <= across + EPS$8) lo = Math.max(lo, cs + cl);
|
|
5817
|
+
if (cs >= across - EPS$8) hi = Math.min(hi, cs);
|
|
5654
5818
|
}
|
|
5655
5819
|
return [lo, hi];
|
|
5656
5820
|
}
|
|
@@ -5661,8 +5825,8 @@ function want(a, b) {
|
|
|
5661
5825
|
if (inner(sb, sa)) return -tb;
|
|
5662
5826
|
return ta === tb ? 0 : Math.sign(ta - tb);
|
|
5663
5827
|
};
|
|
5664
|
-
const left = side(a.s0, b.s0, a.t0, b.t0, (x, y) => x > y + EPS$
|
|
5665
|
-
const right = side(a.s1, b.s1, a.t1, b.t1, (x, y) => x < y - EPS$
|
|
5828
|
+
const left = side(a.s0, b.s0, a.t0, b.t0, (x, y) => x > y + EPS$8);
|
|
5829
|
+
const right = side(a.s1, b.s1, a.t1, b.t1, (x, y) => x < y - EPS$8);
|
|
5666
5830
|
if (left !== 0 && right !== 0 && left !== right) return left;
|
|
5667
5831
|
return left || right;
|
|
5668
5832
|
}
|
|
@@ -5680,7 +5844,7 @@ function place(group, laneGap) {
|
|
|
5680
5844
|
const a = group[i];
|
|
5681
5845
|
const b = group[j];
|
|
5682
5846
|
if (a.pinned && b.pinned) {
|
|
5683
|
-
if (Math.abs(a.across - b.across) <= EPS$
|
|
5847
|
+
if (Math.abs(a.across - b.across) <= EPS$8) continue;
|
|
5684
5848
|
const [x, y] = a.across < b.across ? [i, j] : [j, i];
|
|
5685
5849
|
hard[x].push(y);
|
|
5686
5850
|
hardIn[y]++;
|
|
@@ -5698,7 +5862,7 @@ function place(group, laneGap) {
|
|
|
5698
5862
|
let best = -1;
|
|
5699
5863
|
for (let i = 0; i < n; i++) {
|
|
5700
5864
|
if (done[i] || hardIn[i] > 0) continue;
|
|
5701
|
-
if (best < 0 || softIn[i] < softIn[best] || softIn[i] === softIn[best] && group[i].across < group[best].across - EPS$
|
|
5865
|
+
if (best < 0 || softIn[i] < softIn[best] || softIn[i] === softIn[best] && group[i].across < group[best].across - EPS$8) best = i;
|
|
5702
5866
|
}
|
|
5703
5867
|
done[best] = true;
|
|
5704
5868
|
order.push(best);
|
|
@@ -5711,7 +5875,7 @@ function place(group, laneGap) {
|
|
|
5711
5875
|
let to = k + 1;
|
|
5712
5876
|
for (let m = k + 1; m < order.length; m++) {
|
|
5713
5877
|
const b = group[order[m]];
|
|
5714
|
-
if (b.pinned && Math.abs(b.across - a.across) <= EPS$
|
|
5878
|
+
if (b.pinned && Math.abs(b.across - a.across) <= EPS$8) order.splice(to++, 0, ...order.splice(m, 1));
|
|
5715
5879
|
}
|
|
5716
5880
|
k = to - 1;
|
|
5717
5881
|
}
|
|
@@ -5731,7 +5895,7 @@ function place(group, laneGap) {
|
|
|
5731
5895
|
const width = (run.length - 1) * s;
|
|
5732
5896
|
const mean = run.reduce((t, r) => t + group[r].across, 0) / run.length;
|
|
5733
5897
|
const first = Math.min(Math.max(mean - width / 2, lo + s), hi - s - width);
|
|
5734
|
-
run.forEach((r, m) => at[r] = room > EPS$
|
|
5898
|
+
run.forEach((r, m) => at[r] = room > EPS$8 && s > 0 ? first + m * s : group[r].across);
|
|
5735
5899
|
}
|
|
5736
5900
|
if (k < n) at[i] = group[i].across;
|
|
5737
5901
|
start = k + 1;
|
|
@@ -5741,7 +5905,7 @@ function place(group, laneGap) {
|
|
|
5741
5905
|
}
|
|
5742
5906
|
// src/routers/frames.ts
|
|
5743
5907
|
/** The tiny gap between the bounds and the band of a wall, so that a way along the bounds stays clear of the wall. */
|
|
5744
|
-
const EPS$
|
|
5908
|
+
const EPS$7 = 1e-6;
|
|
5745
5909
|
/**
|
|
5746
5910
|
* This function gives the inner routes of the inner edges (`splitFrames`). Each route stays in the bounds of its frame:
|
|
5747
5911
|
* the box of the frame, smaller by `frameInset`. It goes around the other nodes of the frame.
|
|
@@ -5866,7 +6030,7 @@ function makeRoom$1(f, chain, children, byId, inset, options) {
|
|
|
5866
6030
|
const margin = options.margin ?? 5;
|
|
5867
6031
|
const bounds = shrink(f.box, inset);
|
|
5868
6032
|
const nodes = roomNodes(f, chain, children, byId, bounds, options);
|
|
5869
|
-
const w = shrink(bounds, -(margin / 2 + EPS$
|
|
6033
|
+
const w = shrink(bounds, -(margin / 2 + EPS$7));
|
|
5870
6034
|
const t = 2 * margin + 1;
|
|
5871
6035
|
const walls = [
|
|
5872
6036
|
{
|
|
@@ -6225,7 +6389,7 @@ const LEVEL_LINK_DEFAULTS = Object.freeze({
|
|
|
6225
6389
|
plugInset: 6,
|
|
6226
6390
|
throughCost: 8
|
|
6227
6391
|
});
|
|
6228
|
-
const EPS$
|
|
6392
|
+
const EPS$6 = 1e-6;
|
|
6229
6393
|
/**
|
|
6230
6394
|
* This function removes the repeated points, the points in the middle of a straight run,
|
|
6231
6395
|
* and the points where the way turns back on itself.
|
|
@@ -6240,15 +6404,15 @@ function tidy$1(p) {
|
|
|
6240
6404
|
function tidyPoints(p) {
|
|
6241
6405
|
const out = [];
|
|
6242
6406
|
for (const q of p) {
|
|
6243
|
-
if (out.length > 0 && dist(q, out[out.length - 1]) <= EPS$
|
|
6407
|
+
if (out.length > 0 && dist(q, out[out.length - 1]) <= EPS$6) continue;
|
|
6244
6408
|
while (out.length >= 2) {
|
|
6245
6409
|
const a = out[out.length - 2];
|
|
6246
6410
|
const b = out[out.length - 1];
|
|
6247
6411
|
const cross = (b.x - a.x) * (q.y - b.y) - (b.y - a.y) * (q.x - b.x);
|
|
6248
|
-
if (Math.abs(cross) > EPS$
|
|
6412
|
+
if (Math.abs(cross) > EPS$6 * (1 + dist(a, b) * dist(b, q))) break;
|
|
6249
6413
|
out.pop();
|
|
6250
6414
|
}
|
|
6251
|
-
if (out.length > 0 && dist(q, out[out.length - 1]) <= EPS$
|
|
6415
|
+
if (out.length > 0 && dist(q, out[out.length - 1]) <= EPS$6) continue;
|
|
6252
6416
|
out.push(q);
|
|
6253
6417
|
}
|
|
6254
6418
|
return out;
|
|
@@ -6621,7 +6785,7 @@ function freeSpans(lo, hi, covered) {
|
|
|
6621
6785
|
if (x >= hi) break;
|
|
6622
6786
|
}
|
|
6623
6787
|
if (x < hi) out.push([x, hi]);
|
|
6624
|
-
return out.filter(([a, b]) => b - a > EPS$
|
|
6788
|
+
return out.filter(([a, b]) => b - a > EPS$6);
|
|
6625
6789
|
}
|
|
6626
6790
|
/**
|
|
6627
6791
|
* This function gives the shortest way between the free plugs of the two nodes, or `undefined` when the second corner graph has none.
|
|
@@ -6753,7 +6917,7 @@ function squarePull(p, obstacles, pad, first, last, lookahead = 16) {
|
|
|
6753
6917
|
out.push(...step.legs);
|
|
6754
6918
|
const end = out[out.length - 1];
|
|
6755
6919
|
const before = out[out.length - 2];
|
|
6756
|
-
axis = Math.abs(end.y - before.y) < EPS$
|
|
6920
|
+
axis = Math.abs(end.y - before.y) < EPS$6 ? "x" : Math.abs(end.x - before.x) < EPS$6 ? "y" : void 0;
|
|
6757
6921
|
i = step.j;
|
|
6758
6922
|
}
|
|
6759
6923
|
return out;
|
|
@@ -6763,7 +6927,7 @@ function squarePull(p, obstacles, pad, first, last, lookahead = 16) {
|
|
|
6763
6927
|
* Of two clear corners, it picks the corner that continues the axis `from` and arrives along the axis `to`.
|
|
6764
6928
|
*/
|
|
6765
6929
|
function square(a, b, obstacles, pad, from, to) {
|
|
6766
|
-
if (Math.abs(a.x - b.x) < EPS$
|
|
6930
|
+
if (Math.abs(a.x - b.x) < EPS$6 || Math.abs(a.y - b.y) < EPS$6) return obstacles.clear(a, b, pad) ? [b] : void 0;
|
|
6767
6931
|
const options = [{
|
|
6768
6932
|
c: {
|
|
6769
6933
|
x: b.x,
|
|
@@ -9421,7 +9585,7 @@ const ADAM_SCHEMA = {
|
|
|
9421
9585
|
/** The moment factors of Adam (Kingma and Ba 2015), as the record gives them. */
|
|
9422
9586
|
const BETA1 = .9;
|
|
9423
9587
|
const BETA2 = .999;
|
|
9424
|
-
const EPS$
|
|
9588
|
+
const EPS$5 = 1e-8;
|
|
9425
9589
|
/** The weight of the term that holds a leg near its first place. */
|
|
9426
9590
|
const HOLD = .05;
|
|
9427
9591
|
/** This function gives the point of the segment `ab` nearest to `p`. */
|
|
@@ -9642,7 +9806,7 @@ function adamRoutes(input, result, options = {}) {
|
|
|
9642
9806
|
m2[i] = BETA2 * m2[i] + .0010000000000000009 * g * g;
|
|
9643
9807
|
const mh = m1[i] / (1 - b1);
|
|
9644
9808
|
const vh = m2[i] / (1 - b2);
|
|
9645
|
-
shift[i] = Math.max(-2 * c, Math.min(2 * c, shift[i] - eta * mh / (Math.sqrt(vh) + EPS$
|
|
9809
|
+
shift[i] = Math.max(-2 * c, Math.min(2 * c, shift[i] - eta * mh / (Math.sqrt(vh) + EPS$5)));
|
|
9646
9810
|
}
|
|
9647
9811
|
}
|
|
9648
9812
|
const moved = new Set(legs.map((l) => l.route));
|
|
@@ -10704,7 +10868,7 @@ const LANE_TRACKS = [
|
|
|
10704
10868
|
"left-edge",
|
|
10705
10869
|
"free"
|
|
10706
10870
|
];
|
|
10707
|
-
const EPS$
|
|
10871
|
+
const EPS$4 = 1e-6;
|
|
10708
10872
|
const ROUNDS$1 = 8;
|
|
10709
10873
|
/**
|
|
10710
10874
|
* This function gives each link that runs along a gap its own lane in the gap. The lanes of a gap are `spacing` apart, around its middle line.
|
|
@@ -10729,7 +10893,7 @@ function laneGaps(items, links, options) {
|
|
|
10729
10893
|
})));
|
|
10730
10894
|
const counts = [];
|
|
10731
10895
|
for (const g of boardGaps(items, options.snap)) {
|
|
10732
|
-
if (g.width <= EPS$
|
|
10896
|
+
if (g.width <= EPS$4) continue;
|
|
10733
10897
|
const across = g.axis;
|
|
10734
10898
|
const along = g.axis === "x" ? "y" : "x";
|
|
10735
10899
|
const lo = g.at - g.width;
|
|
@@ -10740,8 +10904,8 @@ function laneGaps(items, links, options) {
|
|
|
10740
10904
|
for (let i = 2; i <= p.length - 2; i++) {
|
|
10741
10905
|
const a = p[i - 1];
|
|
10742
10906
|
const b = p[i];
|
|
10743
|
-
if (Math.abs(a[across] - b[across]) > EPS$
|
|
10744
|
-
if (Math.abs(a[along] - b[along]) <= EPS$
|
|
10907
|
+
if (Math.abs(a[across] - b[across]) > EPS$4 || a[across] <= lo + EPS$4 || a[across] >= hi - EPS$4) continue;
|
|
10908
|
+
if (Math.abs(a[along] - b[along]) <= EPS$4) continue;
|
|
10745
10909
|
const side = (q, r) => Math.sign(r[across] - q[across]);
|
|
10746
10910
|
pieces.push({
|
|
10747
10911
|
link: li,
|
|
@@ -10817,7 +10981,7 @@ function leftEdgeLanes(list, constrained) {
|
|
|
10817
10981
|
const now = [];
|
|
10818
10982
|
let end = -Infinity;
|
|
10819
10983
|
for (const i of byStart) {
|
|
10820
|
-
if (lane[i] >= 0 || wait[i] > 0 || list[i].lo < end - EPS$
|
|
10984
|
+
if (lane[i] >= 0 || wait[i] > 0 || list[i].lo < end - EPS$4) continue;
|
|
10821
10985
|
now.push(i);
|
|
10822
10986
|
end = list[i].hi;
|
|
10823
10987
|
}
|
|
@@ -10840,15 +11004,15 @@ function density(list) {
|
|
|
10840
11004
|
}
|
|
10841
11005
|
return most;
|
|
10842
11006
|
}
|
|
10843
|
-
const overlaps = (P, Q) => Math.min(P.hi, Q.hi) - Math.max(P.lo, Q.lo) > EPS$
|
|
11007
|
+
const overlaps = (P, Q) => Math.min(P.hi, Q.hi) - Math.max(P.lo, Q.lo) > EPS$4;
|
|
10844
11008
|
/**
|
|
10845
11009
|
* This function counts the crossings when the piece `P` is on the near side of the piece `Q`.
|
|
10846
11010
|
* A turn of `P` to the far side crosses `Q` when it is inside the span of `Q`. A turn of `Q` to the near side crosses `P` in the same way.
|
|
10847
11011
|
*/
|
|
10848
11012
|
function cost$1(P, Q) {
|
|
10849
11013
|
let c = 0;
|
|
10850
|
-
for (const [y, s] of P.turns) if (s > 0 && y > Q.lo + EPS$
|
|
10851
|
-
for (const [y, s] of Q.turns) if (s < 0 && y > P.lo + EPS$
|
|
11014
|
+
for (const [y, s] of P.turns) if (s > 0 && y > Q.lo + EPS$4 && y < Q.hi - EPS$4) c++;
|
|
11015
|
+
for (const [y, s] of Q.turns) if (s < 0 && y > P.lo + EPS$4 && y < P.hi - EPS$4) c++;
|
|
10852
11016
|
return c;
|
|
10853
11017
|
}
|
|
10854
11018
|
/** This function gives the pieces of one gap in lane order, from the near side to the far side. */
|
|
@@ -11052,17 +11216,10 @@ function facingEnds(input) {
|
|
|
11052
11216
|
}
|
|
11053
11217
|
return out;
|
|
11054
11218
|
}
|
|
11055
|
-
// src/plugs/
|
|
11219
|
+
// src/plugs/walls.ts
|
|
11056
11220
|
/**
|
|
11057
|
-
* The plug
|
|
11058
|
-
* The order on the wall keeps the order of the far ends, so two routes do not cross at the wall. No plug drops.
|
|
11221
|
+
* The walls of the plug strategies `spread`, `leaders` and `assign`: one side of one node, its room, and the order of its far ends.
|
|
11059
11222
|
*/
|
|
11060
|
-
/** The defaults of the plug strategy `spread`. */
|
|
11061
|
-
const SPREAD_DEFAULTS = Object.freeze({
|
|
11062
|
-
plugGap: 8,
|
|
11063
|
-
inset: 6,
|
|
11064
|
-
rounds: 2
|
|
11065
|
-
});
|
|
11066
11223
|
/** This function gives the axis along a side. */
|
|
11067
11224
|
function alongOf(side) {
|
|
11068
11225
|
return side === "east" || side === "west" ? "y" : "x";
|
|
@@ -11111,6 +11268,17 @@ function keyOf$1(box, side, far) {
|
|
|
11111
11268
|
if (out >= 0) return p;
|
|
11112
11269
|
return along >= 0 ? 2 - p : -2 - p;
|
|
11113
11270
|
}
|
|
11271
|
+
// src/plugs/spread/index.ts
|
|
11272
|
+
/**
|
|
11273
|
+
* The plug strategy `spread` (PLUG-SPREAD): the free plugs of each wall share the room of that wall with a minimum gap.
|
|
11274
|
+
* The order on the wall keeps the order of the far ends, so two routes do not cross at the wall. No plug drops.
|
|
11275
|
+
*/
|
|
11276
|
+
/** The defaults of the plug strategy `spread`. */
|
|
11277
|
+
const SPREAD_DEFAULTS = Object.freeze({
|
|
11278
|
+
plugGap: 8,
|
|
11279
|
+
inset: 6,
|
|
11280
|
+
rounds: 2
|
|
11281
|
+
});
|
|
11114
11282
|
/**
|
|
11115
11283
|
* This function gives the sort key of a far point for a po-leader (EDA-041): its place on the axis along the wall.
|
|
11116
11284
|
* A far point behind the wall gets the key of `keyOf` with a large shift, so it goes to an end of the wall.
|
|
@@ -11156,6 +11324,7 @@ function placeWall(slots, fixed, lo, hi, gap, idealOf = (s) => s.ideal) {
|
|
|
11156
11324
|
part = Math.max(part, p);
|
|
11157
11325
|
parts[part].push(s);
|
|
11158
11326
|
}
|
|
11327
|
+
const ranged = slots.some((s) => s.range !== void 0);
|
|
11159
11328
|
parts.forEach((list, p) => {
|
|
11160
11329
|
if (list.length === 0) return;
|
|
11161
11330
|
const a = ends[p];
|
|
@@ -11166,6 +11335,21 @@ function placeWall(slots, fixed, lo, hi, gap, idealOf = (s) => s.ideal) {
|
|
|
11166
11335
|
const s = steps > 0 ? Math.max(0, Math.min(gap, (b - a) / steps)) : gap;
|
|
11167
11336
|
const lower = a + fa * s;
|
|
11168
11337
|
const upper = Math.max(lower, b - fb * s);
|
|
11338
|
+
if (ranged) {
|
|
11339
|
+
const span = list.map((x) => {
|
|
11340
|
+
if (!x.range) return [lower, upper];
|
|
11341
|
+
const lo = Math.max(lower, x.range[0]);
|
|
11342
|
+
const hi = Math.min(upper, x.range[1]);
|
|
11343
|
+
if (lo <= hi) return [lo, hi];
|
|
11344
|
+
const v = x.range[1] < lower ? lower : upper;
|
|
11345
|
+
return [v, v];
|
|
11346
|
+
});
|
|
11347
|
+
const at = placeInIntervals(list.map((x) => idealOf(x)), span.map((r) => r[0]), span.map((r) => r[1]), s);
|
|
11348
|
+
list.forEach((x, i) => {
|
|
11349
|
+
x.at = at[i];
|
|
11350
|
+
});
|
|
11351
|
+
return;
|
|
11352
|
+
}
|
|
11169
11353
|
const at = placeInOrder(list.map((x) => idealOf(x)), lower, upper, s);
|
|
11170
11354
|
list.forEach((x, i) => {
|
|
11171
11355
|
x.at = at[i];
|
|
@@ -11226,12 +11410,14 @@ function spreadWith(input, options = {}, leader) {
|
|
|
11226
11410
|
if (slots.has(key)) return key;
|
|
11227
11411
|
const side = port?.side ?? sideToward(node.box, toward);
|
|
11228
11412
|
const ideal = placePlug(node, end, toward).point[alongOf(side)];
|
|
11413
|
+
const range = rangeInterval(node.box, side, port, inset);
|
|
11229
11414
|
const slot = {
|
|
11230
11415
|
node,
|
|
11231
11416
|
side,
|
|
11232
11417
|
ideal,
|
|
11233
11418
|
rank: [port ? node.ports.indexOf(port) : -1, slots.size],
|
|
11234
|
-
at: ideal
|
|
11419
|
+
at: ideal,
|
|
11420
|
+
...range ? { range } : {}
|
|
11235
11421
|
};
|
|
11236
11422
|
slots.set(key, slot);
|
|
11237
11423
|
wallOf(node, side).slots.push(slot);
|
|
@@ -11280,6 +11466,467 @@ function spreadWith(input, options = {}, leader) {
|
|
|
11280
11466
|
target: resolve(x.target)
|
|
11281
11467
|
}));
|
|
11282
11468
|
}
|
|
11469
|
+
// src/plugs/assign/index.ts
|
|
11470
|
+
/**
|
|
11471
|
+
* The plug strategy `assign` (PLUG-ASSIGN): the plugs of each wall go to the intervals of their ends, with a least gap.
|
|
11472
|
+
* An interval is the range of the port (PORT-RANGE), or the room of the wall. The assignment is exact for the count of the ends in their intervals.
|
|
11473
|
+
*/
|
|
11474
|
+
/** The defaults of the plug strategy `assign`. */
|
|
11475
|
+
const ASSIGN_DEFAULTS = Object.freeze({
|
|
11476
|
+
plugGap: 8,
|
|
11477
|
+
inset: 6
|
|
11478
|
+
});
|
|
11479
|
+
/** The tolerance of the comparisons of places along a wall. */
|
|
11480
|
+
const EPS$3 = 1e-9;
|
|
11481
|
+
/** This function gives the index of the first value of the sorted list `list` that is `v` or more. */
|
|
11482
|
+
function lowerBound(list, v) {
|
|
11483
|
+
let a = 0;
|
|
11484
|
+
let b = list.length;
|
|
11485
|
+
while (a < b) {
|
|
11486
|
+
const mid = a + b >> 1;
|
|
11487
|
+
if (list[mid] < v) a = mid + 1;
|
|
11488
|
+
else b = mid;
|
|
11489
|
+
}
|
|
11490
|
+
return a;
|
|
11491
|
+
}
|
|
11492
|
+
/**
|
|
11493
|
+
* This function moves the place `p` out of the zones of the fixed plugs: the open intervals of the width `2·s` around each fixed plug.
|
|
11494
|
+
* The list `fixed` is sorted. The place only moves up.
|
|
11495
|
+
*/
|
|
11496
|
+
function pushOut(p, fixed, s) {
|
|
11497
|
+
for (const f of fixed) if (p > f - s + EPS$3 && p < f + s - EPS$3) p = f + s;
|
|
11498
|
+
return p;
|
|
11499
|
+
}
|
|
11500
|
+
/**
|
|
11501
|
+
* This function gives the gap of a wall with `n` plugs: `gap`, or the largest gap that lets all the plugs go in the room.
|
|
11502
|
+
* The plugs keep the gap to the fixed plugs too.
|
|
11503
|
+
*/
|
|
11504
|
+
function wallGap(n, fixed, lo, hi, gap) {
|
|
11505
|
+
if (n <= 1) return gap;
|
|
11506
|
+
if (fixed.length === 0) return Math.max(0, Math.min(gap, (hi - lo) / (n - 1)));
|
|
11507
|
+
const fits = (s) => {
|
|
11508
|
+
let p = lo;
|
|
11509
|
+
for (let c = 0; c < n; c++) {
|
|
11510
|
+
p = pushOut(p, fixed, s);
|
|
11511
|
+
if (p > hi + EPS$3) return false;
|
|
11512
|
+
p += s;
|
|
11513
|
+
}
|
|
11514
|
+
return true;
|
|
11515
|
+
};
|
|
11516
|
+
if (fits(gap)) return gap;
|
|
11517
|
+
let a = 0;
|
|
11518
|
+
let b = gap;
|
|
11519
|
+
for (let i = 0; i < 60; i++) {
|
|
11520
|
+
const mid = (a + b) / 2;
|
|
11521
|
+
if (fits(mid)) a = mid;
|
|
11522
|
+
else b = mid;
|
|
11523
|
+
}
|
|
11524
|
+
return Math.max(0, a - 1e-7);
|
|
11525
|
+
}
|
|
11526
|
+
/**
|
|
11527
|
+
* This function gives the plan of the ends of one wall in the order of their keys, with no crossing at the wall.
|
|
11528
|
+
* The plan has the most ends in their intervals that this order lets. The answer is exact for this order: a table of the least last place
|
|
11529
|
+
* for each count of ends in their intervals.
|
|
11530
|
+
*/
|
|
11531
|
+
function keyOrderPlan(order, win, fixed, lo, hi, s) {
|
|
11532
|
+
const n = order.length;
|
|
11533
|
+
const nf = fixed.length;
|
|
11534
|
+
const at = (i, j, c) => (i * (nf + 1) + j) * (n + 1) + c;
|
|
11535
|
+
const best = new Float64Array((n + 1) * (nf + 1) * (n + 1)).fill(Infinity);
|
|
11536
|
+
const step = new Int8Array(best.length);
|
|
11537
|
+
best[at(0, 0, 0)] = -Infinity;
|
|
11538
|
+
const relax = (k, v, how) => {
|
|
11539
|
+
if (v < best[k]) {
|
|
11540
|
+
best[k] = v;
|
|
11541
|
+
step[k] = how;
|
|
11542
|
+
}
|
|
11543
|
+
};
|
|
11544
|
+
for (let i = 0; i <= n; i++) for (let j = 0; j <= nf; j++) for (let c = 0; c <= i; c++) {
|
|
11545
|
+
const v = best[at(i, j, c)];
|
|
11546
|
+
if (v === Infinity) continue;
|
|
11547
|
+
const next = v === -Infinity ? -Infinity : v + s;
|
|
11548
|
+
if (j < nf && (v === -Infinity || v + s <= fixed[j] + EPS$3)) relax(at(i, j + 1, c), fixed[j], 0);
|
|
11549
|
+
if (i < n) {
|
|
11550
|
+
const w = win[order[i]];
|
|
11551
|
+
if (w) {
|
|
11552
|
+
const p = Math.max(w[0], next);
|
|
11553
|
+
if (p <= w[1] + EPS$3) relax(at(i + 1, j, c + 1), p, 1);
|
|
11554
|
+
}
|
|
11555
|
+
const q = Math.max(lo, next);
|
|
11556
|
+
if (q <= hi + EPS$3) relax(at(i + 1, j, c), q, 2);
|
|
11557
|
+
}
|
|
11558
|
+
}
|
|
11559
|
+
let c = n;
|
|
11560
|
+
while (c >= 0 && best[at(n, nf, c)] === Infinity) c--;
|
|
11561
|
+
if (c < 0) return void 0;
|
|
11562
|
+
const items = [];
|
|
11563
|
+
let i = n;
|
|
11564
|
+
let j = nf;
|
|
11565
|
+
while (i > 0 || j > 0) {
|
|
11566
|
+
const k = at(i, j, c);
|
|
11567
|
+
const how = step[k];
|
|
11568
|
+
if (how === 0) items.push({
|
|
11569
|
+
end: -1,
|
|
11570
|
+
anchored: true,
|
|
11571
|
+
at: fixed[--j]
|
|
11572
|
+
});
|
|
11573
|
+
else {
|
|
11574
|
+
items.push({
|
|
11575
|
+
end: order[--i],
|
|
11576
|
+
anchored: how === 1,
|
|
11577
|
+
at: best[k]
|
|
11578
|
+
});
|
|
11579
|
+
if (how === 1) c--;
|
|
11580
|
+
}
|
|
11581
|
+
}
|
|
11582
|
+
return items.reverse();
|
|
11583
|
+
}
|
|
11584
|
+
/**
|
|
11585
|
+
* This function gives the most ends of a wall that can have their plug in their interval, in any order. It also gives one plan with that count.
|
|
11586
|
+
* Each end without its plug in its interval still gets a plug in the room of the wall: a free plug.
|
|
11587
|
+
*
|
|
11588
|
+
* The plan comes from two facts. First, a plan can move each plug down until it touches its interval, the room, a fixed zone or the plug before it.
|
|
11589
|
+
* Thus each plug is at a start place plus a whole number of gaps. Second, a swap of two plugs makes the last plug of the plan the end with the latest interval end.
|
|
11590
|
+
* Then the ends with an interval start up to its place are before it, and the others after it. This split gives a table over the ends and two places (the recursion `count`).
|
|
11591
|
+
* The free plugs have the room as interval and the latest end. Thus they split the wall into parts, and a second table chains the parts.
|
|
11592
|
+
*/
|
|
11593
|
+
function bestPlan(order, win, ideals, fixed, lo, hi, s) {
|
|
11594
|
+
const n = order.length;
|
|
11595
|
+
const jobs = order.filter((e) => win[e] !== void 0).sort((a, b) => win[a][1] - win[b][1] || win[a][0] - win[b][0] || a - b);
|
|
11596
|
+
const r = jobs.length;
|
|
11597
|
+
const allowed = (t) => t >= lo - EPS$3 && t <= hi + EPS$3 && fixed.every((f) => t <= f - s + EPS$3 || t >= f + s - EPS$3);
|
|
11598
|
+
const starts = [
|
|
11599
|
+
lo,
|
|
11600
|
+
...jobs.map((e) => win[e][0]),
|
|
11601
|
+
...fixed.map((f) => f + s)
|
|
11602
|
+
];
|
|
11603
|
+
const raw = [];
|
|
11604
|
+
for (const b of starts) for (let q = 0; q <= n; q++) {
|
|
11605
|
+
const t = b + q * s;
|
|
11606
|
+
if (t > hi + EPS$3) break;
|
|
11607
|
+
if (allowed(t)) raw.push(t);
|
|
11608
|
+
if (s === 0) break;
|
|
11609
|
+
}
|
|
11610
|
+
raw.sort((a, b) => a - b);
|
|
11611
|
+
const T = [];
|
|
11612
|
+
for (const t of raw) if (T.length === 0 || t - T[T.length - 1] > EPS$3) T.push(t);
|
|
11613
|
+
const m = T.length;
|
|
11614
|
+
const id = (k, ui, vi) => (k * (m + 2) + ui + 1) * (m + 2) + vi + 1;
|
|
11615
|
+
const memo = /* @__PURE__ */ new Map();
|
|
11616
|
+
const pick = /* @__PURE__ */ new Map();
|
|
11617
|
+
const count = (k, ui, vi) => {
|
|
11618
|
+
if (k === 0) return 0;
|
|
11619
|
+
const key = id(k, ui, vi);
|
|
11620
|
+
const got = memo.get(key);
|
|
11621
|
+
if (got !== void 0) return got;
|
|
11622
|
+
const [a, b] = win[jobs[k - 1]];
|
|
11623
|
+
const u = ui < 0 ? -Infinity : T[ui];
|
|
11624
|
+
const v = vi >= m ? Infinity : T[vi];
|
|
11625
|
+
let most = count(k - 1, ui, vi);
|
|
11626
|
+
let choice = -1;
|
|
11627
|
+
if (a > u + EPS$3 && a <= v + EPS$3) {
|
|
11628
|
+
const from = Math.max(a, ui < 0 ? lo : u + s);
|
|
11629
|
+
const to = Math.min(b, vi >= m ? hi : v - s);
|
|
11630
|
+
for (let ti = lowerBound(T, from - EPS$3); ti < m && T[ti] <= to + EPS$3; ti++) {
|
|
11631
|
+
const got2 = 1 + count(k - 1, ui, ti) + count(k - 1, ti, vi);
|
|
11632
|
+
if (got2 > most) {
|
|
11633
|
+
most = got2;
|
|
11634
|
+
choice = ti;
|
|
11635
|
+
}
|
|
11636
|
+
}
|
|
11637
|
+
}
|
|
11638
|
+
memo.set(key, most);
|
|
11639
|
+
if (choice >= 0) pick.set(key, choice);
|
|
11640
|
+
return most;
|
|
11641
|
+
};
|
|
11642
|
+
let total = r === n && count(r, -1, m) === n ? n : -1;
|
|
11643
|
+
let bestQ = 0;
|
|
11644
|
+
let bestI = -1;
|
|
11645
|
+
const chain = [];
|
|
11646
|
+
const back = [];
|
|
11647
|
+
for (let q = 1; q <= n; q++) {
|
|
11648
|
+
const cur = new Float64Array(m).fill(-Infinity);
|
|
11649
|
+
const from = new Int32Array(m).fill(-1);
|
|
11650
|
+
for (let i = 0; i < m; i++) {
|
|
11651
|
+
if (q === 1) {
|
|
11652
|
+
cur[i] = count(r, -1, i);
|
|
11653
|
+
continue;
|
|
11654
|
+
}
|
|
11655
|
+
const prev = chain[q - 2];
|
|
11656
|
+
for (let h = 0; h < i; h++) {
|
|
11657
|
+
if (prev[h] === -Infinity || T[i] - T[h] < s - EPS$3) continue;
|
|
11658
|
+
const v = prev[h] + count(r, h, i);
|
|
11659
|
+
if (v > cur[i]) {
|
|
11660
|
+
cur[i] = v;
|
|
11661
|
+
from[i] = h;
|
|
11662
|
+
}
|
|
11663
|
+
}
|
|
11664
|
+
}
|
|
11665
|
+
chain.push(cur);
|
|
11666
|
+
back.push(from);
|
|
11667
|
+
for (let i = 0; i < m; i++) {
|
|
11668
|
+
if (cur[i] === -Infinity) continue;
|
|
11669
|
+
const a = cur[i] + count(r, i, m);
|
|
11670
|
+
if (a + q >= n && a > total) {
|
|
11671
|
+
total = a;
|
|
11672
|
+
bestQ = q;
|
|
11673
|
+
bestI = i;
|
|
11674
|
+
}
|
|
11675
|
+
}
|
|
11676
|
+
}
|
|
11677
|
+
const placed = /* @__PURE__ */ new Map();
|
|
11678
|
+
const place = (k, ui, vi) => {
|
|
11679
|
+
if (k === 0) return;
|
|
11680
|
+
const t = pick.get(id(k, ui, vi));
|
|
11681
|
+
if (t === void 0) return place(k - 1, ui, vi);
|
|
11682
|
+
placed.set(jobs[k - 1], T[t]);
|
|
11683
|
+
place(k - 1, ui, t);
|
|
11684
|
+
place(k - 1, t, vi);
|
|
11685
|
+
};
|
|
11686
|
+
const free = [];
|
|
11687
|
+
let ui = bestI;
|
|
11688
|
+
for (let q = bestQ; q >= 1; q--) {
|
|
11689
|
+
free.push(T[ui]);
|
|
11690
|
+
const h = back[q - 1][ui];
|
|
11691
|
+
place(r, h, ui);
|
|
11692
|
+
ui = h;
|
|
11693
|
+
}
|
|
11694
|
+
if (bestQ === 0) place(r, -1, m);
|
|
11695
|
+
else place(r, bestI, m);
|
|
11696
|
+
free.reverse();
|
|
11697
|
+
const rest = order.filter((e) => !placed.has(e));
|
|
11698
|
+
const slots = assignInOrder(rest, free);
|
|
11699
|
+
const items = [];
|
|
11700
|
+
for (const [e, p] of placed) items.push({
|
|
11701
|
+
end: e,
|
|
11702
|
+
anchored: true,
|
|
11703
|
+
at: p
|
|
11704
|
+
});
|
|
11705
|
+
rest.forEach((e, i) => items.push({
|
|
11706
|
+
end: e,
|
|
11707
|
+
anchored: false,
|
|
11708
|
+
at: slots[i]
|
|
11709
|
+
}));
|
|
11710
|
+
for (const f of fixed) items.push({
|
|
11711
|
+
end: -1,
|
|
11712
|
+
anchored: true,
|
|
11713
|
+
at: f
|
|
11714
|
+
});
|
|
11715
|
+
return items.sort((a, b) => a.at - b.at || (a.end < 0 ? -1 : b.end < 0 ? 1 : order.indexOf(a.end) - order.indexOf(b.end)));
|
|
11716
|
+
/** This function gives each end of `list` one of the sorted places `free`, in order. The sum of the squares of the moves from the ideal places is the least. */
|
|
11717
|
+
function assignInOrder(list, places) {
|
|
11718
|
+
const a = list.length;
|
|
11719
|
+
const b = places.length;
|
|
11720
|
+
const cost = (i, j) => (places[j] - ideals[list[i]]) ** 2;
|
|
11721
|
+
const g = Array.from({ length: a + 1 }, () => new Float64Array(b + 1).fill(Infinity));
|
|
11722
|
+
for (let j = 0; j <= b; j++) g[0][j] = 0;
|
|
11723
|
+
for (let i = 1; i <= a; i++) for (let j = i; j <= b; j++) g[i][j] = Math.min(g[i][j - 1], g[i - 1][j - 1] + cost(i - 1, j - 1));
|
|
11724
|
+
const out = new Array(a);
|
|
11725
|
+
let j = b;
|
|
11726
|
+
for (let i = a; i >= 1; i--) {
|
|
11727
|
+
while (j > i && g[i][j - 1] === g[i][j]) j--;
|
|
11728
|
+
out[i - 1] = places[j - 1];
|
|
11729
|
+
j--;
|
|
11730
|
+
}
|
|
11731
|
+
return out;
|
|
11732
|
+
}
|
|
11733
|
+
}
|
|
11734
|
+
/**
|
|
11735
|
+
* This function gives the plan of one wall (PLUG-ASSIGN). Each end has an interval on the axis along the wall. The plugs keep at least `gap` between two of them,
|
|
11736
|
+
* and between a plug and a fixed plug at a place of `fixed`. When the room is too short for all the plugs, the gap shrinks evenly. The plan has three goals, in this order:
|
|
11737
|
+
* 1. the most ends with their plug in their interval (exact).
|
|
11738
|
+
* 2. no crossing at the wall: the order of the keys, when that order lets the count of goal 1.
|
|
11739
|
+
* 3. the least sum of the squares of the moves from the ideal places, for the order and the ends of goals 1 and 2.
|
|
11740
|
+
*
|
|
11741
|
+
* An end that cannot get a plug in its interval still gets a plug in the room. When the order of the keys loses ends, the plugs swap their places
|
|
11742
|
+
* to come nearer to that order, while each end keeps its interval.
|
|
11743
|
+
*/
|
|
11744
|
+
function assignWall(ends, room, gap, fixed = []) {
|
|
11745
|
+
const n = ends.length;
|
|
11746
|
+
if (n === 0) return {
|
|
11747
|
+
at: [],
|
|
11748
|
+
anchored: [],
|
|
11749
|
+
gap
|
|
11750
|
+
};
|
|
11751
|
+
const [lo, hi] = room;
|
|
11752
|
+
const pins = [...fixed].sort((a, b) => a - b);
|
|
11753
|
+
let s = wallGap(n, pins, lo, hi, Math.max(0, gap));
|
|
11754
|
+
const win = ends.map((e) => {
|
|
11755
|
+
const a = Math.max(lo, e.lo);
|
|
11756
|
+
const b = Math.min(hi, e.hi);
|
|
11757
|
+
return a <= b + EPS$3 ? [a, Math.max(a, b)] : void 0;
|
|
11758
|
+
});
|
|
11759
|
+
const order = ends.map((_, i) => i).sort((a, b) => ends[a].key - ends[b].key || a - b);
|
|
11760
|
+
let items = keyOrderPlan(order, win, pins, lo, hi, s);
|
|
11761
|
+
if (!items) {
|
|
11762
|
+
s = 0;
|
|
11763
|
+
items = keyOrderPlan(order, win, pins, lo, hi, s);
|
|
11764
|
+
}
|
|
11765
|
+
const inKey = items.filter((x) => x.end >= 0 && x.anchored).length;
|
|
11766
|
+
if (inKey < win.filter((w) => w !== void 0).length && inKey < unionCap(win, pins, lo, hi, s, n)) {
|
|
11767
|
+
const best = bestPlan(order, win, ends.map((e) => e.ideal), pins, lo, hi, s);
|
|
11768
|
+
if (best.filter((x) => x.end >= 0 && x.anchored).length > inKey) items = untangle(best, ends, win);
|
|
11769
|
+
}
|
|
11770
|
+
const span = items.map((x) => x.end < 0 ? [x.at, x.at] : x.anchored ? win[x.end] : [lo, hi]);
|
|
11771
|
+
const placed = placeInIntervals(items.map((x) => x.end < 0 ? x.at : ends[x.end].ideal), span.map((v) => v[0]), span.map((v) => v[1]), s);
|
|
11772
|
+
const at = new Array(n);
|
|
11773
|
+
items.forEach((x, i) => {
|
|
11774
|
+
if (x.end >= 0) at[x.end] = placed[i];
|
|
11775
|
+
});
|
|
11776
|
+
return {
|
|
11777
|
+
at,
|
|
11778
|
+
anchored: ends.map((e, i) => at[i] >= e.lo - 1e-7 && at[i] <= e.hi + 1e-7 && win[i] !== void 0),
|
|
11779
|
+
gap: s
|
|
11780
|
+
};
|
|
11781
|
+
}
|
|
11782
|
+
/** This function gives the most plugs with the gap `s` in the union of the intervals, out of the fixed zones, and at most `n`. It is a bound of goal 1. */
|
|
11783
|
+
function unionCap(win, fixed, lo, hi, s, n) {
|
|
11784
|
+
const parts = win.filter((w) => w !== void 0).sort((a, b) => a[0] - b[0]);
|
|
11785
|
+
let count = 0;
|
|
11786
|
+
let p = -Infinity;
|
|
11787
|
+
for (const [a, b] of parts) {
|
|
11788
|
+
let v = Math.max(a, p, lo);
|
|
11789
|
+
for (;;) {
|
|
11790
|
+
v = pushOut(v, fixed, s);
|
|
11791
|
+
if (v > b + EPS$3 || v > hi + EPS$3 || count >= n) break;
|
|
11792
|
+
count++;
|
|
11793
|
+
p = v + s;
|
|
11794
|
+
v = p;
|
|
11795
|
+
if (s === 0) return n;
|
|
11796
|
+
}
|
|
11797
|
+
}
|
|
11798
|
+
return count;
|
|
11799
|
+
}
|
|
11800
|
+
/**
|
|
11801
|
+
* This function swaps the places of two neighbours of a plan when their keys are in the wrong order, and each end keeps its interval.
|
|
11802
|
+
* Thus the plan comes nearer to the order of the keys. Each swap removes one inversion, so the loop ends.
|
|
11803
|
+
*/
|
|
11804
|
+
function untangle(items, ends, win) {
|
|
11805
|
+
const own = items.filter((x) => x.end >= 0);
|
|
11806
|
+
const ok = (x, p) => !x.anchored || p >= win[x.end][0] - EPS$3 && p <= win[x.end][1] + EPS$3;
|
|
11807
|
+
for (let changed = true, rounds = 0; changed && rounds <= own.length * own.length; rounds++) {
|
|
11808
|
+
changed = false;
|
|
11809
|
+
for (let i = 0; i + 1 < own.length; i++) {
|
|
11810
|
+
const x = own[i];
|
|
11811
|
+
const y = own[i + 1];
|
|
11812
|
+
if (ends[x.end].key <= ends[y.end].key) continue;
|
|
11813
|
+
if (!ok(x, y.at) || !ok(y, x.at)) continue;
|
|
11814
|
+
const t = x.at;
|
|
11815
|
+
x.at = y.at;
|
|
11816
|
+
y.at = t;
|
|
11817
|
+
own[i] = y;
|
|
11818
|
+
own[i + 1] = x;
|
|
11819
|
+
changed = true;
|
|
11820
|
+
}
|
|
11821
|
+
}
|
|
11822
|
+
return items.sort((a, b) => a.at - b.at || (a.end < 0 ? -1 : b.end < 0 ? 1 : ends[a.end].key - ends[b.end].key));
|
|
11823
|
+
}
|
|
11824
|
+
/**
|
|
11825
|
+
* This function gives the plugs of the plug strategy `assign` (PLUG-ASSIGN). A fixed plug stays at its point, and a plug with a side stays on that side.
|
|
11826
|
+
* Each free plug goes on the side that faces the other end (`sideToward`). Each end of a wall has an interval: the range of its port, or the room of the wall.
|
|
11827
|
+
* Then `assignWall` places the plugs of each wall, with at least `plugGap` between two of them. The ends of one port share one plug.
|
|
11828
|
+
*
|
|
11829
|
+
* The output has one entry for each edge with two known nodes, in the order of the edges.
|
|
11830
|
+
*/
|
|
11831
|
+
function assignEnds(input, options = {}) {
|
|
11832
|
+
const { graph } = input;
|
|
11833
|
+
const gap = options.plugGap ?? ASSIGN_DEFAULTS.plugGap;
|
|
11834
|
+
const inset = options.inset ?? ASSIGN_DEFAULTS.inset;
|
|
11835
|
+
const byId = nodeIndex(graph);
|
|
11836
|
+
const slots = /* @__PURE__ */ new Map();
|
|
11837
|
+
const walls = /* @__PURE__ */ new Map();
|
|
11838
|
+
const wallOf = (node, side) => {
|
|
11839
|
+
const key = JSON.stringify([node.id, side]);
|
|
11840
|
+
let wall = walls.get(key);
|
|
11841
|
+
if (!wall) {
|
|
11842
|
+
const fixed = [];
|
|
11843
|
+
for (const p of node.ports ?? []) {
|
|
11844
|
+
const at = portOffset(node.box, p);
|
|
11845
|
+
if (at === void 0) continue;
|
|
11846
|
+
const point = {
|
|
11847
|
+
x: node.box.x + at.x,
|
|
11848
|
+
y: node.box.y + at.y
|
|
11849
|
+
};
|
|
11850
|
+
if ((p.side ?? nearestSide(node.box, point)) === side) fixed.push(point[alongOf(side)]);
|
|
11851
|
+
}
|
|
11852
|
+
walls.set(key, wall = {
|
|
11853
|
+
node,
|
|
11854
|
+
side,
|
|
11855
|
+
slots: [],
|
|
11856
|
+
fixed
|
|
11857
|
+
});
|
|
11858
|
+
}
|
|
11859
|
+
return wall;
|
|
11860
|
+
};
|
|
11861
|
+
const plugOf = (node, end, far) => {
|
|
11862
|
+
const toward = center(far.box);
|
|
11863
|
+
const port = end.port === void 0 ? void 0 : node.ports?.find((p) => p.id === end.port);
|
|
11864
|
+
if (port && portOffset(node.box, port) !== void 0) return placePlug(node, end, toward);
|
|
11865
|
+
const key = port ? JSON.stringify([node.id, port.id]) : JSON.stringify([node.id, slots.size]);
|
|
11866
|
+
if (slots.has(key)) return key;
|
|
11867
|
+
const side = port?.side ?? sideToward(node.box, toward);
|
|
11868
|
+
const ideal = placePlug(node, end, toward).point[alongOf(side)];
|
|
11869
|
+
const range = rangeInterval(node.box, side, port, inset);
|
|
11870
|
+
const slot = {
|
|
11871
|
+
node,
|
|
11872
|
+
side,
|
|
11873
|
+
ideal,
|
|
11874
|
+
at: ideal,
|
|
11875
|
+
...range ? { range } : {}
|
|
11876
|
+
};
|
|
11877
|
+
slots.set(key, slot);
|
|
11878
|
+
wallOf(node, side).slots.push(slot);
|
|
11879
|
+
return key;
|
|
11880
|
+
};
|
|
11881
|
+
const ends = [];
|
|
11882
|
+
for (const e of graph.edges) {
|
|
11883
|
+
const s = byId.get(e.source.node);
|
|
11884
|
+
const t = byId.get(e.target.node);
|
|
11885
|
+
if (!s || !t) continue;
|
|
11886
|
+
const source = plugOf(s, e.source, t);
|
|
11887
|
+
const target = plugOf(t, e.target, s);
|
|
11888
|
+
for (const [own, far] of [[source, target], [target, source]]) {
|
|
11889
|
+
const slot = typeof own === "string" ? slots.get(own) : void 0;
|
|
11890
|
+
if (slot && slot.far === void 0) slot.far = far;
|
|
11891
|
+
}
|
|
11892
|
+
ends.push({
|
|
11893
|
+
edge: e.id,
|
|
11894
|
+
source,
|
|
11895
|
+
target
|
|
11896
|
+
});
|
|
11897
|
+
}
|
|
11898
|
+
const farPoint = (s) => {
|
|
11899
|
+
const far = s.far;
|
|
11900
|
+
if (typeof far !== "string") return far.point;
|
|
11901
|
+
const f = slots.get(far);
|
|
11902
|
+
return pointAt$1(f.node.box, f.side, f.ideal);
|
|
11903
|
+
};
|
|
11904
|
+
for (const wall of walls.values()) {
|
|
11905
|
+
const room = roomOf(wall.node.box, wall.side, inset);
|
|
11906
|
+
const plan = assignWall(wall.slots.map((s) => ({
|
|
11907
|
+
lo: s.range?.[0] ?? room[0],
|
|
11908
|
+
hi: s.range?.[1] ?? room[1],
|
|
11909
|
+
ideal: s.ideal,
|
|
11910
|
+
key: keyOf$1(wall.node.box, wall.side, farPoint(s))
|
|
11911
|
+
})), room, gap, wall.fixed);
|
|
11912
|
+
wall.slots.forEach((s, i) => {
|
|
11913
|
+
s.at = plan.at[i];
|
|
11914
|
+
});
|
|
11915
|
+
}
|
|
11916
|
+
const resolve = (p) => {
|
|
11917
|
+
if (typeof p !== "string") return p;
|
|
11918
|
+
const s = slots.get(p);
|
|
11919
|
+
return {
|
|
11920
|
+
point: pointAt$1(s.node.box, s.side, s.at),
|
|
11921
|
+
normal: SIDE_NORMAL[s.side]
|
|
11922
|
+
};
|
|
11923
|
+
};
|
|
11924
|
+
return ends.map((x) => ({
|
|
11925
|
+
edge: x.edge,
|
|
11926
|
+
source: resolve(x.source),
|
|
11927
|
+
target: resolve(x.target)
|
|
11928
|
+
}));
|
|
11929
|
+
}
|
|
11283
11930
|
// src/plugs/leaders/index.ts
|
|
11284
11931
|
/** The values of `LeaderType`. */
|
|
11285
11932
|
const LEADER_TYPES = Object.freeze([
|
|
@@ -26927,6 +27574,25 @@ const SPREAD_SCHEMA = {
|
|
|
26927
27574
|
describe: "The passes that sort each wall again by the new places of the far ends."
|
|
26928
27575
|
}
|
|
26929
27576
|
};
|
|
27577
|
+
/** The declarations of the options of the plug strategy `assign` (PLUG-ASSIGN). */
|
|
27578
|
+
const ASSIGN_SCHEMA = {
|
|
27579
|
+
plugGap: {
|
|
27580
|
+
type: "number",
|
|
27581
|
+
min: 0,
|
|
27582
|
+
max: 24,
|
|
27583
|
+
step: 1,
|
|
27584
|
+
default: 8,
|
|
27585
|
+
describe: "The least gap between two plugs of one wall. On a short wall, the gap shrinks evenly."
|
|
27586
|
+
},
|
|
27587
|
+
inset: {
|
|
27588
|
+
type: "number",
|
|
27589
|
+
min: 0,
|
|
27590
|
+
max: 12,
|
|
27591
|
+
step: 1,
|
|
27592
|
+
default: 6,
|
|
27593
|
+
describe: "A plug stays this far from the corners of its wall."
|
|
27594
|
+
}
|
|
27595
|
+
};
|
|
26930
27596
|
/** The declarations of the options of the whole strategy `pipeline`. */
|
|
26931
27597
|
const PIPELINE_SCHEMA = {
|
|
26932
27598
|
router: {
|
|
@@ -28862,6 +29528,14 @@ const plugStrategies = Object.freeze({
|
|
|
28862
29528
|
defaults: { ...LEADER_DEFAULTS },
|
|
28863
29529
|
schema: LEADER_SCHEMA,
|
|
28864
29530
|
run: (input, o) => leaderEnds(input, o)
|
|
29531
|
+
}),
|
|
29532
|
+
assign: defineStrategy({
|
|
29533
|
+
step: "plugs",
|
|
29534
|
+
name: "assign",
|
|
29535
|
+
describe: "PLUG-ASSIGN. The plugs of each wall go into the ranges of their ports with a minimum gap. The most ends are in their range, then the order of the far ends.",
|
|
29536
|
+
defaults: { ...ASSIGN_DEFAULTS },
|
|
29537
|
+
schema: ASSIGN_SCHEMA,
|
|
29538
|
+
run: (input, o) => assignEnds(input, o)
|
|
28865
29539
|
})
|
|
28866
29540
|
});
|
|
28867
29541
|
/** The built-in level rules: the strategies of the step `levels`. The router `sections` makes its zoom levels with its option `level`. */
|
|
@@ -29008,6 +29682,42 @@ function sideOf(plug, node) {
|
|
|
29008
29682
|
for (const [side, n] of Object.entries(SIDE_NORMAL)) if (n.x === plug.normal.x && n.y === plug.normal.y) return side;
|
|
29009
29683
|
return nearestSide(node.box, plug.point);
|
|
29010
29684
|
}
|
|
29685
|
+
/**
|
|
29686
|
+
* This function moves the new fixed ports of a side of a node into their ranges (PORT-RANGE). It does this when one port is out of its range.
|
|
29687
|
+
* The ports of the side keep their order, and two of them keep at least `gap` (`placeInIntervals`). A side with each port in its range does not change.
|
|
29688
|
+
*/
|
|
29689
|
+
function keepInRanges(node, ports, gap, inset) {
|
|
29690
|
+
const bySide = /* @__PURE__ */ new Map();
|
|
29691
|
+
for (const p of ports.values()) {
|
|
29692
|
+
const list = bySide.get(p.side);
|
|
29693
|
+
if (list) list.push(p);
|
|
29694
|
+
else bySide.set(p.side, [p]);
|
|
29695
|
+
}
|
|
29696
|
+
const box = node.box;
|
|
29697
|
+
for (const [side, list] of bySide) {
|
|
29698
|
+
const along = alongAxis(side);
|
|
29699
|
+
const v = (p) => p.at[along] + (along === "y" ? box.y : box.x);
|
|
29700
|
+
if (!list.some((p) => {
|
|
29701
|
+
const r = rangeInterval(box, side, p, inset);
|
|
29702
|
+
return r !== void 0 && (v(p) < r[0] - 1e-6 || v(p) > r[1] + 1e-6);
|
|
29703
|
+
})) continue;
|
|
29704
|
+
const start = along === "y" ? box.y : box.x;
|
|
29705
|
+
const len = along === "y" ? box.h : box.w;
|
|
29706
|
+
const sorted = [...list].sort((a, b) => v(a) - v(b));
|
|
29707
|
+
const span = sorted.map((p) => rangeInterval(box, side, p, inset) ?? [start, start + len]);
|
|
29708
|
+
const at = placeInIntervals(sorted.map(v), span.map((r) => r[0]), span.map((r) => r[1]), gap);
|
|
29709
|
+
sorted.forEach((p, i) => {
|
|
29710
|
+
const point = {
|
|
29711
|
+
...p.at,
|
|
29712
|
+
[along]: at[i] - start
|
|
29713
|
+
};
|
|
29714
|
+
ports.set(p.id, {
|
|
29715
|
+
...p,
|
|
29716
|
+
at: point
|
|
29717
|
+
});
|
|
29718
|
+
});
|
|
29719
|
+
}
|
|
29720
|
+
}
|
|
29011
29721
|
/** This function gives an id that no port of the node has, from `base`. */
|
|
29012
29722
|
function freeId(taken, base) {
|
|
29013
29723
|
let id = base;
|
|
@@ -29022,6 +29732,7 @@ function freeId(taken, base) {
|
|
|
29022
29732
|
*
|
|
29023
29733
|
* The rule sees the graph of `corners`: the plugs of `resolvePorts`, without the inner edges of the frames.
|
|
29024
29734
|
* The rule is a strategy of the step `plugs`, or the name of one in the registry.
|
|
29735
|
+
* A new fixed port with a `range` is in its range (PORT-RANGE). When the rule gives a plug out of the range, the new plugs of that side move into their ranges.
|
|
29025
29736
|
* The output is a new graph. The function does not change the input.
|
|
29026
29737
|
*/
|
|
29027
29738
|
function fixPorts(graph, rule, options = {}) {
|
|
@@ -29090,6 +29801,16 @@ function fixPorts(graph, rule, options = {}) {
|
|
|
29090
29801
|
target
|
|
29091
29802
|
};
|
|
29092
29803
|
});
|
|
29804
|
+
const own = strategy.defaults;
|
|
29805
|
+
const given = options.plugOptions ?? {};
|
|
29806
|
+
const num = (a, b, c) => typeof a === "number" ? a : typeof b === "number" ? b : c;
|
|
29807
|
+
const gap = num(given.plugGap, own.plugGap, 0);
|
|
29808
|
+
const inset = num(given.inset, own.inset, 6);
|
|
29809
|
+
const ranges = options.ranges ?? (strategy.name === "assign" ? "rule" : "keep");
|
|
29810
|
+
for (const [id, m] of fixed) {
|
|
29811
|
+
const node = byId.get(id);
|
|
29812
|
+
if (node && ranges === "keep") keepInRanges(node, m, gap, inset);
|
|
29813
|
+
}
|
|
29093
29814
|
const nodes = graph.nodes.map((n) => {
|
|
29094
29815
|
const m = fixed.get(n.id);
|
|
29095
29816
|
const more = added.get(n.id);
|
|
@@ -31043,8 +31764,9 @@ function silhouette(graph, level) {
|
|
|
31043
31764
|
/**
|
|
31044
31765
|
* This function makes a seeded small change of a graph: one node moves by `boardUnit`, one edge goes and one new edge comes.
|
|
31045
31766
|
* The moved box keeps a gap of 4 units to the other boxes. The same graph and the same seed give the same change.
|
|
31767
|
+
* With `edges: false`, the change only moves the node (Z11). The moved node is the node of the full change with the same seed.
|
|
31046
31768
|
*/
|
|
31047
|
-
function changeGraph(graph, seed) {
|
|
31769
|
+
function changeGraph(graph, seed, options = {}) {
|
|
31048
31770
|
const R = rng(seed * 2654435761 + 97);
|
|
31049
31771
|
const n = graph.nodes.length;
|
|
31050
31772
|
const u = boardUnit(graph);
|
|
@@ -31082,7 +31804,7 @@ function changeGraph(graph, seed) {
|
|
|
31082
31804
|
let edges = [...graph.edges];
|
|
31083
31805
|
let removed;
|
|
31084
31806
|
let added;
|
|
31085
|
-
if (edges.length > 1) {
|
|
31807
|
+
if (edges.length > 1 && options.edges !== false) {
|
|
31086
31808
|
const j = Math.floor(R() * edges.length);
|
|
31087
31809
|
const gone = edges[j];
|
|
31088
31810
|
removed = gone.id;
|
|
@@ -31132,6 +31854,40 @@ function routeStability(graph, before, after, options = {}) {
|
|
|
31132
31854
|
moved: s.moved
|
|
31133
31855
|
};
|
|
31134
31856
|
}
|
|
31857
|
+
/**
|
|
31858
|
+
* This function measures the move response of a router (Z11 of MEAS0). `change` is a change of `changeGraph` with `edges: false`.
|
|
31859
|
+
* It gives `undefined` when no node moved. Above `sample` routes, a seeded sample serves, and the sum scales to all the routes.
|
|
31860
|
+
*/
|
|
31861
|
+
function moveResponse(graph, change, before, after, options = {}) {
|
|
31862
|
+
const node = change.moved;
|
|
31863
|
+
if (node === void 0) return void 0;
|
|
31864
|
+
const max = options.sample ?? 2e3;
|
|
31865
|
+
const prev = new Map(before.routes.map((r) => [r.edge, r.points]));
|
|
31866
|
+
const ends = new Map(graph.edges.map((e) => [e.id, e.source.node === node || e.target.node === node]));
|
|
31867
|
+
let routes = after.routes.filter((r) => prev.has(r.edge));
|
|
31868
|
+
const all = routes.length;
|
|
31869
|
+
if (routes.length > max) {
|
|
31870
|
+
const R = rng(options.seed ?? 1);
|
|
31871
|
+
routes = Array.from({ length: max }, () => routes[Math.floor(R() * routes.length)]);
|
|
31872
|
+
}
|
|
31873
|
+
const u = boardUnit(graph);
|
|
31874
|
+
const degree = graph.edges.filter((e) => ends.get(e.id) === true).length;
|
|
31875
|
+
let sum = 0;
|
|
31876
|
+
let far = 0;
|
|
31877
|
+
let spilled = 0;
|
|
31878
|
+
for (const r of routes) {
|
|
31879
|
+
const f = frechet(prev.get(r.edge), r.points);
|
|
31880
|
+
sum += f;
|
|
31881
|
+
if (ends.get(r.edge) === true) continue;
|
|
31882
|
+
far++;
|
|
31883
|
+
if (f > 1) spilled++;
|
|
31884
|
+
}
|
|
31885
|
+
const scale = routes.length > 0 ? all / routes.length : 0;
|
|
31886
|
+
return {
|
|
31887
|
+
gain: sum * scale / u / Math.max(1, degree),
|
|
31888
|
+
spill: far > 0 ? spilled / far : 0
|
|
31889
|
+
};
|
|
31890
|
+
}
|
|
31135
31891
|
// src/bench/measures/room.ts
|
|
31136
31892
|
/** Up to this number of boxes, `roomOrderFaults` examines each pair. */
|
|
31137
31893
|
const EXACT_PAIRS = 2e3;
|
|
@@ -31628,7 +32384,7 @@ function routeSeparation(routes, near = 4, maxAngle = 5) {
|
|
|
31628
32384
|
if (ink <= 0) return 0;
|
|
31629
32385
|
const grid = new Grid(Math.max(16, 4 * near));
|
|
31630
32386
|
legs.forEach((l, i) => grid.addSegment(i, l.a, l.b));
|
|
31631
|
-
const sin =
|
|
32387
|
+
const sin = parallelSine(maxAngle);
|
|
31632
32388
|
let close = 0;
|
|
31633
32389
|
legs.forEach((s, i) => {
|
|
31634
32390
|
const length = dist(s.a, s.b);
|
|
@@ -31653,6 +32409,97 @@ function routeSeparation(routes, near = 4, maxAngle = 5) {
|
|
|
31653
32409
|
});
|
|
31654
32410
|
return Math.min(1, close / ink);
|
|
31655
32411
|
}
|
|
32412
|
+
/** This function gives the sine of the largest angle between two legs that R12 and R16 count as parallel. */
|
|
32413
|
+
function parallelSine(maxAngle) {
|
|
32414
|
+
return Math.sin(maxAngle * Math.PI / 180);
|
|
32415
|
+
}
|
|
32416
|
+
/** The distance in units of the board up to which two parallel legs are neighbors for R16. It is 8 lane widths. */
|
|
32417
|
+
const MEASURE_BALANCE_REACH = 32;
|
|
32418
|
+
/**
|
|
32419
|
+
* This function gives the lane balance of the routes (R16 of MEAS0): the spread of the gaps between parallel routes.
|
|
32420
|
+
*
|
|
32421
|
+
* The legs are the legs of R12. For each leg `s`, its neighbor at each side is the nearest leg `t` of other edges with three properties.
|
|
32422
|
+
* It is within `maxAngle` degrees of parallel. Its projection overlaps `s`. Its distance at the middle of the overlap is less than `reach`.
|
|
32423
|
+
* Each neighbor pair gives a gap `g` with the weight `w`, the length of the overlap. A pair counts one time.
|
|
32424
|
+
* Two legs on one line have the gap 0.
|
|
32425
|
+
*
|
|
32426
|
+
* `cv = sqrt(Σ w (g − ḡ)² / Σ w) / ḡ`, with `ḡ = Σ w g / Σ w`. Lower is better. Routes without a neighbor pair give 0.
|
|
32427
|
+
* R12 counts the parallel ink that is too near. R16 counts uneven gaps, also when each gap is wide.
|
|
32428
|
+
*/
|
|
32429
|
+
function routeBalance(routes, reach = 32, maxAngle = 5) {
|
|
32430
|
+
const legs = legsOf(routes);
|
|
32431
|
+
const grid = new Grid(Math.max(16, reach));
|
|
32432
|
+
legs.forEach((l, i) => grid.addSegment(i, l.a, l.b));
|
|
32433
|
+
const sin = parallelSine(maxAngle);
|
|
32434
|
+
const gaps = /* @__PURE__ */ new Map();
|
|
32435
|
+
legs.forEach((s, i) => {
|
|
32436
|
+
const length = dist(s.a, s.b);
|
|
32437
|
+
if (length <= 0) return;
|
|
32438
|
+
const ux = (s.b.x - s.a.x) / length;
|
|
32439
|
+
const uy = (s.b.y - s.a.y) / length;
|
|
32440
|
+
const best = /* @__PURE__ */ new Map();
|
|
32441
|
+
grid.querySegment(s.a, s.b, reach, (j) => {
|
|
32442
|
+
const t = legs[j];
|
|
32443
|
+
if (j === i || t.edges === s.edges) return;
|
|
32444
|
+
const tx = t.b.x - t.a.x;
|
|
32445
|
+
const ty = t.b.y - t.a.y;
|
|
32446
|
+
const tl2 = tx * tx + ty * ty;
|
|
32447
|
+
const cross = ux * ty - uy * tx;
|
|
32448
|
+
if (tl2 <= 0 || cross * cross > sin * sin * tl2) return;
|
|
32449
|
+
const p = (t.a.x - s.a.x) * ux + (t.a.y - s.a.y) * uy;
|
|
32450
|
+
const q = (t.b.x - s.a.x) * ux + (t.b.y - s.a.y) * uy;
|
|
32451
|
+
const lo = Math.max(0, Math.min(p, q));
|
|
32452
|
+
const hi = Math.min(length, Math.max(p, q));
|
|
32453
|
+
if (hi - lo <= 1e-9) return;
|
|
32454
|
+
const m = (lo + hi) / 2;
|
|
32455
|
+
const px = s.a.x + ux * m;
|
|
32456
|
+
const py = s.a.y + uy * m;
|
|
32457
|
+
const k = ((px - t.a.x) * tx + (py - t.a.y) * ty) / tl2;
|
|
32458
|
+
const o = (t.a.x + tx * k - px) * -uy + (t.a.y + ty * k - py) * ux;
|
|
32459
|
+
const g = Math.abs(o);
|
|
32460
|
+
if (g >= reach) return;
|
|
32461
|
+
const side = o < -1e-9 ? -1 : 1;
|
|
32462
|
+
const now = best.get(side);
|
|
32463
|
+
if (!now || g < now.g) best.set(side, {
|
|
32464
|
+
j,
|
|
32465
|
+
g,
|
|
32466
|
+
w: hi - lo
|
|
32467
|
+
});
|
|
32468
|
+
});
|
|
32469
|
+
for (const n of best.values()) {
|
|
32470
|
+
const key = i < n.j ? `${i},${n.j}` : `${n.j},${i}`;
|
|
32471
|
+
if (!gaps.has(key)) gaps.set(key, {
|
|
32472
|
+
g: n.g,
|
|
32473
|
+
w: n.w
|
|
32474
|
+
});
|
|
32475
|
+
}
|
|
32476
|
+
});
|
|
32477
|
+
const list = [...gaps.values()];
|
|
32478
|
+
const W = list.reduce((sum, x) => sum + x.w, 0);
|
|
32479
|
+
if (list.length === 0 || W <= 0) return {
|
|
32480
|
+
cv: 0,
|
|
32481
|
+
low: 0,
|
|
32482
|
+
pairs: 0
|
|
32483
|
+
};
|
|
32484
|
+
const mean = list.reduce((sum, x) => sum + x.w * x.g, 0) / W;
|
|
32485
|
+
const variance = list.reduce((sum, x) => sum + x.w * (x.g - mean) ** 2, 0) / W;
|
|
32486
|
+
const sorted = [...list].sort((x, y) => x.g - y.g);
|
|
32487
|
+
let acc = 0;
|
|
32488
|
+
let median = sorted[sorted.length - 1].g;
|
|
32489
|
+
for (const x of sorted) {
|
|
32490
|
+
acc += x.w;
|
|
32491
|
+
if (acc >= W / 2) {
|
|
32492
|
+
median = x.g;
|
|
32493
|
+
break;
|
|
32494
|
+
}
|
|
32495
|
+
}
|
|
32496
|
+
const low = list.filter((x) => x.g < median / 2).reduce((sum, x) => sum + x.w, 0) / W;
|
|
32497
|
+
return {
|
|
32498
|
+
cv: mean > 0 ? Math.sqrt(variance) / mean : 0,
|
|
32499
|
+
low,
|
|
32500
|
+
pairs: list.length
|
|
32501
|
+
};
|
|
32502
|
+
}
|
|
31656
32503
|
/**
|
|
31657
32504
|
* This function gives the orthogonality of the routes (R14 of MEAS0): `orth = Σ L(legs within maxAngle degrees of an axis) / Σ_e L(r_e)`.
|
|
31658
32505
|
* Each route counts its own legs, also on a shared segment. The scale is 0 to 1, and higher is better for an orthogonal style.
|
|
@@ -32945,6 +33792,7 @@ function compareStep(step, graph, options = {}) {
|
|
|
32945
33792
|
let rows;
|
|
32946
33793
|
if (step === "router") {
|
|
32947
33794
|
const change = graph.nodes.length <= stabilityMax ? changeGraph(graph, seed) : void 0;
|
|
33795
|
+
const move = graph.nodes.length <= stabilityMax ? changeGraph(graph, seed, { edges: false }) : void 0;
|
|
32948
33796
|
rows = listStrategies(registry, "router").map((strategy) => {
|
|
32949
33797
|
if (graph.nodes.length > (strategy.maxNodes ?? Infinity)) return {
|
|
32950
33798
|
step,
|
|
@@ -32968,6 +33816,28 @@ function compareStep(step, graph, options = {}) {
|
|
|
32968
33816
|
values["Z10.max"] = s.max;
|
|
32969
33817
|
values["Z10.moved"] = s.moved;
|
|
32970
33818
|
}
|
|
33819
|
+
if (move) {
|
|
33820
|
+
const z = moveResponse(graph, move, result, router.route(move.graph), { seed });
|
|
33821
|
+
if (z) {
|
|
33822
|
+
values["Z11.gain"] = z.gain;
|
|
33823
|
+
values["Z11.spill"] = z.spill;
|
|
33824
|
+
}
|
|
33825
|
+
}
|
|
33826
|
+
if (change) {
|
|
33827
|
+
const given = own[strategy.name] ?? {};
|
|
33828
|
+
const base = typeof given.seed === "number" ? given.seed : strategy.defaults?.seed;
|
|
33829
|
+
if (typeof base === "number") {
|
|
33830
|
+
const s = routeStability(graph, result, asRouter(strategy, {
|
|
33831
|
+
...own[strategy.name],
|
|
33832
|
+
seed: base + 1
|
|
33833
|
+
}).route(graph), { seed });
|
|
33834
|
+
values["Z12.mean"] = s.mean;
|
|
33835
|
+
values["Z12.moved"] = s.moved;
|
|
33836
|
+
} else {
|
|
33837
|
+
values["Z12.mean"] = 0;
|
|
33838
|
+
values["Z12.moved"] = 0;
|
|
33839
|
+
}
|
|
33840
|
+
}
|
|
32971
33841
|
return {
|
|
32972
33842
|
step,
|
|
32973
33843
|
strategy: strategy.name,
|
|
@@ -33675,6 +34545,24 @@ const MEASURES = Object.freeze([
|
|
|
33675
34545
|
"higher",
|
|
33676
34546
|
false
|
|
33677
34547
|
],
|
|
34548
|
+
[
|
|
34549
|
+
"R16.cv",
|
|
34550
|
+
"R16",
|
|
34551
|
+
"route.balance.cv",
|
|
34552
|
+
"no unit",
|
|
34553
|
+
"lower",
|
|
34554
|
+
true,
|
|
34555
|
+
"The spread of the gaps between parallel routes: the standard deviation of the gaps over their mean. A value of 0 is even."
|
|
34556
|
+
],
|
|
34557
|
+
[
|
|
34558
|
+
"R16.low",
|
|
34559
|
+
"R16",
|
|
34560
|
+
"route.balance.low",
|
|
34561
|
+
"0 to 1",
|
|
34562
|
+
"lower",
|
|
34563
|
+
true,
|
|
34564
|
+
"The share of the parallel overlap with a gap less than half of the median gap."
|
|
34565
|
+
],
|
|
33678
34566
|
[
|
|
33679
34567
|
"ink",
|
|
33680
34568
|
"R1",
|
|
@@ -34039,6 +34927,42 @@ const MEASURES = Object.freeze([
|
|
|
34039
34927
|
"higher",
|
|
34040
34928
|
false
|
|
34041
34929
|
],
|
|
34930
|
+
[
|
|
34931
|
+
"Z11.gain",
|
|
34932
|
+
"Z11",
|
|
34933
|
+
"route.stability.move.gain",
|
|
34934
|
+
"no unit",
|
|
34935
|
+
"lower",
|
|
34936
|
+
false,
|
|
34937
|
+
"The movement of all the routes after one node moves by one unit, for each edge of that node. A value of 1 is a local response."
|
|
34938
|
+
],
|
|
34939
|
+
[
|
|
34940
|
+
"Z11.spill",
|
|
34941
|
+
"Z11",
|
|
34942
|
+
"route.stability.move.spill",
|
|
34943
|
+
"0 to 1",
|
|
34944
|
+
"lower",
|
|
34945
|
+
false,
|
|
34946
|
+
"The share of the routes of other nodes that move after one node moves by one unit. A value of 0 is a local response."
|
|
34947
|
+
],
|
|
34948
|
+
[
|
|
34949
|
+
"Z12.mean",
|
|
34950
|
+
"Z12",
|
|
34951
|
+
"route.stability.seed.mean",
|
|
34952
|
+
"units of the board",
|
|
34953
|
+
"lower",
|
|
34954
|
+
false,
|
|
34955
|
+
"The mean movement of the routes with the next seed of the strategy. A strategy without a seed has 0."
|
|
34956
|
+
],
|
|
34957
|
+
[
|
|
34958
|
+
"Z12.moved",
|
|
34959
|
+
"Z12",
|
|
34960
|
+
"route.stability.seed.moved",
|
|
34961
|
+
"0 to 1",
|
|
34962
|
+
"lower",
|
|
34963
|
+
false,
|
|
34964
|
+
"The share of the routes that move with the next seed of the strategy. A strategy without a seed has 0."
|
|
34965
|
+
],
|
|
34042
34966
|
[
|
|
34043
34967
|
"level-nesting",
|
|
34044
34968
|
"Z6",
|
|
@@ -37143,6 +38067,9 @@ function rowValues(step, graph, row, base) {
|
|
|
37143
38067
|
const open = openLanes(row.result);
|
|
37144
38068
|
values["R12.share"] = routeSeparation(routes);
|
|
37145
38069
|
values["R14.share"] = orthogonality(routes);
|
|
38070
|
+
const balance = routeBalance(routes);
|
|
38071
|
+
values["R16.cv"] = balance.cv;
|
|
38072
|
+
values["R16.low"] = balance.low;
|
|
37146
38073
|
values["B5.crossings"] = laneCrossings(open.graph);
|
|
37147
38074
|
values["B7.ratio"] = occupiedArea(routes, boardUnit(graph));
|
|
37148
38075
|
const runs = runProfile(open.graph);
|
|
@@ -38589,6 +39516,6 @@ const sharedStretchStrategy = defineStrategy({
|
|
|
38589
39516
|
name: "shared-stretch"
|
|
38590
39517
|
}).route(graph)
|
|
38591
39518
|
});
|
|
38592
|
-
export { ADAM_DEFAULTS, ADAM_SCHEMA, AMBIGUITY_GUARD_DEFAULTS, ANNEALING_DEFAULTS, ANNEALING_SCHEMA, ARC_SOURCES, AREA_DEFAULTS, AREA_WIDTHS, ATTRACTION_DEFAULTS, ATTRACTION_SCHEMA, BACKTRACK_MIN, BACKTRACK_SHARE, BALANCE_DEFAULTS, BALANCE_ENDS, BIPARTITE, BIPARTITE_LAYOUTS, BOARD_PORTFOLIO_DEFAULTS, BOARD_PORTFOLIO_SETTINGS, BREAK, BREAK_EVEN, BREAK_EVEN_DEFAULTS, BRONCHIAL_DEFAULTS, BRONCHIAL_SPLITS, BUILT_IN_STRATEGIES, BoundaryWalk, CANAL_DEFAULTS, CANAL_SCHEMA, CANDIDATE_SOURCES, CAP_SWEEP, CASES, CHANNEL_REACH, CLEARANCE_CAP, COMPARE_ALL_STEPS, COMPARE_STEPS, CONFLUENT_DEFAULTS, CONSENSUS_DEFAULTS, CONSENSUS_LINKAGES, CORRIDOR_DEFAULTS, COVERAGE_FAMILIES, CROSSBAR_DEFAULTS, CUBU_DEFAULTS, CURRICULUM_DEFAULTS, CURRICULUM_ORDERS, CURRICULUM_POOL, CURVE_TYPES, CUT_DEFAULTS, CornerGraph, DEFAULT_RNG, DENSE_GROUPS, DENSITY_KERNELS, DETAIL_DEFAULTS, DIFFUSION_DEFAULTS, DISTORTION_NEIGHBOURS, DIVIDED_DEFAULTS, EDGE_DISTANCES, EDGE_PATH_DEFAULTS, EXACT_CLASSES, EXACT_EDGES_PER_NODE, EXACT_V1, EXACT_V1_BOUNDS, EXACT_V1_BOUNDS_SIZES, EXACT_V1_SEEDS, EXACT_V1_SIZES, FAN_OUT, FDEB_DEFAULTS, FIREFLY_DEFAULTS, FIXTURES, FIXTURE_LAYOUTS, FIXTURE_LOCALITY, FLOW_CLUSTER_DEFAULTS, FLOW_FIELD_DEFAULTS, FRAME_ROWS, FRECHET_DEFAULTS, FRONT_OBJECTIVES, GAP_BASELINES, GAP_BOOTSTRAP, GAP_CAPS, GAP_DEFAULTS, GAP_RULES, GAP_VIEWS, GROUP_SCOPES, GROUP_SPINES, GROWTH_DEFAULTS, GROWTH_SWEEP, GUTTER_BEND_COST, Grid, HDBSCAN_DEFAULTS, HIERARCHY_DEFAULTS, HIERARCHY_GROUPS, HIGHWAYS_ENGINE, HIGHWAYS_FAMILIES, HIGHWAY_BASES, HIGHWAY_BASE_ROUTERS, HOUGH_DEFAULTS, HUB_ALLOCATIONS, HUB_ARC_DEFAULTS, HUB_CANDIDATES, HUB_CHAIN, HYSTERESIS_DEFAULTS, INTERCHANGE_BASES, INTERCHANGE_DEFAULTS, KDEEB_DEFAULTS, KD_DEFAULTS, KENDALL_EXACT, KNEE_DEFAULTS, KNEE_RULES, LANES_DEFAULTS, LANE_ORDERS, LANE_STRETCH_DEFAULTS, LANE_STRETCH_ORDERS, LANE_TRACKS, LEADER_DEFAULTS, LEADER_TYPES, LEVEL_HIGHWAY_DEFAULTS, LINKAGES, LINK_COMMUNITY_DEFAULTS, LOCAL_MESH, MANIFOLD_DEFAULTS, MANIFOLD_SIDES, MANY_GROUPS, MEASURES, MEASURE_LANE_WIDTH, MEET_DEFAULTS, MEMBER_FORMS, MESH_DEFAULTS, MINGLE_DEFAULTS, MIN_EFFECTS, MLSEB_DEFAULTS, MLS_FITS, MODULE_RULES, MOVE_NAMES, NESTED_DEFAULTS, OD_CELL_DEFAULTS, OUTSIDE_SLACK, Obstacles, PACKED_GRID, PICK, PIPELINE, PLAN_CHANGERS, PORTFOLIO_B1, PORTFOLIO_BANDS, PORTFOLIO_BASE_MEMBER, PORTFOLIO_CAPS, PORTFOLIO_FIT, PORTFOLIO_HASHES, PORTFOLIO_KS_API, PORTFOLIO_RULES, PORTFOLIO_SETS, POWER_DEFAULTS, PREFERENCE_DEFAULTS, PREFERENCE_FEATURES, PREFERENCE_PANEL, PROPOSED_RULES, P_HUB_DEFAULTS, QUICKBUNDLES_DEFAULTS, RECORD_EPS, REROUTE_DEFAULTS, REROUTE_SCHEMA, RESISTANCE_DEFAULTS, RIDGE_DEFAULTS, ROAD_CLASS_DEFAULTS, ROOM_FAMILIES, ROUTED_STEPS, ROUTERS, SAME_HIGHWAY, SBEB_DEFAULTS, SCALE_SPACE_DEFAULTS, SCREEN_FAMILY_BY, SCREEN_RULES, SCREEN_SETS, SCREEN_STEPS, SCREEN_V1, SCREEN_V2, SCREEN_V2_HELD_OUT, SCREEN_V3, SCREEN_V3_HELD_OUT, SCREEN_WRAPS, SEARCH_DEFAULTS, SEARCH_MOVES, SECTION_DEFAULTS, SELECT_DEFAULTS, SIDE_NORMAL, SKELETON_GROUPS, SKELETON_TARGETS, SLACK_SWEEP, SLOT_DEFAULTS, SLOT_KEYS, SMALL_CLUSTERED, SOFT_KEY_DEFAULTS, SPACING_LIMIT, SPARSE_LONG, SPECTRAL_DEFAULTS, SPIRAL_DEFAULTS, SPREAD_DEFAULTS, STABLE_ID_DEFAULTS, STEINER_DEFAULTS, STEINER_GROUPS, STEINER_METHODS, STEINER_METRICS, STEPS, STRATEGIES, STREET_DEFAULTS, STREET_SOURCES, STRETCH_DEFAULTS, STRETCH_SWEEP, STUB_DEFAULTS, SUITE_COLUMNS, SWARM_SEARCHES, SoftGraph, SplitTree, TERRITORY_DEFAULTS, TERRITORY_POINTS, THIN_BARS, TIGHT_DEFAULTS, TIGHT_FIRSTS, TIGHT_SCHEMA, TIGHT_TIES, TINY_UNIFORM, TOLERANCE, TRACING_DEFAULTS, TRACING_QUANTILES, TRACING_WEIGHTS, TRACLUS_DEFAULTS, TRAFFIC_RULES, TWO_HUBS, UNEVEN_SIZES, VENATION_BACKBONES, VENATION_DEFAULTS, WEISZFELD_DEFAULTS, WIDTH_SCALES, WSPD_DEFAULTS, WayFinder, ZIPPER_DEFAULTS, activationBase, activationReport, adamRouter, adamRoutes, adamStrategy, adjustedRandIndex, agreementOf, allSections, ambiguity, ambiguityGate, ambiguityPlan, annealWays, annealingRouter, annealingStrategy, arcCurve, arcsin, areaPlan, aroundBox, asRouter, attraction, attractionRouter, attractionStrategy, backboneLinks, backtrackOf, balance, balanceOf, balancePlan, basePlan, benchBendRoom, benchCurveStrategies, benchCurves, benchHighways, benchLevelRoom, benchOne, benchRoom, benchRun, benchTracks, bendCount, bendingEnergy, bicliqueGroups, bigGroups, boardGaps, boardPortfolio, boardUnit, boardWins, bootstrapMedian, boundsFamilyName, boxDisplacement, boxExit, boxPush, boxUnit, boxesOverlap, breakEvenGate, breakEvenPlan, bronchialPlan, buildSections, bundleStretch, bundledShare, byCollection, byDataGroup, canalHubs, canalRouter, canalStrategy, canalWays, candidateArcs, candidatePlan, candidateScore, canonicalJson, capSettings, caseSeed, cellSteps, center, chainClusters, changeGraph, changedDimensions, channelOverflows, channelWidth, characteristicPoints, checkFamilies, checkLevels, checkOptions, checkParents, checkPlan, checkPort, checkProperties, checkSchema, checkSections, clampOptions, clothoidCurve, clusters1d, coAssociation, collapseLinks, commonEdges, compareAnyStep, compareMeasure, compareSpec, compareStep, compatibility, compatibilityMatrix, confluentPlan, consensusGroups, consensusLabels, consensusPlan, controlChain, cornersRouter, corpusManifest, corridorPlan, countCrossings, countOverlaps, createFamilyRegistry, createRegistry, crossbarPlan, crossesItself, crossingAngle, crossingAngles, cubicAt, cubuPlan, curriculum, curvatureVariation, curveDeviation, curveFaults, curveJoints, curveOf, curveRuns, curveSpace, curveStrategies, curvesHash, cutGroups, cutShare, declaresFamily, defineStrategy, denseGroupsBoard, densityPlan, densityRidges, depthLevels, detailLevels, detailWidth, detourSpread, diamondAngle, diffusionPlan, dimensionAt, dimensionUnit, dist, distanceDistortion, distinctPoints, divideHighway, dividedPlan, documentHash, dominates, drawnSegments, edgeBlocks, edgeEnds, edgeLengths, edgePathPlan, edgePaths, edgePlugs, edgeResistance, enumDimension, exactBoard, exactFamily, exactGenerator, exactSeed, exactStretch, exactStretches, exercised, facingEnds, familyCell, familyKind, familyOf, familySeed, farLevel, farLinks, fdebLines, fdebPlan, fft, findStrategy, finderOf, fireflies, firstLines, fitPreferences, fixPorts, fixedPortPoint, fixtureGroupOptions, fixtureParams, fixtureRngSeed, fixtureSpecOf, flowClusterPlan, flowClusters, flowDistance, flowFieldPlan, fnv1a32, follow, formatActivation, formatBendRoom, formatCapped, formatCurves, formatFaults, formatFronts, formatGap, formatHighways, formatInput, formatLevelRoom, formatLevels, formatMeasureTime, formatPaired, formatRoom, formatRules, formatScreen, formatSections, formatSummaries, formatTable, formatTracks, frameRoutes, frechet, frechetBundles, frechetPlan, freeLines, g1Defect, g2Defect, gapBaselines, gapCap, gapClosed, gapLaneCounts, gapLanes, gapNames, gapPlan, gapValues, gateStrategy, getStrategy, goesOutAndBack, graphInput, greedyBicliques, greedyCrossbars, groupEdges, groupFill, groupRun, groupSettings, groupStability, groupStrategies, groupedPlan, growthPlan, growthSettings, guardBreaks, gutterRoutes, halfPower, hasCusp, hdbscanClusters, hdbscanLabels, hdbscanPlan, hierarchyPlan, highwayChurn, highwayCurve, highwayCurves, highwayEdits, highwayIdKeep, highwayMoves, highwayRouter, highwayRouterStrategy, highwayRouters, highwayStrategies, highwaysRegistry, houghLines, houghPeaks, houghPlan, hubArcPlan, hubCandidates, hubChainBoard, hysteresisGate, hysteresisPlan, inflate, inflectionCount, inflectionCurve, inflectionSector, inkSaved, innerPoints, inputGraph, inputId, interchangeCandidates, interchangePlan, isRoutedStep, itemOverlaps, itemSizes, jaccard, jaccardIndex, jogPeaks, joinReports, jsonSafe, kMeans, kdGroups, kdeebLines, kdeebPlan, keepMembers, kendallTau, keyGroups, keyedSections, keysPlan, kneeOf, kneePlan, labelGroups, laneArea, laneCrossings, laneFidelity, laneOrder, laneRoutes, laneSeparation, laneSettings, laneStretches, lanesPlan, lanesThrough, leaderEnds, leafGroups, lengthBetween, levelCut, levelGrouping, levelHighwayPlan, levelMeasures, levelPairs, levelRatio, levelRoom, levelStrategies, levelsOf, lineDensity, linePoint, linkAgreement, linkCommunities, linkCommunityGroups, linkCommunityPlan, linkDensity, listOptions, listStrategies, madeUpPairs, makeFixture, makeRoom, manifestHash, manifoldPlan, manyGroupsBoard, matchHighways, maxStretch, mdf, meanLine, measureBoard, measureByKey, measureByName, measureHighways, measureJogs, measureLevel, measureLevelFaults, measureLinks, measureName, measureQuality, measureRouteFaults, measureStability, meetMember, meetPlan, meetingPoints, memberAt, memberStrategy, mergeAngle, meshPlan, meshWaypoints, minEffectOf, minHash, mingleBundles, minglePlan, mixedSegments, mixesCollections, mlsPoint, mlsebLines, mlsebPlan, modularity, modulesOf, mulberry32, namedObjectives, nearestCentre, nearestOnBoundary, nearestOnLine, nearestSide, nearestSkeleton, nestedGridBoard, nestedGroups, nestedPlan, nestingFaults, nestingViolations, nextRow, nodeAmbiguity, nodeIndex, nodeLinks, numberDimension, numberOf, occupiedArea, odCellPlan, odGroups, offsetLine, offsetPolyline, oneSteiner, openGaps, openLanes, optimaFile, optimumKey, optionDefaults, orderChanges, orderFragility, orderLanes, orderRows, orderStability, orderSuiteRows, orthogonality, outOfBoxes, outerGraph, outputGroups, outputHash, pHubPlan, pMedian, packedGridBoard, pairCosts, paramProblem, paretoFront, parseLines, partWithin, passSettings, pathPoints, peakCurvature, pickLevel, pickMoves, placePlug, planMoves, planOfResult, plugSpacing, plugStrategies, plugsRouter, pointAt, pointBoxDistance, pointDensity, pointGroups, pointOnSide, pointSegmentDistance, polylineLength, portOffset, portfolio, portfolioB1Spec, portfolioBand, portfolioFacts, portfolioKey, portfolioMember, portfolioMembers, portfolioName, portfolioRouter, portfolioStrategy, positionStability, powerPlan, preferences, pullApart, quadtreeGroups, quantile, quickBundles, quickBundlesPlan, randomInt, rankShares, rayToBox, recordLines, recordMoves, rectScattered, regionBounds, register, repairResult, repairStrategy, representative, rerouteRouter, rerouteStrategy, rerouteWays, resample, resistanceClusters, resistancePlan, resolvePorts, resultForm, resultHash, ridgeLines, ridgePlan, rng, roadClassPlan, roomDemand, roomLinks, roomOrderFaults, roomStrategies, roomValues, round3, roundCorners, roundedCurve, routeCrossings, routeInStableOrder, routeMeasures, routePortfolio, routeSeparation, routeStability, routeSymmetry, routerStrategies, routersOf, ruleCounts, runBenchmark, runKey, runPipeline, runProfile, runSuite, sameData, sampleCurve, samplesOf, sbebLines, sbebPlan, scaleClusters, scaleSpaceGroups, scaleSpacePlan, screen, screenInputs, screenSplit, searchPlan, searchScore, sectionsRouter, segmentBounds, segmentBoxDistance, segmentClusters, segmentDistance, segmentHitsBox, segmentHitsRect, segmentKey, segmentsCross, segmentsOf, selectBest, selectPlan, setManifest, settingAt, sha256Hex, shapeSkeleton, sharedRouter, sharedStretchStrategy, sharedStretches, sharedWaysAll, sharedWaysPlan, shuffleEdges, sideAngle, sideToward, signTestPower, silhouette, skeletonGroups, skeletonPath, slackSettings, slotJoin, slotPlan, slotsOf, smoothCurve, snapPlan, softDistance, softKeyClusters, softKeyPlan, softStep, spanningTree, spectralClusters, spectralLabels, spectralPlan, spinePart, spiralJoin, spiralPlan, spiralTree, splineCurve, splitFrames, splitPath, splitPoint, splitTargets, spreadEnds, spreadWith, stableIdGate, stableIdPlan, stableOrder, stableOrderStrategy, steinerPlan, stepRouterStrategy, stepRouters, stepSeed, straightCurve, straightRouter, strategyKey, streetEdges, streetPlan, streetPoint, streetRide, stretchGate, stretchLaneOrders, stretchPlan, stretchSettings, stubPlan, suiteFronts, sumFaults, summarize, summarizeGap, summarizeRows, swarmScore, sweepGrid, sweepOf, sweepRoom, sweepSections, sweepValues, symmetricEigen, territoryPlan, tightRouter, tightStrategy, toSvgPath, totalTurn, tracePlan, tracing, tracingLoads, tracingValue, traclusPlan, treeCost, treeDepth, trunksRouter, turns, turnsOf, unwrappedName, utf8, venationLevels, venationLinks, waySlacks, waypointWay, weberPoint, weiszfeldPlan, wholeBoard, wholeStrategies, withBends, withRepair, withStableOrder, wspdGroups, wspdPlan, zipLegs, zipperPlan };
|
|
39519
|
+
export { ADAM_DEFAULTS, ADAM_SCHEMA, AMBIGUITY_GUARD_DEFAULTS, ANNEALING_DEFAULTS, ANNEALING_SCHEMA, ARC_SOURCES, AREA_DEFAULTS, AREA_WIDTHS, ASSIGN_DEFAULTS, ATTRACTION_DEFAULTS, ATTRACTION_SCHEMA, BACKTRACK_MIN, BACKTRACK_SHARE, BALANCE_DEFAULTS, BALANCE_ENDS, BIPARTITE, BIPARTITE_LAYOUTS, BOARD_PORTFOLIO_DEFAULTS, BOARD_PORTFOLIO_SETTINGS, BREAK, BREAK_EVEN, BREAK_EVEN_DEFAULTS, BRONCHIAL_DEFAULTS, BRONCHIAL_SPLITS, BUILT_IN_STRATEGIES, BoundaryWalk, CANAL_DEFAULTS, CANAL_SCHEMA, CANDIDATE_SOURCES, CAP_SWEEP, CASES, CHANNEL_REACH, CLEARANCE_CAP, COMPARE_ALL_STEPS, COMPARE_STEPS, CONFLUENT_DEFAULTS, CONSENSUS_DEFAULTS, CONSENSUS_LINKAGES, CORRIDOR_DEFAULTS, COVERAGE_FAMILIES, CROSSBAR_DEFAULTS, CUBU_DEFAULTS, CURRICULUM_DEFAULTS, CURRICULUM_ORDERS, CURRICULUM_POOL, CURVE_TYPES, CUT_DEFAULTS, CornerGraph, DEFAULT_RNG, DENSE_GROUPS, DENSITY_KERNELS, DETAIL_DEFAULTS, DIFFUSION_DEFAULTS, DISTORTION_NEIGHBOURS, DIVIDED_DEFAULTS, EDGE_DISTANCES, EDGE_PATH_DEFAULTS, EXACT_CLASSES, EXACT_EDGES_PER_NODE, EXACT_V1, EXACT_V1_BOUNDS, EXACT_V1_BOUNDS_SIZES, EXACT_V1_SEEDS, EXACT_V1_SIZES, FAN_OUT, FDEB_DEFAULTS, FIREFLY_DEFAULTS, FIXTURES, FIXTURE_LAYOUTS, FIXTURE_LOCALITY, FLOW_CLUSTER_DEFAULTS, FLOW_FIELD_DEFAULTS, FRAME_ROWS, FRECHET_DEFAULTS, FRONT_OBJECTIVES, GAP_BASELINES, GAP_BOOTSTRAP, GAP_CAPS, GAP_DEFAULTS, GAP_RULES, GAP_VIEWS, GROUP_SCOPES, GROUP_SPINES, GROWTH_DEFAULTS, GROWTH_SWEEP, GUTTER_BEND_COST, Grid, HDBSCAN_DEFAULTS, HIERARCHY_DEFAULTS, HIERARCHY_GROUPS, HIGHWAYS_ENGINE, HIGHWAYS_FAMILIES, HIGHWAY_BASES, HIGHWAY_BASE_ROUTERS, HOUGH_DEFAULTS, HUB_ALLOCATIONS, HUB_ARC_DEFAULTS, HUB_CANDIDATES, HUB_CHAIN, HYSTERESIS_DEFAULTS, INTERCHANGE_BASES, INTERCHANGE_DEFAULTS, KDEEB_DEFAULTS, KD_DEFAULTS, KENDALL_EXACT, KNEE_DEFAULTS, KNEE_RULES, LANES_DEFAULTS, LANE_ORDERS, LANE_STRETCH_DEFAULTS, LANE_STRETCH_ORDERS, LANE_TRACKS, LEADER_DEFAULTS, LEADER_TYPES, LEVEL_HIGHWAY_DEFAULTS, LINKAGES, LINK_COMMUNITY_DEFAULTS, LOCAL_MESH, MANIFOLD_DEFAULTS, MANIFOLD_SIDES, MANY_GROUPS, MEASURES, MEASURE_BALANCE_REACH, MEASURE_LANE_WIDTH, MEET_DEFAULTS, MEMBER_FORMS, MESH_DEFAULTS, MINGLE_DEFAULTS, MIN_EFFECTS, MLSEB_DEFAULTS, MLS_FITS, MODULE_RULES, MOVE_NAMES, NESTED_DEFAULTS, OD_CELL_DEFAULTS, OUTSIDE_SLACK, Obstacles, PACKED_GRID, PICK, PIPELINE, PLAN_CHANGERS, PORTFOLIO_B1, PORTFOLIO_BANDS, PORTFOLIO_BASE_MEMBER, PORTFOLIO_CAPS, PORTFOLIO_FIT, PORTFOLIO_HASHES, PORTFOLIO_KS_API, PORTFOLIO_RULES, PORTFOLIO_SETS, POWER_DEFAULTS, PREFERENCE_DEFAULTS, PREFERENCE_FEATURES, PREFERENCE_PANEL, PROPOSED_RULES, P_HUB_DEFAULTS, QUICKBUNDLES_DEFAULTS, RECORD_EPS, REROUTE_DEFAULTS, REROUTE_SCHEMA, RESISTANCE_DEFAULTS, RIDGE_DEFAULTS, ROAD_CLASS_DEFAULTS, ROOM_FAMILIES, ROUTED_STEPS, ROUTERS, SAME_HIGHWAY, SBEB_DEFAULTS, SCALE_SPACE_DEFAULTS, SCREEN_FAMILY_BY, SCREEN_RULES, SCREEN_SETS, SCREEN_STEPS, SCREEN_V1, SCREEN_V2, SCREEN_V2_HELD_OUT, SCREEN_V3, SCREEN_V3_HELD_OUT, SCREEN_WRAPS, SEARCH_DEFAULTS, SEARCH_MOVES, SECTION_DEFAULTS, SELECT_DEFAULTS, SIDE_NORMAL, SKELETON_GROUPS, SKELETON_TARGETS, SLACK_SWEEP, SLOT_DEFAULTS, SLOT_KEYS, SMALL_CLUSTERED, SOFT_KEY_DEFAULTS, SPACING_LIMIT, SPARSE_LONG, SPECTRAL_DEFAULTS, SPIRAL_DEFAULTS, SPREAD_DEFAULTS, STABLE_ID_DEFAULTS, STEINER_DEFAULTS, STEINER_GROUPS, STEINER_METHODS, STEINER_METRICS, STEPS, STRATEGIES, STREET_DEFAULTS, STREET_SOURCES, STRETCH_DEFAULTS, STRETCH_SWEEP, STUB_DEFAULTS, SUITE_COLUMNS, SWARM_SEARCHES, SoftGraph, SplitTree, TERRITORY_DEFAULTS, TERRITORY_POINTS, THIN_BARS, TIGHT_DEFAULTS, TIGHT_FIRSTS, TIGHT_SCHEMA, TIGHT_TIES, TINY_UNIFORM, TOLERANCE, TRACING_DEFAULTS, TRACING_QUANTILES, TRACING_WEIGHTS, TRACLUS_DEFAULTS, TRAFFIC_RULES, TWO_HUBS, UNEVEN_SIZES, VENATION_BACKBONES, VENATION_DEFAULTS, WEISZFELD_DEFAULTS, WIDTH_SCALES, WSPD_DEFAULTS, WayFinder, ZIPPER_DEFAULTS, activationBase, activationReport, adamRouter, adamRoutes, adamStrategy, adjustedRandIndex, agreementOf, allSections, ambiguity, ambiguityGate, ambiguityPlan, annealWays, annealingRouter, annealingStrategy, arcCurve, arcsin, areaPlan, aroundBox, asRouter, assignEnds, assignWall, attraction, attractionRouter, attractionStrategy, backboneLinks, backtrackOf, balance, balanceOf, balancePlan, basePlan, benchBendRoom, benchCurveStrategies, benchCurves, benchHighways, benchLevelRoom, benchOne, benchRoom, benchRun, benchTracks, bendCount, bendingEnergy, bicliqueGroups, bigGroups, boardGaps, boardPortfolio, boardUnit, boardWins, bootstrapMedian, boundsFamilyName, boxDisplacement, boxExit, boxPush, boxUnit, boxesOverlap, breakEvenGate, breakEvenPlan, bronchialPlan, buildSections, bundleStretch, bundledShare, byCollection, byDataGroup, canalHubs, canalRouter, canalStrategy, canalWays, candidateArcs, candidatePlan, candidateScore, canonicalJson, capSettings, caseSeed, cellSteps, center, chainClusters, changeGraph, changedDimensions, channelOverflows, channelWidth, characteristicPoints, checkFamilies, checkLevels, checkOptions, checkParents, checkPlan, checkPort, checkProperties, checkSchema, checkSections, clampOptions, clothoidCurve, clusters1d, coAssociation, collapseLinks, commonEdges, compareAnyStep, compareMeasure, compareSpec, compareStep, compatibility, compatibilityMatrix, confluentPlan, consensusGroups, consensusLabels, consensusPlan, controlChain, cornersRouter, corpusManifest, corridorPlan, countCrossings, countOverlaps, createFamilyRegistry, createRegistry, crossbarPlan, crossesItself, crossingAngle, crossingAngles, cubicAt, cubuPlan, curriculum, curvatureVariation, curveDeviation, curveFaults, curveJoints, curveOf, curveRuns, curveSpace, curveStrategies, curvesHash, cutGroups, cutShare, declaresFamily, defineStrategy, denseGroupsBoard, densityPlan, densityRidges, depthLevels, detailLevels, detailWidth, detourSpread, diamondAngle, diffusionPlan, dimensionAt, dimensionUnit, dist, distanceDistortion, distinctPoints, divideHighway, dividedPlan, documentHash, dominates, drawnSegments, edgeBlocks, edgeEnds, edgeLengths, edgePathPlan, edgePaths, edgePlugs, edgeResistance, enumDimension, exactBoard, exactFamily, exactGenerator, exactSeed, exactStretch, exactStretches, exercised, facingEnds, familyCell, familyKind, familyOf, familySeed, farLevel, farLinks, fdebLines, fdebPlan, fft, findStrategy, finderOf, fireflies, firstLines, fitPreferences, fixPorts, fixedPortPoint, fixtureGroupOptions, fixtureParams, fixtureRngSeed, fixtureSpecOf, flowClusterPlan, flowClusters, flowDistance, flowFieldPlan, fnv1a32, follow, formatActivation, formatBendRoom, formatCapped, formatCurves, formatFaults, formatFronts, formatGap, formatHighways, formatInput, formatLevelRoom, formatLevels, formatMeasureTime, formatPaired, formatRoom, formatRules, formatScreen, formatSections, formatSummaries, formatTable, formatTracks, frameRoutes, frechet, frechetBundles, frechetPlan, freeLines, g1Defect, g2Defect, gapBaselines, gapCap, gapClosed, gapLaneCounts, gapLanes, gapNames, gapPlan, gapValues, gateStrategy, getStrategy, goesOutAndBack, graphInput, greedyBicliques, greedyCrossbars, groupEdges, groupFill, groupRun, groupSettings, groupStability, groupStrategies, groupedPlan, growthPlan, growthSettings, guardBreaks, gutterRoutes, halfPower, hasCusp, hdbscanClusters, hdbscanLabels, hdbscanPlan, hierarchyPlan, highwayChurn, highwayCurve, highwayCurves, highwayEdits, highwayIdKeep, highwayMoves, highwayRouter, highwayRouterStrategy, highwayRouters, highwayStrategies, highwaysRegistry, houghLines, houghPeaks, houghPlan, hubArcPlan, hubCandidates, hubChainBoard, hysteresisGate, hysteresisPlan, inflate, inflectionCount, inflectionCurve, inflectionSector, inkSaved, innerPoints, inputGraph, inputId, interchangeCandidates, interchangePlan, isRoutedStep, itemOverlaps, itemSizes, jaccard, jaccardIndex, jogPeaks, joinReports, jsonSafe, kMeans, kdGroups, kdeebLines, kdeebPlan, keepMembers, kendallTau, keyGroups, keyedSections, keysPlan, kneeOf, kneePlan, labelGroups, laneArea, laneCrossings, laneFidelity, laneOrder, laneRoutes, laneSeparation, laneSettings, laneStretches, lanesPlan, lanesThrough, leaderEnds, leafGroups, lengthBetween, levelCut, levelGrouping, levelHighwayPlan, levelMeasures, levelPairs, levelRatio, levelRoom, levelStrategies, levelsOf, lineDensity, linePoint, linkAgreement, linkCommunities, linkCommunityGroups, linkCommunityPlan, linkDensity, listOptions, listStrategies, madeUpPairs, makeFixture, makeRoom, manifestHash, manifoldPlan, manyGroupsBoard, matchHighways, maxStretch, mdf, meanLine, measureBoard, measureByKey, measureByName, measureHighways, measureJogs, measureLevel, measureLevelFaults, measureLinks, measureName, measureQuality, measureRouteFaults, measureStability, meetMember, meetPlan, meetingPoints, memberAt, memberStrategy, mergeAngle, meshPlan, meshWaypoints, minEffectOf, minHash, mingleBundles, minglePlan, mixedSegments, mixesCollections, mlsPoint, mlsebLines, mlsebPlan, modularity, modulesOf, moveResponse, mulberry32, namedObjectives, nearestCentre, nearestOnBoundary, nearestOnLine, nearestSide, nearestSkeleton, nestedGridBoard, nestedGroups, nestedPlan, nestingFaults, nestingViolations, nextRow, nodeAmbiguity, nodeIndex, nodeLinks, numberDimension, numberOf, occupiedArea, odCellPlan, odGroups, offsetLine, offsetPolyline, oneSteiner, openGaps, openLanes, optimaFile, optimumKey, optionDefaults, orderChanges, orderFragility, orderLanes, orderRows, orderStability, orderSuiteRows, orthogonality, outOfBoxes, outerGraph, outputGroups, outputHash, pHubPlan, pMedian, packedGridBoard, pairCosts, paramProblem, paretoFront, parseLines, partWithin, passSettings, pathPoints, peakCurvature, pickLevel, pickMoves, placePlug, planMoves, planOfResult, plugSpacing, plugStrategies, plugsRouter, pointAt, pointBoxDistance, pointDensity, pointGroups, pointOnSide, pointSegmentDistance, polylineLength, portOffset, portfolio, portfolioB1Spec, portfolioBand, portfolioFacts, portfolioKey, portfolioMember, portfolioMembers, portfolioName, portfolioRouter, portfolioStrategy, positionStability, powerPlan, preferences, pullApart, quadtreeGroups, quantile, quickBundles, quickBundlesPlan, randomInt, rankShares, rayToBox, recordLines, recordMoves, rectScattered, regionBounds, register, repairResult, repairStrategy, representative, rerouteRouter, rerouteStrategy, rerouteWays, resample, resistanceClusters, resistancePlan, resolvePorts, resultForm, resultHash, ridgeLines, ridgePlan, rng, roadClassPlan, roomDemand, roomLinks, roomOrderFaults, roomStrategies, roomValues, round3, roundCorners, roundedCurve, routeBalance, routeCrossings, routeInStableOrder, routeMeasures, routePortfolio, routeSeparation, routeStability, routeSymmetry, routerStrategies, routersOf, ruleCounts, runBenchmark, runKey, runPipeline, runProfile, runSuite, sameData, sampleCurve, samplesOf, sbebLines, sbebPlan, scaleClusters, scaleSpaceGroups, scaleSpacePlan, screen, screenInputs, screenSplit, searchPlan, searchScore, sectionsRouter, segmentBounds, segmentBoxDistance, segmentClusters, segmentDistance, segmentHitsBox, segmentHitsRect, segmentKey, segmentsCross, segmentsOf, selectBest, selectPlan, setManifest, settingAt, sha256Hex, shapeSkeleton, sharedRouter, sharedStretchStrategy, sharedStretches, sharedWaysAll, sharedWaysPlan, shuffleEdges, sideAngle, sideToward, signTestPower, silhouette, skeletonGroups, skeletonPath, slackSettings, slotJoin, slotPlan, slotsOf, smoothCurve, snapPlan, softDistance, softKeyClusters, softKeyPlan, softStep, spanningTree, spectralClusters, spectralLabels, spectralPlan, spinePart, spiralJoin, spiralPlan, spiralTree, splineCurve, splitFrames, splitPath, splitPoint, splitTargets, spreadEnds, spreadWith, stableIdGate, stableIdPlan, stableOrder, stableOrderStrategy, steinerPlan, stepRouterStrategy, stepRouters, stepSeed, straightCurve, straightRouter, strategyKey, streetEdges, streetPlan, streetPoint, streetRide, stretchGate, stretchLaneOrders, stretchPlan, stretchSettings, stubPlan, suiteFronts, sumFaults, summarize, summarizeGap, summarizeRows, swarmScore, sweepGrid, sweepOf, sweepRoom, sweepSections, sweepValues, symmetricEigen, territoryPlan, tightRouter, tightStrategy, toSvgPath, totalTurn, tracePlan, tracing, tracingLoads, tracingValue, traclusPlan, treeCost, treeDepth, trunksRouter, turns, turnsOf, unwrappedName, utf8, venationLevels, venationLinks, waySlacks, waypointWay, weberPoint, weiszfeldPlan, wholeBoard, wholeStrategies, withBends, withRepair, withStableOrder, wspdGroups, wspdPlan, zipLegs, zipperPlan };
|
|
38593
39520
|
|
|
38594
39521
|
//# sourceMappingURL=index.js.map
|