@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.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(this.srj.obstacles);
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.getNodesInArea(ptc.x, ptc.y, 0.01, 0.01).filter(
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.remainingHdRoutes[0];
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: opts.hdRoutes?.[0]?.viaDiameter ?? 0.6,
8158
- traceThickness: opts.hdRoutes?.[0]?.traceThickness ?? 0.15
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.getNodesInArea(
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
  );