@tscircuit/schematic-trace-solver 0.0.6 → 0.0.8
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 +0 -5
- package/dist/index.js +451 -338
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts +199 -465
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver_visualize.ts +89 -0
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/anchors.ts +11 -0
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts +45 -0
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry.ts +48 -0
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/host.ts +64 -0
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts +177 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +4 -0
- package/lib/solvers/SchematicTracePipelineSolver/expandChipsToFitPins.ts +41 -0
- package/package.json +1 -1
- package/site/examples/example01-basic.page.tsx +2 -2
package/dist/index.js
CHANGED
|
@@ -7150,9 +7150,292 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
7150
7150
|
}
|
|
7151
7151
|
};
|
|
7152
7152
|
|
|
7153
|
-
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/
|
|
7153
|
+
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry.ts
|
|
7154
7154
|
var NET_LABEL_HORIZONTAL_WIDTH = 0.4;
|
|
7155
7155
|
var NET_LABEL_HORIZONTAL_HEIGHT = 0.2;
|
|
7156
|
+
function getDimsForOrientation(orientation) {
|
|
7157
|
+
if (orientation === "y+" || orientation === "y-") {
|
|
7158
|
+
return {
|
|
7159
|
+
width: NET_LABEL_HORIZONTAL_HEIGHT,
|
|
7160
|
+
height: NET_LABEL_HORIZONTAL_WIDTH
|
|
7161
|
+
};
|
|
7162
|
+
}
|
|
7163
|
+
return {
|
|
7164
|
+
width: NET_LABEL_HORIZONTAL_WIDTH,
|
|
7165
|
+
height: NET_LABEL_HORIZONTAL_HEIGHT
|
|
7166
|
+
};
|
|
7167
|
+
}
|
|
7168
|
+
function getCenterFromAnchor(anchor, orientation, width, height) {
|
|
7169
|
+
switch (orientation) {
|
|
7170
|
+
case "x+":
|
|
7171
|
+
return { x: anchor.x + width / 2, y: anchor.y };
|
|
7172
|
+
case "x-":
|
|
7173
|
+
return { x: anchor.x - width / 2, y: anchor.y };
|
|
7174
|
+
case "y+":
|
|
7175
|
+
return { x: anchor.x, y: anchor.y + height / 2 };
|
|
7176
|
+
case "y-":
|
|
7177
|
+
return { x: anchor.x, y: anchor.y - height / 2 };
|
|
7178
|
+
}
|
|
7179
|
+
}
|
|
7180
|
+
function getRectBounds(center, w, h) {
|
|
7181
|
+
return {
|
|
7182
|
+
minX: center.x - w / 2,
|
|
7183
|
+
minY: center.y - h / 2,
|
|
7184
|
+
maxX: center.x + w / 2,
|
|
7185
|
+
maxY: center.y + h / 2
|
|
7186
|
+
};
|
|
7187
|
+
}
|
|
7188
|
+
|
|
7189
|
+
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
|
|
7190
|
+
function segmentIntersectsRect(p1, p2, rect, EPS = 1e-9) {
|
|
7191
|
+
const isVert = Math.abs(p1.x - p2.x) < EPS;
|
|
7192
|
+
const isHorz = Math.abs(p1.y - p2.y) < EPS;
|
|
7193
|
+
if (!isVert && !isHorz) return false;
|
|
7194
|
+
if (isVert) {
|
|
7195
|
+
const x = p1.x;
|
|
7196
|
+
if (x < rect.minX - EPS || x > rect.maxX + EPS) return false;
|
|
7197
|
+
const segMinY = Math.min(p1.y, p2.y);
|
|
7198
|
+
const segMaxY = Math.max(p1.y, p2.y);
|
|
7199
|
+
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
7200
|
+
return overlap > EPS;
|
|
7201
|
+
} else {
|
|
7202
|
+
const y = p1.y;
|
|
7203
|
+
if (y < rect.minY - EPS || y > rect.maxY + EPS) return false;
|
|
7204
|
+
const segMinX = Math.min(p1.x, p2.x);
|
|
7205
|
+
const segMaxX = Math.max(p1.x, p2.x);
|
|
7206
|
+
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
7207
|
+
return overlap > EPS;
|
|
7208
|
+
}
|
|
7209
|
+
}
|
|
7210
|
+
function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
|
|
7211
|
+
for (const [pairId, solved] of Object.entries(inputTraceMap)) {
|
|
7212
|
+
const pts = solved.tracePath;
|
|
7213
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
7214
|
+
if (pairId === hostPathId && i === hostSegIndex) continue;
|
|
7215
|
+
if (segmentIntersectsRect(pts[i], pts[i + 1], bounds)) return true;
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
return false;
|
|
7219
|
+
}
|
|
7220
|
+
|
|
7221
|
+
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/host.ts
|
|
7222
|
+
function lengthOfTrace(path) {
|
|
7223
|
+
let sum = 0;
|
|
7224
|
+
const pts = path.tracePath;
|
|
7225
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
7226
|
+
sum += Math.abs(pts[i + 1].x - pts[i].x) + Math.abs(pts[i + 1].y - pts[i].y);
|
|
7227
|
+
}
|
|
7228
|
+
return sum;
|
|
7229
|
+
}
|
|
7230
|
+
function chooseHostTraceForGroup(params) {
|
|
7231
|
+
const { inputProblem, inputTraceMap, globalConnNetId, fallbackTrace } = params;
|
|
7232
|
+
const chipsById = Object.fromEntries(
|
|
7233
|
+
inputProblem.chips.map((c) => [c.chipId, c])
|
|
7234
|
+
);
|
|
7235
|
+
const groupTraces = Object.values(inputTraceMap).filter(
|
|
7236
|
+
(t) => t.globalConnNetId === globalConnNetId
|
|
7237
|
+
);
|
|
7238
|
+
const chipIdsInGroup = /* @__PURE__ */ new Set();
|
|
7239
|
+
for (const t of groupTraces) {
|
|
7240
|
+
chipIdsInGroup.add(t.pins[0].chipId);
|
|
7241
|
+
chipIdsInGroup.add(t.pins[1].chipId);
|
|
7242
|
+
}
|
|
7243
|
+
let largestChipId = null;
|
|
7244
|
+
let largestPinCount = -1;
|
|
7245
|
+
for (const id of chipIdsInGroup) {
|
|
7246
|
+
const chip = chipsById[id];
|
|
7247
|
+
const count = chip?.pins?.length ?? 0;
|
|
7248
|
+
if (count > largestPinCount) {
|
|
7249
|
+
largestPinCount = count;
|
|
7250
|
+
largestChipId = id;
|
|
7251
|
+
}
|
|
7252
|
+
}
|
|
7253
|
+
const hostCandidates = largestChipId == null ? [] : groupTraces.filter(
|
|
7254
|
+
(t) => t.pins[0].chipId === largestChipId || t.pins[1].chipId === largestChipId
|
|
7255
|
+
);
|
|
7256
|
+
if (hostCandidates.length > 0) {
|
|
7257
|
+
return hostCandidates.reduce(
|
|
7258
|
+
(a, b) => lengthOfTrace(a) >= lengthOfTrace(b) ? a : b
|
|
7259
|
+
);
|
|
7260
|
+
}
|
|
7261
|
+
return fallbackTrace;
|
|
7262
|
+
}
|
|
7263
|
+
|
|
7264
|
+
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/anchors.ts
|
|
7265
|
+
function anchorsForSegment(a, b) {
|
|
7266
|
+
return [
|
|
7267
|
+
{ x: a.x, y: a.y },
|
|
7268
|
+
{ x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
|
|
7269
|
+
{ x: b.x, y: b.y }
|
|
7270
|
+
];
|
|
7271
|
+
}
|
|
7272
|
+
|
|
7273
|
+
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts
|
|
7274
|
+
function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
7275
|
+
const {
|
|
7276
|
+
inputProblem,
|
|
7277
|
+
inputTraceMap,
|
|
7278
|
+
chipObstacleSpatialIndex,
|
|
7279
|
+
overlappingSameNetTraceGroup,
|
|
7280
|
+
availableOrientations
|
|
7281
|
+
} = params;
|
|
7282
|
+
const pinId = overlappingSameNetTraceGroup.portOnlyPinId;
|
|
7283
|
+
if (!pinId) {
|
|
7284
|
+
return {
|
|
7285
|
+
placement: null,
|
|
7286
|
+
testedCandidates: [],
|
|
7287
|
+
error: "No portOnlyPinId provided"
|
|
7288
|
+
};
|
|
7289
|
+
}
|
|
7290
|
+
let pin = null;
|
|
7291
|
+
for (const chip of inputProblem.chips) {
|
|
7292
|
+
const p = chip.pins.find((pp) => pp.pinId === pinId);
|
|
7293
|
+
if (p) {
|
|
7294
|
+
pin = { x: p.x, y: p.y };
|
|
7295
|
+
break;
|
|
7296
|
+
}
|
|
7297
|
+
}
|
|
7298
|
+
if (!pin) {
|
|
7299
|
+
return {
|
|
7300
|
+
placement: null,
|
|
7301
|
+
testedCandidates: [],
|
|
7302
|
+
error: `Port-only pin not found: ${pinId}`
|
|
7303
|
+
};
|
|
7304
|
+
}
|
|
7305
|
+
const orientations = availableOrientations.length > 0 ? availableOrientations : ["x+", "x-", "y+", "y-"];
|
|
7306
|
+
const anchor = { x: pin.x, y: pin.y };
|
|
7307
|
+
const outwardOf = (o) => o === "x+" ? { x: 1, y: 0 } : o === "x-" ? { x: -1, y: 0 } : o === "y+" ? { x: 0, y: 1 } : { x: 0, y: -1 };
|
|
7308
|
+
const testedCandidates = [];
|
|
7309
|
+
for (const orientation of orientations) {
|
|
7310
|
+
const { width, height } = getDimsForOrientation(orientation);
|
|
7311
|
+
const baseCenter = getCenterFromAnchor(anchor, orientation, width, height);
|
|
7312
|
+
const outward = outwardOf(orientation);
|
|
7313
|
+
const offset = 1e-3;
|
|
7314
|
+
const center = {
|
|
7315
|
+
x: baseCenter.x + outward.x * offset,
|
|
7316
|
+
y: baseCenter.y + outward.y * offset
|
|
7317
|
+
};
|
|
7318
|
+
const bounds = getRectBounds(center, width, height);
|
|
7319
|
+
const chips = chipObstacleSpatialIndex.getChipsInBounds(bounds);
|
|
7320
|
+
if (chips.length > 0) {
|
|
7321
|
+
testedCandidates.push({
|
|
7322
|
+
center,
|
|
7323
|
+
width,
|
|
7324
|
+
height,
|
|
7325
|
+
bounds,
|
|
7326
|
+
anchor,
|
|
7327
|
+
orientation,
|
|
7328
|
+
status: "chip-collision",
|
|
7329
|
+
hostSegIndex: -1
|
|
7330
|
+
});
|
|
7331
|
+
continue;
|
|
7332
|
+
}
|
|
7333
|
+
if (rectIntersectsAnyTrace(
|
|
7334
|
+
bounds,
|
|
7335
|
+
inputTraceMap,
|
|
7336
|
+
"",
|
|
7337
|
+
-1
|
|
7338
|
+
)) {
|
|
7339
|
+
testedCandidates.push({
|
|
7340
|
+
center,
|
|
7341
|
+
width,
|
|
7342
|
+
height,
|
|
7343
|
+
bounds,
|
|
7344
|
+
anchor,
|
|
7345
|
+
orientation,
|
|
7346
|
+
status: "trace-collision",
|
|
7347
|
+
hostSegIndex: -1
|
|
7348
|
+
});
|
|
7349
|
+
continue;
|
|
7350
|
+
}
|
|
7351
|
+
testedCandidates.push({
|
|
7352
|
+
center,
|
|
7353
|
+
width,
|
|
7354
|
+
height,
|
|
7355
|
+
bounds,
|
|
7356
|
+
anchor,
|
|
7357
|
+
orientation,
|
|
7358
|
+
status: "ok",
|
|
7359
|
+
hostSegIndex: -1
|
|
7360
|
+
});
|
|
7361
|
+
const placement = {
|
|
7362
|
+
globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
|
|
7363
|
+
dcConnNetId: void 0,
|
|
7364
|
+
orientation,
|
|
7365
|
+
anchorPoint: anchor,
|
|
7366
|
+
width,
|
|
7367
|
+
height,
|
|
7368
|
+
center
|
|
7369
|
+
};
|
|
7370
|
+
return { placement, testedCandidates };
|
|
7371
|
+
}
|
|
7372
|
+
return {
|
|
7373
|
+
placement: null,
|
|
7374
|
+
testedCandidates,
|
|
7375
|
+
error: "Could not place net label at port without collisions"
|
|
7376
|
+
};
|
|
7377
|
+
}
|
|
7378
|
+
|
|
7379
|
+
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver_visualize.ts
|
|
7380
|
+
function visualizeSingleNetLabelPlacementSolver(solver) {
|
|
7381
|
+
const graphics = visualizeInputProblem(solver.inputProblem);
|
|
7382
|
+
const groupId = solver.overlappingSameNetTraceGroup.globalConnNetId;
|
|
7383
|
+
const host = chooseHostTraceForGroup({
|
|
7384
|
+
inputProblem: solver.inputProblem,
|
|
7385
|
+
inputTraceMap: solver.inputTraceMap,
|
|
7386
|
+
globalConnNetId: groupId,
|
|
7387
|
+
fallbackTrace: solver.overlappingSameNetTraceGroup.overlappingTraces
|
|
7388
|
+
});
|
|
7389
|
+
const groupStroke = getColorFromString(groupId, 0.9);
|
|
7390
|
+
const groupFill = getColorFromString(groupId, 0.5);
|
|
7391
|
+
for (const trace of Object.values(solver.inputTraceMap)) {
|
|
7392
|
+
if (trace.globalConnNetId !== groupId) continue;
|
|
7393
|
+
const isHost = host ? trace.mspPairId === host.mspPairId : false;
|
|
7394
|
+
graphics.lines.push({
|
|
7395
|
+
points: trace.tracePath,
|
|
7396
|
+
strokeColor: isHost ? groupStroke : groupFill,
|
|
7397
|
+
strokeWidth: isHost ? 6e-3 : 3e-3,
|
|
7398
|
+
strokeDash: isHost ? void 0 : "4 2"
|
|
7399
|
+
});
|
|
7400
|
+
}
|
|
7401
|
+
for (const c of solver.testedCandidates) {
|
|
7402
|
+
const fill = c.status === "ok" ? "rgba(0, 180, 0, 0.25)" : c.status === "chip-collision" ? "rgba(220, 0, 0, 0.25)" : c.status === "trace-collision" ? "rgba(220, 140, 0, 0.25)" : "rgba(120, 120, 120, 0.15)";
|
|
7403
|
+
const stroke = c.status === "ok" ? "green" : c.status === "chip-collision" ? "red" : c.status === "trace-collision" ? "orange" : "gray";
|
|
7404
|
+
graphics.rects.push({
|
|
7405
|
+
center: {
|
|
7406
|
+
x: (c.bounds.minX + c.bounds.maxX) / 2,
|
|
7407
|
+
y: (c.bounds.minY + c.bounds.maxY) / 2
|
|
7408
|
+
},
|
|
7409
|
+
width: c.width,
|
|
7410
|
+
height: c.height,
|
|
7411
|
+
fill,
|
|
7412
|
+
strokeColor: stroke
|
|
7413
|
+
});
|
|
7414
|
+
graphics.points.push({
|
|
7415
|
+
x: c.anchor.x,
|
|
7416
|
+
y: c.anchor.y,
|
|
7417
|
+
color: stroke
|
|
7418
|
+
});
|
|
7419
|
+
}
|
|
7420
|
+
if (solver.netLabelPlacement) {
|
|
7421
|
+
const p = solver.netLabelPlacement;
|
|
7422
|
+
graphics.rects.push({
|
|
7423
|
+
center: p.center,
|
|
7424
|
+
width: p.width,
|
|
7425
|
+
height: p.height,
|
|
7426
|
+
fill: "rgba(0, 128, 255, 0.35)",
|
|
7427
|
+
strokeColor: "blue"
|
|
7428
|
+
});
|
|
7429
|
+
graphics.points.push({
|
|
7430
|
+
x: p.anchorPoint.x,
|
|
7431
|
+
y: p.anchorPoint.y,
|
|
7432
|
+
color: "blue"
|
|
7433
|
+
});
|
|
7434
|
+
}
|
|
7435
|
+
return graphics;
|
|
7436
|
+
}
|
|
7437
|
+
|
|
7438
|
+
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts
|
|
7156
7439
|
var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
7157
7440
|
inputProblem;
|
|
7158
7441
|
inputTraceMap;
|
|
@@ -7169,260 +7452,127 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
7169
7452
|
this.availableOrientations = params.availableOrientations;
|
|
7170
7453
|
this.chipObstacleSpatialIndex = params.inputProblem._chipObstacleSpatialIndex ?? new ChipObstacleSpatialIndex(params.inputProblem.chips);
|
|
7171
7454
|
}
|
|
7172
|
-
getDimsForOrientation(orientation) {
|
|
7173
|
-
if (orientation === "y+" || orientation === "y-") {
|
|
7174
|
-
return {
|
|
7175
|
-
width: NET_LABEL_HORIZONTAL_HEIGHT,
|
|
7176
|
-
height: NET_LABEL_HORIZONTAL_WIDTH
|
|
7177
|
-
};
|
|
7178
|
-
}
|
|
7179
|
-
return {
|
|
7180
|
-
width: NET_LABEL_HORIZONTAL_WIDTH,
|
|
7181
|
-
height: NET_LABEL_HORIZONTAL_HEIGHT
|
|
7182
|
-
};
|
|
7183
|
-
}
|
|
7184
|
-
getCenterFromAnchor(anchor, orientation, width, height) {
|
|
7185
|
-
switch (orientation) {
|
|
7186
|
-
case "x+":
|
|
7187
|
-
return { x: anchor.x + width / 2, y: anchor.y };
|
|
7188
|
-
case "x-":
|
|
7189
|
-
return { x: anchor.x - width / 2, y: anchor.y };
|
|
7190
|
-
case "y+":
|
|
7191
|
-
return { x: anchor.x, y: anchor.y + height / 2 };
|
|
7192
|
-
case "y-":
|
|
7193
|
-
return { x: anchor.x, y: anchor.y - height / 2 };
|
|
7194
|
-
}
|
|
7195
|
-
}
|
|
7196
|
-
getRectBounds(center, w, h) {
|
|
7197
|
-
return {
|
|
7198
|
-
minX: center.x - w / 2,
|
|
7199
|
-
minY: center.y - h / 2,
|
|
7200
|
-
maxX: center.x + w / 2,
|
|
7201
|
-
maxY: center.y + h / 2
|
|
7202
|
-
};
|
|
7203
|
-
}
|
|
7204
|
-
segmentIntersectsRect(p1, p2, rect, EPS = 1e-9) {
|
|
7205
|
-
const isVert = Math.abs(p1.x - p2.x) < EPS;
|
|
7206
|
-
const isHorz = Math.abs(p1.y - p2.y) < EPS;
|
|
7207
|
-
if (!isVert && !isHorz) return false;
|
|
7208
|
-
if (isVert) {
|
|
7209
|
-
const x = p1.x;
|
|
7210
|
-
if (x < rect.minX - EPS || x > rect.maxX + EPS) return false;
|
|
7211
|
-
const segMinY = Math.min(p1.y, p2.y);
|
|
7212
|
-
const segMaxY = Math.max(p1.y, p2.y);
|
|
7213
|
-
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
7214
|
-
return overlap > EPS;
|
|
7215
|
-
} else {
|
|
7216
|
-
const y = p1.y;
|
|
7217
|
-
if (y < rect.minY - EPS || y > rect.maxY + EPS) return false;
|
|
7218
|
-
const segMinX = Math.min(p1.x, p2.x);
|
|
7219
|
-
const segMaxX = Math.max(p1.x, p2.x);
|
|
7220
|
-
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
7221
|
-
return overlap > EPS;
|
|
7222
|
-
}
|
|
7223
|
-
}
|
|
7224
|
-
rectIntersectsAnyTrace(bounds, hostPathId, hostSegIndex) {
|
|
7225
|
-
for (const [pairId, solved] of Object.entries(this.inputTraceMap)) {
|
|
7226
|
-
const pts = solved.tracePath;
|
|
7227
|
-
for (let i = 0; i < pts.length - 1; i++) {
|
|
7228
|
-
if (pairId === hostPathId && i === hostSegIndex) continue;
|
|
7229
|
-
if (this.segmentIntersectsRect(pts[i], pts[i + 1], bounds))
|
|
7230
|
-
return true;
|
|
7231
|
-
}
|
|
7232
|
-
}
|
|
7233
|
-
return false;
|
|
7234
|
-
}
|
|
7235
7455
|
_step() {
|
|
7236
7456
|
if (this.netLabelPlacement) {
|
|
7237
7457
|
this.solved = true;
|
|
7238
7458
|
return;
|
|
7239
7459
|
}
|
|
7240
7460
|
if (this.overlappingSameNetTraceGroup.portOnlyPinId) {
|
|
7241
|
-
const
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
this.failed = true;
|
|
7252
|
-
this.error = `Port-only pin not found: ${pinId}`;
|
|
7253
|
-
return;
|
|
7254
|
-
}
|
|
7255
|
-
const orientations2 = this.availableOrientations.length > 0 ? this.availableOrientations : ["x+", "x-", "y+", "y-"];
|
|
7256
|
-
const anchor = { x: pin.x, y: pin.y };
|
|
7257
|
-
const outwardOf = (o) => o === "x+" ? { x: 1, y: 0 } : o === "x-" ? { x: -1, y: 0 } : o === "y+" ? { x: 0, y: 1 } : { x: 0, y: -1 };
|
|
7258
|
-
for (const orientation of orientations2) {
|
|
7259
|
-
const { width, height } = this.getDimsForOrientation(orientation);
|
|
7260
|
-
const baseCenter = this.getCenterFromAnchor(
|
|
7261
|
-
anchor,
|
|
7262
|
-
orientation,
|
|
7263
|
-
width,
|
|
7264
|
-
height
|
|
7265
|
-
);
|
|
7266
|
-
const outward = outwardOf(orientation);
|
|
7267
|
-
const offset = 1e-3;
|
|
7268
|
-
const center = {
|
|
7269
|
-
x: baseCenter.x + outward.x * offset,
|
|
7270
|
-
y: baseCenter.y + outward.y * offset
|
|
7271
|
-
};
|
|
7272
|
-
const bounds = this.getRectBounds(center, width, height);
|
|
7273
|
-
const chips = this.chipObstacleSpatialIndex.getChipsInBounds(bounds);
|
|
7274
|
-
if (chips.length > 0) {
|
|
7275
|
-
this.testedCandidates.push({
|
|
7276
|
-
center,
|
|
7277
|
-
width,
|
|
7278
|
-
height,
|
|
7279
|
-
bounds,
|
|
7280
|
-
anchor,
|
|
7281
|
-
orientation,
|
|
7282
|
-
status: "chip-collision",
|
|
7283
|
-
hostSegIndex: -1
|
|
7284
|
-
});
|
|
7285
|
-
continue;
|
|
7286
|
-
}
|
|
7287
|
-
if (this.rectIntersectsAnyTrace(bounds, "", -1)) {
|
|
7288
|
-
this.testedCandidates.push({
|
|
7289
|
-
center,
|
|
7290
|
-
width,
|
|
7291
|
-
height,
|
|
7292
|
-
bounds,
|
|
7293
|
-
anchor,
|
|
7294
|
-
orientation,
|
|
7295
|
-
status: "trace-collision",
|
|
7296
|
-
hostSegIndex: -1
|
|
7297
|
-
});
|
|
7298
|
-
continue;
|
|
7299
|
-
}
|
|
7300
|
-
this.testedCandidates.push({
|
|
7301
|
-
center,
|
|
7302
|
-
width,
|
|
7303
|
-
height,
|
|
7304
|
-
bounds,
|
|
7305
|
-
anchor,
|
|
7306
|
-
orientation,
|
|
7307
|
-
status: "ok",
|
|
7308
|
-
hostSegIndex: -1
|
|
7309
|
-
});
|
|
7310
|
-
this.netLabelPlacement = {
|
|
7311
|
-
globalConnNetId: this.overlappingSameNetTraceGroup.globalConnNetId,
|
|
7312
|
-
dcConnNetId: void 0,
|
|
7313
|
-
orientation,
|
|
7314
|
-
anchorPoint: anchor,
|
|
7315
|
-
width,
|
|
7316
|
-
height,
|
|
7317
|
-
center
|
|
7318
|
-
};
|
|
7461
|
+
const res = solveNetLabelPlacementForPortOnlyPin({
|
|
7462
|
+
inputProblem: this.inputProblem,
|
|
7463
|
+
inputTraceMap: this.inputTraceMap,
|
|
7464
|
+
chipObstacleSpatialIndex: this.chipObstacleSpatialIndex,
|
|
7465
|
+
overlappingSameNetTraceGroup: this.overlappingSameNetTraceGroup,
|
|
7466
|
+
availableOrientations: this.availableOrientations
|
|
7467
|
+
});
|
|
7468
|
+
this.testedCandidates.push(...res.testedCandidates);
|
|
7469
|
+
if (res.placement) {
|
|
7470
|
+
this.netLabelPlacement = res.placement;
|
|
7319
7471
|
this.solved = true;
|
|
7320
7472
|
return;
|
|
7321
7473
|
}
|
|
7322
7474
|
this.failed = true;
|
|
7323
|
-
this.error = "Could not place net label at port without collisions";
|
|
7475
|
+
this.error = res.error ?? "Could not place net label at port without collisions";
|
|
7324
7476
|
return;
|
|
7325
7477
|
}
|
|
7326
7478
|
const groupId = this.overlappingSameNetTraceGroup.globalConnNetId;
|
|
7327
|
-
|
|
7328
|
-
this.inputProblem
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
);
|
|
7333
|
-
const chipIdsInGroup = /* @__PURE__ */ new Set();
|
|
7334
|
-
for (const t of groupTraces) {
|
|
7335
|
-
chipIdsInGroup.add(t.pins[0].chipId);
|
|
7336
|
-
chipIdsInGroup.add(t.pins[1].chipId);
|
|
7337
|
-
}
|
|
7338
|
-
let largestChipId = null;
|
|
7339
|
-
let largestPinCount = -1;
|
|
7340
|
-
for (const id of chipIdsInGroup) {
|
|
7341
|
-
const chip = chipsById[id];
|
|
7342
|
-
const count = chip?.pins?.length ?? 0;
|
|
7343
|
-
if (count > largestPinCount) {
|
|
7344
|
-
largestPinCount = count;
|
|
7345
|
-
largestChipId = id;
|
|
7346
|
-
}
|
|
7347
|
-
}
|
|
7348
|
-
const lengthOf = (path) => {
|
|
7349
|
-
let sum = 0;
|
|
7350
|
-
const pts2 = path.tracePath;
|
|
7351
|
-
for (let i = 0; i < pts2.length - 1; i++) {
|
|
7352
|
-
sum += Math.abs(pts2[i + 1].x - pts2[i].x) + Math.abs(pts2[i + 1].y - pts2[i].y);
|
|
7353
|
-
}
|
|
7354
|
-
return sum;
|
|
7355
|
-
};
|
|
7356
|
-
const hostCandidates = largestChipId == null ? [] : groupTraces.filter(
|
|
7357
|
-
(t) => t.pins[0].chipId === largestChipId || t.pins[1].chipId === largestChipId
|
|
7358
|
-
);
|
|
7359
|
-
let host = hostCandidates.length > 0 ? hostCandidates.reduce((a, b) => lengthOf(a) >= lengthOf(b) ? a : b) : this.overlappingSameNetTraceGroup.overlappingTraces;
|
|
7479
|
+
let host = chooseHostTraceForGroup({
|
|
7480
|
+
inputProblem: this.inputProblem,
|
|
7481
|
+
inputTraceMap: this.inputTraceMap,
|
|
7482
|
+
globalConnNetId: groupId,
|
|
7483
|
+
fallbackTrace: this.overlappingSameNetTraceGroup.overlappingTraces
|
|
7484
|
+
});
|
|
7360
7485
|
if (!host) {
|
|
7361
7486
|
this.failed = true;
|
|
7362
7487
|
this.error = "No host trace found for net label placement";
|
|
7363
7488
|
return;
|
|
7364
7489
|
}
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
}
|
|
7373
|
-
}
|
|
7490
|
+
const tracesToScanBase = Object.values(this.inputTraceMap).filter(
|
|
7491
|
+
(t) => t.globalConnNetId === groupId
|
|
7492
|
+
);
|
|
7493
|
+
const tracesToScan = this.availableOrientations.length === 1 ? [
|
|
7494
|
+
host,
|
|
7495
|
+
...tracesToScanBase.filter((t) => t.mspPairId !== host.mspPairId)
|
|
7496
|
+
] : [host];
|
|
7374
7497
|
const orientations = this.availableOrientations.length > 0 ? this.availableOrientations : ["x+", "x-", "y+", "y-"];
|
|
7498
|
+
const singleOrientationMode = this.availableOrientations.length === 1;
|
|
7499
|
+
const scoreFor = (orientation, anchor) => {
|
|
7500
|
+
switch (orientation) {
|
|
7501
|
+
case "y+":
|
|
7502
|
+
return anchor.y;
|
|
7503
|
+
case "y-":
|
|
7504
|
+
return -anchor.y;
|
|
7505
|
+
case "x+":
|
|
7506
|
+
return anchor.x;
|
|
7507
|
+
case "x-":
|
|
7508
|
+
return -anchor.x;
|
|
7509
|
+
}
|
|
7510
|
+
};
|
|
7511
|
+
let bestCandidate = null;
|
|
7512
|
+
let bestScore = -Infinity;
|
|
7375
7513
|
const EPS = 1e-6;
|
|
7376
|
-
const
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
const anchors = anchorsForSegment(a, b);
|
|
7395
|
-
for (const anchor of anchors) {
|
|
7396
|
-
for (const orientation of candidateOrients) {
|
|
7397
|
-
const { width, height } = this.getDimsForOrientation(orientation);
|
|
7398
|
-
const center = this.getCenterFromAnchor(
|
|
7399
|
-
anchor,
|
|
7400
|
-
orientation,
|
|
7401
|
-
width,
|
|
7402
|
-
height
|
|
7403
|
-
);
|
|
7404
|
-
const outward = orientation === "x+" ? { x: 1, y: 0 } : orientation === "x-" ? { x: -1, y: 0 } : orientation === "y+" ? { x: 0, y: 1 } : { x: 0, y: -1 };
|
|
7405
|
-
const offset = 1e-4;
|
|
7406
|
-
const testCenter = {
|
|
7407
|
-
x: center.x + outward.x * offset,
|
|
7408
|
-
y: center.y + outward.y * offset
|
|
7409
|
-
};
|
|
7410
|
-
const bounds = this.getRectBounds(testCenter, width, height);
|
|
7411
|
-
const chips = this.chipObstacleSpatialIndex.getChipsInBounds(bounds);
|
|
7412
|
-
if (chips.length > 0) {
|
|
7413
|
-
this.testedCandidates.push({
|
|
7414
|
-
center: testCenter,
|
|
7415
|
-
width,
|
|
7416
|
-
height,
|
|
7417
|
-
bounds,
|
|
7514
|
+
for (const curr of tracesToScan) {
|
|
7515
|
+
const pts = curr.tracePath.slice();
|
|
7516
|
+
for (let si = 0; si < pts.length - 1; si++) {
|
|
7517
|
+
const a = pts[si];
|
|
7518
|
+
const b = pts[si + 1];
|
|
7519
|
+
const isH = Math.abs(a.y - b.y) < EPS;
|
|
7520
|
+
const isV = Math.abs(a.x - b.x) < EPS;
|
|
7521
|
+
if (!isH && !isV) continue;
|
|
7522
|
+
const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
|
|
7523
|
+
const candidateOrients = orientations.filter(
|
|
7524
|
+
(o) => segmentAllowed.includes(o)
|
|
7525
|
+
);
|
|
7526
|
+
if (candidateOrients.length === 0) continue;
|
|
7527
|
+
const anchors = anchorsForSegment(a, b);
|
|
7528
|
+
for (const anchor of anchors) {
|
|
7529
|
+
for (const orientation of candidateOrients) {
|
|
7530
|
+
const { width, height } = getDimsForOrientation(orientation);
|
|
7531
|
+
const center = getCenterFromAnchor(
|
|
7418
7532
|
anchor,
|
|
7419
7533
|
orientation,
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7534
|
+
width,
|
|
7535
|
+
height
|
|
7536
|
+
);
|
|
7537
|
+
const outward = orientation === "x+" ? { x: 1, y: 0 } : orientation === "x-" ? { x: -1, y: 0 } : orientation === "y+" ? { x: 0, y: 1 } : { x: 0, y: -1 };
|
|
7538
|
+
const offset = 1e-4;
|
|
7539
|
+
const testCenter = {
|
|
7540
|
+
x: center.x + outward.x * offset,
|
|
7541
|
+
y: center.y + outward.y * offset
|
|
7542
|
+
};
|
|
7543
|
+
const bounds = getRectBounds(testCenter, width, height);
|
|
7544
|
+
const chips = this.chipObstacleSpatialIndex.getChipsInBounds(bounds);
|
|
7545
|
+
if (chips.length > 0) {
|
|
7546
|
+
this.testedCandidates.push({
|
|
7547
|
+
center: testCenter,
|
|
7548
|
+
width,
|
|
7549
|
+
height,
|
|
7550
|
+
bounds,
|
|
7551
|
+
anchor,
|
|
7552
|
+
orientation,
|
|
7553
|
+
status: "chip-collision",
|
|
7554
|
+
hostSegIndex: si
|
|
7555
|
+
});
|
|
7556
|
+
continue;
|
|
7557
|
+
}
|
|
7558
|
+
if (rectIntersectsAnyTrace(
|
|
7559
|
+
bounds,
|
|
7560
|
+
this.inputTraceMap,
|
|
7561
|
+
curr.mspPairId,
|
|
7562
|
+
si
|
|
7563
|
+
)) {
|
|
7564
|
+
this.testedCandidates.push({
|
|
7565
|
+
center: testCenter,
|
|
7566
|
+
width,
|
|
7567
|
+
height,
|
|
7568
|
+
bounds,
|
|
7569
|
+
anchor,
|
|
7570
|
+
orientation,
|
|
7571
|
+
status: "trace-collision",
|
|
7572
|
+
hostSegIndex: si
|
|
7573
|
+
});
|
|
7574
|
+
continue;
|
|
7575
|
+
}
|
|
7426
7576
|
this.testedCandidates.push({
|
|
7427
7577
|
center: testCenter,
|
|
7428
7578
|
width,
|
|
@@ -7430,121 +7580,58 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
7430
7580
|
bounds,
|
|
7431
7581
|
anchor,
|
|
7432
7582
|
orientation,
|
|
7433
|
-
status: "
|
|
7583
|
+
status: "ok",
|
|
7434
7584
|
hostSegIndex: si
|
|
7435
7585
|
});
|
|
7436
|
-
|
|
7586
|
+
if (singleOrientationMode) {
|
|
7587
|
+
const s = scoreFor(orientation, anchor);
|
|
7588
|
+
if (s > bestScore + 1e-9) {
|
|
7589
|
+
bestScore = s;
|
|
7590
|
+
bestCandidate = {
|
|
7591
|
+
anchor,
|
|
7592
|
+
orientation,
|
|
7593
|
+
width,
|
|
7594
|
+
height,
|
|
7595
|
+
center,
|
|
7596
|
+
hostSegIndex: si,
|
|
7597
|
+
dcConnNetId: curr.dcConnNetId
|
|
7598
|
+
};
|
|
7599
|
+
}
|
|
7600
|
+
continue;
|
|
7601
|
+
}
|
|
7602
|
+
this.netLabelPlacement = {
|
|
7603
|
+
globalConnNetId: this.overlappingSameNetTraceGroup.globalConnNetId,
|
|
7604
|
+
dcConnNetId: curr.dcConnNetId,
|
|
7605
|
+
orientation,
|
|
7606
|
+
anchorPoint: anchor,
|
|
7607
|
+
width,
|
|
7608
|
+
height,
|
|
7609
|
+
center
|
|
7610
|
+
};
|
|
7611
|
+
this.solved = true;
|
|
7612
|
+
return;
|
|
7437
7613
|
}
|
|
7438
|
-
this.testedCandidates.push({
|
|
7439
|
-
center: testCenter,
|
|
7440
|
-
width,
|
|
7441
|
-
height,
|
|
7442
|
-
bounds,
|
|
7443
|
-
anchor,
|
|
7444
|
-
orientation,
|
|
7445
|
-
status: "ok",
|
|
7446
|
-
hostSegIndex: si
|
|
7447
|
-
});
|
|
7448
|
-
this.netLabelPlacement = {
|
|
7449
|
-
globalConnNetId: this.overlappingSameNetTraceGroup.globalConnNetId,
|
|
7450
|
-
dcConnNetId: host.dcConnNetId,
|
|
7451
|
-
orientation,
|
|
7452
|
-
anchorPoint: anchor,
|
|
7453
|
-
width,
|
|
7454
|
-
height,
|
|
7455
|
-
center
|
|
7456
|
-
};
|
|
7457
|
-
this.solved = true;
|
|
7458
|
-
return;
|
|
7459
7614
|
}
|
|
7460
7615
|
}
|
|
7461
7616
|
}
|
|
7617
|
+
if (singleOrientationMode && bestCandidate) {
|
|
7618
|
+
this.netLabelPlacement = {
|
|
7619
|
+
globalConnNetId: this.overlappingSameNetTraceGroup.globalConnNetId,
|
|
7620
|
+
dcConnNetId: bestCandidate.dcConnNetId,
|
|
7621
|
+
orientation: bestCandidate.orientation,
|
|
7622
|
+
anchorPoint: bestCandidate.anchor,
|
|
7623
|
+
width: bestCandidate.width,
|
|
7624
|
+
height: bestCandidate.height,
|
|
7625
|
+
center: bestCandidate.center
|
|
7626
|
+
};
|
|
7627
|
+
this.solved = true;
|
|
7628
|
+
return;
|
|
7629
|
+
}
|
|
7462
7630
|
this.failed = true;
|
|
7463
7631
|
this.error = "Could not place net label without collisions";
|
|
7464
7632
|
}
|
|
7465
7633
|
visualize() {
|
|
7466
|
-
|
|
7467
|
-
const groupId = this.overlappingSameNetTraceGroup.globalConnNetId;
|
|
7468
|
-
const chipsById = Object.fromEntries(
|
|
7469
|
-
this.inputProblem.chips.map((c) => [c.chipId, c])
|
|
7470
|
-
);
|
|
7471
|
-
const groupTraces = Object.values(this.inputTraceMap).filter(
|
|
7472
|
-
(t) => t.globalConnNetId === groupId
|
|
7473
|
-
);
|
|
7474
|
-
const chipIdsInGroup = /* @__PURE__ */ new Set();
|
|
7475
|
-
for (const t of groupTraces) {
|
|
7476
|
-
chipIdsInGroup.add(t.pins[0].chipId);
|
|
7477
|
-
chipIdsInGroup.add(t.pins[1].chipId);
|
|
7478
|
-
}
|
|
7479
|
-
let largestChipId = null;
|
|
7480
|
-
let largestPinCount = -1;
|
|
7481
|
-
for (const id of chipIdsInGroup) {
|
|
7482
|
-
const chip = chipsById[id];
|
|
7483
|
-
const count = chip?.pins?.length ?? 0;
|
|
7484
|
-
if (count > largestPinCount) {
|
|
7485
|
-
largestPinCount = count;
|
|
7486
|
-
largestChipId = id;
|
|
7487
|
-
}
|
|
7488
|
-
}
|
|
7489
|
-
const lengthOf = (path) => {
|
|
7490
|
-
let sum = 0;
|
|
7491
|
-
const pts = path.tracePath;
|
|
7492
|
-
for (let i = 0; i < pts.length - 1; i++) {
|
|
7493
|
-
sum += Math.abs(pts[i + 1].x - pts[i].x) + Math.abs(pts[i + 1].y - pts[i].y);
|
|
7494
|
-
}
|
|
7495
|
-
return sum;
|
|
7496
|
-
};
|
|
7497
|
-
const hostCandidates = largestChipId == null ? [] : groupTraces.filter(
|
|
7498
|
-
(t) => t.pins[0].chipId === largestChipId || t.pins[1].chipId === largestChipId
|
|
7499
|
-
);
|
|
7500
|
-
const host = hostCandidates.length > 0 ? hostCandidates.reduce((a, b) => lengthOf(a) >= lengthOf(b) ? a : b) : this.overlappingSameNetTraceGroup.overlappingTraces;
|
|
7501
|
-
const groupStroke = getColorFromString(groupId, 0.9);
|
|
7502
|
-
const groupFill = getColorFromString(groupId, 0.5);
|
|
7503
|
-
for (const trace of Object.values(this.inputTraceMap)) {
|
|
7504
|
-
if (trace.globalConnNetId !== groupId) continue;
|
|
7505
|
-
const isHost = host ? trace.mspPairId === host.mspPairId : false;
|
|
7506
|
-
graphics.lines.push({
|
|
7507
|
-
points: trace.tracePath,
|
|
7508
|
-
strokeColor: isHost ? groupStroke : groupFill,
|
|
7509
|
-
strokeWidth: isHost ? 6e-3 : 3e-3,
|
|
7510
|
-
strokeDash: isHost ? void 0 : "4 2"
|
|
7511
|
-
});
|
|
7512
|
-
}
|
|
7513
|
-
for (const c of this.testedCandidates) {
|
|
7514
|
-
const fill = c.status === "ok" ? "rgba(0, 180, 0, 0.25)" : c.status === "chip-collision" ? "rgba(220, 0, 0, 0.25)" : c.status === "trace-collision" ? "rgba(220, 140, 0, 0.25)" : "rgba(120, 120, 120, 0.15)";
|
|
7515
|
-
const stroke = c.status === "ok" ? "green" : c.status === "chip-collision" ? "red" : c.status === "trace-collision" ? "orange" : "gray";
|
|
7516
|
-
graphics.rects.push({
|
|
7517
|
-
center: {
|
|
7518
|
-
x: (c.bounds.minX + c.bounds.maxX) / 2,
|
|
7519
|
-
y: (c.bounds.minY + c.bounds.maxY) / 2
|
|
7520
|
-
},
|
|
7521
|
-
width: c.width,
|
|
7522
|
-
height: c.height,
|
|
7523
|
-
fill,
|
|
7524
|
-
strokeColor: stroke
|
|
7525
|
-
});
|
|
7526
|
-
graphics.points.push({
|
|
7527
|
-
x: c.anchor.x,
|
|
7528
|
-
y: c.anchor.y,
|
|
7529
|
-
color: stroke
|
|
7530
|
-
});
|
|
7531
|
-
}
|
|
7532
|
-
if (this.netLabelPlacement) {
|
|
7533
|
-
const p = this.netLabelPlacement;
|
|
7534
|
-
graphics.rects.push({
|
|
7535
|
-
center: p.center,
|
|
7536
|
-
width: p.width,
|
|
7537
|
-
height: p.height,
|
|
7538
|
-
fill: "rgba(0, 128, 255, 0.35)",
|
|
7539
|
-
strokeColor: "blue"
|
|
7540
|
-
});
|
|
7541
|
-
graphics.points.push({
|
|
7542
|
-
x: p.anchorPoint.x,
|
|
7543
|
-
y: p.anchorPoint.y,
|
|
7544
|
-
color: "blue"
|
|
7545
|
-
});
|
|
7546
|
-
}
|
|
7547
|
-
return graphics;
|
|
7634
|
+
return visualizeSingleNetLabelPlacementSolver(this);
|
|
7548
7635
|
}
|
|
7549
7636
|
};
|
|
7550
7637
|
|
|
@@ -7891,6 +7978,31 @@ var correctPinsInsideChips = (problem) => {
|
|
|
7891
7978
|
}
|
|
7892
7979
|
};
|
|
7893
7980
|
|
|
7981
|
+
// lib/solvers/SchematicTracePipelineSolver/expandChipsToFitPins.ts
|
|
7982
|
+
var expandChipsToFitPins = (problem) => {
|
|
7983
|
+
for (const chip of problem.chips) {
|
|
7984
|
+
const halfWidth = chip.width / 2;
|
|
7985
|
+
const halfHeight = chip.height / 2;
|
|
7986
|
+
let maxDx = 0;
|
|
7987
|
+
let maxDy = 0;
|
|
7988
|
+
for (const pin of chip.pins) {
|
|
7989
|
+
const dx = Math.abs(pin.x - chip.center.x);
|
|
7990
|
+
const dy = Math.abs(pin.y - chip.center.y);
|
|
7991
|
+
if (dx > maxDx) maxDx = dx;
|
|
7992
|
+
if (dy > maxDy) maxDy = dy;
|
|
7993
|
+
}
|
|
7994
|
+
const newHalfWidth = Math.max(halfWidth, maxDx);
|
|
7995
|
+
const newHalfHeight = Math.max(halfHeight, maxDy);
|
|
7996
|
+
if (newHalfWidth > halfWidth || newHalfHeight > halfHeight) {
|
|
7997
|
+
chip.width = newHalfWidth * 2;
|
|
7998
|
+
chip.height = newHalfHeight * 2;
|
|
7999
|
+
for (const pin of chip.pins) {
|
|
8000
|
+
pin._facingDirection = void 0;
|
|
8001
|
+
}
|
|
8002
|
+
}
|
|
8003
|
+
}
|
|
8004
|
+
};
|
|
8005
|
+
|
|
7894
8006
|
// lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
|
|
7895
8007
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
7896
8008
|
return {
|
|
@@ -8002,6 +8114,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
8002
8114
|
...original,
|
|
8003
8115
|
_chipObstacleSpatialIndex: void 0
|
|
8004
8116
|
});
|
|
8117
|
+
expandChipsToFitPins(cloned);
|
|
8005
8118
|
correctPinsInsideChips(cloned);
|
|
8006
8119
|
return cloned;
|
|
8007
8120
|
}
|