@tscircuit/capacity-autorouter 0.0.20 → 0.0.21

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 CHANGED
@@ -18,6 +18,7 @@ interface SimpleRouteJson {
18
18
  interface Obstacle {
19
19
  type: "rect";
20
20
  layers: string[];
21
+ zLayers?: number[];
21
22
  center: {
22
23
  x: number;
23
24
  y: number;
@@ -72,6 +73,7 @@ interface CapacityMeshNode {
72
73
  _containsObstacle?: boolean;
73
74
  _containsTarget?: boolean;
74
75
  _targetConnectionName?: string;
76
+ _shouldBeInGraph?: boolean;
75
77
  _parent?: CapacityMeshNode;
76
78
  }
77
79
  interface CapacityMeshEdge {
@@ -110,6 +112,7 @@ declare class CapacityMeshEdgeSolver extends BaseSolver {
110
112
  getNextCapacityMeshEdgeId(): string;
111
113
  step(): void;
112
114
  private areNodesBordering;
115
+ private doNodesHaveSharedLayer;
113
116
  visualize(): GraphicsObject;
114
117
  }
115
118
 
@@ -127,7 +130,8 @@ declare class CapacityMeshNodeSolver extends BaseSolver {
127
130
  opts: CapacityMeshNodeSolverOptions;
128
131
  unfinishedNodes: CapacityMeshNode[];
129
132
  finishedNodes: CapacityMeshNode[];
130
- nodeToOverlappingObstaclesMap: Map<CapacityMeshNodeId, Obstacle[]>;
133
+ nodeToXYOverlappingObstaclesMap: Map<CapacityMeshNodeId, Obstacle[]>;
134
+ layerCount: number;
131
135
  MAX_DEPTH: number;
132
136
  targets: Target[];
133
137
  constructor(srj: SimpleRouteJson, opts?: CapacityMeshNodeSolverOptions);
@@ -135,7 +139,8 @@ declare class CapacityMeshNodeSolver extends BaseSolver {
135
139
  getNextNodeId(): string;
136
140
  getCapacityFromDepth(depth: number): number;
137
141
  getTargetIfNodeContainsTarget(node: CapacityMeshNode): Target | null;
138
- getOverlappingObstacles(node: CapacityMeshNode): Obstacle[];
142
+ getXYOverlappingObstacles(node: CapacityMeshNode): Obstacle[];
143
+ getXYZOverlappingObstacles(node: CapacityMeshNode): Obstacle[];
139
144
  /**
140
145
  * Checks if the given mesh node overlaps with any obstacle.
141
146
  * We treat both obstacles and nodes as axis‐aligned rectangles.
@@ -146,7 +151,7 @@ declare class CapacityMeshNodeSolver extends BaseSolver {
146
151
  */
147
152
  isNodeCompletelyInsideObstacle(node: CapacityMeshNode): boolean;
148
153
  getChildNodes(parent: CapacityMeshNode): CapacityMeshNode[];
149
- shouldNodeBeSubdivided(node: CapacityMeshNode): boolean;
154
+ shouldNodeBeXYSubdivided(node: CapacityMeshNode): boolean;
150
155
  _step(): void;
151
156
  /**
152
157
  * Creates a GraphicsObject to visualize the mesh, its nodes, obstacles, and connection points.
package/dist/index.js CHANGED
@@ -140,7 +140,7 @@ var CapacityMeshEdgeSolver = class extends BaseSolver {
140
140
  this.edges = [];
141
141
  for (let i = 0; i < this.nodes.length; i++) {
142
142
  for (let j = i + 1; j < this.nodes.length; j++) {
143
- if (this.areNodesBordering(this.nodes[i], this.nodes[j])) {
143
+ if (this.areNodesBordering(this.nodes[i], this.nodes[j]) && this.doNodesHaveSharedLayer(this.nodes[i], this.nodes[j])) {
144
144
  this.edges.push({
145
145
  capacityMeshEdgeId: this.getNextCapacityMeshEdgeId(),
146
146
  nodeIds: [
@@ -194,16 +194,35 @@ var CapacityMeshEdgeSolver = class extends BaseSolver {
194
194
  const shareHorizontalBorder = (Math.abs(n1Bottom - n2Top) < epsilon || Math.abs(n1Top - n2Bottom) < epsilon) && Math.min(n1Right, n2Right) - Math.max(n1Left, n2Left) >= epsilon;
195
195
  return shareVerticalBorder || shareHorizontalBorder;
196
196
  }
197
+ doNodesHaveSharedLayer(node1, node2) {
198
+ return node1.availableZ.some((z) => node2.availableZ.includes(z));
199
+ }
197
200
  visualize() {
198
201
  const graphics = {
199
202
  lines: [],
200
203
  points: [],
201
- rects: this.nodes.map((node) => ({
202
- width: Math.max(node.width - 2, node.width * 0.8),
203
- height: Math.max(node.height - 2, node.height * 0.8),
204
- center: node.center,
205
- fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : node._containsTarget ? "rgba(0,255,0,0.2)" : "rgba(0,0,0,0.1)"
206
- })),
204
+ rects: this.nodes.map((node) => {
205
+ const lowestZ = Math.min(...node.availableZ);
206
+ return {
207
+ width: Math.max(node.width - 2, node.width * 0.8),
208
+ height: Math.max(node.height - 2, node.height * 0.8),
209
+ center: {
210
+ x: node.center.x + lowestZ * node.width * 0.05,
211
+ y: node.center.y - lowestZ * node.width * 0.05
212
+ },
213
+ fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : {
214
+ "0,1": "rgba(0,0,0,0.1)",
215
+ "0": "rgba(0,200,200, 0.1)",
216
+ "1": "rgba(0,0,200, 0.1)"
217
+ }[node.availableZ.join(",")] ?? "rgba(0,200,200,0.1)",
218
+ label: [
219
+ node.capacityMeshNodeId,
220
+ `availableZ: ${node.availableZ.join(",")}`,
221
+ `target? ${node._containsTarget ?? false}`,
222
+ `obs? ${node._containsObstacle ?? false}`
223
+ ].join("\n")
224
+ };
225
+ }),
207
226
  circles: []
208
227
  };
209
228
  for (const edge of this.edges) {
@@ -1074,7 +1093,14 @@ function doRectsOverlap(rect1, rect2) {
1074
1093
  return rect1Left <= rect2Right && rect1Right >= rect2Left && rect1Top <= rect2Bottom && rect1Bottom >= rect2Top;
1075
1094
  }
1076
1095
 
1077
- // lib/solvers/CapacityMeshSolver/CapacityMeshNodeSolver.ts
1096
+ // lib/utils/mapLayerNameToZ.ts
1097
+ var mapLayerNameToZ = (layerName, layerCount) => {
1098
+ if (layerName === "top") return 0;
1099
+ if (layerName === "bottom") return layerCount - 1;
1100
+ return parseInt(layerName.slice(5));
1101
+ };
1102
+
1103
+ // lib/solvers/CapacityMeshSolver/CapacityMeshNodeSolver1.ts
1078
1104
  var CapacityMeshNodeSolver = class extends BaseSolver {
1079
1105
  constructor(srj, opts = {}) {
1080
1106
  super();
@@ -1082,6 +1108,16 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1082
1108
  this.opts = opts;
1083
1109
  this.MAX_DEPTH = opts?.capacityDepth ?? this.MAX_DEPTH;
1084
1110
  this.MAX_ITERATIONS = 1e5;
1111
+ this.layerCount = srj.layerCount ?? 2;
1112
+ for (const obstacle of srj.obstacles) {
1113
+ if (!obstacle.zLayers) {
1114
+ const zLayers = [];
1115
+ for (const layer of obstacle.layers) {
1116
+ zLayers.push(mapLayerNameToZ(layer, srj.layerCount));
1117
+ }
1118
+ obstacle.zLayers = zLayers;
1119
+ }
1120
+ }
1085
1121
  const boundsCenter = {
1086
1122
  x: (srj.bounds.minX + srj.bounds.maxX) / 2,
1087
1123
  y: (srj.bounds.minY + srj.bounds.maxY) / 2
@@ -1106,7 +1142,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1106
1142
  }
1107
1143
  ];
1108
1144
  this.finishedNodes = [];
1109
- this.nodeToOverlappingObstaclesMap = /* @__PURE__ */ new Map();
1145
+ this.nodeToXYOverlappingObstaclesMap = /* @__PURE__ */ new Map();
1110
1146
  this.targets = this.srj.connections.flatMap(
1111
1147
  (c) => c.pointsToConnect.map((p) => ({
1112
1148
  ...p,
@@ -1117,7 +1153,8 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1117
1153
  }
1118
1154
  unfinishedNodes;
1119
1155
  finishedNodes;
1120
- nodeToOverlappingObstaclesMap;
1156
+ nodeToXYOverlappingObstaclesMap;
1157
+ layerCount;
1121
1158
  // targetObstacleMap: Record<string, { obstacle: Obstacle, node: CapacityMeshNode }>
1122
1159
  MAX_DEPTH = 4;
1123
1160
  targets;
@@ -1129,7 +1166,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1129
1166
  return (this.MAX_DEPTH - depth + 1) ** 2;
1130
1167
  }
1131
1168
  getTargetIfNodeContainsTarget(node) {
1132
- const overlappingObstacles = this.getOverlappingObstacles(node);
1169
+ const overlappingObstacles = this.getXYOverlappingObstacles(node);
1133
1170
  for (const target of this.targets) {
1134
1171
  const targetObstacle = overlappingObstacles.find(
1135
1172
  (o) => isPointInRect(target, o)
@@ -1145,8 +1182,8 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1145
1182
  }
1146
1183
  return null;
1147
1184
  }
1148
- getOverlappingObstacles(node) {
1149
- const cachedObstacles = this.nodeToOverlappingObstaclesMap.get(
1185
+ getXYOverlappingObstacles(node) {
1186
+ const cachedObstacles = this.nodeToXYOverlappingObstaclesMap.get(
1150
1187
  node.capacityMeshNodeId
1151
1188
  );
1152
1189
  if (cachedObstacles) {
@@ -1157,7 +1194,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1157
1194
  const nodeRight = node.center.x + node.width / 2;
1158
1195
  const nodeTop = node.center.y - node.height / 2;
1159
1196
  const nodeBottom = node.center.y + node.height / 2;
1160
- const obstacles = node._parent ? this.getOverlappingObstacles(node._parent) : this.srj.obstacles;
1197
+ const obstacles = node._parent ? this.getXYOverlappingObstacles(node._parent) : this.srj.obstacles;
1161
1198
  for (const obstacle of obstacles) {
1162
1199
  const obsLeft = obstacle.center.x - obstacle.width / 2;
1163
1200
  const obsRight = obstacle.center.x + obstacle.width / 2;
@@ -1165,20 +1202,38 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1165
1202
  const obsBottom = obstacle.center.y + obstacle.height / 2;
1166
1203
  if (nodeRight >= obsLeft && nodeLeft <= obsRight && nodeBottom >= obsTop && nodeTop <= obsBottom) {
1167
1204
  overlappingObstacles.push(obstacle);
1205
+ continue;
1206
+ }
1207
+ if (nodeLeft >= obsLeft && nodeRight <= obsRight && nodeTop >= obsTop && nodeBottom <= obsBottom) {
1208
+ overlappingObstacles.push(obstacle);
1209
+ continue;
1210
+ }
1211
+ if (obsLeft >= nodeLeft && obsRight <= nodeRight && obsTop >= nodeTop && obsBottom <= nodeBottom) {
1212
+ overlappingObstacles.push(obstacle);
1168
1213
  }
1169
1214
  }
1170
- this.nodeToOverlappingObstaclesMap.set(
1215
+ this.nodeToXYOverlappingObstaclesMap.set(
1171
1216
  node.capacityMeshNodeId,
1172
1217
  overlappingObstacles
1173
1218
  );
1174
1219
  return overlappingObstacles;
1175
1220
  }
1221
+ getXYZOverlappingObstacles(node) {
1222
+ const xyOverlappingObstacles = this.getXYOverlappingObstacles(node);
1223
+ const xyzOverlappingObstacles = [];
1224
+ for (const obstacle of xyOverlappingObstacles) {
1225
+ if (node.availableZ.some((z) => obstacle.zLayers.includes(z))) {
1226
+ xyzOverlappingObstacles.push(obstacle);
1227
+ }
1228
+ }
1229
+ return xyzOverlappingObstacles;
1230
+ }
1176
1231
  /**
1177
1232
  * Checks if the given mesh node overlaps with any obstacle.
1178
1233
  * We treat both obstacles and nodes as axis‐aligned rectangles.
1179
1234
  */
1180
1235
  doesNodeOverlapObstacle(node) {
1181
- const overlappingObstacles = this.getOverlappingObstacles(node);
1236
+ const overlappingObstacles = this.getXYZOverlappingObstacles(node);
1182
1237
  if (overlappingObstacles.length > 0) {
1183
1238
  return true;
1184
1239
  }
@@ -1195,7 +1250,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1195
1250
  * Checks if the entire node is contained within any obstacle.
1196
1251
  */
1197
1252
  isNodeCompletelyInsideObstacle(node) {
1198
- const overlappingObstacles = this.getOverlappingObstacles(node);
1253
+ const overlappingObstacles = this.getXYZOverlappingObstacles(node);
1199
1254
  const nodeLeft = node.center.x - node.width / 2;
1200
1255
  const nodeRight = node.center.x + node.width / 2;
1201
1256
  const nodeTop = node.center.y - node.height / 2;
@@ -1263,7 +1318,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1263
1318
  }
1264
1319
  return childNodes;
1265
1320
  }
1266
- shouldNodeBeSubdivided(node) {
1321
+ shouldNodeBeXYSubdivided(node) {
1267
1322
  if (node._depth >= this.MAX_DEPTH) return false;
1268
1323
  if (node._containsTarget) return true;
1269
1324
  if (node._containsObstacle && !node._completelyInsideObstacle) return true;
@@ -1279,7 +1334,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1279
1334
  const finishedNewNodes = [];
1280
1335
  const unfinishedNewNodes = [];
1281
1336
  for (const newNode of newNodes) {
1282
- const shouldBeSubdivided = this.shouldNodeBeSubdivided(newNode);
1337
+ const shouldBeSubdivided = this.shouldNodeBeXYSubdivided(newNode);
1283
1338
  if (shouldBeSubdivided) {
1284
1339
  unfinishedNewNodes.push(newNode);
1285
1340
  } else if (!shouldBeSubdivided && !newNode._containsObstacle) {
@@ -1317,20 +1372,33 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
1317
1372
  height: obstacle.height,
1318
1373
  fill: "rgba(255,0,0,0.3)",
1319
1374
  stroke: "red",
1320
- label: "obstacle"
1375
+ label: ["obstacle", obstacle.zLayers.join(",")].join("\n")
1321
1376
  });
1322
1377
  }
1323
1378
  const allNodes = [...this.finishedNodes, ...this.unfinishedNodes];
1324
1379
  for (const node of allNodes) {
1380
+ const lowestZ = Math.min(...node.availableZ);
1325
1381
  graphics.rects.push({
1326
- center: node.center,
1382
+ center: {
1383
+ x: node.center.x + lowestZ * node.width * 0.05,
1384
+ y: node.center.y - lowestZ * node.width * 0.05
1385
+ },
1327
1386
  width: Math.max(node.width - 2, node.width * 0.8),
1328
1387
  height: Math.max(node.height - 2, node.height * 0.8),
1329
- fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : "rgba(0,0,0,0.1)",
1330
- label: `${node.capacityMeshNodeId}
1331
- availableZ: ${node.availableZ.join(",")}`
1388
+ fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : {
1389
+ "0,1": "rgba(0,0,0,0.1)",
1390
+ "0": "rgba(0,200,200, 0.1)",
1391
+ "1": "rgba(0,0,200, 0.1)"
1392
+ }[node.availableZ.join(",")] ?? "rgba(0,200,200,0.1)",
1393
+ label: [
1394
+ node.capacityMeshNodeId,
1395
+ `availableZ: ${node.availableZ.join(",")}`,
1396
+ `target? ${node._containsTarget ?? false}`,
1397
+ `obs? ${node._containsObstacle ?? false}`
1398
+ ].join("\n")
1332
1399
  });
1333
1400
  }
1401
+ graphics.rects.sort((a, b) => a.center.y - b.center.y);
1334
1402
  this.srj.connections.forEach((connection, index) => {
1335
1403
  const color = COLORS[index % COLORS.length];
1336
1404
  for (const pt of connection.pointsToConnect) {
@@ -3717,13 +3785,6 @@ var convertHdRouteToSimplifiedRoute = (hdRoute, layerCount) => {
3717
3785
  return result;
3718
3786
  };
3719
3787
 
3720
- // lib/utils/mapLayerNameToZ.ts
3721
- var mapLayerNameToZ = (layerName, layerCount) => {
3722
- if (layerName === "top") return 0;
3723
- if (layerName === "bottom") return layerCount - 1;
3724
- return parseInt(layerName.slice(5));
3725
- };
3726
-
3727
3788
  // lib/solvers/RouteStitchingSolver/SingleHighDensityRouteStitchSolver.ts
3728
3789
  var SingleHighDensityRouteStitchSolver = class extends BaseSolver {
3729
3790
  mergedHdRoute;
@@ -5197,7 +5258,7 @@ Layer: ${segmentPoint.z}`,
5197
5258
  }
5198
5259
  };
5199
5260
 
5200
- // lib/solvers/CapacityMeshSolver/CapacityMeshSolver.ts
5261
+ // lib/solvers/AutoroutingPipelineSolver.ts
5201
5262
  function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
5202
5263
  return {
5203
5264
  solverName,