@tscircuit/schematic-trace-solver 0.0.182 → 0.0.184
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 +5 -0
- package/dist/index.js +542 -132
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +30 -12
- package/lib/solvers/SameNetJunctionAlignmentSolver/collapseRedundantSharedEndpointStubs.ts +267 -0
- package/lib/solvers/SameNetJunctionAlignmentSolver/collapseSameNetCycles.ts +1 -1
- package/lib/solvers/SameNetJunctionAlignmentSolver/getSharedPin.ts +13 -0
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver.ts +45 -2
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getPinDirection.ts +58 -10
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +166 -57
- package/lib/solvers/TraceCleanupSolver/hasCollisionsWithLabels.ts +108 -3
- package/lib/solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts +62 -15
- package/lib/solvers/TraceCleanupSolver/turnMinimization.ts +5 -0
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +13 -20
- package/tests/bug-reports/bug-report-20260707T020342Z/__snapshots__/bug-report-20260707T020342Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T020342Z/bug-report-20260707T020342Z.test.ts +10 -0
- package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T141025Z/__snapshots__/bug-report-20260707T141025Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T141421Z/__snapshots__/bug-report-20260707T141421Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260708T095725Z/__snapshots__/bug-report-20260708T095725Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260716T144856Z/__snapshots__/bug-report-20260716T144856Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260717T022934Z/__snapshots__/bug-report-20260717T022934Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260717T042845Z/__snapshots__/bug-report-20260717T042845Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260724T175257Z/__snapshots__/bug-report-20260724T175257Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260728T144234Z/__snapshots__/bug-report-20260728T144234Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260728T144234Z/bug-report-20260728T144234Z.test.ts +2 -0
- package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260730T061837Z/bug-report-20260730T061837Z.test.ts +1 -1
- package/tests/bug-reports/bug-report-20260731T052229Z/__snapshots__/bug-report-20260731T052229Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260804T225912Z/__snapshots__/bug-report-20260804T225912Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260815T073240Z/__snapshots__/bug-report-20260815T073240Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260825T045913Z/__snapshots__/bug-report-20260825T045913Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260825T103621Z/__snapshots__/bug-report-20260825T103621Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260901T064117Z/__snapshots__/bug-report-20260901T064117Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260901T134241Z/__snapshots__/bug-report-20260901T134241Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260902T092425Z/__snapshots__/bug-report-20260902T092425Z.snap.svg +2 -2
- package/tests/examples/__snapshots__/example02.snap.svg +2 -2
- package/tests/examples/__snapshots__/example13.snap.svg +2 -2
- package/tests/examples/__snapshots__/example14.snap.svg +2 -2
- package/tests/examples/__snapshots__/example15.snap.svg +2 -2
- package/tests/examples/__snapshots__/example18.snap.svg +2 -2
- package/tests/examples/__snapshots__/example19.snap.svg +2 -2
- package/tests/examples/__snapshots__/example21.snap.svg +2 -2
- package/tests/examples/__snapshots__/example27.snap.svg +2 -2
- package/tests/examples/__snapshots__/example29.snap.svg +2 -2
- package/tests/examples/__snapshots__/example42.snap.svg +2 -2
- package/tests/examples/__snapshots__/example45.snap.svg +2 -2
- package/tests/examples/__snapshots__/example46.snap.svg +2 -2
- package/tests/examples/__snapshots__/example47.snap.svg +2 -2
- package/tests/examples/__snapshots__/example51.snap.svg +2 -2
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +2 -2
- package/tests/repros/__snapshots__/board-15984-same-net-junction.snap.svg +2 -2
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +13 -13
- package/tests/repros/__snapshots__/bugreport-001-gnd-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/netlabel-connector-through-rail-label.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-battery-management-bq24073.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bc107a-common-emitter-routing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bluetooth-controller-ground-decoupling-groups.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-board-589-regulator-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-board-8090-power-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bq24074-battery-charger.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bq40z60-current-sense.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-cc2340r5.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-ground-inline-label-fallback.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-esp12f-section.snap.svg +508 -0
- package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-hdc2080-ground-label-alignment.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-hdc3020-ground-label-alignment.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-hub-usb-sheet.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ina237-current-monitor.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-isolated-rs485-isow7841.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-mouse-switch-ground-unnecessary-jog.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-mspm0l1306-capacitor-symmetry.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-pga300-c6-trace-alignment.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-pga300-redundant-ground-traces.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +26 -26
- package/tests/repros/__snapshots__/repro-power-group-rail-labels.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-powerbank-3v-system-power.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-rectifier-trace-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-rf1-unnecessary-dogleg.snap.svg +5 -5
- package/tests/repros/__snapshots__/repro-rp2040-gamepad-trace-alignment.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-rp2040-usb-cc2-ground-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-smartwatch-power-sheet.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida-01389-hbridge.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida00553-j4-cell-divider.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida010076-j4-ground-bus.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tmp1075-ground-label-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tps61222-trace-intersection.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-trellis-core-gnd-net-label-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-type-c-vbus-led-ground-label.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro130-bq27441-fuel-gauge-trace-through-c1.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +2 -2
- package/tests/repros/assets/repro-esp12f-status-section.input.json +1394 -0
- package/tests/repros/repro-esp12f-section.test.ts +12 -0
- package/tests/solvers/SameNetJunctionAlignmentSolver/collapse-redundant-shared-endpoint-stubs.test.ts +101 -0
package/dist/index.js
CHANGED
|
@@ -111,7 +111,7 @@ var arePinsInDifferentSchematicSections = (inputProblem, p1, p2) => {
|
|
|
111
111
|
};
|
|
112
112
|
|
|
113
113
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getPinDirection.ts
|
|
114
|
-
var
|
|
114
|
+
var getPinDirectionCandidates = (pin, chip, connectedPin) => {
|
|
115
115
|
const { x, y } = pin;
|
|
116
116
|
const { center, width, height } = chip;
|
|
117
117
|
const yPlusEdge = center.y + height / 2;
|
|
@@ -128,17 +128,34 @@ var getPinDirection = (pin, chip) => {
|
|
|
128
128
|
xPlusDistance,
|
|
129
129
|
xMinusDistance
|
|
130
130
|
);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
131
|
+
const primaryDirection = minDistance === yPlusDistance ? "y+" : minDistance === yMinusDistance ? "y-" : minDistance === xPlusDistance ? "x+" : "x-";
|
|
132
|
+
const matchingDirections = [
|
|
133
|
+
{ direction: "y+", distance: yPlusDistance },
|
|
134
|
+
{ direction: "y-", distance: yMinusDistance },
|
|
135
|
+
{ direction: "x+", distance: xPlusDistance },
|
|
136
|
+
{ direction: "x-", distance: xMinusDistance }
|
|
137
|
+
].filter(({ distance: distance7 }) => Math.abs(distance7 - minDistance) <= 1e-9).map(({ direction }) => direction);
|
|
138
|
+
const closestDirections = [
|
|
139
|
+
primaryDirection,
|
|
140
|
+
...matchingDirections.filter((direction) => direction !== primaryDirection)
|
|
141
|
+
];
|
|
142
|
+
if (!connectedPin || closestDirections.length <= 1) {
|
|
143
|
+
return closestDirections;
|
|
136
144
|
}
|
|
137
|
-
|
|
138
|
-
|
|
145
|
+
const xDistance = connectedPin.x - pin.x;
|
|
146
|
+
const yDistance = connectedPin.y - pin.y;
|
|
147
|
+
const directionTowardConnectedPin = Math.abs(xDistance) >= Math.abs(yDistance) ? xDistance >= 0 ? "x+" : "x-" : yDistance >= 0 ? "y+" : "y-";
|
|
148
|
+
if (!closestDirections.includes(directionTowardConnectedPin)) {
|
|
149
|
+
return closestDirections;
|
|
139
150
|
}
|
|
140
|
-
return
|
|
151
|
+
return [
|
|
152
|
+
directionTowardConnectedPin,
|
|
153
|
+
...closestDirections.filter(
|
|
154
|
+
(direction) => direction !== directionTowardConnectedPin
|
|
155
|
+
)
|
|
156
|
+
];
|
|
141
157
|
};
|
|
158
|
+
var getPinDirection = (pin, chip, connectedPin) => getPinDirectionCandidates(pin, chip, connectedPin)[0];
|
|
142
159
|
|
|
143
160
|
// lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem.ts
|
|
144
161
|
var visualizeInputProblem = (inputProblem, opts = {}) => {
|
|
@@ -1353,6 +1370,38 @@ var pinsFaceEachOther = ({
|
|
|
1353
1370
|
}
|
|
1354
1371
|
return yDistance > 0 ? pin1._facingDirection === "y+" && pin2._facingDirection === "y-" : pin1._facingDirection === "y-" && pin2._facingDirection === "y+";
|
|
1355
1372
|
};
|
|
1373
|
+
var getPathLength = (points) => {
|
|
1374
|
+
let length = 0;
|
|
1375
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
1376
|
+
length += Math.abs(points[i + 1].x - points[i].x) + Math.abs(points[i + 1].y - points[i].y);
|
|
1377
|
+
}
|
|
1378
|
+
return length;
|
|
1379
|
+
};
|
|
1380
|
+
var getInitialPathForPins = ({
|
|
1381
|
+
pins,
|
|
1382
|
+
obstacles
|
|
1383
|
+
}) => {
|
|
1384
|
+
const [pin1, pin2] = pins;
|
|
1385
|
+
const directShortPath = calculateDirectShortPath(pin1, pin2);
|
|
1386
|
+
const defaultElbow = calculateElbowForPins({
|
|
1387
|
+
pin1,
|
|
1388
|
+
pin2,
|
|
1389
|
+
overshoot: 0.2
|
|
1390
|
+
});
|
|
1391
|
+
const routingDistance = Math.abs(pin1.x - pin2.x) + Math.abs(pin1.y - pin2.y);
|
|
1392
|
+
const adaptiveElbow = calculateElbowForPins({
|
|
1393
|
+
pin1,
|
|
1394
|
+
pin2,
|
|
1395
|
+
overshoot: Math.min(0.2, Math.max(0.02, routingDistance / 4))
|
|
1396
|
+
});
|
|
1397
|
+
const adaptiveElbowIsShorter = getPathLength(adaptiveElbow) < getPathLength(defaultElbow);
|
|
1398
|
+
const defaultElbowBacktracks = getPathLength(defaultElbow) > routingDistance + 1e-9;
|
|
1399
|
+
const shouldUseAdaptiveElbow = findFirstCollision(adaptiveElbow, obstacles) === null && (pinsFaceEachOther({ pin1, pin2 }) && defaultElbowBacktracks && adaptiveElbowIsShorter || findFirstCollision(defaultElbow, obstacles) !== null);
|
|
1400
|
+
return {
|
|
1401
|
+
path: directShortPath ?? (shouldUseAdaptiveElbow ? adaptiveElbow : defaultElbow),
|
|
1402
|
+
isDirectShortPath: directShortPath !== null
|
|
1403
|
+
};
|
|
1404
|
+
};
|
|
1356
1405
|
var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
1357
1406
|
pins;
|
|
1358
1407
|
connectionPair;
|
|
@@ -1364,9 +1413,12 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1364
1413
|
aabb;
|
|
1365
1414
|
baseElbow;
|
|
1366
1415
|
preferExteriorDetours;
|
|
1416
|
+
reserveNetLabelClearance;
|
|
1367
1417
|
solvedTracePath = null;
|
|
1368
1418
|
queue = [];
|
|
1369
1419
|
visited = /* @__PURE__ */ new Set();
|
|
1420
|
+
inferredPinIndexes = /* @__PURE__ */ new Set();
|
|
1421
|
+
hasAmbiguousPinDirections = false;
|
|
1370
1422
|
constructor(params) {
|
|
1371
1423
|
super();
|
|
1372
1424
|
this.pins = params.pins;
|
|
@@ -1374,14 +1426,9 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1374
1426
|
this.inputProblem = params.inputProblem;
|
|
1375
1427
|
this.chipMap = params.chipMap;
|
|
1376
1428
|
this.preferExteriorDetours = params.preferExteriorDetours ?? true;
|
|
1377
|
-
|
|
1378
|
-
if (!pin._facingDirection) {
|
|
1379
|
-
const chip = this.chipMap[pin.chipId];
|
|
1380
|
-
pin._facingDirection = getPinDirection(pin, chip);
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1429
|
+
this.reserveNetLabelClearance = params.reserveNetLabelClearance ?? true;
|
|
1383
1430
|
this.obstacles = getObstacleRects(this.inputProblem, {
|
|
1384
|
-
textBoxPadding: this.getTextBoxPaddingForConnectionPair()
|
|
1431
|
+
textBoxPadding: this.reserveNetLabelClearance ? this.getTextBoxPaddingForConnectionPair() : void 0
|
|
1385
1432
|
});
|
|
1386
1433
|
this.textObstacles = new Set(this.obstacles.filter(isTextBoxObstacle));
|
|
1387
1434
|
const endpointChipIds = new Set(this.pins.map((pin) => pin.chipId));
|
|
@@ -1390,36 +1437,68 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1390
1437
|
(obstacle) => obstacle.textBox.chipId !== void 0 && endpointChipIds.has(obstacle.textBox.chipId)
|
|
1391
1438
|
)
|
|
1392
1439
|
);
|
|
1393
|
-
const
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
pin1,
|
|
1403
|
-
pin2,
|
|
1404
|
-
overshoot: Math.min(0.2, Math.max(0.02, routingDistance / 4))
|
|
1440
|
+
const directionOptions = this.pins.map((pin, pinIndex) => {
|
|
1441
|
+
if (pin._facingDirection) return [pin._facingDirection];
|
|
1442
|
+
this.inferredPinIndexes.add(pinIndex);
|
|
1443
|
+
const connectedPin = this.pins[pinIndex === 0 ? 1 : 0];
|
|
1444
|
+
return getPinDirectionCandidates(
|
|
1445
|
+
pin,
|
|
1446
|
+
this.chipMap[pin.chipId],
|
|
1447
|
+
connectedPin
|
|
1448
|
+
);
|
|
1405
1449
|
});
|
|
1406
|
-
const
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1450
|
+
const directionPairs = directionOptions[0].flatMap(
|
|
1451
|
+
(firstDirection, firstIndex) => directionOptions[1].map((secondDirection, secondIndex) => ({
|
|
1452
|
+
directions: [firstDirection, secondDirection],
|
|
1453
|
+
preferenceIndex: firstIndex + secondIndex
|
|
1454
|
+
}))
|
|
1455
|
+
);
|
|
1456
|
+
this.hasAmbiguousPinDirections = directionOptions.some(
|
|
1457
|
+
(directions) => directions.length > 1
|
|
1458
|
+
);
|
|
1459
|
+
const rankedDirectionPairs = directionPairs.map(({ directions, preferenceIndex }) => {
|
|
1460
|
+
const candidatePins = this.pins.map((pin, index) => ({
|
|
1461
|
+
...pin,
|
|
1462
|
+
_facingDirection: directions[index]
|
|
1463
|
+
}));
|
|
1464
|
+
const initialPath = getInitialPathForPins({
|
|
1465
|
+
pins: candidatePins,
|
|
1466
|
+
obstacles: this.obstacles
|
|
1467
|
+
});
|
|
1468
|
+
return {
|
|
1469
|
+
directions,
|
|
1470
|
+
baseElbow: initialPath.path,
|
|
1471
|
+
isDirectShortPath: initialPath.isDirectShortPath,
|
|
1472
|
+
preferenceIndex,
|
|
1473
|
+
collisionCount: findFirstCollision(initialPath.path, this.obstacles) === null ? 0 : 1,
|
|
1474
|
+
pathLength: getPathLength(initialPath.path)
|
|
1475
|
+
};
|
|
1476
|
+
}).sort(
|
|
1477
|
+
(first, second) => first.collisionCount - second.collisionCount || first.pathLength - second.pathLength || first.preferenceIndex - second.preferenceIndex
|
|
1478
|
+
);
|
|
1479
|
+
const preferredCandidate = rankedDirectionPairs[0];
|
|
1480
|
+
for (const [pinIndex, pin] of this.pins.entries()) {
|
|
1481
|
+
pin._facingDirection = preferredCandidate.directions[pinIndex];
|
|
1412
1482
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1483
|
+
const [pin1, pin2] = this.pins;
|
|
1484
|
+
this.baseElbow = preferredCandidate.baseElbow;
|
|
1485
|
+
if (preferredCandidate.isDirectShortPath) {
|
|
1486
|
+
this.solvedTracePath = preferredCandidate.baseElbow;
|
|
1415
1487
|
}
|
|
1416
|
-
this.solvedTracePath = directShortPath;
|
|
1417
1488
|
this.aabb = aabbFromPoints(
|
|
1418
1489
|
{ x: pin1.x, y: pin1.y },
|
|
1419
1490
|
{ x: pin2.x, y: pin2.y }
|
|
1420
1491
|
);
|
|
1421
|
-
|
|
1422
|
-
|
|
1492
|
+
for (const candidate of rankedDirectionPairs) {
|
|
1493
|
+
const key = pathKey(candidate.baseElbow);
|
|
1494
|
+
if (this.visited.has(key)) continue;
|
|
1495
|
+
this.visited.add(key);
|
|
1496
|
+
this.queue.push({
|
|
1497
|
+
path: candidate.baseElbow,
|
|
1498
|
+
collisionRects: /* @__PURE__ */ new Set(),
|
|
1499
|
+
directions: candidate.directions
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1423
1502
|
}
|
|
1424
1503
|
getConstructorParams() {
|
|
1425
1504
|
return {
|
|
@@ -1427,7 +1506,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1427
1506
|
pins: this.pins,
|
|
1428
1507
|
connectionPair: this.connectionPair,
|
|
1429
1508
|
inputProblem: this.inputProblem,
|
|
1430
|
-
preferExteriorDetours: this.preferExteriorDetours
|
|
1509
|
+
preferExteriorDetours: this.preferExteriorDetours,
|
|
1510
|
+
reserveNetLabelClearance: this.reserveNetLabelClearance
|
|
1431
1511
|
};
|
|
1432
1512
|
}
|
|
1433
1513
|
getTextBoxPaddingForConnectionPair() {
|
|
@@ -1490,11 +1570,7 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1490
1570
|
return null;
|
|
1491
1571
|
}
|
|
1492
1572
|
pathLength(pts) {
|
|
1493
|
-
|
|
1494
|
-
for (let i = 0; i < pts.length - 1; i++) {
|
|
1495
|
-
sum += Math.abs(pts[i + 1].x - pts[i].x) + Math.abs(pts[i + 1].y - pts[i].y);
|
|
1496
|
-
}
|
|
1497
|
-
return sum;
|
|
1573
|
+
return getPathLength(pts);
|
|
1498
1574
|
}
|
|
1499
1575
|
getPinBandPenalty(path) {
|
|
1500
1576
|
let penalty = 0;
|
|
@@ -1529,7 +1605,7 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1529
1605
|
this.error = "No collision-free path found";
|
|
1530
1606
|
return;
|
|
1531
1607
|
}
|
|
1532
|
-
const { path, collisionRects } = state;
|
|
1608
|
+
const { path, collisionRects, directions } = state;
|
|
1533
1609
|
const [PA, PB] = this.pins;
|
|
1534
1610
|
const collision = findFirstCollision(path, this.obstacles, {
|
|
1535
1611
|
excludeRectsForSegment: (segIndex2) => {
|
|
@@ -1583,7 +1659,15 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1583
1659
|
const last = path[path.length - 1];
|
|
1584
1660
|
const EPS17 = 1e-9;
|
|
1585
1661
|
const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS17 && Math.abs(p.y - q.y) < EPS17;
|
|
1586
|
-
if (samePoint(first, { x: PA.x, y: PA.y }) && samePoint(last, { x: PB.x, y: PB.y })
|
|
1662
|
+
if (samePoint(first, { x: PA.x, y: PA.y }) && samePoint(last, { x: PB.x, y: PB.y }) && (!this.hasAmbiguousPinDirections || pathMatchesPinDirections({
|
|
1663
|
+
path,
|
|
1664
|
+
pin1: { ...PA, _facingDirection: directions[0] },
|
|
1665
|
+
pin2: { ...PB, _facingDirection: directions[1] }
|
|
1666
|
+
}))) {
|
|
1667
|
+
for (const pinIndex of this.inferredPinIndexes) {
|
|
1668
|
+
const direction = pinIndex === 0 ? segmentDirection(path[0], path[1]) : segmentDirection(path.at(-1), path.at(-2));
|
|
1669
|
+
if (direction) this.pins[pinIndex]._facingDirection = direction;
|
|
1670
|
+
}
|
|
1587
1671
|
this.solvedTracePath = path;
|
|
1588
1672
|
this.solved = true;
|
|
1589
1673
|
}
|
|
@@ -1616,7 +1700,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1616
1700
|
nextCollisionRects.add(rect);
|
|
1617
1701
|
this.queue.push({
|
|
1618
1702
|
path: detour,
|
|
1619
|
-
collisionRects: nextCollisionRects
|
|
1703
|
+
collisionRects: nextCollisionRects,
|
|
1704
|
+
directions
|
|
1620
1705
|
});
|
|
1621
1706
|
}
|
|
1622
1707
|
return;
|
|
@@ -1725,7 +1810,11 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1725
1810
|
(a2, b2) => a2.length - b2.length || a2.pinBandPenalty - b2.pinBandPenalty
|
|
1726
1811
|
);
|
|
1727
1812
|
for (const st of newStates) {
|
|
1728
|
-
this.queue.push({
|
|
1813
|
+
this.queue.push({
|
|
1814
|
+
path: st.path,
|
|
1815
|
+
collisionRects: st.collisionRects,
|
|
1816
|
+
directions
|
|
1817
|
+
});
|
|
1729
1818
|
}
|
|
1730
1819
|
}
|
|
1731
1820
|
visualize() {
|
|
@@ -1789,6 +1878,7 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
1789
1878
|
queuedConnectionPairs;
|
|
1790
1879
|
chipMap;
|
|
1791
1880
|
currentConnectionPair = null;
|
|
1881
|
+
retryingWithoutNetLabelClearance = false;
|
|
1792
1882
|
solvedTracePaths = [];
|
|
1793
1883
|
failedConnectionPairs = [];
|
|
1794
1884
|
constructor(params) {
|
|
@@ -1813,6 +1903,7 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
1813
1903
|
if (this.activeSubSolver?.solved) {
|
|
1814
1904
|
this.solvedTracePaths.push({
|
|
1815
1905
|
...this.currentConnectionPair,
|
|
1906
|
+
pins: this.activeSubSolver.pins,
|
|
1816
1907
|
tracePath: this.activeSubSolver.solvedTracePath,
|
|
1817
1908
|
mspConnectionPairIds: [this.currentConnectionPair.mspPairId],
|
|
1818
1909
|
pinIds: [
|
|
@@ -1822,8 +1913,28 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
1822
1913
|
});
|
|
1823
1914
|
this.activeSubSolver = null;
|
|
1824
1915
|
this.currentConnectionPair = null;
|
|
1916
|
+
this.retryingWithoutNetLabelClearance = false;
|
|
1825
1917
|
}
|
|
1826
1918
|
if (this.activeSubSolver?.failed) {
|
|
1919
|
+
if (this.currentConnectionPair && !this.retryingWithoutNetLabelClearance && this.activeSubSolver.hasAmbiguousPinDirections) {
|
|
1920
|
+
const connectionPair2 = this.currentConnectionPair;
|
|
1921
|
+
this.retryingWithoutNetLabelClearance = true;
|
|
1922
|
+
this.activeSubSolver = new SchematicTraceSingleLineSolver2({
|
|
1923
|
+
inputProblem: this.inputProblem,
|
|
1924
|
+
pins: connectionPair2.pins.map((pin) => ({
|
|
1925
|
+
...pin
|
|
1926
|
+
})),
|
|
1927
|
+
connectionPair: connectionPair2,
|
|
1928
|
+
chipMap: this.chipMap,
|
|
1929
|
+
preferExteriorDetours: shouldPreferExteriorDetours({
|
|
1930
|
+
connectionPair: connectionPair2,
|
|
1931
|
+
allConnectionPairs: this.mspConnectionPairs,
|
|
1932
|
+
inputProblem: this.inputProblem
|
|
1933
|
+
}),
|
|
1934
|
+
reserveNetLabelClearance: false
|
|
1935
|
+
});
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1827
1938
|
if (this.currentConnectionPair) {
|
|
1828
1939
|
this.failedConnectionPairs.push({
|
|
1829
1940
|
...this.currentConnectionPair,
|
|
@@ -1832,6 +1943,7 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
1832
1943
|
}
|
|
1833
1944
|
this.activeSubSolver = null;
|
|
1834
1945
|
this.currentConnectionPair = null;
|
|
1946
|
+
this.retryingWithoutNetLabelClearance = false;
|
|
1835
1947
|
}
|
|
1836
1948
|
if (this.activeSubSolver) {
|
|
1837
1949
|
this.activeSubSolver.step();
|
|
@@ -1843,7 +1955,15 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
1843
1955
|
return;
|
|
1844
1956
|
}
|
|
1845
1957
|
this.currentConnectionPair = connectionPair;
|
|
1846
|
-
|
|
1958
|
+
this.retryingWithoutNetLabelClearance = false;
|
|
1959
|
+
const hasAmbiguousCornerPin = connectionPair.pins.some((pin) => {
|
|
1960
|
+
if (pin._facingDirection) return false;
|
|
1961
|
+
const chip = this.chipMap[pin.chipId];
|
|
1962
|
+
return chip && getPinDirectionCandidates(pin, chip).length > 1;
|
|
1963
|
+
});
|
|
1964
|
+
const pins = hasAmbiguousCornerPin ? connectionPair.pins.map((pin) => ({
|
|
1965
|
+
...pin
|
|
1966
|
+
})) : connectionPair.pins;
|
|
1847
1967
|
this.activeSubSolver = new SchematicTraceSingleLineSolver2({
|
|
1848
1968
|
inputProblem: this.inputProblem,
|
|
1849
1969
|
pins,
|
|
@@ -4254,7 +4374,7 @@ var doesPathOverlapTraceStrokes = (path, traces) => {
|
|
|
4254
4374
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts
|
|
4255
4375
|
var MAX_TRIES = 5;
|
|
4256
4376
|
var PATH_LENGTH_EPSILON = 1e-9;
|
|
4257
|
-
var
|
|
4377
|
+
var getPathLength2 = (points) => {
|
|
4258
4378
|
let length = 0;
|
|
4259
4379
|
for (let pointIndex = 0; pointIndex < points.length - 1; pointIndex++) {
|
|
4260
4380
|
const point = points[pointIndex];
|
|
@@ -4304,7 +4424,7 @@ var SingleOverlapSolver = class extends BaseSolver {
|
|
|
4304
4424
|
);
|
|
4305
4425
|
}
|
|
4306
4426
|
this.queuedCandidatePaths = [...candidateByPath.values()].sort((a, b) => {
|
|
4307
|
-
const pathLengthDifference =
|
|
4427
|
+
const pathLengthDifference = getPathLength2(a) - getPathLength2(b);
|
|
4308
4428
|
if (Math.abs(pathLengthDifference) >= PATH_LENGTH_EPSILON) {
|
|
4309
4429
|
return pathLengthDifference;
|
|
4310
4430
|
}
|
|
@@ -5238,12 +5358,62 @@ var tryConnectPoints = (start, end) => {
|
|
|
5238
5358
|
};
|
|
5239
5359
|
|
|
5240
5360
|
// lib/solvers/TraceCleanupSolver/hasCollisionsWithLabels.ts
|
|
5241
|
-
var
|
|
5361
|
+
var EPSILON = 1e-9;
|
|
5362
|
+
var rangesMeetWithoutOverlap = (firstMin, firstMax, secondMin, secondMax) => firstMax >= secondMin - EPSILON && secondMax >= firstMin - EPSILON && Math.min(firstMax, secondMax) - Math.max(firstMin, secondMin) <= EPSILON;
|
|
5363
|
+
var pointsEqual = (first, second) => Math.abs(first.x - second.x) <= EPSILON && Math.abs(first.y - second.y) <= EPSILON;
|
|
5364
|
+
var continuesExistingBoundarySegment = ({
|
|
5365
|
+
start,
|
|
5366
|
+
end,
|
|
5367
|
+
label,
|
|
5368
|
+
originalPath
|
|
5369
|
+
}) => {
|
|
5370
|
+
const isVertical6 = Math.abs(start.x - end.x) <= EPSILON;
|
|
5371
|
+
const isHorizontal5 = Math.abs(start.y - end.y) <= EPSILON;
|
|
5372
|
+
const isOnBoundary = isVertical6 ? Math.abs(start.x - label.minX) <= EPSILON || Math.abs(start.x - label.maxX) <= EPSILON : isHorizontal5 ? Math.abs(start.y - label.minY) <= EPSILON || Math.abs(start.y - label.maxY) <= EPSILON : false;
|
|
5373
|
+
if (!isOnBoundary) return false;
|
|
5374
|
+
for (let i = 0; i < originalPath.length - 1; i++) {
|
|
5375
|
+
const isEndpointSegment = i === 0 || i === originalPath.length - 2;
|
|
5376
|
+
if (!isEndpointSegment) continue;
|
|
5377
|
+
const originalStart = originalPath[i];
|
|
5378
|
+
const originalEnd = originalPath[i + 1];
|
|
5379
|
+
const innerEndpoint = i === 0 ? originalEnd : originalStart;
|
|
5380
|
+
if (!pointsEqual(start, innerEndpoint) && !pointsEqual(end, innerEndpoint)) {
|
|
5381
|
+
continue;
|
|
5382
|
+
}
|
|
5383
|
+
if (!segmentIntersectsRect(originalStart, originalEnd, label)) continue;
|
|
5384
|
+
if (isVertical6 && Math.abs(originalStart.x - originalEnd.x) <= EPSILON && Math.abs(originalStart.x - start.x) <= EPSILON && rangesMeetWithoutOverlap(
|
|
5385
|
+
Math.min(start.y, end.y),
|
|
5386
|
+
Math.max(start.y, end.y),
|
|
5387
|
+
Math.min(originalStart.y, originalEnd.y),
|
|
5388
|
+
Math.max(originalStart.y, originalEnd.y)
|
|
5389
|
+
)) {
|
|
5390
|
+
return true;
|
|
5391
|
+
}
|
|
5392
|
+
if (isHorizontal5 && Math.abs(originalStart.y - originalEnd.y) <= EPSILON && Math.abs(originalStart.y - start.y) <= EPSILON && rangesMeetWithoutOverlap(
|
|
5393
|
+
Math.min(start.x, end.x),
|
|
5394
|
+
Math.max(start.x, end.x),
|
|
5395
|
+
Math.min(originalStart.x, originalEnd.x),
|
|
5396
|
+
Math.max(originalStart.x, originalEnd.x)
|
|
5397
|
+
)) {
|
|
5398
|
+
return true;
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5401
|
+
return false;
|
|
5402
|
+
};
|
|
5403
|
+
var hasCollisionsWithLabels = (pathSegments, labels, options = {}) => {
|
|
5242
5404
|
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
5243
5405
|
const p1 = pathSegments[i];
|
|
5244
5406
|
const p2 = pathSegments[i + 1];
|
|
5245
5407
|
for (const label of labels) {
|
|
5246
5408
|
if (segmentIntersectsRect(p1, p2, label)) {
|
|
5409
|
+
if (options.originalPath && continuesExistingBoundarySegment({
|
|
5410
|
+
start: p1,
|
|
5411
|
+
end: p2,
|
|
5412
|
+
label,
|
|
5413
|
+
originalPath: options.originalPath
|
|
5414
|
+
})) {
|
|
5415
|
+
continue;
|
|
5416
|
+
}
|
|
5247
5417
|
return true;
|
|
5248
5418
|
}
|
|
5249
5419
|
}
|
|
@@ -5300,7 +5470,8 @@ var minimizeTurns = ({
|
|
|
5300
5470
|
path,
|
|
5301
5471
|
obstacles,
|
|
5302
5472
|
labelBounds,
|
|
5303
|
-
originalPath
|
|
5473
|
+
originalPath,
|
|
5474
|
+
allowLabelBoundaryExtension = false
|
|
5304
5475
|
}) => {
|
|
5305
5476
|
if (path.length <= 2) {
|
|
5306
5477
|
return path;
|
|
@@ -5336,7 +5507,8 @@ var minimizeTurns = ({
|
|
|
5336
5507
|
const collidesWithObstacles = hasCollisions(connection, obstacles);
|
|
5337
5508
|
const collidesWithLabels = hasCollisionsWithLabels(
|
|
5338
5509
|
connection,
|
|
5339
|
-
labelBounds
|
|
5510
|
+
labelBounds,
|
|
5511
|
+
allowLabelBoundaryExtension ? { originalPath } : {}
|
|
5340
5512
|
);
|
|
5341
5513
|
if (!collidesWithObstacles && !collidesWithLabels) {
|
|
5342
5514
|
const newTurns = countTurns(testPath);
|
|
@@ -5385,7 +5557,8 @@ var minimizeTurns = ({
|
|
|
5385
5557
|
);
|
|
5386
5558
|
const collidesWithLabels = hasCollisionsWithLabels(
|
|
5387
5559
|
connectionSegments,
|
|
5388
|
-
labelBounds
|
|
5560
|
+
labelBounds,
|
|
5561
|
+
allowLabelBoundaryExtension ? { originalPath } : {}
|
|
5389
5562
|
);
|
|
5390
5563
|
if (!collidesWithObstacles && !collidesWithLabels) {
|
|
5391
5564
|
const newTurns = countTurns(testPath);
|
|
@@ -5420,7 +5593,8 @@ var minimizeTurns = ({
|
|
|
5420
5593
|
const collidesWithObstacles = hasCollisions([p1, p3], obstacles);
|
|
5421
5594
|
const collidesWithLabels = hasCollisionsWithLabels(
|
|
5422
5595
|
[p1, p3],
|
|
5423
|
-
labelBounds
|
|
5596
|
+
labelBounds,
|
|
5597
|
+
allowLabelBoundaryExtension ? { originalPath } : {}
|
|
5424
5598
|
);
|
|
5425
5599
|
if (!collidesWithObstacles && !collidesWithLabels) {
|
|
5426
5600
|
optimizedPath = testPath;
|
|
@@ -5448,7 +5622,7 @@ var getRailOrientation = (a, b) => {
|
|
|
5448
5622
|
return null;
|
|
5449
5623
|
};
|
|
5450
5624
|
var rangesTouchOrOverlap = (a, b) => Math.min(a.maxAlong, b.maxAlong) - Math.max(a.minAlong, b.minAlong) >= -RAIL_ALIGNMENT_EPSILON;
|
|
5451
|
-
var
|
|
5625
|
+
var pointsEqual2 = (a, b) => nearlyEqual(a.x, b.x) && nearlyEqual(a.y, b.y);
|
|
5452
5626
|
var getDistinctCoordinates = (coordinates) => {
|
|
5453
5627
|
const distinct = [];
|
|
5454
5628
|
for (const coordinate of coordinates) {
|
|
@@ -5570,6 +5744,19 @@ var shortenExcessiveLabelPaddingDetour = ({
|
|
|
5570
5744
|
};
|
|
5571
5745
|
|
|
5572
5746
|
// lib/solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts
|
|
5747
|
+
var PATH_LENGTH_EPSILON2 = 1e-9;
|
|
5748
|
+
var getPathLength3 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
|
|
5749
|
+
const previousPoint = path[pointIndex];
|
|
5750
|
+
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
5751
|
+
}, 0);
|
|
5752
|
+
var chooseLengthPreservingBoundaryRoute = ({
|
|
5753
|
+
strictPath,
|
|
5754
|
+
boundaryPath
|
|
5755
|
+
}) => {
|
|
5756
|
+
const doesNotAddTurns = countTurns(boundaryPath) <= countTurns(strictPath);
|
|
5757
|
+
const preservesLength = Math.abs(getPathLength3(boundaryPath) - getPathLength3(strictPath)) <= PATH_LENGTH_EPSILON2;
|
|
5758
|
+
return doesNotAddTurns && preservesLength ? boundaryPath : strictPath;
|
|
5759
|
+
};
|
|
5573
5760
|
var minimizeTurnsWithFilteredLabels = ({
|
|
5574
5761
|
targetMspConnectionPairId,
|
|
5575
5762
|
traces,
|
|
@@ -5632,21 +5819,33 @@ var minimizeTurnsWithFilteredLabels = ({
|
|
|
5632
5819
|
minY: nl.center.y - nl.height / 2 - paddingBuffer,
|
|
5633
5820
|
maxY: nl.center.y + nl.height / 2 + paddingBuffer
|
|
5634
5821
|
}));
|
|
5635
|
-
const
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5822
|
+
const minimizeForObstacles = (obstacles) => {
|
|
5823
|
+
const strictPath2 = minimizeTurns({
|
|
5824
|
+
path: originalPath,
|
|
5825
|
+
obstacles,
|
|
5826
|
+
labelBounds,
|
|
5827
|
+
originalPath
|
|
5828
|
+
});
|
|
5829
|
+
const boundaryPath = minimizeTurns({
|
|
5830
|
+
path: originalPath,
|
|
5831
|
+
obstacles,
|
|
5832
|
+
labelBounds,
|
|
5833
|
+
originalPath,
|
|
5834
|
+
allowLabelBoundaryExtension: true
|
|
5835
|
+
});
|
|
5836
|
+
return chooseLengthPreservingBoundaryRoute({
|
|
5837
|
+
strictPath: strictPath2,
|
|
5838
|
+
boundaryPath
|
|
5839
|
+
});
|
|
5840
|
+
};
|
|
5841
|
+
const strictPath = minimizeForObstacles([
|
|
5842
|
+
...staticObstacles,
|
|
5843
|
+
...getTraceObstacles2(otherTraces)
|
|
5844
|
+
]);
|
|
5845
|
+
const relaxedPath = minimizeForObstacles([
|
|
5846
|
+
...staticObstacles,
|
|
5847
|
+
...getTraceObstacles2(relaxedObstacleTraces)
|
|
5848
|
+
]);
|
|
5650
5849
|
const sameNetTraces = otherTraces.filter(
|
|
5651
5850
|
(trace) => trace.globalConnNetId === targetTrace.globalConnNetId
|
|
5652
5851
|
);
|
|
@@ -6038,7 +6237,7 @@ var segmentRunsAlongRectBoundary = (start, end, rect) => {
|
|
|
6038
6237
|
|
|
6039
6238
|
// lib/solvers/Example28Solver/geometry.ts
|
|
6040
6239
|
var getPathKey = (path) => path.map((point) => `${point.x},${point.y}`).join(";");
|
|
6041
|
-
var
|
|
6240
|
+
var getPathLength4 = (path) => {
|
|
6042
6241
|
let length = 0;
|
|
6043
6242
|
for (let i = 0; i < path.length - 1; i++) {
|
|
6044
6243
|
length += Math.abs(path[i + 1].x - path[i].x) + Math.abs(path[i + 1].y - path[i].y);
|
|
@@ -6192,7 +6391,7 @@ var getTraceGeometryMetrics = (traces, allTraces) => ({
|
|
|
6192
6391
|
),
|
|
6193
6392
|
visibleLength: getVisibleTraceLength(traces),
|
|
6194
6393
|
pathLength: traces.reduce(
|
|
6195
|
-
(sum, trace) => sum +
|
|
6394
|
+
(sum, trace) => sum + getPathLength4(trace.tracePath),
|
|
6196
6395
|
0
|
|
6197
6396
|
),
|
|
6198
6397
|
otherNetCrossings: countOtherNetCrossings(traces, allTraces)
|
|
@@ -6214,7 +6413,7 @@ var isReadabilityImprovement = (candidate, baseline) => candidate.turnCount <= b
|
|
|
6214
6413
|
|
|
6215
6414
|
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/evaluateRailGroup.ts
|
|
6216
6415
|
var tracePathChanged = (original, candidate) => original.tracePath.length !== candidate.tracePath.length || candidate.tracePath.some(
|
|
6217
|
-
(point, index) => !
|
|
6416
|
+
(point, index) => !pointsEqual2(point, original.tracePath[index])
|
|
6218
6417
|
);
|
|
6219
6418
|
var evaluateRailGroup = ({
|
|
6220
6419
|
group,
|
|
@@ -7165,7 +7364,7 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
7165
7364
|
candidate.traceId
|
|
7166
7365
|
).isColliding && (crossing.isInitialBundleCrossing || !candidate.collision.isColliding)
|
|
7167
7366
|
).sort(
|
|
7168
|
-
(first, second) => Number(first.collision.isColliding) - Number(second.collision.isColliding) ||
|
|
7367
|
+
(first, second) => Number(first.collision.isColliding) - Number(second.collision.isColliding) || getPathLength4(first.path) - getPathLength4(second.path)
|
|
7169
7368
|
);
|
|
7170
7369
|
const bestCandidate = validCandidates[0];
|
|
7171
7370
|
if (!bestCandidate) return false;
|
|
@@ -7505,7 +7704,7 @@ var rerouteGeneratedNetLabelConnectorCrossings = ({
|
|
|
7505
7704
|
chipBounds: [],
|
|
7506
7705
|
clearance
|
|
7507
7706
|
}).filter(
|
|
7508
|
-
(candidate) =>
|
|
7707
|
+
(candidate) => getPathLength4(candidate.path) <= getPathLength4(trace.tracePath) + EPS12 && countTurns(candidate.path) <= countTurns(trace.tracePath) + 2 && !isPathCollidingWithObstacles(
|
|
7509
7708
|
candidate.path,
|
|
7510
7709
|
componentAndTextObstacles
|
|
7511
7710
|
) && !hasCollisionsWithLabels(candidate.path, foreignLabelBounds) && !isPathColliding(candidate.path, foreignTraces, trace.mspPairId).isColliding && !doesPathCoincideWithTraces(candidate.path, foreignTraces)
|
|
@@ -7515,7 +7714,7 @@ var rerouteGeneratedNetLabelConnectorCrossings = ({
|
|
|
7515
7714
|
}));
|
|
7516
7715
|
});
|
|
7517
7716
|
candidates.sort((first, second) => {
|
|
7518
|
-
const lengthDifference =
|
|
7717
|
+
const lengthDifference = getPathLength4(first.path) - getPathLength4(second.path);
|
|
7519
7718
|
return Math.abs(lengthDifference) > EPS12 ? lengthDifference : countTurns(first.path) - countTurns(second.path);
|
|
7520
7719
|
});
|
|
7521
7720
|
const bestCandidate = candidates[0];
|
|
@@ -7715,7 +7914,7 @@ var extendVerticalTracePathAtInteriorPoint = ({
|
|
|
7715
7914
|
extensionEndPoint
|
|
7716
7915
|
}) => {
|
|
7717
7916
|
const sourceIndex = tracePath.findIndex(
|
|
7718
|
-
(point) =>
|
|
7917
|
+
(point) => pointsEqual2(point, sourcePoint)
|
|
7719
7918
|
);
|
|
7720
7919
|
if (sourceIndex <= 0 || sourceIndex >= tracePath.length - 1) return null;
|
|
7721
7920
|
const extensionDirectionY = extensionEndPoint.y - sourcePoint.y;
|
|
@@ -8294,7 +8493,7 @@ var scoreTracePath = ({
|
|
|
8294
8493
|
labelHugDistance: getLabelHugDistance(tracePath, obstacleLabel),
|
|
8295
8494
|
traceIntersections: countTraceIntersections(candidateTrace, outputTraces),
|
|
8296
8495
|
chipBoundaryOverlap: getChipBoundaryOverlap(tracePath, chipObstacles),
|
|
8297
|
-
pathLength:
|
|
8496
|
+
pathLength: getPathLength4(tracePath)
|
|
8298
8497
|
};
|
|
8299
8498
|
};
|
|
8300
8499
|
var countTraceIntersections = (trace, outputTraces) => {
|
|
@@ -8758,7 +8957,7 @@ var getConnectorTracePath = (source, target, orientation) => simplifyOrthogonalP
|
|
|
8758
8957
|
);
|
|
8759
8958
|
var simplifyOrthogonalPath = (path) => {
|
|
8760
8959
|
const deduped = path.filter(
|
|
8761
|
-
(point, index) => index === 0 || !
|
|
8960
|
+
(point, index) => index === 0 || !pointsEqual3(point, path[index - 1])
|
|
8762
8961
|
);
|
|
8763
8962
|
if (deduped.length < 3) return deduped;
|
|
8764
8963
|
const simplified = [deduped[0]];
|
|
@@ -8774,7 +8973,7 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
8774
8973
|
simplified.push(deduped[deduped.length - 1]);
|
|
8775
8974
|
return simplified;
|
|
8776
8975
|
};
|
|
8777
|
-
var
|
|
8976
|
+
var pointsEqual3 = (a, b) => sameX2(a, b) && sameY2(a, b);
|
|
8778
8977
|
var sameX2 = (a, b) => Math.abs(a.x - b.x) <= EPS13;
|
|
8779
8978
|
var sameY2 = (a, b) => Math.abs(a.y - b.y) <= EPS13;
|
|
8780
8979
|
var getMaxSearchDistance = (inputProblem) => {
|
|
@@ -12476,7 +12675,7 @@ var removeConsecutiveDuplicatePoints = (path) => {
|
|
|
12476
12675
|
}
|
|
12477
12676
|
return filteredPath;
|
|
12478
12677
|
};
|
|
12479
|
-
var
|
|
12678
|
+
var getPathLength5 = (path) => {
|
|
12480
12679
|
let pathLength = 0;
|
|
12481
12680
|
for (let pointIndex = 0; pointIndex < path.length - 1; pointIndex++) {
|
|
12482
12681
|
const startPoint = path[pointIndex];
|
|
@@ -12560,7 +12759,7 @@ var getPerimeterCandidates = ({
|
|
|
12560
12759
|
);
|
|
12561
12760
|
}
|
|
12562
12761
|
return candidates.sort(
|
|
12563
|
-
(firstPath, secondPath) =>
|
|
12762
|
+
(firstPath, secondPath) => getPathLength5(firstPath) - getPathLength5(secondPath)
|
|
12564
12763
|
);
|
|
12565
12764
|
};
|
|
12566
12765
|
var getSegmentMidpoint = (startPoint, endPoint) => {
|
|
@@ -12665,7 +12864,7 @@ var getJunctionCandidates = ({
|
|
|
12665
12864
|
}
|
|
12666
12865
|
}
|
|
12667
12866
|
return candidates.sort(
|
|
12668
|
-
(firstPath, secondPath) =>
|
|
12867
|
+
(firstPath, secondPath) => getPathLength5(firstPath) - getPathLength5(secondPath)
|
|
12669
12868
|
);
|
|
12670
12869
|
};
|
|
12671
12870
|
var pathCollidesWithObstacles = ({
|
|
@@ -13031,24 +13230,228 @@ var findNearestSharedPinExitRail = ({
|
|
|
13031
13230
|
return nearestRail;
|
|
13032
13231
|
};
|
|
13033
13232
|
|
|
13233
|
+
// lib/solvers/SameNetJunctionAlignmentSolver/getSharedPin.ts
|
|
13234
|
+
var getSharedPin = ({
|
|
13235
|
+
donorTrace,
|
|
13236
|
+
branchTrace
|
|
13237
|
+
}) => {
|
|
13238
|
+
const branchPinIds = new Set(branchTrace.pins.map((pin) => pin.pinId));
|
|
13239
|
+
return donorTrace.pins.find((pin) => branchPinIds.has(pin.pinId)) ?? null;
|
|
13240
|
+
};
|
|
13241
|
+
|
|
13242
|
+
// lib/solvers/SameNetJunctionAlignmentSolver/collapseRedundantSharedEndpointStubs.ts
|
|
13243
|
+
var getSegmentAxis3 = (start, end) => {
|
|
13244
|
+
if (nearlyEqual(start.x, end.x)) return "y";
|
|
13245
|
+
if (nearlyEqual(start.y, end.y)) return "x";
|
|
13246
|
+
return null;
|
|
13247
|
+
};
|
|
13248
|
+
var getPathFromSharedPin = ({
|
|
13249
|
+
trace,
|
|
13250
|
+
sharedPinId
|
|
13251
|
+
}) => {
|
|
13252
|
+
const tracePath = simplifyPath(trace.tracePath);
|
|
13253
|
+
if (trace.pins[0]?.pinId === sharedPinId) return tracePath;
|
|
13254
|
+
return tracePath.reverse();
|
|
13255
|
+
};
|
|
13256
|
+
var traceCanLoseSharedPrefix = ({
|
|
13257
|
+
trace,
|
|
13258
|
+
sharedPrefix,
|
|
13259
|
+
netLabelPlacements
|
|
13260
|
+
}) => {
|
|
13261
|
+
return !netLabelPlacements.some(
|
|
13262
|
+
(label) => label.mspConnectionPairIds.includes(trace.mspPairId) && tracePathContainsPoint(sharedPrefix, label.anchorPoint)
|
|
13263
|
+
);
|
|
13264
|
+
};
|
|
13265
|
+
var getTraceWithoutSharedPrefix = ({
|
|
13266
|
+
trace,
|
|
13267
|
+
pathFromSharedPin,
|
|
13268
|
+
sharedPinId,
|
|
13269
|
+
branchPoint
|
|
13270
|
+
}) => {
|
|
13271
|
+
const branchSegmentIndex = pathFromSharedPin.findIndex((point, index) => {
|
|
13272
|
+
const nextPoint = pathFromSharedPin[index + 1];
|
|
13273
|
+
if (!nextPoint) return false;
|
|
13274
|
+
return tracePathContainsPoint([point, nextPoint], branchPoint);
|
|
13275
|
+
});
|
|
13276
|
+
if (branchSegmentIndex < 0) return null;
|
|
13277
|
+
const pathFromJunction = simplifyPath([
|
|
13278
|
+
branchPoint,
|
|
13279
|
+
...pathFromSharedPin.slice(branchSegmentIndex + 1)
|
|
13280
|
+
]);
|
|
13281
|
+
let tracePath = pathFromJunction;
|
|
13282
|
+
if (trace.pins[0]?.pinId !== sharedPinId) {
|
|
13283
|
+
tracePath = pathFromJunction.reverse();
|
|
13284
|
+
}
|
|
13285
|
+
return { ...trace, tracePath };
|
|
13286
|
+
};
|
|
13287
|
+
var collapseRedundantSharedEndpointStubs = ({
|
|
13288
|
+
traces,
|
|
13289
|
+
netLabelPlacements,
|
|
13290
|
+
netLabelConnectorTraceIds,
|
|
13291
|
+
multiPinNetPinIds
|
|
13292
|
+
}) => {
|
|
13293
|
+
const outputTraces = [...traces];
|
|
13294
|
+
for (let firstIndex = 0; firstIndex < outputTraces.length; firstIndex++) {
|
|
13295
|
+
const firstTrace = outputTraces[firstIndex];
|
|
13296
|
+
if (netLabelConnectorTraceIds.has(firstTrace.mspPairId)) continue;
|
|
13297
|
+
for (let secondIndex = firstIndex + 1; secondIndex < outputTraces.length; secondIndex++) {
|
|
13298
|
+
const secondTrace = outputTraces[secondIndex];
|
|
13299
|
+
if (netLabelConnectorTraceIds.has(secondTrace.mspPairId) || firstTrace.globalConnNetId !== secondTrace.globalConnNetId) {
|
|
13300
|
+
continue;
|
|
13301
|
+
}
|
|
13302
|
+
const sharedPin = getSharedPin({
|
|
13303
|
+
donorTrace: firstTrace,
|
|
13304
|
+
branchTrace: secondTrace
|
|
13305
|
+
});
|
|
13306
|
+
if (!sharedPin || !multiPinNetPinIds.has(sharedPin.pinId)) continue;
|
|
13307
|
+
const firstPath = getPathFromSharedPin({
|
|
13308
|
+
trace: firstTrace,
|
|
13309
|
+
sharedPinId: sharedPin.pinId
|
|
13310
|
+
});
|
|
13311
|
+
const secondPath = getPathFromSharedPin({
|
|
13312
|
+
trace: secondTrace,
|
|
13313
|
+
sharedPinId: sharedPin.pinId
|
|
13314
|
+
});
|
|
13315
|
+
if (firstPath.length < 2 || secondPath.length < 2) continue;
|
|
13316
|
+
const departureAxis = getSegmentAxis3(firstPath[0], firstPath[1]);
|
|
13317
|
+
const secondDepartureAxis = getSegmentAxis3(secondPath[0], secondPath[1]);
|
|
13318
|
+
if (!departureAxis || departureAxis !== secondDepartureAxis) continue;
|
|
13319
|
+
const firstDepartureDirection = firstPath[1][departureAxis] - firstPath[0][departureAxis];
|
|
13320
|
+
const secondDepartureDirection = secondPath[1][departureAxis] - secondPath[0][departureAxis];
|
|
13321
|
+
if (!pointsEqual2(firstPath[1], secondPath[1]) && Math.sign(firstDepartureDirection) === Math.sign(secondDepartureDirection)) {
|
|
13322
|
+
let traceIndexToCollapse2 = secondIndex;
|
|
13323
|
+
let traceToCollapse2 = secondTrace;
|
|
13324
|
+
let pathToCollapse2 = secondPath;
|
|
13325
|
+
if (Math.abs(firstDepartureDirection) < Math.abs(secondDepartureDirection)) {
|
|
13326
|
+
traceIndexToCollapse2 = firstIndex;
|
|
13327
|
+
traceToCollapse2 = firstTrace;
|
|
13328
|
+
pathToCollapse2 = firstPath;
|
|
13329
|
+
}
|
|
13330
|
+
const branchPoint2 = pathToCollapse2[1];
|
|
13331
|
+
if (!traceCanLoseSharedPrefix({
|
|
13332
|
+
trace: traceToCollapse2,
|
|
13333
|
+
sharedPrefix: [pathToCollapse2[0], branchPoint2],
|
|
13334
|
+
netLabelPlacements
|
|
13335
|
+
})) {
|
|
13336
|
+
if (traceIndexToCollapse2 === firstIndex) {
|
|
13337
|
+
traceIndexToCollapse2 = secondIndex;
|
|
13338
|
+
traceToCollapse2 = secondTrace;
|
|
13339
|
+
pathToCollapse2 = secondPath;
|
|
13340
|
+
} else {
|
|
13341
|
+
traceIndexToCollapse2 = firstIndex;
|
|
13342
|
+
traceToCollapse2 = firstTrace;
|
|
13343
|
+
pathToCollapse2 = firstPath;
|
|
13344
|
+
}
|
|
13345
|
+
}
|
|
13346
|
+
if (!traceCanLoseSharedPrefix({
|
|
13347
|
+
trace: traceToCollapse2,
|
|
13348
|
+
sharedPrefix: [pathToCollapse2[0], branchPoint2],
|
|
13349
|
+
netLabelPlacements
|
|
13350
|
+
})) {
|
|
13351
|
+
continue;
|
|
13352
|
+
}
|
|
13353
|
+
const collapsedTrace2 = getTraceWithoutSharedPrefix({
|
|
13354
|
+
trace: traceToCollapse2,
|
|
13355
|
+
pathFromSharedPin: pathToCollapse2,
|
|
13356
|
+
sharedPinId: sharedPin.pinId,
|
|
13357
|
+
branchPoint: branchPoint2
|
|
13358
|
+
});
|
|
13359
|
+
if (!collapsedTrace2) continue;
|
|
13360
|
+
outputTraces[traceIndexToCollapse2] = collapsedTrace2;
|
|
13361
|
+
break;
|
|
13362
|
+
}
|
|
13363
|
+
if (firstPath.length < 3 || secondPath.length < 3) continue;
|
|
13364
|
+
if (!pointsEqual2(firstPath[1], secondPath[1])) continue;
|
|
13365
|
+
const railAxis = getSegmentAxis3(firstPath[1], firstPath[2]);
|
|
13366
|
+
const secondRailAxis = getSegmentAxis3(secondPath[1], secondPath[2]);
|
|
13367
|
+
if (!railAxis || railAxis !== secondRailAxis || railAxis === departureAxis) {
|
|
13368
|
+
continue;
|
|
13369
|
+
}
|
|
13370
|
+
const firstRailDirection = firstPath[2][railAxis] - firstPath[1][railAxis];
|
|
13371
|
+
const secondRailDirection = secondPath[2][railAxis] - secondPath[1][railAxis];
|
|
13372
|
+
const railsHaveSameDirection = Math.sign(firstRailDirection) === Math.sign(secondRailDirection);
|
|
13373
|
+
const sharedStub = firstPath.slice(0, 2);
|
|
13374
|
+
if (!railsHaveSameDirection && !nearlyEqual(
|
|
13375
|
+
Math.abs(firstRailDirection),
|
|
13376
|
+
Math.abs(secondRailDirection)
|
|
13377
|
+
) && netLabelPlacements.some(
|
|
13378
|
+
(label) => label.globalConnNetId === firstTrace.globalConnNetId && tracePathContainsPoint(sharedStub, label.anchorPoint)
|
|
13379
|
+
)) {
|
|
13380
|
+
continue;
|
|
13381
|
+
}
|
|
13382
|
+
let traceIndexToCollapse = secondIndex;
|
|
13383
|
+
let traceToCollapse = secondTrace;
|
|
13384
|
+
let pathToCollapse = secondPath;
|
|
13385
|
+
let branchPoint = firstPath[1];
|
|
13386
|
+
if (railsHaveSameDirection && Math.abs(firstRailDirection) < Math.abs(secondRailDirection)) {
|
|
13387
|
+
traceIndexToCollapse = firstIndex;
|
|
13388
|
+
traceToCollapse = firstTrace;
|
|
13389
|
+
pathToCollapse = firstPath;
|
|
13390
|
+
branchPoint = firstPath[2];
|
|
13391
|
+
} else if (railsHaveSameDirection) {
|
|
13392
|
+
branchPoint = secondPath[2];
|
|
13393
|
+
}
|
|
13394
|
+
const sharedPrefix = [pathToCollapse[0], pathToCollapse[1], branchPoint];
|
|
13395
|
+
if (!traceCanLoseSharedPrefix({
|
|
13396
|
+
trace: traceToCollapse,
|
|
13397
|
+
sharedPrefix,
|
|
13398
|
+
netLabelPlacements
|
|
13399
|
+
})) {
|
|
13400
|
+
if (traceIndexToCollapse === firstIndex) {
|
|
13401
|
+
traceIndexToCollapse = secondIndex;
|
|
13402
|
+
traceToCollapse = secondTrace;
|
|
13403
|
+
pathToCollapse = secondPath;
|
|
13404
|
+
} else {
|
|
13405
|
+
traceIndexToCollapse = firstIndex;
|
|
13406
|
+
traceToCollapse = firstTrace;
|
|
13407
|
+
pathToCollapse = firstPath;
|
|
13408
|
+
}
|
|
13409
|
+
}
|
|
13410
|
+
if (!traceCanLoseSharedPrefix({
|
|
13411
|
+
trace: traceToCollapse,
|
|
13412
|
+
sharedPrefix: [pathToCollapse[0], pathToCollapse[1], branchPoint],
|
|
13413
|
+
netLabelPlacements
|
|
13414
|
+
})) {
|
|
13415
|
+
continue;
|
|
13416
|
+
}
|
|
13417
|
+
const collapsedTrace = getTraceWithoutSharedPrefix({
|
|
13418
|
+
trace: traceToCollapse,
|
|
13419
|
+
pathFromSharedPin: pathToCollapse,
|
|
13420
|
+
sharedPinId: sharedPin.pinId,
|
|
13421
|
+
branchPoint
|
|
13422
|
+
});
|
|
13423
|
+
if (!collapsedTrace) continue;
|
|
13424
|
+
outputTraces[traceIndexToCollapse] = collapsedTrace;
|
|
13425
|
+
break;
|
|
13426
|
+
}
|
|
13427
|
+
}
|
|
13428
|
+
return outputTraces;
|
|
13429
|
+
};
|
|
13430
|
+
|
|
13034
13431
|
// lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts
|
|
13035
13432
|
var MAX_ALIGNED_LOAD_PIN_OFFSET = 0.2;
|
|
13036
13433
|
var MAX_SAME_NET_LABEL_BOUNDARY_RAIL_OFFSET = 0.2;
|
|
13037
13434
|
var MAX_SHARED_PIN_RAIL_OFFSET = 0.05;
|
|
13038
13435
|
var MAX_SHARED_ENDPOINT_RAIL_OFFSET = 0.8;
|
|
13039
13436
|
var MIN_RETURN_STEM_LENGTH = 0.05;
|
|
13040
|
-
var
|
|
13437
|
+
var getMultiPinNetPinIds = (inputProblem) => {
|
|
13438
|
+
const { netConnMap } = getConnectivityMapsFromInputProblem(inputProblem);
|
|
13439
|
+
const inputPinIds = new Set(
|
|
13440
|
+
inputProblem.chips.flatMap((chip) => chip.pins.map((pin) => pin.pinId))
|
|
13441
|
+
);
|
|
13442
|
+
return new Set(
|
|
13443
|
+
[...inputPinIds].filter((pinId) => {
|
|
13444
|
+
const globalNetId = netConnMap.getNetConnectedToId(pinId);
|
|
13445
|
+
if (!globalNetId) return false;
|
|
13446
|
+
return netConnMap.getIdsConnectedToNet(globalNetId).filter((connectedId) => inputPinIds.has(connectedId)).length > 2;
|
|
13447
|
+
})
|
|
13448
|
+
);
|
|
13449
|
+
};
|
|
13450
|
+
var getSegmentAxis4 = (start, end) => {
|
|
13041
13451
|
if (isHorizontal2(start, end)) return "x";
|
|
13042
13452
|
if (isVertical2(start, end)) return "y";
|
|
13043
13453
|
return null;
|
|
13044
13454
|
};
|
|
13045
|
-
var getSharedPin = ({
|
|
13046
|
-
donorTrace,
|
|
13047
|
-
branchTrace
|
|
13048
|
-
}) => {
|
|
13049
|
-
const branchPinIds = new Set(branchTrace.pins.map((pin) => pin.pinId));
|
|
13050
|
-
return donorTrace.pins.find((pin) => branchPinIds.has(pin.pinId)) ?? null;
|
|
13051
|
-
};
|
|
13052
13455
|
var getOtherPin = ({
|
|
13053
13456
|
trace,
|
|
13054
13457
|
sharedPin
|
|
@@ -13274,8 +13677,8 @@ var getAlignedSharedEndpointRailPath = ({
|
|
|
13274
13677
|
const donorPath = pathFromShared(donorTrace);
|
|
13275
13678
|
const branchPath = pathFromShared(branchTrace);
|
|
13276
13679
|
if (donorPath.length < 3 || branchPath.length < 4) return null;
|
|
13277
|
-
const donorDepartureAxis =
|
|
13278
|
-
const branchDepartureAxis =
|
|
13680
|
+
const donorDepartureAxis = getSegmentAxis4(donorPath[0], donorPath[1]);
|
|
13681
|
+
const branchDepartureAxis = getSegmentAxis4(branchPath[0], branchPath[1]);
|
|
13279
13682
|
if (!donorDepartureAxis || donorDepartureAxis !== branchDepartureAxis) {
|
|
13280
13683
|
return null;
|
|
13281
13684
|
}
|
|
@@ -13283,8 +13686,8 @@ var getAlignedSharedEndpointRailPath = ({
|
|
|
13283
13686
|
const branchDeparture = branchPath[1][branchDepartureAxis] - branchPath[0][branchDepartureAxis];
|
|
13284
13687
|
if (Math.sign(donorDeparture) !== Math.sign(branchDeparture)) return null;
|
|
13285
13688
|
let railIndex = 1;
|
|
13286
|
-
let donorRailAxis =
|
|
13287
|
-
let branchRailAxis =
|
|
13689
|
+
let donorRailAxis = getSegmentAxis4(donorPath[1], donorPath[2]);
|
|
13690
|
+
let branchRailAxis = getSegmentAxis4(branchPath[1], branchPath[2]);
|
|
13288
13691
|
if (!donorRailAxis || donorRailAxis !== branchRailAxis || donorRailAxis === donorDepartureAxis) {
|
|
13289
13692
|
return null;
|
|
13290
13693
|
}
|
|
@@ -13292,11 +13695,11 @@ var getAlignedSharedEndpointRailPath = ({
|
|
|
13292
13695
|
if (firstRailsAreAligned) {
|
|
13293
13696
|
railIndex++;
|
|
13294
13697
|
if (!donorPath[railIndex + 2] || !branchPath[railIndex + 2]) return null;
|
|
13295
|
-
donorRailAxis =
|
|
13698
|
+
donorRailAxis = getSegmentAxis4(
|
|
13296
13699
|
donorPath[railIndex],
|
|
13297
13700
|
donorPath[railIndex + 1]
|
|
13298
13701
|
);
|
|
13299
|
-
branchRailAxis =
|
|
13702
|
+
branchRailAxis = getSegmentAxis4(
|
|
13300
13703
|
branchPath[railIndex],
|
|
13301
13704
|
branchPath[railIndex + 1]
|
|
13302
13705
|
);
|
|
@@ -13304,7 +13707,7 @@ var getAlignedSharedEndpointRailPath = ({
|
|
|
13304
13707
|
}
|
|
13305
13708
|
let branchParallelRailCount = 0;
|
|
13306
13709
|
for (let index = 1; index < branchPath.length - 2; index++) {
|
|
13307
|
-
if (
|
|
13710
|
+
if (getSegmentAxis4(branchPath[index], branchPath[index + 1]) === branchRailAxis) {
|
|
13308
13711
|
branchParallelRailCount++;
|
|
13309
13712
|
}
|
|
13310
13713
|
}
|
|
@@ -13346,13 +13749,13 @@ var getAlignedAttachedLabelConnectorPath = ({
|
|
|
13346
13749
|
const junction = connectorPath[0];
|
|
13347
13750
|
const turn = connectorPath[1];
|
|
13348
13751
|
const railEnd = connectorPath[2];
|
|
13349
|
-
const departureAxis =
|
|
13350
|
-
const railAxis =
|
|
13752
|
+
const departureAxis = getSegmentAxis4(junction, turn);
|
|
13753
|
+
const railAxis = getSegmentAxis4(turn, railEnd);
|
|
13351
13754
|
if (!departureAxis || !railAxis || departureAxis === railAxis) return null;
|
|
13352
13755
|
const donorSegmentIndex = donorTrace.tracePath.findIndex(
|
|
13353
13756
|
(point, index, path) => {
|
|
13354
13757
|
const next = path[index + 1];
|
|
13355
|
-
return next &&
|
|
13758
|
+
return next && getSegmentAxis4(point, next) === departureAxis && tracePathContainsPoint([point, next], junction) && tracePathContainsPoint([point, next], turn);
|
|
13356
13759
|
}
|
|
13357
13760
|
);
|
|
13358
13761
|
if (donorSegmentIndex < 0) return null;
|
|
@@ -13365,7 +13768,7 @@ var getAlignedAttachedLabelConnectorPath = ({
|
|
|
13365
13768
|
donorSegmentIndex > 0 ? [donorTrace.tracePath[donorSegmentIndex - 1], donorSegmentStart] : null,
|
|
13366
13769
|
donorSegmentIndex + 2 < donorTrace.tracePath.length ? [donorSegmentEnd, donorTrace.tracePath[donorSegmentIndex + 2]] : null
|
|
13367
13770
|
].flatMap(
|
|
13368
|
-
(segment) => segment &&
|
|
13771
|
+
(segment) => segment && getSegmentAxis4(segment[0], segment[1]) === railAxis ? [segment] : []
|
|
13369
13772
|
);
|
|
13370
13773
|
if (adjacentDonorRails.length === 0) return null;
|
|
13371
13774
|
const railCoordinateAxis = railAxis === "x" ? "y" : "x";
|
|
@@ -13448,7 +13851,7 @@ var preserveAttachedLabelConnectorJunctions = ({
|
|
|
13448
13851
|
if (!movedJunction) return null;
|
|
13449
13852
|
const neighborIndex = endpointIndex === 0 ? 1 : endpointIndex - 1;
|
|
13450
13853
|
const neighbor = connector.tracePath[neighborIndex];
|
|
13451
|
-
if (!neighbor ||
|
|
13854
|
+
if (!neighbor || getSegmentAxis4(originalJunction, neighbor) !== getSegmentAxis4(movedJunction, neighbor)) {
|
|
13452
13855
|
return null;
|
|
13453
13856
|
}
|
|
13454
13857
|
const movedConnector = {
|
|
@@ -13871,6 +14274,13 @@ var alignSameNetJunctions = ({
|
|
|
13871
14274
|
}
|
|
13872
14275
|
}
|
|
13873
14276
|
}
|
|
14277
|
+
const collapsedSharedEndpointStubs = collapseRedundantSharedEndpointStubs({
|
|
14278
|
+
traces: outputTraces,
|
|
14279
|
+
netLabelPlacements: outputNetLabelPlacements,
|
|
14280
|
+
netLabelConnectorTraceIds,
|
|
14281
|
+
multiPinNetPinIds: getMultiPinNetPinIds(inputProblem)
|
|
14282
|
+
});
|
|
14283
|
+
outputTraces = collapsedSharedEndpointStubs;
|
|
13874
14284
|
return {
|
|
13875
14285
|
traces: outputTraces,
|
|
13876
14286
|
netLabelPlacements: outputNetLabelPlacements,
|
|
@@ -13885,8 +14295,8 @@ var getTracePathStartingAtPin = (trace, pin) => {
|
|
|
13885
14295
|
const pathStart = trace.tracePath[0];
|
|
13886
14296
|
const pathEnd = trace.tracePath.at(-1);
|
|
13887
14297
|
if (!pathStart || !pathEnd) return null;
|
|
13888
|
-
if (
|
|
13889
|
-
if (
|
|
14298
|
+
if (pointsEqual2(pathStart, pin)) return trace.tracePath;
|
|
14299
|
+
if (pointsEqual2(pathEnd, pin)) return [...trace.tracePath].reverse();
|
|
13890
14300
|
return null;
|
|
13891
14301
|
};
|
|
13892
14302
|
var getPerpendicularPathCrossings = (targetPath, donorPath) => {
|
|
@@ -13908,7 +14318,7 @@ var getPerpendicularPathCrossings = (targetPath, donorPath) => {
|
|
|
13908
14318
|
donorStart,
|
|
13909
14319
|
donorEnd
|
|
13910
14320
|
);
|
|
13911
|
-
if (!intersectionPoint ||
|
|
14321
|
+
if (!intersectionPoint || pointsEqual2(intersectionPoint, sharedEndpoint)) {
|
|
13912
14322
|
continue;
|
|
13913
14323
|
}
|
|
13914
14324
|
crossings.push({
|
|
@@ -13931,7 +14341,7 @@ var buildCollapsedCyclePath = ({
|
|
|
13931
14341
|
crossing.intersectionPoint,
|
|
13932
14342
|
...targetPath.slice(crossing.targetSegmentIndex + 1)
|
|
13933
14343
|
]);
|
|
13934
|
-
if (
|
|
14344
|
+
if (pointsEqual2(targetTrace.tracePath[0], targetPath[0])) {
|
|
13935
14345
|
return pathFromSharedPin;
|
|
13936
14346
|
}
|
|
13937
14347
|
return pathFromSharedPin.reverse();
|
|
@@ -14379,8 +14789,8 @@ var generateElbowTransitionSimplificationCandidates = ({
|
|
|
14379
14789
|
};
|
|
14380
14790
|
|
|
14381
14791
|
// lib/solvers/TraceElbowTransitionSimplificationSolver/TraceElbowTransitionSimplificationSolver.ts
|
|
14382
|
-
var
|
|
14383
|
-
var
|
|
14792
|
+
var PATH_LENGTH_EPSILON3 = 1e-9;
|
|
14793
|
+
var getPathLength6 = (points) => points.slice(1).reduce((length, point, pointIndex) => {
|
|
14384
14794
|
const previousPoint = points[pointIndex];
|
|
14385
14795
|
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
14386
14796
|
}, 0);
|
|
@@ -14452,8 +14862,8 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
14452
14862
|
netLabels: this.input.netLabelPlacements
|
|
14453
14863
|
}).length;
|
|
14454
14864
|
const isSimplerEquivalentReroute = candidateOverlapCount < initialRerouteOverlapCount && Math.abs(
|
|
14455
|
-
|
|
14456
|
-
) <
|
|
14865
|
+
getPathLength6(simplifiedCandidate) - getPathLength6(reroutedPath)
|
|
14866
|
+
) < PATH_LENGTH_EPSILON3 && simplifiedCandidate.length < reroutedPath.length && preservesLabelAnchors(
|
|
14457
14867
|
this.input.netLabelPlacements,
|
|
14458
14868
|
[completedReroute.initialTrace],
|
|
14459
14869
|
[candidateTrace]
|
|
@@ -14471,7 +14881,7 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
14471
14881
|
({ label }) => `${label.globalConnNetId}:${label.netId}`
|
|
14472
14882
|
)
|
|
14473
14883
|
);
|
|
14474
|
-
const initialPathLength =
|
|
14884
|
+
const initialPathLength = getPathLength6(tracePath);
|
|
14475
14885
|
const validCandidates = [...candidateByPath.values()].filter(
|
|
14476
14886
|
(candidatePath) => {
|
|
14477
14887
|
const candidateTrace = { ...trace, tracePath: candidatePath };
|
|
@@ -14483,7 +14893,7 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
14483
14893
|
({ label }) => initialOverlapIds.has(`${label.globalConnNetId}:${label.netId}`)
|
|
14484
14894
|
);
|
|
14485
14895
|
const reducesCollisions = candidateOverlaps.length < initialOverlaps.length;
|
|
14486
|
-
const simplifiesGeometry = candidateOverlaps.length === initialOverlaps.length &&
|
|
14896
|
+
const simplifiesGeometry = candidateOverlaps.length === initialOverlaps.length && getPathLength6(candidatePath) <= initialPathLength + PATH_LENGTH_EPSILON3 && candidatePath.length < tracePath.length;
|
|
14487
14897
|
return candidateOnlyKeepsExistingOverlaps && (reducesCollisions || simplifiesGeometry) && preservesLabelAnchors(
|
|
14488
14898
|
this.input.netLabelPlacements,
|
|
14489
14899
|
[trace],
|
|
@@ -14498,7 +14908,7 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
14498
14908
|
validCandidates.sort((a, b) => {
|
|
14499
14909
|
const overlapDifference = getOverlapCount(a) - getOverlapCount(b);
|
|
14500
14910
|
if (overlapDifference !== 0) return overlapDifference;
|
|
14501
|
-
return
|
|
14911
|
+
return getPathLength6(a) - getPathLength6(b) || a.length - b.length;
|
|
14502
14912
|
});
|
|
14503
14913
|
const bestCandidate = validCandidates[0];
|
|
14504
14914
|
if (!bestCandidate) return;
|
|
@@ -14741,7 +15151,7 @@ var getInlineBounds = (placement) => {
|
|
|
14741
15151
|
maxY: placement.center.y + renderedHeight / 2
|
|
14742
15152
|
};
|
|
14743
15153
|
};
|
|
14744
|
-
var
|
|
15154
|
+
var pointsEqual4 = (a, b) => Math.abs(a.x - b.x) <= POINT_EPSILON && Math.abs(a.y - b.y) <= POINT_EPSILON;
|
|
14745
15155
|
var pathIntersectsBounds = (path, bounds) => {
|
|
14746
15156
|
for (let index = 0; index < path.length - 1; index++) {
|
|
14747
15157
|
const start = path[index];
|
|
@@ -14837,13 +15247,13 @@ var findConnectorTraceIndex = (label, traces) => traces.findIndex((trace) => {
|
|
|
14837
15247
|
const first = trace.tracePath[0];
|
|
14838
15248
|
const last = trace.tracePath.at(-1);
|
|
14839
15249
|
return Boolean(
|
|
14840
|
-
first &&
|
|
15250
|
+
first && pointsEqual4(first, label.anchorPoint) || last && pointsEqual4(last, label.anchorPoint)
|
|
14841
15251
|
);
|
|
14842
15252
|
});
|
|
14843
15253
|
var canAddConnectorAtAnchor = (label, traces, pinMap) => {
|
|
14844
15254
|
if (label.pinIds.some((pinId) => {
|
|
14845
15255
|
const pin = pinMap[pinId];
|
|
14846
|
-
return pin &&
|
|
15256
|
+
return pin && pointsEqual4(pin, label.anchorPoint);
|
|
14847
15257
|
})) {
|
|
14848
15258
|
return true;
|
|
14849
15259
|
}
|
|
@@ -14853,8 +15263,8 @@ var canAddConnectorAtAnchor = (label, traces, pinMap) => {
|
|
|
14853
15263
|
};
|
|
14854
15264
|
var moveConnectorEndpoint = (trace, oldAnchor, newAnchor) => {
|
|
14855
15265
|
const tracePath = trace.tracePath.map((point) => ({ ...point }));
|
|
14856
|
-
if (
|
|
14857
|
-
if (
|
|
15266
|
+
if (pointsEqual4(tracePath[0], oldAnchor)) tracePath[0] = newAnchor;
|
|
15267
|
+
if (pointsEqual4(tracePath.at(-1), oldAnchor)) {
|
|
14858
15268
|
tracePath[tracePath.length - 1] = newAnchor;
|
|
14859
15269
|
}
|
|
14860
15270
|
return { ...trace, tracePath };
|
|
@@ -15321,14 +15731,14 @@ var pathIntersectsRenderedLabel = (path, label) => {
|
|
|
15321
15731
|
|
|
15322
15732
|
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15323
15733
|
var EPS15 = 1e-6;
|
|
15324
|
-
var
|
|
15734
|
+
var getPathLength7 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
|
|
15325
15735
|
const previousPoint = path[pointIndex];
|
|
15326
15736
|
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
15327
15737
|
}, 0);
|
|
15328
15738
|
var pathsEqual = (first, second) => first.length === second.length && first.every(
|
|
15329
15739
|
(point, index) => Math.abs(point.x - second[index].x) <= EPS15 && Math.abs(point.y - second[index].y) <= EPS15
|
|
15330
15740
|
);
|
|
15331
|
-
var isStrictlySimpler = (candidate, current) => candidate.length < current.length &&
|
|
15741
|
+
var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength7(candidate) <= getPathLength7(current) + EPS15;
|
|
15332
15742
|
var getIntersectionKeys = (path, otherPath) => {
|
|
15333
15743
|
const intersections = /* @__PURE__ */ new Set();
|
|
15334
15744
|
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
@@ -16291,22 +16701,22 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
16291
16701
|
|
|
16292
16702
|
// lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict.ts
|
|
16293
16703
|
import { doSegmentsIntersect as doSegmentsIntersect4 } from "@tscircuit/math-utils";
|
|
16294
|
-
var
|
|
16704
|
+
var EPSILON2 = 1e-6;
|
|
16295
16705
|
var isStrictlyBetween2 = ({
|
|
16296
16706
|
coordinate,
|
|
16297
16707
|
segmentStartCoordinate,
|
|
16298
16708
|
segmentEndCoordinate
|
|
16299
|
-
}) => coordinate > Math.min(segmentStartCoordinate, segmentEndCoordinate) +
|
|
16709
|
+
}) => coordinate > Math.min(segmentStartCoordinate, segmentEndCoordinate) + EPSILON2 && coordinate < Math.max(segmentStartCoordinate, segmentEndCoordinate) - EPSILON2;
|
|
16300
16710
|
var isStrictInteriorPerpendicularCrossing = ({
|
|
16301
16711
|
firstSegmentStart,
|
|
16302
16712
|
firstSegmentEnd,
|
|
16303
16713
|
secondSegmentStart,
|
|
16304
16714
|
secondSegmentEnd
|
|
16305
16715
|
}) => {
|
|
16306
|
-
const firstIsHorizontal = Math.abs(firstSegmentStart.y - firstSegmentEnd.y) <=
|
|
16307
|
-
const firstIsVertical = Math.abs(firstSegmentStart.x - firstSegmentEnd.x) <=
|
|
16308
|
-
const secondIsHorizontal = Math.abs(secondSegmentStart.y - secondSegmentEnd.y) <=
|
|
16309
|
-
const secondIsVertical = Math.abs(secondSegmentStart.x - secondSegmentEnd.x) <=
|
|
16716
|
+
const firstIsHorizontal = Math.abs(firstSegmentStart.y - firstSegmentEnd.y) <= EPSILON2;
|
|
16717
|
+
const firstIsVertical = Math.abs(firstSegmentStart.x - firstSegmentEnd.x) <= EPSILON2;
|
|
16718
|
+
const secondIsHorizontal = Math.abs(secondSegmentStart.y - secondSegmentEnd.y) <= EPSILON2;
|
|
16719
|
+
const secondIsVertical = Math.abs(secondSegmentStart.x - secondSegmentEnd.x) <= EPSILON2;
|
|
16310
16720
|
let horizontalStart;
|
|
16311
16721
|
let horizontalEnd;
|
|
16312
16722
|
if (firstIsHorizontal) {
|
|
@@ -16465,7 +16875,7 @@ var reduceTraceCrossings = ({
|
|
|
16465
16875
|
globalConnNetId,
|
|
16466
16876
|
otherTraces
|
|
16467
16877
|
});
|
|
16468
|
-
let bestPathLength =
|
|
16878
|
+
let bestPathLength = getPathLength4(tracePath);
|
|
16469
16879
|
for (const candidate of getEndpointAlignedSegmentCandidates(tracePath)) {
|
|
16470
16880
|
if (!isCandidateValid(candidate)) continue;
|
|
16471
16881
|
const crossingCount = countOtherNetCrossings2({
|
|
@@ -16473,7 +16883,7 @@ var reduceTraceCrossings = ({
|
|
|
16473
16883
|
globalConnNetId,
|
|
16474
16884
|
otherTraces
|
|
16475
16885
|
});
|
|
16476
|
-
const pathLength =
|
|
16886
|
+
const pathLength = getPathLength4(candidate);
|
|
16477
16887
|
if (crossingCount < bestCrossingCount || crossingCount === bestCrossingCount && pathLength < bestPathLength) {
|
|
16478
16888
|
bestPath = candidate;
|
|
16479
16889
|
bestCrossingCount = crossingCount;
|