@tscircuit/capacity-autorouter 0.0.54 → 0.0.55
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 +27 -7
- package/dist/index.js +969 -7
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -968,8 +968,935 @@ var calculateOptimalCapacityDepth = (initialWidth, targetMinCapacity = 0.5, maxD
|
|
|
968
968
|
return Math.max(1, depth);
|
|
969
969
|
};
|
|
970
970
|
|
|
971
|
+
// node_modules/quickselect/index.js
|
|
972
|
+
function quickselect(arr, k, left = 0, right = arr.length - 1, compare = defaultCompare) {
|
|
973
|
+
while (right > left) {
|
|
974
|
+
if (right - left > 600) {
|
|
975
|
+
const n = right - left + 1;
|
|
976
|
+
const m = k - left + 1;
|
|
977
|
+
const z = Math.log(n);
|
|
978
|
+
const s = 0.5 * Math.exp(2 * z / 3);
|
|
979
|
+
const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
|
|
980
|
+
const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
|
|
981
|
+
const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
|
|
982
|
+
quickselect(arr, k, newLeft, newRight, compare);
|
|
983
|
+
}
|
|
984
|
+
const t = arr[k];
|
|
985
|
+
let i = left;
|
|
986
|
+
let j = right;
|
|
987
|
+
swap(arr, left, k);
|
|
988
|
+
if (compare(arr[right], t) > 0) swap(arr, left, right);
|
|
989
|
+
while (i < j) {
|
|
990
|
+
swap(arr, i, j);
|
|
991
|
+
i++;
|
|
992
|
+
j--;
|
|
993
|
+
while (compare(arr[i], t) < 0) i++;
|
|
994
|
+
while (compare(arr[j], t) > 0) j--;
|
|
995
|
+
}
|
|
996
|
+
if (compare(arr[left], t) === 0) swap(arr, left, j);
|
|
997
|
+
else {
|
|
998
|
+
j++;
|
|
999
|
+
swap(arr, j, right);
|
|
1000
|
+
}
|
|
1001
|
+
if (j <= k) left = j + 1;
|
|
1002
|
+
if (k <= j) right = j - 1;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
function swap(arr, i, j) {
|
|
1006
|
+
const tmp = arr[i];
|
|
1007
|
+
arr[i] = arr[j];
|
|
1008
|
+
arr[j] = tmp;
|
|
1009
|
+
}
|
|
1010
|
+
function defaultCompare(a, b) {
|
|
1011
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// node_modules/rbush/index.js
|
|
1015
|
+
var RBush = class {
|
|
1016
|
+
constructor(maxEntries = 9) {
|
|
1017
|
+
this._maxEntries = Math.max(4, maxEntries);
|
|
1018
|
+
this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
|
|
1019
|
+
this.clear();
|
|
1020
|
+
}
|
|
1021
|
+
all() {
|
|
1022
|
+
return this._all(this.data, []);
|
|
1023
|
+
}
|
|
1024
|
+
search(bbox) {
|
|
1025
|
+
let node = this.data;
|
|
1026
|
+
const result = [];
|
|
1027
|
+
if (!intersects(bbox, node)) return result;
|
|
1028
|
+
const toBBox = this.toBBox;
|
|
1029
|
+
const nodesToSearch = [];
|
|
1030
|
+
while (node) {
|
|
1031
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
1032
|
+
const child = node.children[i];
|
|
1033
|
+
const childBBox = node.leaf ? toBBox(child) : child;
|
|
1034
|
+
if (intersects(bbox, childBBox)) {
|
|
1035
|
+
if (node.leaf) result.push(child);
|
|
1036
|
+
else if (contains(bbox, childBBox)) this._all(child, result);
|
|
1037
|
+
else nodesToSearch.push(child);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
node = nodesToSearch.pop();
|
|
1041
|
+
}
|
|
1042
|
+
return result;
|
|
1043
|
+
}
|
|
1044
|
+
collides(bbox) {
|
|
1045
|
+
let node = this.data;
|
|
1046
|
+
if (!intersects(bbox, node)) return false;
|
|
1047
|
+
const nodesToSearch = [];
|
|
1048
|
+
while (node) {
|
|
1049
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
1050
|
+
const child = node.children[i];
|
|
1051
|
+
const childBBox = node.leaf ? this.toBBox(child) : child;
|
|
1052
|
+
if (intersects(bbox, childBBox)) {
|
|
1053
|
+
if (node.leaf || contains(bbox, childBBox)) return true;
|
|
1054
|
+
nodesToSearch.push(child);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
node = nodesToSearch.pop();
|
|
1058
|
+
}
|
|
1059
|
+
return false;
|
|
1060
|
+
}
|
|
1061
|
+
load(data) {
|
|
1062
|
+
if (!(data && data.length)) return this;
|
|
1063
|
+
if (data.length < this._minEntries) {
|
|
1064
|
+
for (let i = 0; i < data.length; i++) {
|
|
1065
|
+
this.insert(data[i]);
|
|
1066
|
+
}
|
|
1067
|
+
return this;
|
|
1068
|
+
}
|
|
1069
|
+
let node = this._build(data.slice(), 0, data.length - 1, 0);
|
|
1070
|
+
if (!this.data.children.length) {
|
|
1071
|
+
this.data = node;
|
|
1072
|
+
} else if (this.data.height === node.height) {
|
|
1073
|
+
this._splitRoot(this.data, node);
|
|
1074
|
+
} else {
|
|
1075
|
+
if (this.data.height < node.height) {
|
|
1076
|
+
const tmpNode = this.data;
|
|
1077
|
+
this.data = node;
|
|
1078
|
+
node = tmpNode;
|
|
1079
|
+
}
|
|
1080
|
+
this._insert(node, this.data.height - node.height - 1, true);
|
|
1081
|
+
}
|
|
1082
|
+
return this;
|
|
1083
|
+
}
|
|
1084
|
+
insert(item) {
|
|
1085
|
+
if (item) this._insert(item, this.data.height - 1);
|
|
1086
|
+
return this;
|
|
1087
|
+
}
|
|
1088
|
+
clear() {
|
|
1089
|
+
this.data = createNode([]);
|
|
1090
|
+
return this;
|
|
1091
|
+
}
|
|
1092
|
+
remove(item, equalsFn) {
|
|
1093
|
+
if (!item) return this;
|
|
1094
|
+
let node = this.data;
|
|
1095
|
+
const bbox = this.toBBox(item);
|
|
1096
|
+
const path = [];
|
|
1097
|
+
const indexes = [];
|
|
1098
|
+
let i, parent, goingUp;
|
|
1099
|
+
while (node || path.length) {
|
|
1100
|
+
if (!node) {
|
|
1101
|
+
node = path.pop();
|
|
1102
|
+
parent = path[path.length - 1];
|
|
1103
|
+
i = indexes.pop();
|
|
1104
|
+
goingUp = true;
|
|
1105
|
+
}
|
|
1106
|
+
if (node.leaf) {
|
|
1107
|
+
const index = findItem(item, node.children, equalsFn);
|
|
1108
|
+
if (index !== -1) {
|
|
1109
|
+
node.children.splice(index, 1);
|
|
1110
|
+
path.push(node);
|
|
1111
|
+
this._condense(path);
|
|
1112
|
+
return this;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
if (!goingUp && !node.leaf && contains(node, bbox)) {
|
|
1116
|
+
path.push(node);
|
|
1117
|
+
indexes.push(i);
|
|
1118
|
+
i = 0;
|
|
1119
|
+
parent = node;
|
|
1120
|
+
node = node.children[0];
|
|
1121
|
+
} else if (parent) {
|
|
1122
|
+
i++;
|
|
1123
|
+
node = parent.children[i];
|
|
1124
|
+
goingUp = false;
|
|
1125
|
+
} else node = null;
|
|
1126
|
+
}
|
|
1127
|
+
return this;
|
|
1128
|
+
}
|
|
1129
|
+
toBBox(item) {
|
|
1130
|
+
return item;
|
|
1131
|
+
}
|
|
1132
|
+
compareMinX(a, b) {
|
|
1133
|
+
return a.minX - b.minX;
|
|
1134
|
+
}
|
|
1135
|
+
compareMinY(a, b) {
|
|
1136
|
+
return a.minY - b.minY;
|
|
1137
|
+
}
|
|
1138
|
+
toJSON() {
|
|
1139
|
+
return this.data;
|
|
1140
|
+
}
|
|
1141
|
+
fromJSON(data) {
|
|
1142
|
+
this.data = data;
|
|
1143
|
+
return this;
|
|
1144
|
+
}
|
|
1145
|
+
_all(node, result) {
|
|
1146
|
+
const nodesToSearch = [];
|
|
1147
|
+
while (node) {
|
|
1148
|
+
if (node.leaf) result.push(...node.children);
|
|
1149
|
+
else nodesToSearch.push(...node.children);
|
|
1150
|
+
node = nodesToSearch.pop();
|
|
1151
|
+
}
|
|
1152
|
+
return result;
|
|
1153
|
+
}
|
|
1154
|
+
_build(items, left, right, height) {
|
|
1155
|
+
const N = right - left + 1;
|
|
1156
|
+
let M = this._maxEntries;
|
|
1157
|
+
let node;
|
|
1158
|
+
if (N <= M) {
|
|
1159
|
+
node = createNode(items.slice(left, right + 1));
|
|
1160
|
+
calcBBox(node, this.toBBox);
|
|
1161
|
+
return node;
|
|
1162
|
+
}
|
|
1163
|
+
if (!height) {
|
|
1164
|
+
height = Math.ceil(Math.log(N) / Math.log(M));
|
|
1165
|
+
M = Math.ceil(N / Math.pow(M, height - 1));
|
|
1166
|
+
}
|
|
1167
|
+
node = createNode([]);
|
|
1168
|
+
node.leaf = false;
|
|
1169
|
+
node.height = height;
|
|
1170
|
+
const N2 = Math.ceil(N / M);
|
|
1171
|
+
const N1 = N2 * Math.ceil(Math.sqrt(M));
|
|
1172
|
+
multiSelect(items, left, right, N1, this.compareMinX);
|
|
1173
|
+
for (let i = left; i <= right; i += N1) {
|
|
1174
|
+
const right2 = Math.min(i + N1 - 1, right);
|
|
1175
|
+
multiSelect(items, i, right2, N2, this.compareMinY);
|
|
1176
|
+
for (let j = i; j <= right2; j += N2) {
|
|
1177
|
+
const right3 = Math.min(j + N2 - 1, right2);
|
|
1178
|
+
node.children.push(this._build(items, j, right3, height - 1));
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
calcBBox(node, this.toBBox);
|
|
1182
|
+
return node;
|
|
1183
|
+
}
|
|
1184
|
+
_chooseSubtree(bbox, node, level, path) {
|
|
1185
|
+
while (true) {
|
|
1186
|
+
path.push(node);
|
|
1187
|
+
if (node.leaf || path.length - 1 === level) break;
|
|
1188
|
+
let minArea = Infinity;
|
|
1189
|
+
let minEnlargement = Infinity;
|
|
1190
|
+
let targetNode;
|
|
1191
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
1192
|
+
const child = node.children[i];
|
|
1193
|
+
const area = bboxArea(child);
|
|
1194
|
+
const enlargement = enlargedArea(bbox, child) - area;
|
|
1195
|
+
if (enlargement < minEnlargement) {
|
|
1196
|
+
minEnlargement = enlargement;
|
|
1197
|
+
minArea = area < minArea ? area : minArea;
|
|
1198
|
+
targetNode = child;
|
|
1199
|
+
} else if (enlargement === minEnlargement) {
|
|
1200
|
+
if (area < minArea) {
|
|
1201
|
+
minArea = area;
|
|
1202
|
+
targetNode = child;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
node = targetNode || node.children[0];
|
|
1207
|
+
}
|
|
1208
|
+
return node;
|
|
1209
|
+
}
|
|
1210
|
+
_insert(item, level, isNode) {
|
|
1211
|
+
const bbox = isNode ? item : this.toBBox(item);
|
|
1212
|
+
const insertPath = [];
|
|
1213
|
+
const node = this._chooseSubtree(bbox, this.data, level, insertPath);
|
|
1214
|
+
node.children.push(item);
|
|
1215
|
+
extend(node, bbox);
|
|
1216
|
+
while (level >= 0) {
|
|
1217
|
+
if (insertPath[level].children.length > this._maxEntries) {
|
|
1218
|
+
this._split(insertPath, level);
|
|
1219
|
+
level--;
|
|
1220
|
+
} else break;
|
|
1221
|
+
}
|
|
1222
|
+
this._adjustParentBBoxes(bbox, insertPath, level);
|
|
1223
|
+
}
|
|
1224
|
+
// split overflowed node into two
|
|
1225
|
+
_split(insertPath, level) {
|
|
1226
|
+
const node = insertPath[level];
|
|
1227
|
+
const M = node.children.length;
|
|
1228
|
+
const m = this._minEntries;
|
|
1229
|
+
this._chooseSplitAxis(node, m, M);
|
|
1230
|
+
const splitIndex = this._chooseSplitIndex(node, m, M);
|
|
1231
|
+
const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
|
|
1232
|
+
newNode.height = node.height;
|
|
1233
|
+
newNode.leaf = node.leaf;
|
|
1234
|
+
calcBBox(node, this.toBBox);
|
|
1235
|
+
calcBBox(newNode, this.toBBox);
|
|
1236
|
+
if (level) insertPath[level - 1].children.push(newNode);
|
|
1237
|
+
else this._splitRoot(node, newNode);
|
|
1238
|
+
}
|
|
1239
|
+
_splitRoot(node, newNode) {
|
|
1240
|
+
this.data = createNode([node, newNode]);
|
|
1241
|
+
this.data.height = node.height + 1;
|
|
1242
|
+
this.data.leaf = false;
|
|
1243
|
+
calcBBox(this.data, this.toBBox);
|
|
1244
|
+
}
|
|
1245
|
+
_chooseSplitIndex(node, m, M) {
|
|
1246
|
+
let index;
|
|
1247
|
+
let minOverlap = Infinity;
|
|
1248
|
+
let minArea = Infinity;
|
|
1249
|
+
for (let i = m; i <= M - m; i++) {
|
|
1250
|
+
const bbox1 = distBBox(node, 0, i, this.toBBox);
|
|
1251
|
+
const bbox2 = distBBox(node, i, M, this.toBBox);
|
|
1252
|
+
const overlap = intersectionArea(bbox1, bbox2);
|
|
1253
|
+
const area = bboxArea(bbox1) + bboxArea(bbox2);
|
|
1254
|
+
if (overlap < minOverlap) {
|
|
1255
|
+
minOverlap = overlap;
|
|
1256
|
+
index = i;
|
|
1257
|
+
minArea = area < minArea ? area : minArea;
|
|
1258
|
+
} else if (overlap === minOverlap) {
|
|
1259
|
+
if (area < minArea) {
|
|
1260
|
+
minArea = area;
|
|
1261
|
+
index = i;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
return index || M - m;
|
|
1266
|
+
}
|
|
1267
|
+
// sorts node children by the best axis for split
|
|
1268
|
+
_chooseSplitAxis(node, m, M) {
|
|
1269
|
+
const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
|
|
1270
|
+
const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
|
|
1271
|
+
const xMargin = this._allDistMargin(node, m, M, compareMinX);
|
|
1272
|
+
const yMargin = this._allDistMargin(node, m, M, compareMinY);
|
|
1273
|
+
if (xMargin < yMargin) node.children.sort(compareMinX);
|
|
1274
|
+
}
|
|
1275
|
+
// total margin of all possible split distributions where each node is at least m full
|
|
1276
|
+
_allDistMargin(node, m, M, compare) {
|
|
1277
|
+
node.children.sort(compare);
|
|
1278
|
+
const toBBox = this.toBBox;
|
|
1279
|
+
const leftBBox = distBBox(node, 0, m, toBBox);
|
|
1280
|
+
const rightBBox = distBBox(node, M - m, M, toBBox);
|
|
1281
|
+
let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
|
|
1282
|
+
for (let i = m; i < M - m; i++) {
|
|
1283
|
+
const child = node.children[i];
|
|
1284
|
+
extend(leftBBox, node.leaf ? toBBox(child) : child);
|
|
1285
|
+
margin += bboxMargin(leftBBox);
|
|
1286
|
+
}
|
|
1287
|
+
for (let i = M - m - 1; i >= m; i--) {
|
|
1288
|
+
const child = node.children[i];
|
|
1289
|
+
extend(rightBBox, node.leaf ? toBBox(child) : child);
|
|
1290
|
+
margin += bboxMargin(rightBBox);
|
|
1291
|
+
}
|
|
1292
|
+
return margin;
|
|
1293
|
+
}
|
|
1294
|
+
_adjustParentBBoxes(bbox, path, level) {
|
|
1295
|
+
for (let i = level; i >= 0; i--) {
|
|
1296
|
+
extend(path[i], bbox);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
_condense(path) {
|
|
1300
|
+
for (let i = path.length - 1, siblings; i >= 0; i--) {
|
|
1301
|
+
if (path[i].children.length === 0) {
|
|
1302
|
+
if (i > 0) {
|
|
1303
|
+
siblings = path[i - 1].children;
|
|
1304
|
+
siblings.splice(siblings.indexOf(path[i]), 1);
|
|
1305
|
+
} else this.clear();
|
|
1306
|
+
} else calcBBox(path[i], this.toBBox);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
function findItem(item, items, equalsFn) {
|
|
1311
|
+
if (!equalsFn) return items.indexOf(item);
|
|
1312
|
+
for (let i = 0; i < items.length; i++) {
|
|
1313
|
+
if (equalsFn(item, items[i])) return i;
|
|
1314
|
+
}
|
|
1315
|
+
return -1;
|
|
1316
|
+
}
|
|
1317
|
+
function calcBBox(node, toBBox) {
|
|
1318
|
+
distBBox(node, 0, node.children.length, toBBox, node);
|
|
1319
|
+
}
|
|
1320
|
+
function distBBox(node, k, p, toBBox, destNode) {
|
|
1321
|
+
if (!destNode) destNode = createNode(null);
|
|
1322
|
+
destNode.minX = Infinity;
|
|
1323
|
+
destNode.minY = Infinity;
|
|
1324
|
+
destNode.maxX = -Infinity;
|
|
1325
|
+
destNode.maxY = -Infinity;
|
|
1326
|
+
for (let i = k; i < p; i++) {
|
|
1327
|
+
const child = node.children[i];
|
|
1328
|
+
extend(destNode, node.leaf ? toBBox(child) : child);
|
|
1329
|
+
}
|
|
1330
|
+
return destNode;
|
|
1331
|
+
}
|
|
1332
|
+
function extend(a, b) {
|
|
1333
|
+
a.minX = Math.min(a.minX, b.minX);
|
|
1334
|
+
a.minY = Math.min(a.minY, b.minY);
|
|
1335
|
+
a.maxX = Math.max(a.maxX, b.maxX);
|
|
1336
|
+
a.maxY = Math.max(a.maxY, b.maxY);
|
|
1337
|
+
return a;
|
|
1338
|
+
}
|
|
1339
|
+
function compareNodeMinX(a, b) {
|
|
1340
|
+
return a.minX - b.minX;
|
|
1341
|
+
}
|
|
1342
|
+
function compareNodeMinY(a, b) {
|
|
1343
|
+
return a.minY - b.minY;
|
|
1344
|
+
}
|
|
1345
|
+
function bboxArea(a) {
|
|
1346
|
+
return (a.maxX - a.minX) * (a.maxY - a.minY);
|
|
1347
|
+
}
|
|
1348
|
+
function bboxMargin(a) {
|
|
1349
|
+
return a.maxX - a.minX + (a.maxY - a.minY);
|
|
1350
|
+
}
|
|
1351
|
+
function enlargedArea(a, b) {
|
|
1352
|
+
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));
|
|
1353
|
+
}
|
|
1354
|
+
function intersectionArea(a, b) {
|
|
1355
|
+
const minX = Math.max(a.minX, b.minX);
|
|
1356
|
+
const minY = Math.max(a.minY, b.minY);
|
|
1357
|
+
const maxX = Math.min(a.maxX, b.maxX);
|
|
1358
|
+
const maxY = Math.min(a.maxY, b.maxY);
|
|
1359
|
+
return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
|
|
1360
|
+
}
|
|
1361
|
+
function contains(a, b) {
|
|
1362
|
+
return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
|
|
1363
|
+
}
|
|
1364
|
+
function intersects(a, b) {
|
|
1365
|
+
return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
|
|
1366
|
+
}
|
|
1367
|
+
function createNode(children) {
|
|
1368
|
+
return {
|
|
1369
|
+
children,
|
|
1370
|
+
height: 1,
|
|
1371
|
+
leaf: true,
|
|
1372
|
+
minX: Infinity,
|
|
1373
|
+
minY: Infinity,
|
|
1374
|
+
maxX: -Infinity,
|
|
1375
|
+
maxY: -Infinity
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
function multiSelect(arr, left, right, n, compare) {
|
|
1379
|
+
const stack = [left, right];
|
|
1380
|
+
while (stack.length) {
|
|
1381
|
+
right = stack.pop();
|
|
1382
|
+
left = stack.pop();
|
|
1383
|
+
if (right - left <= n) continue;
|
|
1384
|
+
const mid = left + Math.ceil((right - left) / n / 2) * n;
|
|
1385
|
+
quickselect(arr, mid, left, right, compare);
|
|
1386
|
+
stack.push(left, mid, mid, right);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
// lib/data-structures/RbushIndex.ts
|
|
1391
|
+
var RbushIndex = class {
|
|
1392
|
+
tree;
|
|
1393
|
+
constructor(maxEntries = 9) {
|
|
1394
|
+
this.tree = new RBush(maxEntries);
|
|
1395
|
+
}
|
|
1396
|
+
insert(item, minX, minY, maxX, maxY) {
|
|
1397
|
+
this.tree.insert({ minX, minY, maxX, maxY, data: item });
|
|
1398
|
+
}
|
|
1399
|
+
bulkLoad(items) {
|
|
1400
|
+
const nodes = items.map(({ item, minX, minY, maxX, maxY }) => ({
|
|
1401
|
+
minX,
|
|
1402
|
+
minY,
|
|
1403
|
+
maxX,
|
|
1404
|
+
maxY,
|
|
1405
|
+
data: item
|
|
1406
|
+
}));
|
|
1407
|
+
this.tree.load(nodes);
|
|
1408
|
+
}
|
|
1409
|
+
search(minX, minY, maxX, maxY) {
|
|
1410
|
+
return this.tree.search({ minX, minY, maxX, maxY }).map((n) => n.data);
|
|
1411
|
+
}
|
|
1412
|
+
clear() {
|
|
1413
|
+
this.tree.clear();
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
|
|
1417
|
+
// node_modules/flatqueue/index.js
|
|
1418
|
+
var FlatQueue = class {
|
|
1419
|
+
constructor() {
|
|
1420
|
+
this.ids = [];
|
|
1421
|
+
this.values = [];
|
|
1422
|
+
this.length = 0;
|
|
1423
|
+
}
|
|
1424
|
+
clear() {
|
|
1425
|
+
this.length = 0;
|
|
1426
|
+
}
|
|
1427
|
+
push(id, value) {
|
|
1428
|
+
let pos = this.length++;
|
|
1429
|
+
while (pos > 0) {
|
|
1430
|
+
const parent = pos - 1 >> 1;
|
|
1431
|
+
const parentValue = this.values[parent];
|
|
1432
|
+
if (value >= parentValue) break;
|
|
1433
|
+
this.ids[pos] = this.ids[parent];
|
|
1434
|
+
this.values[pos] = parentValue;
|
|
1435
|
+
pos = parent;
|
|
1436
|
+
}
|
|
1437
|
+
this.ids[pos] = id;
|
|
1438
|
+
this.values[pos] = value;
|
|
1439
|
+
}
|
|
1440
|
+
pop() {
|
|
1441
|
+
if (this.length === 0) return void 0;
|
|
1442
|
+
const top = this.ids[0];
|
|
1443
|
+
this.length--;
|
|
1444
|
+
if (this.length > 0) {
|
|
1445
|
+
const id = this.ids[0] = this.ids[this.length];
|
|
1446
|
+
const value = this.values[0] = this.values[this.length];
|
|
1447
|
+
const halfLength = this.length >> 1;
|
|
1448
|
+
let pos = 0;
|
|
1449
|
+
while (pos < halfLength) {
|
|
1450
|
+
let left = (pos << 1) + 1;
|
|
1451
|
+
const right = left + 1;
|
|
1452
|
+
let bestIndex = this.ids[left];
|
|
1453
|
+
let bestValue = this.values[left];
|
|
1454
|
+
const rightValue = this.values[right];
|
|
1455
|
+
if (right < this.length && rightValue < bestValue) {
|
|
1456
|
+
left = right;
|
|
1457
|
+
bestIndex = this.ids[right];
|
|
1458
|
+
bestValue = rightValue;
|
|
1459
|
+
}
|
|
1460
|
+
if (bestValue >= value) break;
|
|
1461
|
+
this.ids[pos] = bestIndex;
|
|
1462
|
+
this.values[pos] = bestValue;
|
|
1463
|
+
pos = left;
|
|
1464
|
+
}
|
|
1465
|
+
this.ids[pos] = id;
|
|
1466
|
+
this.values[pos] = value;
|
|
1467
|
+
}
|
|
1468
|
+
return top;
|
|
1469
|
+
}
|
|
1470
|
+
peek() {
|
|
1471
|
+
if (this.length === 0) return void 0;
|
|
1472
|
+
return this.ids[0];
|
|
1473
|
+
}
|
|
1474
|
+
peekValue() {
|
|
1475
|
+
if (this.length === 0) return void 0;
|
|
1476
|
+
return this.values[0];
|
|
1477
|
+
}
|
|
1478
|
+
shrink() {
|
|
1479
|
+
this.ids.length = this.values.length = this.length;
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
// node_modules/flatbush/index.js
|
|
1484
|
+
var ARRAY_TYPES = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array];
|
|
1485
|
+
var VERSION = 3;
|
|
1486
|
+
var Flatbush = class _Flatbush {
|
|
1487
|
+
/**
|
|
1488
|
+
* Recreate a Flatbush index from raw `ArrayBuffer` or `SharedArrayBuffer` data.
|
|
1489
|
+
* @param {ArrayBuffer | SharedArrayBuffer} data
|
|
1490
|
+
* @param {number} [byteOffset=0] byte offset to the start of the Flatbush buffer in the referenced ArrayBuffer.
|
|
1491
|
+
* @returns {Flatbush} index
|
|
1492
|
+
*/
|
|
1493
|
+
static from(data, byteOffset = 0) {
|
|
1494
|
+
if (byteOffset % 8 !== 0) {
|
|
1495
|
+
throw new Error("byteOffset must be 8-byte aligned.");
|
|
1496
|
+
}
|
|
1497
|
+
if (!data || data.byteLength === void 0 || data.buffer) {
|
|
1498
|
+
throw new Error("Data must be an instance of ArrayBuffer or SharedArrayBuffer.");
|
|
1499
|
+
}
|
|
1500
|
+
const [magic, versionAndType] = new Uint8Array(data, byteOffset + 0, 2);
|
|
1501
|
+
if (magic !== 251) {
|
|
1502
|
+
throw new Error("Data does not appear to be in a Flatbush format.");
|
|
1503
|
+
}
|
|
1504
|
+
const version = versionAndType >> 4;
|
|
1505
|
+
if (version !== VERSION) {
|
|
1506
|
+
throw new Error(`Got v${version} data when expected v${VERSION}.`);
|
|
1507
|
+
}
|
|
1508
|
+
const ArrayType = ARRAY_TYPES[versionAndType & 15];
|
|
1509
|
+
if (!ArrayType) {
|
|
1510
|
+
throw new Error("Unrecognized array type.");
|
|
1511
|
+
}
|
|
1512
|
+
const [nodeSize] = new Uint16Array(data, byteOffset + 2, 1);
|
|
1513
|
+
const [numItems] = new Uint32Array(data, byteOffset + 4, 1);
|
|
1514
|
+
return new _Flatbush(numItems, nodeSize, ArrayType, void 0, data, byteOffset);
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* Create a Flatbush index that will hold a given number of items.
|
|
1518
|
+
* @param {number} numItems
|
|
1519
|
+
* @param {number} [nodeSize=16] Size of the tree node (16 by default).
|
|
1520
|
+
* @param {TypedArrayConstructor} [ArrayType=Float64Array] The array type used for coordinates storage (`Float64Array` by default).
|
|
1521
|
+
* @param {ArrayBufferConstructor | SharedArrayBufferConstructor} [ArrayBufferType=ArrayBuffer] The array buffer type used to store data (`ArrayBuffer` by default).
|
|
1522
|
+
* @param {ArrayBuffer | SharedArrayBuffer} [data] (Only used internally)
|
|
1523
|
+
* @param {number} [byteOffset=0] (Only used internally)
|
|
1524
|
+
*/
|
|
1525
|
+
constructor(numItems, nodeSize = 16, ArrayType = Float64Array, ArrayBufferType = ArrayBuffer, data, byteOffset = 0) {
|
|
1526
|
+
if (numItems === void 0) throw new Error("Missing required argument: numItems.");
|
|
1527
|
+
if (isNaN(numItems) || numItems <= 0) throw new Error(`Unexpected numItems value: ${numItems}.`);
|
|
1528
|
+
this.numItems = +numItems;
|
|
1529
|
+
this.nodeSize = Math.min(Math.max(+nodeSize, 2), 65535);
|
|
1530
|
+
this.byteOffset = byteOffset;
|
|
1531
|
+
let n = numItems;
|
|
1532
|
+
let numNodes = n;
|
|
1533
|
+
this._levelBounds = [n * 4];
|
|
1534
|
+
do {
|
|
1535
|
+
n = Math.ceil(n / this.nodeSize);
|
|
1536
|
+
numNodes += n;
|
|
1537
|
+
this._levelBounds.push(numNodes * 4);
|
|
1538
|
+
} while (n !== 1);
|
|
1539
|
+
this.ArrayType = ArrayType;
|
|
1540
|
+
this.IndexArrayType = numNodes < 16384 ? Uint16Array : Uint32Array;
|
|
1541
|
+
const arrayTypeIndex = ARRAY_TYPES.indexOf(this.ArrayType);
|
|
1542
|
+
const nodesByteSize = numNodes * 4 * this.ArrayType.BYTES_PER_ELEMENT;
|
|
1543
|
+
if (arrayTypeIndex < 0) {
|
|
1544
|
+
throw new Error(`Unexpected typed array class: ${ArrayType}.`);
|
|
1545
|
+
}
|
|
1546
|
+
if (data && data.byteLength !== void 0 && !data.buffer) {
|
|
1547
|
+
this.data = data;
|
|
1548
|
+
this._boxes = new this.ArrayType(this.data, byteOffset + 8, numNodes * 4);
|
|
1549
|
+
this._indices = new this.IndexArrayType(this.data, byteOffset + 8 + nodesByteSize, numNodes);
|
|
1550
|
+
this._pos = numNodes * 4;
|
|
1551
|
+
this.minX = this._boxes[this._pos - 4];
|
|
1552
|
+
this.minY = this._boxes[this._pos - 3];
|
|
1553
|
+
this.maxX = this._boxes[this._pos - 2];
|
|
1554
|
+
this.maxY = this._boxes[this._pos - 1];
|
|
1555
|
+
} else {
|
|
1556
|
+
this.data = new ArrayBufferType(8 + nodesByteSize + numNodes * this.IndexArrayType.BYTES_PER_ELEMENT);
|
|
1557
|
+
this._boxes = new this.ArrayType(this.data, 8, numNodes * 4);
|
|
1558
|
+
this._indices = new this.IndexArrayType(this.data, 8 + nodesByteSize, numNodes);
|
|
1559
|
+
this._pos = 0;
|
|
1560
|
+
this.minX = Infinity;
|
|
1561
|
+
this.minY = Infinity;
|
|
1562
|
+
this.maxX = -Infinity;
|
|
1563
|
+
this.maxY = -Infinity;
|
|
1564
|
+
new Uint8Array(this.data, 0, 2).set([251, (VERSION << 4) + arrayTypeIndex]);
|
|
1565
|
+
new Uint16Array(this.data, 2, 1)[0] = nodeSize;
|
|
1566
|
+
new Uint32Array(this.data, 4, 1)[0] = numItems;
|
|
1567
|
+
}
|
|
1568
|
+
this._queue = new FlatQueue();
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Add a given rectangle to the index.
|
|
1572
|
+
* @param {number} minX
|
|
1573
|
+
* @param {number} minY
|
|
1574
|
+
* @param {number} maxX
|
|
1575
|
+
* @param {number} maxY
|
|
1576
|
+
* @returns {number} A zero-based, incremental number that represents the newly added rectangle.
|
|
1577
|
+
*/
|
|
1578
|
+
add(minX, minY, maxX = minX, maxY = minY) {
|
|
1579
|
+
const index = this._pos >> 2;
|
|
1580
|
+
const boxes = this._boxes;
|
|
1581
|
+
this._indices[index] = index;
|
|
1582
|
+
boxes[this._pos++] = minX;
|
|
1583
|
+
boxes[this._pos++] = minY;
|
|
1584
|
+
boxes[this._pos++] = maxX;
|
|
1585
|
+
boxes[this._pos++] = maxY;
|
|
1586
|
+
if (minX < this.minX) this.minX = minX;
|
|
1587
|
+
if (minY < this.minY) this.minY = minY;
|
|
1588
|
+
if (maxX > this.maxX) this.maxX = maxX;
|
|
1589
|
+
if (maxY > this.maxY) this.maxY = maxY;
|
|
1590
|
+
return index;
|
|
1591
|
+
}
|
|
1592
|
+
/** Perform indexing of the added rectangles. */
|
|
1593
|
+
finish() {
|
|
1594
|
+
if (this._pos >> 2 !== this.numItems) {
|
|
1595
|
+
throw new Error(`Added ${this._pos >> 2} items when expected ${this.numItems}.`);
|
|
1596
|
+
}
|
|
1597
|
+
const boxes = this._boxes;
|
|
1598
|
+
if (this.numItems <= this.nodeSize) {
|
|
1599
|
+
boxes[this._pos++] = this.minX;
|
|
1600
|
+
boxes[this._pos++] = this.minY;
|
|
1601
|
+
boxes[this._pos++] = this.maxX;
|
|
1602
|
+
boxes[this._pos++] = this.maxY;
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
const width = this.maxX - this.minX || 1;
|
|
1606
|
+
const height = this.maxY - this.minY || 1;
|
|
1607
|
+
const hilbertValues = new Uint32Array(this.numItems);
|
|
1608
|
+
const hilbertMax = (1 << 16) - 1;
|
|
1609
|
+
for (let i = 0, pos = 0; i < this.numItems; i++) {
|
|
1610
|
+
const minX = boxes[pos++];
|
|
1611
|
+
const minY = boxes[pos++];
|
|
1612
|
+
const maxX = boxes[pos++];
|
|
1613
|
+
const maxY = boxes[pos++];
|
|
1614
|
+
const x = Math.floor(hilbertMax * ((minX + maxX) / 2 - this.minX) / width);
|
|
1615
|
+
const y = Math.floor(hilbertMax * ((minY + maxY) / 2 - this.minY) / height);
|
|
1616
|
+
hilbertValues[i] = hilbert(x, y);
|
|
1617
|
+
}
|
|
1618
|
+
sort(hilbertValues, boxes, this._indices, 0, this.numItems - 1, this.nodeSize);
|
|
1619
|
+
for (let i = 0, pos = 0; i < this._levelBounds.length - 1; i++) {
|
|
1620
|
+
const end = this._levelBounds[i];
|
|
1621
|
+
while (pos < end) {
|
|
1622
|
+
const nodeIndex = pos;
|
|
1623
|
+
let nodeMinX = boxes[pos++];
|
|
1624
|
+
let nodeMinY = boxes[pos++];
|
|
1625
|
+
let nodeMaxX = boxes[pos++];
|
|
1626
|
+
let nodeMaxY = boxes[pos++];
|
|
1627
|
+
for (let j = 1; j < this.nodeSize && pos < end; j++) {
|
|
1628
|
+
nodeMinX = Math.min(nodeMinX, boxes[pos++]);
|
|
1629
|
+
nodeMinY = Math.min(nodeMinY, boxes[pos++]);
|
|
1630
|
+
nodeMaxX = Math.max(nodeMaxX, boxes[pos++]);
|
|
1631
|
+
nodeMaxY = Math.max(nodeMaxY, boxes[pos++]);
|
|
1632
|
+
}
|
|
1633
|
+
this._indices[this._pos >> 2] = nodeIndex;
|
|
1634
|
+
boxes[this._pos++] = nodeMinX;
|
|
1635
|
+
boxes[this._pos++] = nodeMinY;
|
|
1636
|
+
boxes[this._pos++] = nodeMaxX;
|
|
1637
|
+
boxes[this._pos++] = nodeMaxY;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Search the index by a bounding box.
|
|
1643
|
+
* @param {number} minX
|
|
1644
|
+
* @param {number} minY
|
|
1645
|
+
* @param {number} maxX
|
|
1646
|
+
* @param {number} maxY
|
|
1647
|
+
* @param {(index: number) => boolean} [filterFn] An optional function for filtering the results.
|
|
1648
|
+
* @returns {number[]} An array of indices of items intersecting or touching the given bounding box.
|
|
1649
|
+
*/
|
|
1650
|
+
search(minX, minY, maxX, maxY, filterFn) {
|
|
1651
|
+
if (this._pos !== this._boxes.length) {
|
|
1652
|
+
throw new Error("Data not yet indexed - call index.finish().");
|
|
1653
|
+
}
|
|
1654
|
+
let nodeIndex = this._boxes.length - 4;
|
|
1655
|
+
const queue = [];
|
|
1656
|
+
const results = [];
|
|
1657
|
+
while (nodeIndex !== void 0) {
|
|
1658
|
+
const end = Math.min(nodeIndex + this.nodeSize * 4, upperBound(nodeIndex, this._levelBounds));
|
|
1659
|
+
for (let pos = nodeIndex; pos < end; pos += 4) {
|
|
1660
|
+
if (maxX < this._boxes[pos]) continue;
|
|
1661
|
+
if (maxY < this._boxes[pos + 1]) continue;
|
|
1662
|
+
if (minX > this._boxes[pos + 2]) continue;
|
|
1663
|
+
if (minY > this._boxes[pos + 3]) continue;
|
|
1664
|
+
const index = this._indices[pos >> 2] | 0;
|
|
1665
|
+
if (nodeIndex >= this.numItems * 4) {
|
|
1666
|
+
queue.push(index);
|
|
1667
|
+
} else if (filterFn === void 0 || filterFn(index)) {
|
|
1668
|
+
results.push(index);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
nodeIndex = queue.pop();
|
|
1672
|
+
}
|
|
1673
|
+
return results;
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Search items in order of distance from the given point.
|
|
1677
|
+
* @param {number} x
|
|
1678
|
+
* @param {number} y
|
|
1679
|
+
* @param {number} [maxResults=Infinity]
|
|
1680
|
+
* @param {number} [maxDistance=Infinity]
|
|
1681
|
+
* @param {(index: number) => boolean} [filterFn] An optional function for filtering the results.
|
|
1682
|
+
* @returns {number[]} An array of indices of items found.
|
|
1683
|
+
*/
|
|
1684
|
+
neighbors(x, y, maxResults = Infinity, maxDistance = Infinity, filterFn) {
|
|
1685
|
+
if (this._pos !== this._boxes.length) {
|
|
1686
|
+
throw new Error("Data not yet indexed - call index.finish().");
|
|
1687
|
+
}
|
|
1688
|
+
let nodeIndex = this._boxes.length - 4;
|
|
1689
|
+
const q = this._queue;
|
|
1690
|
+
const results = [];
|
|
1691
|
+
const maxDistSquared = maxDistance * maxDistance;
|
|
1692
|
+
outer: while (nodeIndex !== void 0) {
|
|
1693
|
+
const end = Math.min(nodeIndex + this.nodeSize * 4, upperBound(nodeIndex, this._levelBounds));
|
|
1694
|
+
for (let pos = nodeIndex; pos < end; pos += 4) {
|
|
1695
|
+
const index = this._indices[pos >> 2] | 0;
|
|
1696
|
+
const dx = axisDist(x, this._boxes[pos], this._boxes[pos + 2]);
|
|
1697
|
+
const dy = axisDist(y, this._boxes[pos + 1], this._boxes[pos + 3]);
|
|
1698
|
+
const dist = dx * dx + dy * dy;
|
|
1699
|
+
if (dist > maxDistSquared) continue;
|
|
1700
|
+
if (nodeIndex >= this.numItems * 4) {
|
|
1701
|
+
q.push(index << 1, dist);
|
|
1702
|
+
} else if (filterFn === void 0 || filterFn(index)) {
|
|
1703
|
+
q.push((index << 1) + 1, dist);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
while (q.length && q.peek() & 1) {
|
|
1707
|
+
const dist = q.peekValue();
|
|
1708
|
+
if (dist > maxDistSquared) break outer;
|
|
1709
|
+
results.push(q.pop() >> 1);
|
|
1710
|
+
if (results.length === maxResults) break outer;
|
|
1711
|
+
}
|
|
1712
|
+
nodeIndex = q.length ? q.pop() >> 1 : void 0;
|
|
1713
|
+
}
|
|
1714
|
+
q.clear();
|
|
1715
|
+
return results;
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
function axisDist(k, min, max) {
|
|
1719
|
+
return k < min ? min - k : k <= max ? 0 : k - max;
|
|
1720
|
+
}
|
|
1721
|
+
function upperBound(value, arr) {
|
|
1722
|
+
let i = 0;
|
|
1723
|
+
let j = arr.length - 1;
|
|
1724
|
+
while (i < j) {
|
|
1725
|
+
const m = i + j >> 1;
|
|
1726
|
+
if (arr[m] > value) {
|
|
1727
|
+
j = m;
|
|
1728
|
+
} else {
|
|
1729
|
+
i = m + 1;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
return arr[i];
|
|
1733
|
+
}
|
|
1734
|
+
function sort(values, boxes, indices, left, right, nodeSize) {
|
|
1735
|
+
if (Math.floor(left / nodeSize) >= Math.floor(right / nodeSize)) return;
|
|
1736
|
+
const pivot = values[left + right >> 1];
|
|
1737
|
+
let i = left - 1;
|
|
1738
|
+
let j = right + 1;
|
|
1739
|
+
while (true) {
|
|
1740
|
+
do
|
|
1741
|
+
i++;
|
|
1742
|
+
while (values[i] < pivot);
|
|
1743
|
+
do
|
|
1744
|
+
j--;
|
|
1745
|
+
while (values[j] > pivot);
|
|
1746
|
+
if (i >= j) break;
|
|
1747
|
+
swap2(values, boxes, indices, i, j);
|
|
1748
|
+
}
|
|
1749
|
+
sort(values, boxes, indices, left, j, nodeSize);
|
|
1750
|
+
sort(values, boxes, indices, j + 1, right, nodeSize);
|
|
1751
|
+
}
|
|
1752
|
+
function swap2(values, boxes, indices, i, j) {
|
|
1753
|
+
const temp = values[i];
|
|
1754
|
+
values[i] = values[j];
|
|
1755
|
+
values[j] = temp;
|
|
1756
|
+
const k = 4 * i;
|
|
1757
|
+
const m = 4 * j;
|
|
1758
|
+
const a = boxes[k];
|
|
1759
|
+
const b = boxes[k + 1];
|
|
1760
|
+
const c = boxes[k + 2];
|
|
1761
|
+
const d = boxes[k + 3];
|
|
1762
|
+
boxes[k] = boxes[m];
|
|
1763
|
+
boxes[k + 1] = boxes[m + 1];
|
|
1764
|
+
boxes[k + 2] = boxes[m + 2];
|
|
1765
|
+
boxes[k + 3] = boxes[m + 3];
|
|
1766
|
+
boxes[m] = a;
|
|
1767
|
+
boxes[m + 1] = b;
|
|
1768
|
+
boxes[m + 2] = c;
|
|
1769
|
+
boxes[m + 3] = d;
|
|
1770
|
+
const e = indices[i];
|
|
1771
|
+
indices[i] = indices[j];
|
|
1772
|
+
indices[j] = e;
|
|
1773
|
+
}
|
|
1774
|
+
function hilbert(x, y) {
|
|
1775
|
+
let a = x ^ y;
|
|
1776
|
+
let b = 65535 ^ a;
|
|
1777
|
+
let c = 65535 ^ (x | y);
|
|
1778
|
+
let d = x & (y ^ 65535);
|
|
1779
|
+
let A = a | b >> 1;
|
|
1780
|
+
let B = a >> 1 ^ a;
|
|
1781
|
+
let C = c >> 1 ^ b & d >> 1 ^ c;
|
|
1782
|
+
let D = a & c >> 1 ^ d >> 1 ^ d;
|
|
1783
|
+
a = A;
|
|
1784
|
+
b = B;
|
|
1785
|
+
c = C;
|
|
1786
|
+
d = D;
|
|
1787
|
+
A = a & a >> 2 ^ b & b >> 2;
|
|
1788
|
+
B = a & b >> 2 ^ b & (a ^ b) >> 2;
|
|
1789
|
+
C ^= a & c >> 2 ^ b & d >> 2;
|
|
1790
|
+
D ^= b & c >> 2 ^ (a ^ b) & d >> 2;
|
|
1791
|
+
a = A;
|
|
1792
|
+
b = B;
|
|
1793
|
+
c = C;
|
|
1794
|
+
d = D;
|
|
1795
|
+
A = a & a >> 4 ^ b & b >> 4;
|
|
1796
|
+
B = a & b >> 4 ^ b & (a ^ b) >> 4;
|
|
1797
|
+
C ^= a & c >> 4 ^ b & d >> 4;
|
|
1798
|
+
D ^= b & c >> 4 ^ (a ^ b) & d >> 4;
|
|
1799
|
+
a = A;
|
|
1800
|
+
b = B;
|
|
1801
|
+
c = C;
|
|
1802
|
+
d = D;
|
|
1803
|
+
C ^= a & c >> 8 ^ b & d >> 8;
|
|
1804
|
+
D ^= b & c >> 8 ^ (a ^ b) & d >> 8;
|
|
1805
|
+
a = C ^ C >> 1;
|
|
1806
|
+
b = D ^ D >> 1;
|
|
1807
|
+
let i0 = x ^ y;
|
|
1808
|
+
let i1 = b | 65535 ^ (i0 | a);
|
|
1809
|
+
i0 = (i0 | i0 << 8) & 16711935;
|
|
1810
|
+
i0 = (i0 | i0 << 4) & 252645135;
|
|
1811
|
+
i0 = (i0 | i0 << 2) & 858993459;
|
|
1812
|
+
i0 = (i0 | i0 << 1) & 1431655765;
|
|
1813
|
+
i1 = (i1 | i1 << 8) & 16711935;
|
|
1814
|
+
i1 = (i1 | i1 << 4) & 252645135;
|
|
1815
|
+
i1 = (i1 | i1 << 2) & 858993459;
|
|
1816
|
+
i1 = (i1 | i1 << 1) & 1431655765;
|
|
1817
|
+
return (i1 << 1 | i0) >>> 0;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// lib/data-structures/FlatbushIndex.ts
|
|
1821
|
+
var FlatbushIndex = class {
|
|
1822
|
+
index;
|
|
1823
|
+
items = [];
|
|
1824
|
+
currentIndex = 0;
|
|
1825
|
+
constructor(numItems) {
|
|
1826
|
+
this.index = new Flatbush(numItems);
|
|
1827
|
+
}
|
|
1828
|
+
insert(item, minX, minY, maxX, maxY) {
|
|
1829
|
+
if (this.currentIndex >= this.index.numItems) {
|
|
1830
|
+
throw new Error("Exceeded initial capacity");
|
|
1831
|
+
}
|
|
1832
|
+
this.items[this.currentIndex] = item;
|
|
1833
|
+
this.index.add(minX, minY, maxX, maxY);
|
|
1834
|
+
this.currentIndex++;
|
|
1835
|
+
}
|
|
1836
|
+
finish() {
|
|
1837
|
+
this.index.finish();
|
|
1838
|
+
}
|
|
1839
|
+
search(minX, minY, maxX, maxY) {
|
|
1840
|
+
const ids = this.index.search(minX, minY, maxX, maxY);
|
|
1841
|
+
return ids.map((id) => this.items[id] || null).filter(Boolean);
|
|
1842
|
+
}
|
|
1843
|
+
clear() {
|
|
1844
|
+
this.items = [];
|
|
1845
|
+
this.index = new Flatbush(0);
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
|
|
971
1849
|
// lib/data-structures/ObstacleTree.ts
|
|
972
1850
|
var ObstacleSpatialHashIndex = class {
|
|
1851
|
+
idx;
|
|
1852
|
+
storage = [];
|
|
1853
|
+
constructor(implementation = "native", obstacles = []) {
|
|
1854
|
+
if (implementation === "flatbush") {
|
|
1855
|
+
this.idx = new FlatbushIndex(obstacles.length);
|
|
1856
|
+
} else if (implementation === "rbush") {
|
|
1857
|
+
this.idx = new RbushIndex();
|
|
1858
|
+
} else {
|
|
1859
|
+
this.idx = new class {
|
|
1860
|
+
shi = new NativeObstacleTree(obstacles);
|
|
1861
|
+
insert(item) {
|
|
1862
|
+
}
|
|
1863
|
+
search(minX, minY, maxX, maxY) {
|
|
1864
|
+
const centerX = (minX + maxX) / 2;
|
|
1865
|
+
const centerY = (minY + maxY) / 2;
|
|
1866
|
+
const width = maxX - minX;
|
|
1867
|
+
const height = maxY - minY;
|
|
1868
|
+
return this.shi.getNodesInArea(centerX, centerY, width, height);
|
|
1869
|
+
}
|
|
1870
|
+
clear() {
|
|
1871
|
+
}
|
|
1872
|
+
}();
|
|
1873
|
+
}
|
|
1874
|
+
obstacles.forEach((o) => this.insert(o));
|
|
1875
|
+
if (implementation === "flatbush") this.idx.finish?.();
|
|
1876
|
+
}
|
|
1877
|
+
insert(o) {
|
|
1878
|
+
this.storage.push(o);
|
|
1879
|
+
this.idx.insert(
|
|
1880
|
+
o,
|
|
1881
|
+
o.center.x - o.width / 2,
|
|
1882
|
+
o.center.y - o.height / 2,
|
|
1883
|
+
o.center.x + o.width / 2,
|
|
1884
|
+
o.center.y + o.height / 2
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
search(bbox) {
|
|
1888
|
+
return this.idx.search(bbox.minX, bbox.minY, bbox.maxX, bbox.maxY);
|
|
1889
|
+
}
|
|
1890
|
+
searchArea(centerX, centerY, width, height) {
|
|
1891
|
+
return this.search({
|
|
1892
|
+
minX: centerX - width / 2,
|
|
1893
|
+
minY: centerY - height / 2,
|
|
1894
|
+
maxX: centerX + width / 2,
|
|
1895
|
+
maxY: centerY + height / 2
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
};
|
|
1899
|
+
var NativeObstacleTree = class {
|
|
973
1900
|
constructor(obstacles) {
|
|
974
1901
|
this.obstacles = obstacles;
|
|
975
1902
|
this.buckets = /* @__PURE__ */ new Map();
|
|
@@ -1115,7 +2042,10 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1115
2042
|
];
|
|
1116
2043
|
this.finishedNodes = [];
|
|
1117
2044
|
this.nodeToXYOverlappingObstaclesMap = /* @__PURE__ */ new Map();
|
|
1118
|
-
this.obstacleTree = new ObstacleSpatialHashIndex(
|
|
2045
|
+
this.obstacleTree = new ObstacleSpatialHashIndex(
|
|
2046
|
+
"flatbush",
|
|
2047
|
+
this.srj.obstacles
|
|
2048
|
+
);
|
|
1119
2049
|
this.targets = this.computeTargets();
|
|
1120
2050
|
this.targetTree = new TargetTree(this.targets);
|
|
1121
2051
|
}
|
|
@@ -1132,7 +2062,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1132
2062
|
const targets = [];
|
|
1133
2063
|
for (const conn of this.srj.connections) {
|
|
1134
2064
|
for (const ptc of conn.pointsToConnect) {
|
|
1135
|
-
const obstacles = this.obstacleTree.
|
|
2065
|
+
const obstacles = this.obstacleTree.searchArea(ptc.x, ptc.y, 0.01, 0.01).filter(
|
|
1136
2066
|
(o) => o.zLayers.some((z) => ptc.layer === "top" ? z === 0 : z === 1)
|
|
1137
2067
|
);
|
|
1138
2068
|
let bounds = {
|
|
@@ -8128,7 +9058,7 @@ var SingleHighDensityRouteStitchSolver = class extends BaseSolver {
|
|
|
8128
9058
|
super();
|
|
8129
9059
|
this.remainingHdRoutes = [...opts.hdRoutes];
|
|
8130
9060
|
this.colorMap = opts.colorMap ?? {};
|
|
8131
|
-
const firstRoute = this.
|
|
9061
|
+
const { firstRoute } = this.getDisjointedRoute();
|
|
8132
9062
|
const firstRouteToStartDist = Math.min(
|
|
8133
9063
|
distance(firstRoute.route[0], opts.start),
|
|
8134
9064
|
distance(firstRoute.route[firstRoute.route.length - 1], opts.start)
|
|
@@ -8154,10 +9084,42 @@ var SingleHighDensityRouteStitchSolver = class extends BaseSolver {
|
|
|
8154
9084
|
}
|
|
8155
9085
|
],
|
|
8156
9086
|
vias: [],
|
|
8157
|
-
viaDiameter:
|
|
8158
|
-
traceThickness:
|
|
9087
|
+
viaDiameter: firstRoute.viaDiameter,
|
|
9088
|
+
traceThickness: firstRoute.traceThickness
|
|
8159
9089
|
};
|
|
8160
9090
|
}
|
|
9091
|
+
/**
|
|
9092
|
+
* Scan `remainingHdRoutes` and find a route that has **one** end that is not
|
|
9093
|
+
* within `5e-6` of the start or end of any other route on the same layer.
|
|
9094
|
+
* That “lonely” end marks one extremity of the whole chain, which we use as
|
|
9095
|
+
* our starting segment. If no such route exists (e.g., the data form a loop),
|
|
9096
|
+
* we simply return the first route so the solver can proceed.
|
|
9097
|
+
*/
|
|
9098
|
+
getDisjointedRoute() {
|
|
9099
|
+
const TOL = 5e-6;
|
|
9100
|
+
for (const candidate of this.remainingHdRoutes) {
|
|
9101
|
+
const candidateEnds = [
|
|
9102
|
+
candidate.route[0],
|
|
9103
|
+
candidate.route[candidate.route.length - 1]
|
|
9104
|
+
];
|
|
9105
|
+
const hasLonelyEnd = candidateEnds.some((end) => {
|
|
9106
|
+
return !this.remainingHdRoutes.some((other) => {
|
|
9107
|
+
if (other === candidate) return false;
|
|
9108
|
+
const otherEnds = [
|
|
9109
|
+
other.route[0],
|
|
9110
|
+
other.route[other.route.length - 1]
|
|
9111
|
+
];
|
|
9112
|
+
return otherEnds.some(
|
|
9113
|
+
(oe) => oe.z === end.z && distance(end, oe) < TOL
|
|
9114
|
+
);
|
|
9115
|
+
});
|
|
9116
|
+
});
|
|
9117
|
+
if (hasLonelyEnd) {
|
|
9118
|
+
return { firstRoute: candidate };
|
|
9119
|
+
}
|
|
9120
|
+
}
|
|
9121
|
+
return { firstRoute: this.remainingHdRoutes[0] };
|
|
9122
|
+
}
|
|
8161
9123
|
_step() {
|
|
8162
9124
|
if (this.remainingHdRoutes.length === 0) {
|
|
8163
9125
|
this.mergedHdRoute.route.push({
|
|
@@ -13299,7 +14261,7 @@ var SingleRouteUselessViaRemovalSolver = class extends BaseSolver {
|
|
|
13299
14261
|
width: Math.abs(A.x - B.x),
|
|
13300
14262
|
height: Math.abs(A.y - B.y)
|
|
13301
14263
|
};
|
|
13302
|
-
const obstacles = this.obstacleSHI.
|
|
14264
|
+
const obstacles = this.obstacleSHI.searchArea(
|
|
13303
14265
|
segmentBox.centerX,
|
|
13304
14266
|
segmentBox.centerY,
|
|
13305
14267
|
segmentBox.width + (this.TRACE_THICKNESS + this.OBSTACLE_MARGIN) * 2,
|
|
@@ -13372,7 +14334,7 @@ var UselessViaRemovalSolver = class extends BaseSolver {
|
|
|
13372
14334
|
this.unsimplifiedHdRoutes = input.unsimplifiedHdRoutes;
|
|
13373
14335
|
this.optimizedHdRoutes = [];
|
|
13374
14336
|
this.unprocessedRoutes = [...input.unsimplifiedHdRoutes];
|
|
13375
|
-
this.obstacleSHI = new ObstacleSpatialHashIndex(input.obstacles);
|
|
14337
|
+
this.obstacleSHI = new ObstacleSpatialHashIndex("flatbush", input.obstacles);
|
|
13376
14338
|
this.hdRouteSHI = new HighDensityRouteSpatialIndex(
|
|
13377
14339
|
this.unsimplifiedHdRoutes
|
|
13378
14340
|
);
|