@tscircuit/capacity-autorouter 0.0.54 → 0.0.56
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/dist/index.d.ts +68 -42
- package/dist/index.js +1189 -152
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -47,6 +47,7 @@ var BaseSolver = class {
|
|
|
47
47
|
activeSubSolver;
|
|
48
48
|
failedSubSolvers;
|
|
49
49
|
timeToSolve;
|
|
50
|
+
stats = {};
|
|
50
51
|
/** DO NOT OVERRIDE! Override _step() instead */
|
|
51
52
|
step() {
|
|
52
53
|
if (this.solved) return;
|
|
@@ -65,6 +66,9 @@ var BaseSolver = class {
|
|
|
65
66
|
console.error(this.error);
|
|
66
67
|
this.failed = true;
|
|
67
68
|
}
|
|
69
|
+
if ("computeProgress" in this) {
|
|
70
|
+
this.progress = this.computeProgress();
|
|
71
|
+
}
|
|
68
72
|
}
|
|
69
73
|
_step() {
|
|
70
74
|
}
|
|
@@ -968,8 +972,935 @@ var calculateOptimalCapacityDepth = (initialWidth, targetMinCapacity = 0.5, maxD
|
|
|
968
972
|
return Math.max(1, depth);
|
|
969
973
|
};
|
|
970
974
|
|
|
975
|
+
// node_modules/quickselect/index.js
|
|
976
|
+
function quickselect(arr, k, left = 0, right = arr.length - 1, compare = defaultCompare) {
|
|
977
|
+
while (right > left) {
|
|
978
|
+
if (right - left > 600) {
|
|
979
|
+
const n = right - left + 1;
|
|
980
|
+
const m = k - left + 1;
|
|
981
|
+
const z = Math.log(n);
|
|
982
|
+
const s = 0.5 * Math.exp(2 * z / 3);
|
|
983
|
+
const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
|
|
984
|
+
const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
|
|
985
|
+
const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
|
|
986
|
+
quickselect(arr, k, newLeft, newRight, compare);
|
|
987
|
+
}
|
|
988
|
+
const t = arr[k];
|
|
989
|
+
let i = left;
|
|
990
|
+
let j = right;
|
|
991
|
+
swap(arr, left, k);
|
|
992
|
+
if (compare(arr[right], t) > 0) swap(arr, left, right);
|
|
993
|
+
while (i < j) {
|
|
994
|
+
swap(arr, i, j);
|
|
995
|
+
i++;
|
|
996
|
+
j--;
|
|
997
|
+
while (compare(arr[i], t) < 0) i++;
|
|
998
|
+
while (compare(arr[j], t) > 0) j--;
|
|
999
|
+
}
|
|
1000
|
+
if (compare(arr[left], t) === 0) swap(arr, left, j);
|
|
1001
|
+
else {
|
|
1002
|
+
j++;
|
|
1003
|
+
swap(arr, j, right);
|
|
1004
|
+
}
|
|
1005
|
+
if (j <= k) left = j + 1;
|
|
1006
|
+
if (k <= j) right = j - 1;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
function swap(arr, i, j) {
|
|
1010
|
+
const tmp = arr[i];
|
|
1011
|
+
arr[i] = arr[j];
|
|
1012
|
+
arr[j] = tmp;
|
|
1013
|
+
}
|
|
1014
|
+
function defaultCompare(a, b) {
|
|
1015
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// node_modules/rbush/index.js
|
|
1019
|
+
var RBush = class {
|
|
1020
|
+
constructor(maxEntries = 9) {
|
|
1021
|
+
this._maxEntries = Math.max(4, maxEntries);
|
|
1022
|
+
this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
|
|
1023
|
+
this.clear();
|
|
1024
|
+
}
|
|
1025
|
+
all() {
|
|
1026
|
+
return this._all(this.data, []);
|
|
1027
|
+
}
|
|
1028
|
+
search(bbox) {
|
|
1029
|
+
let node = this.data;
|
|
1030
|
+
const result = [];
|
|
1031
|
+
if (!intersects(bbox, node)) return result;
|
|
1032
|
+
const toBBox = this.toBBox;
|
|
1033
|
+
const nodesToSearch = [];
|
|
1034
|
+
while (node) {
|
|
1035
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
1036
|
+
const child = node.children[i];
|
|
1037
|
+
const childBBox = node.leaf ? toBBox(child) : child;
|
|
1038
|
+
if (intersects(bbox, childBBox)) {
|
|
1039
|
+
if (node.leaf) result.push(child);
|
|
1040
|
+
else if (contains(bbox, childBBox)) this._all(child, result);
|
|
1041
|
+
else nodesToSearch.push(child);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
node = nodesToSearch.pop();
|
|
1045
|
+
}
|
|
1046
|
+
return result;
|
|
1047
|
+
}
|
|
1048
|
+
collides(bbox) {
|
|
1049
|
+
let node = this.data;
|
|
1050
|
+
if (!intersects(bbox, node)) return false;
|
|
1051
|
+
const nodesToSearch = [];
|
|
1052
|
+
while (node) {
|
|
1053
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
1054
|
+
const child = node.children[i];
|
|
1055
|
+
const childBBox = node.leaf ? this.toBBox(child) : child;
|
|
1056
|
+
if (intersects(bbox, childBBox)) {
|
|
1057
|
+
if (node.leaf || contains(bbox, childBBox)) return true;
|
|
1058
|
+
nodesToSearch.push(child);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
node = nodesToSearch.pop();
|
|
1062
|
+
}
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
load(data) {
|
|
1066
|
+
if (!(data && data.length)) return this;
|
|
1067
|
+
if (data.length < this._minEntries) {
|
|
1068
|
+
for (let i = 0; i < data.length; i++) {
|
|
1069
|
+
this.insert(data[i]);
|
|
1070
|
+
}
|
|
1071
|
+
return this;
|
|
1072
|
+
}
|
|
1073
|
+
let node = this._build(data.slice(), 0, data.length - 1, 0);
|
|
1074
|
+
if (!this.data.children.length) {
|
|
1075
|
+
this.data = node;
|
|
1076
|
+
} else if (this.data.height === node.height) {
|
|
1077
|
+
this._splitRoot(this.data, node);
|
|
1078
|
+
} else {
|
|
1079
|
+
if (this.data.height < node.height) {
|
|
1080
|
+
const tmpNode = this.data;
|
|
1081
|
+
this.data = node;
|
|
1082
|
+
node = tmpNode;
|
|
1083
|
+
}
|
|
1084
|
+
this._insert(node, this.data.height - node.height - 1, true);
|
|
1085
|
+
}
|
|
1086
|
+
return this;
|
|
1087
|
+
}
|
|
1088
|
+
insert(item) {
|
|
1089
|
+
if (item) this._insert(item, this.data.height - 1);
|
|
1090
|
+
return this;
|
|
1091
|
+
}
|
|
1092
|
+
clear() {
|
|
1093
|
+
this.data = createNode([]);
|
|
1094
|
+
return this;
|
|
1095
|
+
}
|
|
1096
|
+
remove(item, equalsFn) {
|
|
1097
|
+
if (!item) return this;
|
|
1098
|
+
let node = this.data;
|
|
1099
|
+
const bbox = this.toBBox(item);
|
|
1100
|
+
const path = [];
|
|
1101
|
+
const indexes = [];
|
|
1102
|
+
let i, parent, goingUp;
|
|
1103
|
+
while (node || path.length) {
|
|
1104
|
+
if (!node) {
|
|
1105
|
+
node = path.pop();
|
|
1106
|
+
parent = path[path.length - 1];
|
|
1107
|
+
i = indexes.pop();
|
|
1108
|
+
goingUp = true;
|
|
1109
|
+
}
|
|
1110
|
+
if (node.leaf) {
|
|
1111
|
+
const index = findItem(item, node.children, equalsFn);
|
|
1112
|
+
if (index !== -1) {
|
|
1113
|
+
node.children.splice(index, 1);
|
|
1114
|
+
path.push(node);
|
|
1115
|
+
this._condense(path);
|
|
1116
|
+
return this;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
if (!goingUp && !node.leaf && contains(node, bbox)) {
|
|
1120
|
+
path.push(node);
|
|
1121
|
+
indexes.push(i);
|
|
1122
|
+
i = 0;
|
|
1123
|
+
parent = node;
|
|
1124
|
+
node = node.children[0];
|
|
1125
|
+
} else if (parent) {
|
|
1126
|
+
i++;
|
|
1127
|
+
node = parent.children[i];
|
|
1128
|
+
goingUp = false;
|
|
1129
|
+
} else node = null;
|
|
1130
|
+
}
|
|
1131
|
+
return this;
|
|
1132
|
+
}
|
|
1133
|
+
toBBox(item) {
|
|
1134
|
+
return item;
|
|
1135
|
+
}
|
|
1136
|
+
compareMinX(a, b) {
|
|
1137
|
+
return a.minX - b.minX;
|
|
1138
|
+
}
|
|
1139
|
+
compareMinY(a, b) {
|
|
1140
|
+
return a.minY - b.minY;
|
|
1141
|
+
}
|
|
1142
|
+
toJSON() {
|
|
1143
|
+
return this.data;
|
|
1144
|
+
}
|
|
1145
|
+
fromJSON(data) {
|
|
1146
|
+
this.data = data;
|
|
1147
|
+
return this;
|
|
1148
|
+
}
|
|
1149
|
+
_all(node, result) {
|
|
1150
|
+
const nodesToSearch = [];
|
|
1151
|
+
while (node) {
|
|
1152
|
+
if (node.leaf) result.push(...node.children);
|
|
1153
|
+
else nodesToSearch.push(...node.children);
|
|
1154
|
+
node = nodesToSearch.pop();
|
|
1155
|
+
}
|
|
1156
|
+
return result;
|
|
1157
|
+
}
|
|
1158
|
+
_build(items, left, right, height) {
|
|
1159
|
+
const N = right - left + 1;
|
|
1160
|
+
let M = this._maxEntries;
|
|
1161
|
+
let node;
|
|
1162
|
+
if (N <= M) {
|
|
1163
|
+
node = createNode(items.slice(left, right + 1));
|
|
1164
|
+
calcBBox(node, this.toBBox);
|
|
1165
|
+
return node;
|
|
1166
|
+
}
|
|
1167
|
+
if (!height) {
|
|
1168
|
+
height = Math.ceil(Math.log(N) / Math.log(M));
|
|
1169
|
+
M = Math.ceil(N / Math.pow(M, height - 1));
|
|
1170
|
+
}
|
|
1171
|
+
node = createNode([]);
|
|
1172
|
+
node.leaf = false;
|
|
1173
|
+
node.height = height;
|
|
1174
|
+
const N2 = Math.ceil(N / M);
|
|
1175
|
+
const N1 = N2 * Math.ceil(Math.sqrt(M));
|
|
1176
|
+
multiSelect(items, left, right, N1, this.compareMinX);
|
|
1177
|
+
for (let i = left; i <= right; i += N1) {
|
|
1178
|
+
const right2 = Math.min(i + N1 - 1, right);
|
|
1179
|
+
multiSelect(items, i, right2, N2, this.compareMinY);
|
|
1180
|
+
for (let j = i; j <= right2; j += N2) {
|
|
1181
|
+
const right3 = Math.min(j + N2 - 1, right2);
|
|
1182
|
+
node.children.push(this._build(items, j, right3, height - 1));
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
calcBBox(node, this.toBBox);
|
|
1186
|
+
return node;
|
|
1187
|
+
}
|
|
1188
|
+
_chooseSubtree(bbox, node, level, path) {
|
|
1189
|
+
while (true) {
|
|
1190
|
+
path.push(node);
|
|
1191
|
+
if (node.leaf || path.length - 1 === level) break;
|
|
1192
|
+
let minArea = Infinity;
|
|
1193
|
+
let minEnlargement = Infinity;
|
|
1194
|
+
let targetNode;
|
|
1195
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
1196
|
+
const child = node.children[i];
|
|
1197
|
+
const area = bboxArea(child);
|
|
1198
|
+
const enlargement = enlargedArea(bbox, child) - area;
|
|
1199
|
+
if (enlargement < minEnlargement) {
|
|
1200
|
+
minEnlargement = enlargement;
|
|
1201
|
+
minArea = area < minArea ? area : minArea;
|
|
1202
|
+
targetNode = child;
|
|
1203
|
+
} else if (enlargement === minEnlargement) {
|
|
1204
|
+
if (area < minArea) {
|
|
1205
|
+
minArea = area;
|
|
1206
|
+
targetNode = child;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
node = targetNode || node.children[0];
|
|
1211
|
+
}
|
|
1212
|
+
return node;
|
|
1213
|
+
}
|
|
1214
|
+
_insert(item, level, isNode) {
|
|
1215
|
+
const bbox = isNode ? item : this.toBBox(item);
|
|
1216
|
+
const insertPath = [];
|
|
1217
|
+
const node = this._chooseSubtree(bbox, this.data, level, insertPath);
|
|
1218
|
+
node.children.push(item);
|
|
1219
|
+
extend(node, bbox);
|
|
1220
|
+
while (level >= 0) {
|
|
1221
|
+
if (insertPath[level].children.length > this._maxEntries) {
|
|
1222
|
+
this._split(insertPath, level);
|
|
1223
|
+
level--;
|
|
1224
|
+
} else break;
|
|
1225
|
+
}
|
|
1226
|
+
this._adjustParentBBoxes(bbox, insertPath, level);
|
|
1227
|
+
}
|
|
1228
|
+
// split overflowed node into two
|
|
1229
|
+
_split(insertPath, level) {
|
|
1230
|
+
const node = insertPath[level];
|
|
1231
|
+
const M = node.children.length;
|
|
1232
|
+
const m = this._minEntries;
|
|
1233
|
+
this._chooseSplitAxis(node, m, M);
|
|
1234
|
+
const splitIndex = this._chooseSplitIndex(node, m, M);
|
|
1235
|
+
const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
|
|
1236
|
+
newNode.height = node.height;
|
|
1237
|
+
newNode.leaf = node.leaf;
|
|
1238
|
+
calcBBox(node, this.toBBox);
|
|
1239
|
+
calcBBox(newNode, this.toBBox);
|
|
1240
|
+
if (level) insertPath[level - 1].children.push(newNode);
|
|
1241
|
+
else this._splitRoot(node, newNode);
|
|
1242
|
+
}
|
|
1243
|
+
_splitRoot(node, newNode) {
|
|
1244
|
+
this.data = createNode([node, newNode]);
|
|
1245
|
+
this.data.height = node.height + 1;
|
|
1246
|
+
this.data.leaf = false;
|
|
1247
|
+
calcBBox(this.data, this.toBBox);
|
|
1248
|
+
}
|
|
1249
|
+
_chooseSplitIndex(node, m, M) {
|
|
1250
|
+
let index;
|
|
1251
|
+
let minOverlap = Infinity;
|
|
1252
|
+
let minArea = Infinity;
|
|
1253
|
+
for (let i = m; i <= M - m; i++) {
|
|
1254
|
+
const bbox1 = distBBox(node, 0, i, this.toBBox);
|
|
1255
|
+
const bbox2 = distBBox(node, i, M, this.toBBox);
|
|
1256
|
+
const overlap = intersectionArea(bbox1, bbox2);
|
|
1257
|
+
const area = bboxArea(bbox1) + bboxArea(bbox2);
|
|
1258
|
+
if (overlap < minOverlap) {
|
|
1259
|
+
minOverlap = overlap;
|
|
1260
|
+
index = i;
|
|
1261
|
+
minArea = area < minArea ? area : minArea;
|
|
1262
|
+
} else if (overlap === minOverlap) {
|
|
1263
|
+
if (area < minArea) {
|
|
1264
|
+
minArea = area;
|
|
1265
|
+
index = i;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return index || M - m;
|
|
1270
|
+
}
|
|
1271
|
+
// sorts node children by the best axis for split
|
|
1272
|
+
_chooseSplitAxis(node, m, M) {
|
|
1273
|
+
const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
|
|
1274
|
+
const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
|
|
1275
|
+
const xMargin = this._allDistMargin(node, m, M, compareMinX);
|
|
1276
|
+
const yMargin = this._allDistMargin(node, m, M, compareMinY);
|
|
1277
|
+
if (xMargin < yMargin) node.children.sort(compareMinX);
|
|
1278
|
+
}
|
|
1279
|
+
// total margin of all possible split distributions where each node is at least m full
|
|
1280
|
+
_allDistMargin(node, m, M, compare) {
|
|
1281
|
+
node.children.sort(compare);
|
|
1282
|
+
const toBBox = this.toBBox;
|
|
1283
|
+
const leftBBox = distBBox(node, 0, m, toBBox);
|
|
1284
|
+
const rightBBox = distBBox(node, M - m, M, toBBox);
|
|
1285
|
+
let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
|
|
1286
|
+
for (let i = m; i < M - m; i++) {
|
|
1287
|
+
const child = node.children[i];
|
|
1288
|
+
extend(leftBBox, node.leaf ? toBBox(child) : child);
|
|
1289
|
+
margin += bboxMargin(leftBBox);
|
|
1290
|
+
}
|
|
1291
|
+
for (let i = M - m - 1; i >= m; i--) {
|
|
1292
|
+
const child = node.children[i];
|
|
1293
|
+
extend(rightBBox, node.leaf ? toBBox(child) : child);
|
|
1294
|
+
margin += bboxMargin(rightBBox);
|
|
1295
|
+
}
|
|
1296
|
+
return margin;
|
|
1297
|
+
}
|
|
1298
|
+
_adjustParentBBoxes(bbox, path, level) {
|
|
1299
|
+
for (let i = level; i >= 0; i--) {
|
|
1300
|
+
extend(path[i], bbox);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
_condense(path) {
|
|
1304
|
+
for (let i = path.length - 1, siblings; i >= 0; i--) {
|
|
1305
|
+
if (path[i].children.length === 0) {
|
|
1306
|
+
if (i > 0) {
|
|
1307
|
+
siblings = path[i - 1].children;
|
|
1308
|
+
siblings.splice(siblings.indexOf(path[i]), 1);
|
|
1309
|
+
} else this.clear();
|
|
1310
|
+
} else calcBBox(path[i], this.toBBox);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
function findItem(item, items, equalsFn) {
|
|
1315
|
+
if (!equalsFn) return items.indexOf(item);
|
|
1316
|
+
for (let i = 0; i < items.length; i++) {
|
|
1317
|
+
if (equalsFn(item, items[i])) return i;
|
|
1318
|
+
}
|
|
1319
|
+
return -1;
|
|
1320
|
+
}
|
|
1321
|
+
function calcBBox(node, toBBox) {
|
|
1322
|
+
distBBox(node, 0, node.children.length, toBBox, node);
|
|
1323
|
+
}
|
|
1324
|
+
function distBBox(node, k, p, toBBox, destNode) {
|
|
1325
|
+
if (!destNode) destNode = createNode(null);
|
|
1326
|
+
destNode.minX = Infinity;
|
|
1327
|
+
destNode.minY = Infinity;
|
|
1328
|
+
destNode.maxX = -Infinity;
|
|
1329
|
+
destNode.maxY = -Infinity;
|
|
1330
|
+
for (let i = k; i < p; i++) {
|
|
1331
|
+
const child = node.children[i];
|
|
1332
|
+
extend(destNode, node.leaf ? toBBox(child) : child);
|
|
1333
|
+
}
|
|
1334
|
+
return destNode;
|
|
1335
|
+
}
|
|
1336
|
+
function extend(a, b) {
|
|
1337
|
+
a.minX = Math.min(a.minX, b.minX);
|
|
1338
|
+
a.minY = Math.min(a.minY, b.minY);
|
|
1339
|
+
a.maxX = Math.max(a.maxX, b.maxX);
|
|
1340
|
+
a.maxY = Math.max(a.maxY, b.maxY);
|
|
1341
|
+
return a;
|
|
1342
|
+
}
|
|
1343
|
+
function compareNodeMinX(a, b) {
|
|
1344
|
+
return a.minX - b.minX;
|
|
1345
|
+
}
|
|
1346
|
+
function compareNodeMinY(a, b) {
|
|
1347
|
+
return a.minY - b.minY;
|
|
1348
|
+
}
|
|
1349
|
+
function bboxArea(a) {
|
|
1350
|
+
return (a.maxX - a.minX) * (a.maxY - a.minY);
|
|
1351
|
+
}
|
|
1352
|
+
function bboxMargin(a) {
|
|
1353
|
+
return a.maxX - a.minX + (a.maxY - a.minY);
|
|
1354
|
+
}
|
|
1355
|
+
function enlargedArea(a, b) {
|
|
1356
|
+
return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
|
|
1357
|
+
}
|
|
1358
|
+
function intersectionArea(a, b) {
|
|
1359
|
+
const minX = Math.max(a.minX, b.minX);
|
|
1360
|
+
const minY = Math.max(a.minY, b.minY);
|
|
1361
|
+
const maxX = Math.min(a.maxX, b.maxX);
|
|
1362
|
+
const maxY = Math.min(a.maxY, b.maxY);
|
|
1363
|
+
return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
|
|
1364
|
+
}
|
|
1365
|
+
function contains(a, b) {
|
|
1366
|
+
return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
|
|
1367
|
+
}
|
|
1368
|
+
function intersects(a, b) {
|
|
1369
|
+
return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
|
|
1370
|
+
}
|
|
1371
|
+
function createNode(children) {
|
|
1372
|
+
return {
|
|
1373
|
+
children,
|
|
1374
|
+
height: 1,
|
|
1375
|
+
leaf: true,
|
|
1376
|
+
minX: Infinity,
|
|
1377
|
+
minY: Infinity,
|
|
1378
|
+
maxX: -Infinity,
|
|
1379
|
+
maxY: -Infinity
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
function multiSelect(arr, left, right, n, compare) {
|
|
1383
|
+
const stack = [left, right];
|
|
1384
|
+
while (stack.length) {
|
|
1385
|
+
right = stack.pop();
|
|
1386
|
+
left = stack.pop();
|
|
1387
|
+
if (right - left <= n) continue;
|
|
1388
|
+
const mid = left + Math.ceil((right - left) / n / 2) * n;
|
|
1389
|
+
quickselect(arr, mid, left, right, compare);
|
|
1390
|
+
stack.push(left, mid, mid, right);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
// lib/data-structures/RbushIndex.ts
|
|
1395
|
+
var RbushIndex = class {
|
|
1396
|
+
tree;
|
|
1397
|
+
constructor(maxEntries = 9) {
|
|
1398
|
+
this.tree = new RBush(maxEntries);
|
|
1399
|
+
}
|
|
1400
|
+
insert(item, minX, minY, maxX, maxY) {
|
|
1401
|
+
this.tree.insert({ minX, minY, maxX, maxY, data: item });
|
|
1402
|
+
}
|
|
1403
|
+
bulkLoad(items) {
|
|
1404
|
+
const nodes = items.map(({ item, minX, minY, maxX, maxY }) => ({
|
|
1405
|
+
minX,
|
|
1406
|
+
minY,
|
|
1407
|
+
maxX,
|
|
1408
|
+
maxY,
|
|
1409
|
+
data: item
|
|
1410
|
+
}));
|
|
1411
|
+
this.tree.load(nodes);
|
|
1412
|
+
}
|
|
1413
|
+
search(minX, minY, maxX, maxY) {
|
|
1414
|
+
return this.tree.search({ minX, minY, maxX, maxY }).map((n) => n.data);
|
|
1415
|
+
}
|
|
1416
|
+
clear() {
|
|
1417
|
+
this.tree.clear();
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
|
|
1421
|
+
// node_modules/flatqueue/index.js
|
|
1422
|
+
var FlatQueue = class {
|
|
1423
|
+
constructor() {
|
|
1424
|
+
this.ids = [];
|
|
1425
|
+
this.values = [];
|
|
1426
|
+
this.length = 0;
|
|
1427
|
+
}
|
|
1428
|
+
clear() {
|
|
1429
|
+
this.length = 0;
|
|
1430
|
+
}
|
|
1431
|
+
push(id, value) {
|
|
1432
|
+
let pos = this.length++;
|
|
1433
|
+
while (pos > 0) {
|
|
1434
|
+
const parent = pos - 1 >> 1;
|
|
1435
|
+
const parentValue = this.values[parent];
|
|
1436
|
+
if (value >= parentValue) break;
|
|
1437
|
+
this.ids[pos] = this.ids[parent];
|
|
1438
|
+
this.values[pos] = parentValue;
|
|
1439
|
+
pos = parent;
|
|
1440
|
+
}
|
|
1441
|
+
this.ids[pos] = id;
|
|
1442
|
+
this.values[pos] = value;
|
|
1443
|
+
}
|
|
1444
|
+
pop() {
|
|
1445
|
+
if (this.length === 0) return void 0;
|
|
1446
|
+
const top = this.ids[0];
|
|
1447
|
+
this.length--;
|
|
1448
|
+
if (this.length > 0) {
|
|
1449
|
+
const id = this.ids[0] = this.ids[this.length];
|
|
1450
|
+
const value = this.values[0] = this.values[this.length];
|
|
1451
|
+
const halfLength = this.length >> 1;
|
|
1452
|
+
let pos = 0;
|
|
1453
|
+
while (pos < halfLength) {
|
|
1454
|
+
let left = (pos << 1) + 1;
|
|
1455
|
+
const right = left + 1;
|
|
1456
|
+
let bestIndex = this.ids[left];
|
|
1457
|
+
let bestValue = this.values[left];
|
|
1458
|
+
const rightValue = this.values[right];
|
|
1459
|
+
if (right < this.length && rightValue < bestValue) {
|
|
1460
|
+
left = right;
|
|
1461
|
+
bestIndex = this.ids[right];
|
|
1462
|
+
bestValue = rightValue;
|
|
1463
|
+
}
|
|
1464
|
+
if (bestValue >= value) break;
|
|
1465
|
+
this.ids[pos] = bestIndex;
|
|
1466
|
+
this.values[pos] = bestValue;
|
|
1467
|
+
pos = left;
|
|
1468
|
+
}
|
|
1469
|
+
this.ids[pos] = id;
|
|
1470
|
+
this.values[pos] = value;
|
|
1471
|
+
}
|
|
1472
|
+
return top;
|
|
1473
|
+
}
|
|
1474
|
+
peek() {
|
|
1475
|
+
if (this.length === 0) return void 0;
|
|
1476
|
+
return this.ids[0];
|
|
1477
|
+
}
|
|
1478
|
+
peekValue() {
|
|
1479
|
+
if (this.length === 0) return void 0;
|
|
1480
|
+
return this.values[0];
|
|
1481
|
+
}
|
|
1482
|
+
shrink() {
|
|
1483
|
+
this.ids.length = this.values.length = this.length;
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
|
|
1487
|
+
// node_modules/flatbush/index.js
|
|
1488
|
+
var ARRAY_TYPES = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array];
|
|
1489
|
+
var VERSION = 3;
|
|
1490
|
+
var Flatbush = class _Flatbush {
|
|
1491
|
+
/**
|
|
1492
|
+
* Recreate a Flatbush index from raw `ArrayBuffer` or `SharedArrayBuffer` data.
|
|
1493
|
+
* @param {ArrayBuffer | SharedArrayBuffer} data
|
|
1494
|
+
* @param {number} [byteOffset=0] byte offset to the start of the Flatbush buffer in the referenced ArrayBuffer.
|
|
1495
|
+
* @returns {Flatbush} index
|
|
1496
|
+
*/
|
|
1497
|
+
static from(data, byteOffset = 0) {
|
|
1498
|
+
if (byteOffset % 8 !== 0) {
|
|
1499
|
+
throw new Error("byteOffset must be 8-byte aligned.");
|
|
1500
|
+
}
|
|
1501
|
+
if (!data || data.byteLength === void 0 || data.buffer) {
|
|
1502
|
+
throw new Error("Data must be an instance of ArrayBuffer or SharedArrayBuffer.");
|
|
1503
|
+
}
|
|
1504
|
+
const [magic, versionAndType] = new Uint8Array(data, byteOffset + 0, 2);
|
|
1505
|
+
if (magic !== 251) {
|
|
1506
|
+
throw new Error("Data does not appear to be in a Flatbush format.");
|
|
1507
|
+
}
|
|
1508
|
+
const version = versionAndType >> 4;
|
|
1509
|
+
if (version !== VERSION) {
|
|
1510
|
+
throw new Error(`Got v${version} data when expected v${VERSION}.`);
|
|
1511
|
+
}
|
|
1512
|
+
const ArrayType = ARRAY_TYPES[versionAndType & 15];
|
|
1513
|
+
if (!ArrayType) {
|
|
1514
|
+
throw new Error("Unrecognized array type.");
|
|
1515
|
+
}
|
|
1516
|
+
const [nodeSize] = new Uint16Array(data, byteOffset + 2, 1);
|
|
1517
|
+
const [numItems] = new Uint32Array(data, byteOffset + 4, 1);
|
|
1518
|
+
return new _Flatbush(numItems, nodeSize, ArrayType, void 0, data, byteOffset);
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Create a Flatbush index that will hold a given number of items.
|
|
1522
|
+
* @param {number} numItems
|
|
1523
|
+
* @param {number} [nodeSize=16] Size of the tree node (16 by default).
|
|
1524
|
+
* @param {TypedArrayConstructor} [ArrayType=Float64Array] The array type used for coordinates storage (`Float64Array` by default).
|
|
1525
|
+
* @param {ArrayBufferConstructor | SharedArrayBufferConstructor} [ArrayBufferType=ArrayBuffer] The array buffer type used to store data (`ArrayBuffer` by default).
|
|
1526
|
+
* @param {ArrayBuffer | SharedArrayBuffer} [data] (Only used internally)
|
|
1527
|
+
* @param {number} [byteOffset=0] (Only used internally)
|
|
1528
|
+
*/
|
|
1529
|
+
constructor(numItems, nodeSize = 16, ArrayType = Float64Array, ArrayBufferType = ArrayBuffer, data, byteOffset = 0) {
|
|
1530
|
+
if (numItems === void 0) throw new Error("Missing required argument: numItems.");
|
|
1531
|
+
if (isNaN(numItems) || numItems <= 0) throw new Error(`Unexpected numItems value: ${numItems}.`);
|
|
1532
|
+
this.numItems = +numItems;
|
|
1533
|
+
this.nodeSize = Math.min(Math.max(+nodeSize, 2), 65535);
|
|
1534
|
+
this.byteOffset = byteOffset;
|
|
1535
|
+
let n = numItems;
|
|
1536
|
+
let numNodes = n;
|
|
1537
|
+
this._levelBounds = [n * 4];
|
|
1538
|
+
do {
|
|
1539
|
+
n = Math.ceil(n / this.nodeSize);
|
|
1540
|
+
numNodes += n;
|
|
1541
|
+
this._levelBounds.push(numNodes * 4);
|
|
1542
|
+
} while (n !== 1);
|
|
1543
|
+
this.ArrayType = ArrayType;
|
|
1544
|
+
this.IndexArrayType = numNodes < 16384 ? Uint16Array : Uint32Array;
|
|
1545
|
+
const arrayTypeIndex = ARRAY_TYPES.indexOf(this.ArrayType);
|
|
1546
|
+
const nodesByteSize = numNodes * 4 * this.ArrayType.BYTES_PER_ELEMENT;
|
|
1547
|
+
if (arrayTypeIndex < 0) {
|
|
1548
|
+
throw new Error(`Unexpected typed array class: ${ArrayType}.`);
|
|
1549
|
+
}
|
|
1550
|
+
if (data && data.byteLength !== void 0 && !data.buffer) {
|
|
1551
|
+
this.data = data;
|
|
1552
|
+
this._boxes = new this.ArrayType(this.data, byteOffset + 8, numNodes * 4);
|
|
1553
|
+
this._indices = new this.IndexArrayType(this.data, byteOffset + 8 + nodesByteSize, numNodes);
|
|
1554
|
+
this._pos = numNodes * 4;
|
|
1555
|
+
this.minX = this._boxes[this._pos - 4];
|
|
1556
|
+
this.minY = this._boxes[this._pos - 3];
|
|
1557
|
+
this.maxX = this._boxes[this._pos - 2];
|
|
1558
|
+
this.maxY = this._boxes[this._pos - 1];
|
|
1559
|
+
} else {
|
|
1560
|
+
this.data = new ArrayBufferType(8 + nodesByteSize + numNodes * this.IndexArrayType.BYTES_PER_ELEMENT);
|
|
1561
|
+
this._boxes = new this.ArrayType(this.data, 8, numNodes * 4);
|
|
1562
|
+
this._indices = new this.IndexArrayType(this.data, 8 + nodesByteSize, numNodes);
|
|
1563
|
+
this._pos = 0;
|
|
1564
|
+
this.minX = Infinity;
|
|
1565
|
+
this.minY = Infinity;
|
|
1566
|
+
this.maxX = -Infinity;
|
|
1567
|
+
this.maxY = -Infinity;
|
|
1568
|
+
new Uint8Array(this.data, 0, 2).set([251, (VERSION << 4) + arrayTypeIndex]);
|
|
1569
|
+
new Uint16Array(this.data, 2, 1)[0] = nodeSize;
|
|
1570
|
+
new Uint32Array(this.data, 4, 1)[0] = numItems;
|
|
1571
|
+
}
|
|
1572
|
+
this._queue = new FlatQueue();
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Add a given rectangle to the index.
|
|
1576
|
+
* @param {number} minX
|
|
1577
|
+
* @param {number} minY
|
|
1578
|
+
* @param {number} maxX
|
|
1579
|
+
* @param {number} maxY
|
|
1580
|
+
* @returns {number} A zero-based, incremental number that represents the newly added rectangle.
|
|
1581
|
+
*/
|
|
1582
|
+
add(minX, minY, maxX = minX, maxY = minY) {
|
|
1583
|
+
const index = this._pos >> 2;
|
|
1584
|
+
const boxes = this._boxes;
|
|
1585
|
+
this._indices[index] = index;
|
|
1586
|
+
boxes[this._pos++] = minX;
|
|
1587
|
+
boxes[this._pos++] = minY;
|
|
1588
|
+
boxes[this._pos++] = maxX;
|
|
1589
|
+
boxes[this._pos++] = maxY;
|
|
1590
|
+
if (minX < this.minX) this.minX = minX;
|
|
1591
|
+
if (minY < this.minY) this.minY = minY;
|
|
1592
|
+
if (maxX > this.maxX) this.maxX = maxX;
|
|
1593
|
+
if (maxY > this.maxY) this.maxY = maxY;
|
|
1594
|
+
return index;
|
|
1595
|
+
}
|
|
1596
|
+
/** Perform indexing of the added rectangles. */
|
|
1597
|
+
finish() {
|
|
1598
|
+
if (this._pos >> 2 !== this.numItems) {
|
|
1599
|
+
throw new Error(`Added ${this._pos >> 2} items when expected ${this.numItems}.`);
|
|
1600
|
+
}
|
|
1601
|
+
const boxes = this._boxes;
|
|
1602
|
+
if (this.numItems <= this.nodeSize) {
|
|
1603
|
+
boxes[this._pos++] = this.minX;
|
|
1604
|
+
boxes[this._pos++] = this.minY;
|
|
1605
|
+
boxes[this._pos++] = this.maxX;
|
|
1606
|
+
boxes[this._pos++] = this.maxY;
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
const width = this.maxX - this.minX || 1;
|
|
1610
|
+
const height = this.maxY - this.minY || 1;
|
|
1611
|
+
const hilbertValues = new Uint32Array(this.numItems);
|
|
1612
|
+
const hilbertMax = (1 << 16) - 1;
|
|
1613
|
+
for (let i = 0, pos = 0; i < this.numItems; i++) {
|
|
1614
|
+
const minX = boxes[pos++];
|
|
1615
|
+
const minY = boxes[pos++];
|
|
1616
|
+
const maxX = boxes[pos++];
|
|
1617
|
+
const maxY = boxes[pos++];
|
|
1618
|
+
const x = Math.floor(hilbertMax * ((minX + maxX) / 2 - this.minX) / width);
|
|
1619
|
+
const y = Math.floor(hilbertMax * ((minY + maxY) / 2 - this.minY) / height);
|
|
1620
|
+
hilbertValues[i] = hilbert(x, y);
|
|
1621
|
+
}
|
|
1622
|
+
sort(hilbertValues, boxes, this._indices, 0, this.numItems - 1, this.nodeSize);
|
|
1623
|
+
for (let i = 0, pos = 0; i < this._levelBounds.length - 1; i++) {
|
|
1624
|
+
const end = this._levelBounds[i];
|
|
1625
|
+
while (pos < end) {
|
|
1626
|
+
const nodeIndex = pos;
|
|
1627
|
+
let nodeMinX = boxes[pos++];
|
|
1628
|
+
let nodeMinY = boxes[pos++];
|
|
1629
|
+
let nodeMaxX = boxes[pos++];
|
|
1630
|
+
let nodeMaxY = boxes[pos++];
|
|
1631
|
+
for (let j = 1; j < this.nodeSize && pos < end; j++) {
|
|
1632
|
+
nodeMinX = Math.min(nodeMinX, boxes[pos++]);
|
|
1633
|
+
nodeMinY = Math.min(nodeMinY, boxes[pos++]);
|
|
1634
|
+
nodeMaxX = Math.max(nodeMaxX, boxes[pos++]);
|
|
1635
|
+
nodeMaxY = Math.max(nodeMaxY, boxes[pos++]);
|
|
1636
|
+
}
|
|
1637
|
+
this._indices[this._pos >> 2] = nodeIndex;
|
|
1638
|
+
boxes[this._pos++] = nodeMinX;
|
|
1639
|
+
boxes[this._pos++] = nodeMinY;
|
|
1640
|
+
boxes[this._pos++] = nodeMaxX;
|
|
1641
|
+
boxes[this._pos++] = nodeMaxY;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* Search the index by a bounding box.
|
|
1647
|
+
* @param {number} minX
|
|
1648
|
+
* @param {number} minY
|
|
1649
|
+
* @param {number} maxX
|
|
1650
|
+
* @param {number} maxY
|
|
1651
|
+
* @param {(index: number) => boolean} [filterFn] An optional function for filtering the results.
|
|
1652
|
+
* @returns {number[]} An array of indices of items intersecting or touching the given bounding box.
|
|
1653
|
+
*/
|
|
1654
|
+
search(minX, minY, maxX, maxY, filterFn) {
|
|
1655
|
+
if (this._pos !== this._boxes.length) {
|
|
1656
|
+
throw new Error("Data not yet indexed - call index.finish().");
|
|
1657
|
+
}
|
|
1658
|
+
let nodeIndex = this._boxes.length - 4;
|
|
1659
|
+
const queue = [];
|
|
1660
|
+
const results = [];
|
|
1661
|
+
while (nodeIndex !== void 0) {
|
|
1662
|
+
const end = Math.min(nodeIndex + this.nodeSize * 4, upperBound(nodeIndex, this._levelBounds));
|
|
1663
|
+
for (let pos = nodeIndex; pos < end; pos += 4) {
|
|
1664
|
+
if (maxX < this._boxes[pos]) continue;
|
|
1665
|
+
if (maxY < this._boxes[pos + 1]) continue;
|
|
1666
|
+
if (minX > this._boxes[pos + 2]) continue;
|
|
1667
|
+
if (minY > this._boxes[pos + 3]) continue;
|
|
1668
|
+
const index = this._indices[pos >> 2] | 0;
|
|
1669
|
+
if (nodeIndex >= this.numItems * 4) {
|
|
1670
|
+
queue.push(index);
|
|
1671
|
+
} else if (filterFn === void 0 || filterFn(index)) {
|
|
1672
|
+
results.push(index);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
nodeIndex = queue.pop();
|
|
1676
|
+
}
|
|
1677
|
+
return results;
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* Search items in order of distance from the given point.
|
|
1681
|
+
* @param {number} x
|
|
1682
|
+
* @param {number} y
|
|
1683
|
+
* @param {number} [maxResults=Infinity]
|
|
1684
|
+
* @param {number} [maxDistance=Infinity]
|
|
1685
|
+
* @param {(index: number) => boolean} [filterFn] An optional function for filtering the results.
|
|
1686
|
+
* @returns {number[]} An array of indices of items found.
|
|
1687
|
+
*/
|
|
1688
|
+
neighbors(x, y, maxResults = Infinity, maxDistance = Infinity, filterFn) {
|
|
1689
|
+
if (this._pos !== this._boxes.length) {
|
|
1690
|
+
throw new Error("Data not yet indexed - call index.finish().");
|
|
1691
|
+
}
|
|
1692
|
+
let nodeIndex = this._boxes.length - 4;
|
|
1693
|
+
const q = this._queue;
|
|
1694
|
+
const results = [];
|
|
1695
|
+
const maxDistSquared = maxDistance * maxDistance;
|
|
1696
|
+
outer: while (nodeIndex !== void 0) {
|
|
1697
|
+
const end = Math.min(nodeIndex + this.nodeSize * 4, upperBound(nodeIndex, this._levelBounds));
|
|
1698
|
+
for (let pos = nodeIndex; pos < end; pos += 4) {
|
|
1699
|
+
const index = this._indices[pos >> 2] | 0;
|
|
1700
|
+
const dx = axisDist(x, this._boxes[pos], this._boxes[pos + 2]);
|
|
1701
|
+
const dy = axisDist(y, this._boxes[pos + 1], this._boxes[pos + 3]);
|
|
1702
|
+
const dist = dx * dx + dy * dy;
|
|
1703
|
+
if (dist > maxDistSquared) continue;
|
|
1704
|
+
if (nodeIndex >= this.numItems * 4) {
|
|
1705
|
+
q.push(index << 1, dist);
|
|
1706
|
+
} else if (filterFn === void 0 || filterFn(index)) {
|
|
1707
|
+
q.push((index << 1) + 1, dist);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
while (q.length && q.peek() & 1) {
|
|
1711
|
+
const dist = q.peekValue();
|
|
1712
|
+
if (dist > maxDistSquared) break outer;
|
|
1713
|
+
results.push(q.pop() >> 1);
|
|
1714
|
+
if (results.length === maxResults) break outer;
|
|
1715
|
+
}
|
|
1716
|
+
nodeIndex = q.length ? q.pop() >> 1 : void 0;
|
|
1717
|
+
}
|
|
1718
|
+
q.clear();
|
|
1719
|
+
return results;
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
function axisDist(k, min, max) {
|
|
1723
|
+
return k < min ? min - k : k <= max ? 0 : k - max;
|
|
1724
|
+
}
|
|
1725
|
+
function upperBound(value, arr) {
|
|
1726
|
+
let i = 0;
|
|
1727
|
+
let j = arr.length - 1;
|
|
1728
|
+
while (i < j) {
|
|
1729
|
+
const m = i + j >> 1;
|
|
1730
|
+
if (arr[m] > value) {
|
|
1731
|
+
j = m;
|
|
1732
|
+
} else {
|
|
1733
|
+
i = m + 1;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return arr[i];
|
|
1737
|
+
}
|
|
1738
|
+
function sort(values, boxes, indices, left, right, nodeSize) {
|
|
1739
|
+
if (Math.floor(left / nodeSize) >= Math.floor(right / nodeSize)) return;
|
|
1740
|
+
const pivot = values[left + right >> 1];
|
|
1741
|
+
let i = left - 1;
|
|
1742
|
+
let j = right + 1;
|
|
1743
|
+
while (true) {
|
|
1744
|
+
do
|
|
1745
|
+
i++;
|
|
1746
|
+
while (values[i] < pivot);
|
|
1747
|
+
do
|
|
1748
|
+
j--;
|
|
1749
|
+
while (values[j] > pivot);
|
|
1750
|
+
if (i >= j) break;
|
|
1751
|
+
swap2(values, boxes, indices, i, j);
|
|
1752
|
+
}
|
|
1753
|
+
sort(values, boxes, indices, left, j, nodeSize);
|
|
1754
|
+
sort(values, boxes, indices, j + 1, right, nodeSize);
|
|
1755
|
+
}
|
|
1756
|
+
function swap2(values, boxes, indices, i, j) {
|
|
1757
|
+
const temp = values[i];
|
|
1758
|
+
values[i] = values[j];
|
|
1759
|
+
values[j] = temp;
|
|
1760
|
+
const k = 4 * i;
|
|
1761
|
+
const m = 4 * j;
|
|
1762
|
+
const a = boxes[k];
|
|
1763
|
+
const b = boxes[k + 1];
|
|
1764
|
+
const c = boxes[k + 2];
|
|
1765
|
+
const d = boxes[k + 3];
|
|
1766
|
+
boxes[k] = boxes[m];
|
|
1767
|
+
boxes[k + 1] = boxes[m + 1];
|
|
1768
|
+
boxes[k + 2] = boxes[m + 2];
|
|
1769
|
+
boxes[k + 3] = boxes[m + 3];
|
|
1770
|
+
boxes[m] = a;
|
|
1771
|
+
boxes[m + 1] = b;
|
|
1772
|
+
boxes[m + 2] = c;
|
|
1773
|
+
boxes[m + 3] = d;
|
|
1774
|
+
const e = indices[i];
|
|
1775
|
+
indices[i] = indices[j];
|
|
1776
|
+
indices[j] = e;
|
|
1777
|
+
}
|
|
1778
|
+
function hilbert(x, y) {
|
|
1779
|
+
let a = x ^ y;
|
|
1780
|
+
let b = 65535 ^ a;
|
|
1781
|
+
let c = 65535 ^ (x | y);
|
|
1782
|
+
let d = x & (y ^ 65535);
|
|
1783
|
+
let A = a | b >> 1;
|
|
1784
|
+
let B = a >> 1 ^ a;
|
|
1785
|
+
let C = c >> 1 ^ b & d >> 1 ^ c;
|
|
1786
|
+
let D = a & c >> 1 ^ d >> 1 ^ d;
|
|
1787
|
+
a = A;
|
|
1788
|
+
b = B;
|
|
1789
|
+
c = C;
|
|
1790
|
+
d = D;
|
|
1791
|
+
A = a & a >> 2 ^ b & b >> 2;
|
|
1792
|
+
B = a & b >> 2 ^ b & (a ^ b) >> 2;
|
|
1793
|
+
C ^= a & c >> 2 ^ b & d >> 2;
|
|
1794
|
+
D ^= b & c >> 2 ^ (a ^ b) & d >> 2;
|
|
1795
|
+
a = A;
|
|
1796
|
+
b = B;
|
|
1797
|
+
c = C;
|
|
1798
|
+
d = D;
|
|
1799
|
+
A = a & a >> 4 ^ b & b >> 4;
|
|
1800
|
+
B = a & b >> 4 ^ b & (a ^ b) >> 4;
|
|
1801
|
+
C ^= a & c >> 4 ^ b & d >> 4;
|
|
1802
|
+
D ^= b & c >> 4 ^ (a ^ b) & d >> 4;
|
|
1803
|
+
a = A;
|
|
1804
|
+
b = B;
|
|
1805
|
+
c = C;
|
|
1806
|
+
d = D;
|
|
1807
|
+
C ^= a & c >> 8 ^ b & d >> 8;
|
|
1808
|
+
D ^= b & c >> 8 ^ (a ^ b) & d >> 8;
|
|
1809
|
+
a = C ^ C >> 1;
|
|
1810
|
+
b = D ^ D >> 1;
|
|
1811
|
+
let i0 = x ^ y;
|
|
1812
|
+
let i1 = b | 65535 ^ (i0 | a);
|
|
1813
|
+
i0 = (i0 | i0 << 8) & 16711935;
|
|
1814
|
+
i0 = (i0 | i0 << 4) & 252645135;
|
|
1815
|
+
i0 = (i0 | i0 << 2) & 858993459;
|
|
1816
|
+
i0 = (i0 | i0 << 1) & 1431655765;
|
|
1817
|
+
i1 = (i1 | i1 << 8) & 16711935;
|
|
1818
|
+
i1 = (i1 | i1 << 4) & 252645135;
|
|
1819
|
+
i1 = (i1 | i1 << 2) & 858993459;
|
|
1820
|
+
i1 = (i1 | i1 << 1) & 1431655765;
|
|
1821
|
+
return (i1 << 1 | i0) >>> 0;
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
// lib/data-structures/FlatbushIndex.ts
|
|
1825
|
+
var FlatbushIndex = class {
|
|
1826
|
+
index;
|
|
1827
|
+
items = [];
|
|
1828
|
+
currentIndex = 0;
|
|
1829
|
+
constructor(numItems) {
|
|
1830
|
+
this.index = new Flatbush(numItems);
|
|
1831
|
+
}
|
|
1832
|
+
insert(item, minX, minY, maxX, maxY) {
|
|
1833
|
+
if (this.currentIndex >= this.index.numItems) {
|
|
1834
|
+
throw new Error("Exceeded initial capacity");
|
|
1835
|
+
}
|
|
1836
|
+
this.items[this.currentIndex] = item;
|
|
1837
|
+
this.index.add(minX, minY, maxX, maxY);
|
|
1838
|
+
this.currentIndex++;
|
|
1839
|
+
}
|
|
1840
|
+
finish() {
|
|
1841
|
+
this.index.finish();
|
|
1842
|
+
}
|
|
1843
|
+
search(minX, minY, maxX, maxY) {
|
|
1844
|
+
const ids = this.index.search(minX, minY, maxX, maxY);
|
|
1845
|
+
return ids.map((id) => this.items[id] || null).filter(Boolean);
|
|
1846
|
+
}
|
|
1847
|
+
clear() {
|
|
1848
|
+
this.items = [];
|
|
1849
|
+
this.index = new Flatbush(0);
|
|
1850
|
+
}
|
|
1851
|
+
};
|
|
1852
|
+
|
|
971
1853
|
// lib/data-structures/ObstacleTree.ts
|
|
972
1854
|
var ObstacleSpatialHashIndex = class {
|
|
1855
|
+
idx;
|
|
1856
|
+
storage = [];
|
|
1857
|
+
constructor(implementation = "native", obstacles = []) {
|
|
1858
|
+
if (implementation === "flatbush") {
|
|
1859
|
+
this.idx = new FlatbushIndex(obstacles.length);
|
|
1860
|
+
} else if (implementation === "rbush") {
|
|
1861
|
+
this.idx = new RbushIndex();
|
|
1862
|
+
} else {
|
|
1863
|
+
this.idx = new class {
|
|
1864
|
+
shi = new NativeObstacleTree(obstacles);
|
|
1865
|
+
insert(item) {
|
|
1866
|
+
}
|
|
1867
|
+
search(minX, minY, maxX, maxY) {
|
|
1868
|
+
const centerX = (minX + maxX) / 2;
|
|
1869
|
+
const centerY = (minY + maxY) / 2;
|
|
1870
|
+
const width = maxX - minX;
|
|
1871
|
+
const height = maxY - minY;
|
|
1872
|
+
return this.shi.getNodesInArea(centerX, centerY, width, height);
|
|
1873
|
+
}
|
|
1874
|
+
clear() {
|
|
1875
|
+
}
|
|
1876
|
+
}();
|
|
1877
|
+
}
|
|
1878
|
+
obstacles.forEach((o) => this.insert(o));
|
|
1879
|
+
if (implementation === "flatbush") this.idx.finish?.();
|
|
1880
|
+
}
|
|
1881
|
+
insert(o) {
|
|
1882
|
+
this.storage.push(o);
|
|
1883
|
+
this.idx.insert(
|
|
1884
|
+
o,
|
|
1885
|
+
o.center.x - o.width / 2,
|
|
1886
|
+
o.center.y - o.height / 2,
|
|
1887
|
+
o.center.x + o.width / 2,
|
|
1888
|
+
o.center.y + o.height / 2
|
|
1889
|
+
);
|
|
1890
|
+
}
|
|
1891
|
+
search(bbox) {
|
|
1892
|
+
return this.idx.search(bbox.minX, bbox.minY, bbox.maxX, bbox.maxY);
|
|
1893
|
+
}
|
|
1894
|
+
searchArea(centerX, centerY, width, height) {
|
|
1895
|
+
return this.search({
|
|
1896
|
+
minX: centerX - width / 2,
|
|
1897
|
+
minY: centerY - height / 2,
|
|
1898
|
+
maxX: centerX + width / 2,
|
|
1899
|
+
maxY: centerY + height / 2
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
var NativeObstacleTree = class {
|
|
973
1904
|
constructor(obstacles) {
|
|
974
1905
|
this.obstacles = obstacles;
|
|
975
1906
|
this.buckets = /* @__PURE__ */ new Map();
|
|
@@ -1115,7 +2046,10 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1115
2046
|
];
|
|
1116
2047
|
this.finishedNodes = [];
|
|
1117
2048
|
this.nodeToXYOverlappingObstaclesMap = /* @__PURE__ */ new Map();
|
|
1118
|
-
this.obstacleTree = new ObstacleSpatialHashIndex(
|
|
2049
|
+
this.obstacleTree = new ObstacleSpatialHashIndex(
|
|
2050
|
+
"flatbush",
|
|
2051
|
+
this.srj.obstacles
|
|
2052
|
+
);
|
|
1119
2053
|
this.targets = this.computeTargets();
|
|
1120
2054
|
this.targetTree = new TargetTree(this.targets);
|
|
1121
2055
|
}
|
|
@@ -1132,7 +2066,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1132
2066
|
const targets = [];
|
|
1133
2067
|
for (const conn of this.srj.connections) {
|
|
1134
2068
|
for (const ptc of conn.pointsToConnect) {
|
|
1135
|
-
const obstacles = this.obstacleTree.
|
|
2069
|
+
const obstacles = this.obstacleTree.searchArea(ptc.x, ptc.y, 0.01, 0.01).filter(
|
|
1136
2070
|
(o) => o.zLayers.some((z) => ptc.layer === "top" ? z === 0 : z === 1)
|
|
1137
2071
|
);
|
|
1138
2072
|
let bounds = {
|
|
@@ -1972,7 +2906,7 @@ var CapacitySegmentToPointSolver = class extends BaseSolver {
|
|
|
1972
2906
|
}
|
|
1973
2907
|
};
|
|
1974
2908
|
|
|
1975
|
-
// node_modules/@tscircuit/math-utils/dist/chunk-
|
|
2909
|
+
// node_modules/@tscircuit/math-utils/dist/chunk-3453HRP7.js
|
|
1976
2910
|
function doSegmentsIntersect(p1, q1, p2, q2) {
|
|
1977
2911
|
const o1 = orientation(p1, q1, p2);
|
|
1978
2912
|
const o2 = orientation(p1, q1, q2);
|
|
@@ -2044,7 +2978,7 @@ function clamp(value, min, max) {
|
|
|
2044
2978
|
return Math.max(min, Math.min(max, value));
|
|
2045
2979
|
}
|
|
2046
2980
|
|
|
2047
|
-
// node_modules/@tscircuit/math-utils/dist/chunk-
|
|
2981
|
+
// node_modules/@tscircuit/math-utils/dist/chunk-FWQGMQBW.js
|
|
2048
2982
|
function segmentToSegmentMinDistance(a, b, u, v) {
|
|
2049
2983
|
if (a.x === b.x && a.y === b.y) {
|
|
2050
2984
|
return pointToSegmentDistance(a, u, v);
|
|
@@ -3078,12 +4012,15 @@ var HyperParameterSupervisorSolver = class extends BaseSolver {
|
|
|
3078
4012
|
}
|
|
3079
4013
|
return bestSolver;
|
|
3080
4014
|
}
|
|
4015
|
+
getFailureMessage() {
|
|
4016
|
+
return "All solvers failed in hyper solver.";
|
|
4017
|
+
}
|
|
3081
4018
|
_step() {
|
|
3082
4019
|
if (!this.supervisedSolvers) this.initializeSolvers();
|
|
3083
4020
|
const supervisedSolver = this.getSupervisedSolverWithBestFitness();
|
|
3084
4021
|
if (!supervisedSolver) {
|
|
3085
4022
|
this.failed = true;
|
|
3086
|
-
this.error =
|
|
4023
|
+
this.error = this.getFailureMessage();
|
|
3087
4024
|
return;
|
|
3088
4025
|
}
|
|
3089
4026
|
for (let i = 0; i < this.MIN_SUBSTEPS; i++) {
|
|
@@ -5332,10 +6269,13 @@ var Vertex = class {
|
|
|
5332
6269
|
y;
|
|
5333
6270
|
out;
|
|
5334
6271
|
// Outgoing half-edge indices
|
|
6272
|
+
connectionNames;
|
|
6273
|
+
// Names of connections passing through this vertex
|
|
5335
6274
|
constructor(x, y) {
|
|
5336
6275
|
this.x = x;
|
|
5337
6276
|
this.y = y;
|
|
5338
6277
|
this.out = [];
|
|
6278
|
+
this.connectionNames = /* @__PURE__ */ new Set();
|
|
5339
6279
|
}
|
|
5340
6280
|
};
|
|
5341
6281
|
var HalfEdge = class {
|
|
@@ -5419,9 +6359,17 @@ function getCentroidsFromInnerBoxIntersections(rectangle, userSegments) {
|
|
|
5419
6359
|
return t1 - t2;
|
|
5420
6360
|
});
|
|
5421
6361
|
for (let k = 0; k < list.length - 1; ++k) {
|
|
5422
|
-
const
|
|
5423
|
-
const
|
|
5424
|
-
|
|
6362
|
+
const p1 = list[k];
|
|
6363
|
+
const p2 = list[k + 1];
|
|
6364
|
+
const v1 = getVertexId(p1);
|
|
6365
|
+
const v2 = getVertexId(p2);
|
|
6366
|
+
if (v1 !== v2) {
|
|
6367
|
+
undirectedEdges.push([v1, v2]);
|
|
6368
|
+
if (s.connectionName) {
|
|
6369
|
+
vertices[v1].connectionNames.add(s.connectionName);
|
|
6370
|
+
vertices[v2].connectionNames.add(s.connectionName);
|
|
6371
|
+
}
|
|
6372
|
+
}
|
|
5425
6373
|
}
|
|
5426
6374
|
}
|
|
5427
6375
|
const halfEdges = [];
|
|
@@ -5478,8 +6426,11 @@ function getCentroidsFromInnerBoxIntersections(rectangle, userSegments) {
|
|
|
5478
6426
|
if (c) {
|
|
5479
6427
|
centroids.push(c);
|
|
5480
6428
|
faces.push({
|
|
5481
|
-
vertices: poly.map((
|
|
5482
|
-
|
|
6429
|
+
vertices: poly.map((v) => ({
|
|
6430
|
+
x: v.x,
|
|
6431
|
+
y: v.y,
|
|
6432
|
+
connectionNames: v.connectionNames.size > 0 ? v.connectionNames : void 0
|
|
6433
|
+
})),
|
|
5483
6434
|
centroid: c
|
|
5484
6435
|
});
|
|
5485
6436
|
}
|
|
@@ -6065,6 +7016,7 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
|
|
|
6065
7016
|
obstacleMargin = 0.1;
|
|
6066
7017
|
traceWidth = 0.15;
|
|
6067
7018
|
availableZ = [];
|
|
7019
|
+
uniqueConnections = 0;
|
|
6068
7020
|
lastCandidate = null;
|
|
6069
7021
|
maxViaCount;
|
|
6070
7022
|
minViaCount;
|
|
@@ -6092,6 +7044,7 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
|
|
|
6092
7044
|
const uniqueConnections = new Set(
|
|
6093
7045
|
this.nodeWithPortPoints.portPoints.map((pp) => pp.connectionName)
|
|
6094
7046
|
).size;
|
|
7047
|
+
this.uniqueConnections = uniqueConnections;
|
|
6095
7048
|
const { numSameLayerCrossings, numTransitions } = getIntraNodeCrossings(
|
|
6096
7049
|
this.nodeWithPortPoints
|
|
6097
7050
|
);
|
|
@@ -6100,11 +7053,6 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
|
|
|
6100
7053
|
Math.floor(areaInsideNode / areaPerVia),
|
|
6101
7054
|
Math.ceil(uniqueConnections * 1.5)
|
|
6102
7055
|
);
|
|
6103
|
-
if (uniqueConnections > 5) {
|
|
6104
|
-
this.failed = true;
|
|
6105
|
-
this.error = `Limit is currently set to 6 unique connections, ${uniqueConnections} found`;
|
|
6106
|
-
return;
|
|
6107
|
-
}
|
|
6108
7056
|
if (this.minViaCount > this.SEGMENTS_PER_POLYLINE * (uniqueConnections / 2)) {
|
|
6109
7057
|
this.failed = true;
|
|
6110
7058
|
this.error = `Not possible to solve problem with given SEGMENTS_PER_POLYLINE (${this.SEGMENTS_PER_POLYLINE}), atleast ${this.minViaCount} vias are required`;
|
|
@@ -6843,7 +7791,7 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
|
|
|
6843
7791
|
strokeColor: segmentColor,
|
|
6844
7792
|
strokeWidth: this.traceWidth,
|
|
6845
7793
|
// TODO: Use actual trace thickness from HighDensityRoute?
|
|
6846
|
-
strokeDash: !isLayer0 ?
|
|
7794
|
+
strokeDash: !isLayer0 ? [0.15, 0.15] : void 0,
|
|
6847
7795
|
// Dashed for layers > 0
|
|
6848
7796
|
label: `${polyLine.connectionName} segment (z=${segmentLayer})`
|
|
6849
7797
|
});
|
|
@@ -7572,7 +8520,7 @@ var HighDensitySolver = class extends BaseSolver {
|
|
|
7572
8520
|
if (this.failedSolvers.length > 0) {
|
|
7573
8521
|
this.solved = false;
|
|
7574
8522
|
this.failed = true;
|
|
7575
|
-
this.error = `Failed to solve ${this.failedSolvers.length} nodes`;
|
|
8523
|
+
this.error = `Failed to solve ${this.failedSolvers.length} nodes, ${this.failedSolvers.slice(0, 5).map((fs) => fs.nodeWithPortPoints.capacityMeshNodeId)}`;
|
|
7576
8524
|
return;
|
|
7577
8525
|
}
|
|
7578
8526
|
this.solved = true;
|
|
@@ -7644,7 +8592,8 @@ var HighDensitySolver = class extends BaseSolver {
|
|
|
7644
8592
|
graphics.lines.push({
|
|
7645
8593
|
points: [start, end],
|
|
7646
8594
|
strokeColor: "red",
|
|
7647
|
-
strokeDash: "10, 5"
|
|
8595
|
+
strokeDash: "10, 5",
|
|
8596
|
+
layer: "did_not_connect"
|
|
7648
8597
|
});
|
|
7649
8598
|
}
|
|
7650
8599
|
}
|
|
@@ -8128,7 +9077,7 @@ var SingleHighDensityRouteStitchSolver = class extends BaseSolver {
|
|
|
8128
9077
|
super();
|
|
8129
9078
|
this.remainingHdRoutes = [...opts.hdRoutes];
|
|
8130
9079
|
this.colorMap = opts.colorMap ?? {};
|
|
8131
|
-
const firstRoute = this.
|
|
9080
|
+
const { firstRoute } = this.getDisjointedRoute();
|
|
8132
9081
|
const firstRouteToStartDist = Math.min(
|
|
8133
9082
|
distance(firstRoute.route[0], opts.start),
|
|
8134
9083
|
distance(firstRoute.route[firstRoute.route.length - 1], opts.start)
|
|
@@ -8154,10 +9103,42 @@ var SingleHighDensityRouteStitchSolver = class extends BaseSolver {
|
|
|
8154
9103
|
}
|
|
8155
9104
|
],
|
|
8156
9105
|
vias: [],
|
|
8157
|
-
viaDiameter:
|
|
8158
|
-
traceThickness:
|
|
9106
|
+
viaDiameter: firstRoute.viaDiameter,
|
|
9107
|
+
traceThickness: firstRoute.traceThickness
|
|
8159
9108
|
};
|
|
8160
9109
|
}
|
|
9110
|
+
/**
|
|
9111
|
+
* Scan `remainingHdRoutes` and find a route that has **one** end that is not
|
|
9112
|
+
* within `5e-6` of the start or end of any other route on the same layer.
|
|
9113
|
+
* That “lonely” end marks one extremity of the whole chain, which we use as
|
|
9114
|
+
* our starting segment. If no such route exists (e.g., the data form a loop),
|
|
9115
|
+
* we simply return the first route so the solver can proceed.
|
|
9116
|
+
*/
|
|
9117
|
+
getDisjointedRoute() {
|
|
9118
|
+
const TOL = 5e-6;
|
|
9119
|
+
for (const candidate of this.remainingHdRoutes) {
|
|
9120
|
+
const candidateEnds = [
|
|
9121
|
+
candidate.route[0],
|
|
9122
|
+
candidate.route[candidate.route.length - 1]
|
|
9123
|
+
];
|
|
9124
|
+
const hasLonelyEnd = candidateEnds.some((end) => {
|
|
9125
|
+
return !this.remainingHdRoutes.some((other) => {
|
|
9126
|
+
if (other === candidate) return false;
|
|
9127
|
+
const otherEnds = [
|
|
9128
|
+
other.route[0],
|
|
9129
|
+
other.route[other.route.length - 1]
|
|
9130
|
+
];
|
|
9131
|
+
return otherEnds.some(
|
|
9132
|
+
(oe) => oe.z === end.z && distance(end, oe) < TOL
|
|
9133
|
+
);
|
|
9134
|
+
});
|
|
9135
|
+
});
|
|
9136
|
+
if (hasLonelyEnd) {
|
|
9137
|
+
return { firstRoute: candidate };
|
|
9138
|
+
}
|
|
9139
|
+
}
|
|
9140
|
+
return { firstRoute: this.remainingHdRoutes[0] };
|
|
9141
|
+
}
|
|
8161
9142
|
_step() {
|
|
8162
9143
|
if (this.remainingHdRoutes.length === 0) {
|
|
8163
9144
|
this.mergedHdRoute.route.push({
|
|
@@ -10514,7 +11495,7 @@ ${percent}% (Pf: ${(probabilityOfFailure * 100).toFixed(1)}%)`;
|
|
|
10514
11495
|
}
|
|
10515
11496
|
|
|
10516
11497
|
// lib/solvers/CapacityPathingSectionSolver/CapacityPathingSingleSectionPathingSolver.ts
|
|
10517
|
-
var
|
|
11498
|
+
var CapacityPathingSingleSectionSolver = class extends BaseSolver {
|
|
10518
11499
|
GREEDY_MULTIPLIER = 1.5;
|
|
10519
11500
|
sectionNodes;
|
|
10520
11501
|
sectionEdges;
|
|
@@ -10526,6 +11507,7 @@ var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
|
|
|
10526
11507
|
colorMap;
|
|
10527
11508
|
usedNodeCapacityMap;
|
|
10528
11509
|
// Tracks capacity usage *within this solver's run*
|
|
11510
|
+
centerNodeId;
|
|
10529
11511
|
MAX_CANDIDATES_IN_MEMORY = 1e4;
|
|
10530
11512
|
// A* state
|
|
10531
11513
|
currentConnectionIndex = 0;
|
|
@@ -10539,6 +11521,7 @@ var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
|
|
|
10539
11521
|
// Default, similar to CapacityPathingSolver5
|
|
10540
11522
|
constructor(params) {
|
|
10541
11523
|
super();
|
|
11524
|
+
this.centerNodeId = params.centerNodeId;
|
|
10542
11525
|
this.sectionNodes = params.sectionNodes;
|
|
10543
11526
|
this.sectionEdges = params.sectionEdges;
|
|
10544
11527
|
this.sectionConnectionTerminals = params.sectionConnectionTerminals.map(
|
|
@@ -10712,6 +11695,28 @@ var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
|
|
|
10712
11695
|
candidates.push(newCandidate);
|
|
10713
11696
|
}
|
|
10714
11697
|
}
|
|
11698
|
+
computeProgress() {
|
|
11699
|
+
const totalConnections = this.sectionConnectionTerminals.length;
|
|
11700
|
+
if (totalConnections === 0) return 1;
|
|
11701
|
+
const completedConnections = this.currentConnectionIndex;
|
|
11702
|
+
let progress = completedConnections / totalConnections;
|
|
11703
|
+
if (this.currentConnectionIndex < totalConnections && this.candidates && this.candidates.length > 0 && this.activeCandidateStraightLineDistance && this.activeCandidateStraightLineDistance > 0) {
|
|
11704
|
+
const bestCandidate = this.candidates.reduce(
|
|
11705
|
+
(best, current) => current.f < best.f ? current : best
|
|
11706
|
+
);
|
|
11707
|
+
const currentConnectionProgress = Math.max(
|
|
11708
|
+
0,
|
|
11709
|
+
Math.min(
|
|
11710
|
+
1,
|
|
11711
|
+
1 - bestCandidate.h / this.activeCandidateStraightLineDistance
|
|
11712
|
+
)
|
|
11713
|
+
);
|
|
11714
|
+
progress += currentConnectionProgress / totalConnections;
|
|
11715
|
+
} else if (this.solved) {
|
|
11716
|
+
progress = 1;
|
|
11717
|
+
}
|
|
11718
|
+
return Math.min(1, progress);
|
|
11719
|
+
}
|
|
10715
11720
|
_setupAStar(startNode, endNode) {
|
|
10716
11721
|
this.candidates = [
|
|
10717
11722
|
{ prevCandidate: null, node: startNode, f: 0, g: 0, h: 0 }
|
|
@@ -10816,133 +11821,157 @@ var CapacityPathingSingleSectionPathingSolver = class extends BaseSolver {
|
|
|
10816
11821
|
return baseGraphics;
|
|
10817
11822
|
}
|
|
10818
11823
|
};
|
|
11824
|
+
var CapacityPathingSingleSectionPathingSolver = CapacityPathingSingleSectionSolver;
|
|
10819
11825
|
|
|
10820
|
-
// lib/solvers/CapacityPathingSectionSolver/
|
|
10821
|
-
var
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
nodes;
|
|
10825
|
-
nodeMap;
|
|
10826
|
-
edges;
|
|
10827
|
-
nodeEdgeMap;
|
|
10828
|
-
expansionDegrees;
|
|
10829
|
-
colorMap;
|
|
10830
|
-
sectionNodes;
|
|
10831
|
-
sectionEdges;
|
|
10832
|
-
// Added sectionEdges property
|
|
10833
|
-
sectionConnectionTerminals;
|
|
10834
|
-
activeSubSolver = null;
|
|
11826
|
+
// lib/solvers/CapacityPathingSectionSolver/HyperCapacityPathingSingleSectionSolver.ts
|
|
11827
|
+
var HyperCapacityPathingSingleSectionSolver = class extends HyperParameterSupervisorSolver {
|
|
11828
|
+
constructorParams;
|
|
11829
|
+
winningSolver;
|
|
10835
11830
|
constructor(params) {
|
|
10836
11831
|
super();
|
|
10837
|
-
this.MAX_ITERATIONS =
|
|
10838
|
-
this.
|
|
10839
|
-
this.centerNodeId = params.centerNodeId;
|
|
10840
|
-
this.connectionsWithNodes = params.connectionsWithNodes;
|
|
10841
|
-
this.nodes = params.nodes;
|
|
10842
|
-
this.nodeMap = new Map(this.nodes.map((n) => [n.capacityMeshNodeId, n]));
|
|
10843
|
-
this.edges = params.edges;
|
|
10844
|
-
this.nodeEdgeMap = getNodeEdgeMap(this.edges);
|
|
10845
|
-
this.expansionDegrees = params.hyperParameters?.EXPANSION_DEGREES ?? 3;
|
|
10846
|
-
this.sectionNodes = [];
|
|
10847
|
-
this.sectionEdges = [];
|
|
10848
|
-
this.sectionConnectionTerminals = [];
|
|
10849
|
-
this.computeSectionNodesTerminalsAndEdges();
|
|
10850
|
-
this.activeSubSolver = new CapacityPathingSingleSectionPathingSolver({
|
|
10851
|
-
sectionConnectionTerminals: this.sectionConnectionTerminals,
|
|
10852
|
-
sectionNodes: this.sectionNodes,
|
|
10853
|
-
sectionEdges: this.sectionEdges,
|
|
10854
|
-
colorMap: this.colorMap,
|
|
10855
|
-
hyperParameters: params.hyperParameters
|
|
10856
|
-
});
|
|
11832
|
+
this.MAX_ITERATIONS = 1e4;
|
|
11833
|
+
this.constructorParams = params;
|
|
10857
11834
|
}
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
const queue = [
|
|
10861
|
-
{ nodeId: this.centerNodeId, depth: 0 }
|
|
10862
|
-
];
|
|
10863
|
-
sectionNodeIds.add(this.centerNodeId);
|
|
10864
|
-
let head = 0;
|
|
10865
|
-
while (head < queue.length) {
|
|
10866
|
-
const { nodeId, depth } = queue[head++];
|
|
10867
|
-
if (depth >= this.expansionDegrees) continue;
|
|
10868
|
-
const neighbors = this.nodeEdgeMap.get(nodeId)?.flatMap((edge) => edge.nodeIds.filter((id) => id !== nodeId)) ?? [];
|
|
10869
|
-
for (const neighborId of neighbors) {
|
|
10870
|
-
if (!sectionNodeIds.has(neighborId)) {
|
|
10871
|
-
sectionNodeIds.add(neighborId);
|
|
10872
|
-
queue.push({ nodeId: neighborId, depth: depth + 1 });
|
|
10873
|
-
}
|
|
10874
|
-
}
|
|
10875
|
-
}
|
|
10876
|
-
this.sectionNodes = Array.from(sectionNodeIds).map(
|
|
10877
|
-
(id) => this.nodeMap.get(id)
|
|
10878
|
-
);
|
|
10879
|
-
this.sectionEdges = this.edges.filter((edge) => {
|
|
10880
|
-
const [nodeIdA, nodeIdB] = edge.nodeIds;
|
|
10881
|
-
return sectionNodeIds.has(nodeIdA) && sectionNodeIds.has(nodeIdB);
|
|
10882
|
-
});
|
|
10883
|
-
this.sectionConnectionTerminals = [];
|
|
10884
|
-
for (const conn of this.connectionsWithNodes) {
|
|
10885
|
-
if (!conn.path) continue;
|
|
10886
|
-
let startNodeId = null;
|
|
10887
|
-
let endNodeId = null;
|
|
10888
|
-
for (const node of conn.path) {
|
|
10889
|
-
if (sectionNodeIds.has(node.capacityMeshNodeId)) {
|
|
10890
|
-
startNodeId = node.capacityMeshNodeId;
|
|
10891
|
-
break;
|
|
10892
|
-
}
|
|
10893
|
-
}
|
|
10894
|
-
for (let i = conn.path.length - 1; i >= 0; i--) {
|
|
10895
|
-
const node = conn.path[i];
|
|
10896
|
-
if (sectionNodeIds.has(node.capacityMeshNodeId)) {
|
|
10897
|
-
endNodeId = node.capacityMeshNodeId;
|
|
10898
|
-
break;
|
|
10899
|
-
}
|
|
10900
|
-
}
|
|
10901
|
-
if (startNodeId && endNodeId) {
|
|
10902
|
-
this.sectionConnectionTerminals.push({
|
|
10903
|
-
connectionName: conn.connection.name,
|
|
10904
|
-
startNodeId,
|
|
10905
|
-
endNodeId
|
|
10906
|
-
});
|
|
10907
|
-
}
|
|
10908
|
-
}
|
|
11835
|
+
computeG(solver) {
|
|
11836
|
+
return solver.iterations / 100;
|
|
10909
11837
|
}
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
if (this.activeSubSolver?.solved) {
|
|
10913
|
-
this.solved = true;
|
|
10914
|
-
return;
|
|
10915
|
-
}
|
|
10916
|
-
if (this.activeSubSolver?.failed) {
|
|
10917
|
-
this.failed = true;
|
|
10918
|
-
this.error = this.activeSubSolver.error;
|
|
10919
|
-
return;
|
|
10920
|
-
}
|
|
11838
|
+
computeH(solver) {
|
|
11839
|
+
return solver.computeProgress();
|
|
10921
11840
|
}
|
|
10922
|
-
|
|
11841
|
+
getCombinationDefs() {
|
|
11842
|
+
return [["orderings10"]];
|
|
11843
|
+
}
|
|
11844
|
+
getFailureMessage() {
|
|
11845
|
+
return `All CapacityPathingSingleSection solvers failed for "${this.centerNodeId}"`;
|
|
11846
|
+
}
|
|
11847
|
+
getHyperParameterDefs() {
|
|
10923
11848
|
return [
|
|
10924
11849
|
{
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
11850
|
+
name: "orderings10",
|
|
11851
|
+
possibleValues: [
|
|
11852
|
+
{
|
|
11853
|
+
SHUFFLE_SEED: 0
|
|
11854
|
+
},
|
|
11855
|
+
{
|
|
11856
|
+
SHUFFLE_SEED: 1
|
|
11857
|
+
},
|
|
11858
|
+
{
|
|
11859
|
+
SHUFFLE_SEED: 2
|
|
11860
|
+
},
|
|
11861
|
+
{
|
|
11862
|
+
SHUFFLE_SEED: 3
|
|
11863
|
+
},
|
|
11864
|
+
{
|
|
11865
|
+
SHUFFLE_SEED: 4
|
|
11866
|
+
},
|
|
11867
|
+
{
|
|
11868
|
+
SHUFFLE_SEED: 5
|
|
11869
|
+
},
|
|
11870
|
+
{
|
|
11871
|
+
SHUFFLE_SEED: 6
|
|
11872
|
+
},
|
|
11873
|
+
{
|
|
11874
|
+
SHUFFLE_SEED: 7
|
|
11875
|
+
},
|
|
11876
|
+
{
|
|
11877
|
+
SHUFFLE_SEED: 8
|
|
11878
|
+
},
|
|
11879
|
+
{
|
|
11880
|
+
SHUFFLE_SEED: 9
|
|
11881
|
+
}
|
|
11882
|
+
]
|
|
10930
11883
|
}
|
|
10931
11884
|
];
|
|
10932
11885
|
}
|
|
10933
|
-
|
|
10934
|
-
return
|
|
10935
|
-
|
|
10936
|
-
|
|
10937
|
-
|
|
10938
|
-
|
|
10939
|
-
|
|
10940
|
-
colorMap: this.colorMap,
|
|
10941
|
-
centerNodeId: this.centerNodeId,
|
|
10942
|
-
nodeOpacity: 1e-3,
|
|
10943
|
-
title: `Section Solver (Center: ${this.centerNodeId}, Hops: ${this.expansionDegrees})`
|
|
11886
|
+
generateSolver(hyperParameters) {
|
|
11887
|
+
return new CapacityPathingSingleSectionPathingSolver({
|
|
11888
|
+
...this.constructorParams,
|
|
11889
|
+
hyperParameters: {
|
|
11890
|
+
...this.constructorParams.hyperParameters,
|
|
11891
|
+
...hyperParameters
|
|
11892
|
+
}
|
|
10944
11893
|
});
|
|
10945
11894
|
}
|
|
11895
|
+
onSolve({
|
|
11896
|
+
solver
|
|
11897
|
+
}) {
|
|
11898
|
+
this.winningSolver = solver;
|
|
11899
|
+
}
|
|
11900
|
+
get centerNodeId() {
|
|
11901
|
+
return this.constructorParams.centerNodeId;
|
|
11902
|
+
}
|
|
11903
|
+
get sectionNodes() {
|
|
11904
|
+
return this.constructorParams.sectionNodes;
|
|
11905
|
+
}
|
|
11906
|
+
get sectionConnectionTerminals() {
|
|
11907
|
+
return this.winningSolver?.sectionConnectionTerminals;
|
|
11908
|
+
}
|
|
11909
|
+
};
|
|
11910
|
+
|
|
11911
|
+
// lib/solvers/CapacityPathingSectionSolver/computeSectionNodesTerminalsAndEdges.ts
|
|
11912
|
+
var computeSectionNodesTerminalsAndEdges = (opts) => {
|
|
11913
|
+
const {
|
|
11914
|
+
centerNodeId,
|
|
11915
|
+
connectionsWithNodes,
|
|
11916
|
+
nodeMap,
|
|
11917
|
+
edges,
|
|
11918
|
+
nodeEdgeMap,
|
|
11919
|
+
expansionDegrees
|
|
11920
|
+
} = opts;
|
|
11921
|
+
const sectionNodeIds = /* @__PURE__ */ new Set();
|
|
11922
|
+
const queue = [
|
|
11923
|
+
{ nodeId: centerNodeId, depth: 0 }
|
|
11924
|
+
];
|
|
11925
|
+
sectionNodeIds.add(centerNodeId);
|
|
11926
|
+
let head = 0;
|
|
11927
|
+
while (head < queue.length) {
|
|
11928
|
+
const { nodeId, depth } = queue[head++];
|
|
11929
|
+
if (depth >= expansionDegrees) continue;
|
|
11930
|
+
const neighbors = nodeEdgeMap.get(nodeId)?.flatMap((edge) => edge.nodeIds.filter((id) => id !== nodeId)) ?? [];
|
|
11931
|
+
for (const neighborId of neighbors) {
|
|
11932
|
+
if (!sectionNodeIds.has(neighborId)) {
|
|
11933
|
+
sectionNodeIds.add(neighborId);
|
|
11934
|
+
queue.push({ nodeId: neighborId, depth: depth + 1 });
|
|
11935
|
+
}
|
|
11936
|
+
}
|
|
11937
|
+
}
|
|
11938
|
+
const sectionNodes = Array.from(sectionNodeIds).map((id) => nodeMap.get(id));
|
|
11939
|
+
const sectionEdges = edges.filter((edge) => {
|
|
11940
|
+
const [nodeIdA, nodeIdB] = edge.nodeIds;
|
|
11941
|
+
return sectionNodeIds.has(nodeIdA) && sectionNodeIds.has(nodeIdB);
|
|
11942
|
+
});
|
|
11943
|
+
const sectionConnectionTerminals = [];
|
|
11944
|
+
for (const conn of connectionsWithNodes) {
|
|
11945
|
+
if (!conn.path) continue;
|
|
11946
|
+
let startNodeId = null;
|
|
11947
|
+
let endNodeId = null;
|
|
11948
|
+
for (const node of conn.path) {
|
|
11949
|
+
if (sectionNodeIds.has(node.capacityMeshNodeId)) {
|
|
11950
|
+
startNodeId = node.capacityMeshNodeId;
|
|
11951
|
+
break;
|
|
11952
|
+
}
|
|
11953
|
+
}
|
|
11954
|
+
for (let i = conn.path.length - 1; i >= 0; i--) {
|
|
11955
|
+
const node = conn.path[i];
|
|
11956
|
+
if (sectionNodeIds.has(node.capacityMeshNodeId)) {
|
|
11957
|
+
endNodeId = node.capacityMeshNodeId;
|
|
11958
|
+
break;
|
|
11959
|
+
}
|
|
11960
|
+
}
|
|
11961
|
+
if (startNodeId && endNodeId) {
|
|
11962
|
+
sectionConnectionTerminals.push({
|
|
11963
|
+
connectionName: conn.connection.name,
|
|
11964
|
+
startNodeId,
|
|
11965
|
+
endNodeId
|
|
11966
|
+
});
|
|
11967
|
+
}
|
|
11968
|
+
}
|
|
11969
|
+
return {
|
|
11970
|
+
sectionConnectionTerminals,
|
|
11971
|
+
sectionNodes,
|
|
11972
|
+
sectionEdges,
|
|
11973
|
+
centerNodeId
|
|
11974
|
+
};
|
|
10946
11975
|
};
|
|
10947
11976
|
|
|
10948
11977
|
// lib/solvers/CapacityPathingSectionSolver/CapacityPathingMultiSectionSolver.ts
|
|
@@ -10950,6 +11979,7 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
|
|
|
10950
11979
|
simpleRouteJson;
|
|
10951
11980
|
nodes;
|
|
10952
11981
|
edges;
|
|
11982
|
+
nodeEdgeMap;
|
|
10953
11983
|
connectionsWithNodes = [];
|
|
10954
11984
|
// Initialize here
|
|
10955
11985
|
colorMap;
|
|
@@ -10961,6 +11991,7 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
|
|
|
10961
11991
|
// Added
|
|
10962
11992
|
nodeCapacityPercentMap = /* @__PURE__ */ new Map();
|
|
10963
11993
|
nodeOptimizationAttemptCountMap = /* @__PURE__ */ new Map();
|
|
11994
|
+
currentSection = null;
|
|
10964
11995
|
sectionSolver = null;
|
|
10965
11996
|
MAX_ATTEMPTS_PER_NODE = 10;
|
|
10966
11997
|
MINIMUM_PROBABILITY_OF_FAILURE_TO_OPTIMIZE = 0.05;
|
|
@@ -10975,6 +12006,7 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
|
|
|
10975
12006
|
this.nodeMap = new Map(
|
|
10976
12007
|
this.nodes.map((node) => [node.capacityMeshNodeId, node])
|
|
10977
12008
|
);
|
|
12009
|
+
this.nodeEdgeMap = getNodeEdgeMap(this.edges);
|
|
10978
12010
|
this.initialSolver = new CapacityPathingGreedySolver({
|
|
10979
12011
|
simpleRouteJson: this.simpleRouteJson,
|
|
10980
12012
|
nodes: this.nodes,
|
|
@@ -11040,16 +12072,21 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
|
|
|
11040
12072
|
this.solved = true;
|
|
11041
12073
|
return;
|
|
11042
12074
|
}
|
|
11043
|
-
|
|
12075
|
+
const section = computeSectionNodesTerminalsAndEdges({
|
|
11044
12076
|
centerNodeId,
|
|
11045
12077
|
connectionsWithNodes: this.connectionsWithNodes,
|
|
11046
|
-
|
|
12078
|
+
nodeMap: this.nodeMap,
|
|
11047
12079
|
edges: this.edges,
|
|
12080
|
+
expansionDegrees: this.MAX_EXPANSION_DEGREES,
|
|
12081
|
+
nodeEdgeMap: this.nodeEdgeMap
|
|
12082
|
+
});
|
|
12083
|
+
this.currentSection = section;
|
|
12084
|
+
this.sectionSolver = new HyperCapacityPathingSingleSectionSolver({
|
|
12085
|
+
sectionConnectionTerminals: section.sectionConnectionTerminals,
|
|
12086
|
+
sectionEdges: section.sectionEdges,
|
|
12087
|
+
sectionNodes: section.sectionNodes,
|
|
11048
12088
|
colorMap: this.colorMap,
|
|
11049
|
-
|
|
11050
|
-
EXPANSION_DEGREES: this.MAX_EXPANSION_DEGREES,
|
|
11051
|
-
SHUFFLE_SEED: this.iterations
|
|
11052
|
-
}
|
|
12089
|
+
centerNodeId: section.centerNodeId
|
|
11053
12090
|
});
|
|
11054
12091
|
this.activeSubSolver = this.sectionSolver;
|
|
11055
12092
|
this.nodeOptimizationAttemptCountMap.set(
|
|
@@ -11060,7 +12097,7 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
|
|
|
11060
12097
|
this.sectionSolver.step();
|
|
11061
12098
|
if (this.sectionSolver.failed) {
|
|
11062
12099
|
console.warn(
|
|
11063
|
-
`Section solver failed for node ${this.
|
|
12100
|
+
`Section solver failed for node ${this.currentSection.centerNodeId}. Error: ${this.sectionSolver.error}`
|
|
11064
12101
|
);
|
|
11065
12102
|
this.sectionSolver = null;
|
|
11066
12103
|
this.activeSubSolver = null;
|
|
@@ -11068,12 +12105,12 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
|
|
|
11068
12105
|
}
|
|
11069
12106
|
if (this.sectionSolver.solved) {
|
|
11070
12107
|
const solvedSectionSolver = this.sectionSolver;
|
|
11071
|
-
const pathingSolver = solvedSectionSolver
|
|
12108
|
+
const pathingSolver = solvedSectionSolver?.activeSubSolver || solvedSectionSolver;
|
|
11072
12109
|
this.sectionSolver = null;
|
|
11073
12110
|
this.activeSubSolver = null;
|
|
11074
12111
|
if (!pathingSolver || !pathingSolver.solved) {
|
|
11075
12112
|
console.warn(
|
|
11076
|
-
`Pathing sub-solver for section ${
|
|
12113
|
+
`Pathing sub-solver for section ${this.currentSection.centerNodeId} did not complete successfully. Discarding results.`
|
|
11077
12114
|
);
|
|
11078
12115
|
return;
|
|
11079
12116
|
}
|
|
@@ -11134,18 +12171,18 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
|
|
|
11134
12171
|
* connectionsWithNodes list.
|
|
11135
12172
|
*/
|
|
11136
12173
|
_mergeSolvedSectionPaths(solvedSectionSolver) {
|
|
11137
|
-
const
|
|
11138
|
-
if (!
|
|
12174
|
+
const centerNodeId = solvedSectionSolver.centerNodeId;
|
|
12175
|
+
if (!solvedSectionSolver || !solvedSectionSolver.solved) {
|
|
11139
12176
|
console.warn(
|
|
11140
|
-
`Pathing sub-solver for section ${
|
|
12177
|
+
`Pathing sub-solver for section ${centerNodeId} did not complete successfully. Skipping merge.`
|
|
11141
12178
|
);
|
|
11142
12179
|
return;
|
|
11143
12180
|
}
|
|
11144
|
-
const solvedTerminals =
|
|
12181
|
+
const solvedTerminals = solvedSectionSolver.sectionConnectionTerminals;
|
|
11145
12182
|
for (const solvedTerminal of solvedTerminals) {
|
|
11146
12183
|
if (!solvedTerminal.path) {
|
|
11147
12184
|
console.warn(
|
|
11148
|
-
`No path found for connection ${solvedTerminal.connectionName} in section ${
|
|
12185
|
+
`No path found for connection ${solvedTerminal.connectionName} in section ${centerNodeId}`
|
|
11149
12186
|
);
|
|
11150
12187
|
continue;
|
|
11151
12188
|
}
|
|
@@ -13299,7 +14336,7 @@ var SingleRouteUselessViaRemovalSolver = class extends BaseSolver {
|
|
|
13299
14336
|
width: Math.abs(A.x - B.x),
|
|
13300
14337
|
height: Math.abs(A.y - B.y)
|
|
13301
14338
|
};
|
|
13302
|
-
const obstacles = this.obstacleSHI.
|
|
14339
|
+
const obstacles = this.obstacleSHI.searchArea(
|
|
13303
14340
|
segmentBox.centerX,
|
|
13304
14341
|
segmentBox.centerY,
|
|
13305
14342
|
segmentBox.width + (this.TRACE_THICKNESS + this.OBSTACLE_MARGIN) * 2,
|
|
@@ -13372,7 +14409,7 @@ var UselessViaRemovalSolver = class extends BaseSolver {
|
|
|
13372
14409
|
this.unsimplifiedHdRoutes = input.unsimplifiedHdRoutes;
|
|
13373
14410
|
this.optimizedHdRoutes = [];
|
|
13374
14411
|
this.unprocessedRoutes = [...input.unsimplifiedHdRoutes];
|
|
13375
|
-
this.obstacleSHI = new ObstacleSpatialHashIndex(input.obstacles);
|
|
14412
|
+
this.obstacleSHI = new ObstacleSpatialHashIndex("flatbush", input.obstacles);
|
|
13376
14413
|
this.hdRouteSHI = new HighDensityRouteSpatialIndex(
|
|
13377
14414
|
this.unsimplifiedHdRoutes
|
|
13378
14415
|
);
|