@tscircuit/schematic-trace-solver 0.0.181 → 0.0.183
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 +318 -113
- package/lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts +10 -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-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +13 -20
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +10 -10
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +13 -13
- package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +181 -181
- package/tests/repros/__snapshots__/repro-mcp73831-charger-traces.snap.svg +10 -10
- package/tests/repros/__snapshots__/repro-mouse-switch-ground-unnecessary-jog.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +8 -8
- package/tests/repros/__snapshots__/repro-rf1-unnecessary-dogleg.snap.svg +5 -5
- package/tests/solvers/InlineNetLabelSolver/push-anchored-net-labels-away.test.ts +62 -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 = ({
|
|
@@ -13885,8 +14084,8 @@ var getTracePathStartingAtPin = (trace, pin) => {
|
|
|
13885
14084
|
const pathStart = trace.tracePath[0];
|
|
13886
14085
|
const pathEnd = trace.tracePath.at(-1);
|
|
13887
14086
|
if (!pathStart || !pathEnd) return null;
|
|
13888
|
-
if (
|
|
13889
|
-
if (
|
|
14087
|
+
if (pointsEqual2(pathStart, pin)) return trace.tracePath;
|
|
14088
|
+
if (pointsEqual2(pathEnd, pin)) return [...trace.tracePath].reverse();
|
|
13890
14089
|
return null;
|
|
13891
14090
|
};
|
|
13892
14091
|
var getPerpendicularPathCrossings = (targetPath, donorPath) => {
|
|
@@ -13908,7 +14107,7 @@ var getPerpendicularPathCrossings = (targetPath, donorPath) => {
|
|
|
13908
14107
|
donorStart,
|
|
13909
14108
|
donorEnd
|
|
13910
14109
|
);
|
|
13911
|
-
if (!intersectionPoint ||
|
|
14110
|
+
if (!intersectionPoint || pointsEqual2(intersectionPoint, sharedEndpoint)) {
|
|
13912
14111
|
continue;
|
|
13913
14112
|
}
|
|
13914
14113
|
crossings.push({
|
|
@@ -13931,7 +14130,7 @@ var buildCollapsedCyclePath = ({
|
|
|
13931
14130
|
crossing.intersectionPoint,
|
|
13932
14131
|
...targetPath.slice(crossing.targetSegmentIndex + 1)
|
|
13933
14132
|
]);
|
|
13934
|
-
if (
|
|
14133
|
+
if (pointsEqual2(targetTrace.tracePath[0], targetPath[0])) {
|
|
13935
14134
|
return pathFromSharedPin;
|
|
13936
14135
|
}
|
|
13937
14136
|
return pathFromSharedPin.reverse();
|
|
@@ -14379,8 +14578,8 @@ var generateElbowTransitionSimplificationCandidates = ({
|
|
|
14379
14578
|
};
|
|
14380
14579
|
|
|
14381
14580
|
// lib/solvers/TraceElbowTransitionSimplificationSolver/TraceElbowTransitionSimplificationSolver.ts
|
|
14382
|
-
var
|
|
14383
|
-
var
|
|
14581
|
+
var PATH_LENGTH_EPSILON3 = 1e-9;
|
|
14582
|
+
var getPathLength6 = (points) => points.slice(1).reduce((length, point, pointIndex) => {
|
|
14384
14583
|
const previousPoint = points[pointIndex];
|
|
14385
14584
|
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
14386
14585
|
}, 0);
|
|
@@ -14452,8 +14651,8 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
14452
14651
|
netLabels: this.input.netLabelPlacements
|
|
14453
14652
|
}).length;
|
|
14454
14653
|
const isSimplerEquivalentReroute = candidateOverlapCount < initialRerouteOverlapCount && Math.abs(
|
|
14455
|
-
|
|
14456
|
-
) <
|
|
14654
|
+
getPathLength6(simplifiedCandidate) - getPathLength6(reroutedPath)
|
|
14655
|
+
) < PATH_LENGTH_EPSILON3 && simplifiedCandidate.length < reroutedPath.length && preservesLabelAnchors(
|
|
14457
14656
|
this.input.netLabelPlacements,
|
|
14458
14657
|
[completedReroute.initialTrace],
|
|
14459
14658
|
[candidateTrace]
|
|
@@ -14471,7 +14670,7 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
14471
14670
|
({ label }) => `${label.globalConnNetId}:${label.netId}`
|
|
14472
14671
|
)
|
|
14473
14672
|
);
|
|
14474
|
-
const initialPathLength =
|
|
14673
|
+
const initialPathLength = getPathLength6(tracePath);
|
|
14475
14674
|
const validCandidates = [...candidateByPath.values()].filter(
|
|
14476
14675
|
(candidatePath) => {
|
|
14477
14676
|
const candidateTrace = { ...trace, tracePath: candidatePath };
|
|
@@ -14483,7 +14682,7 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
14483
14682
|
({ label }) => initialOverlapIds.has(`${label.globalConnNetId}:${label.netId}`)
|
|
14484
14683
|
);
|
|
14485
14684
|
const reducesCollisions = candidateOverlaps.length < initialOverlaps.length;
|
|
14486
|
-
const simplifiesGeometry = candidateOverlaps.length === initialOverlaps.length &&
|
|
14685
|
+
const simplifiesGeometry = candidateOverlaps.length === initialOverlaps.length && getPathLength6(candidatePath) <= initialPathLength + PATH_LENGTH_EPSILON3 && candidatePath.length < tracePath.length;
|
|
14487
14686
|
return candidateOnlyKeepsExistingOverlaps && (reducesCollisions || simplifiesGeometry) && preservesLabelAnchors(
|
|
14488
14687
|
this.input.netLabelPlacements,
|
|
14489
14688
|
[trace],
|
|
@@ -14498,7 +14697,7 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
14498
14697
|
validCandidates.sort((a, b) => {
|
|
14499
14698
|
const overlapDifference = getOverlapCount(a) - getOverlapCount(b);
|
|
14500
14699
|
if (overlapDifference !== 0) return overlapDifference;
|
|
14501
|
-
return
|
|
14700
|
+
return getPathLength6(a) - getPathLength6(b) || a.length - b.length;
|
|
14502
14701
|
});
|
|
14503
14702
|
const bestCandidate = validCandidates[0];
|
|
14504
14703
|
if (!bestCandidate) return;
|
|
@@ -14741,7 +14940,7 @@ var getInlineBounds = (placement) => {
|
|
|
14741
14940
|
maxY: placement.center.y + renderedHeight / 2
|
|
14742
14941
|
};
|
|
14743
14942
|
};
|
|
14744
|
-
var
|
|
14943
|
+
var pointsEqual4 = (a, b) => Math.abs(a.x - b.x) <= POINT_EPSILON && Math.abs(a.y - b.y) <= POINT_EPSILON;
|
|
14745
14944
|
var pathIntersectsBounds = (path, bounds) => {
|
|
14746
14945
|
for (let index = 0; index < path.length - 1; index++) {
|
|
14747
14946
|
const start = path[index];
|
|
@@ -14837,13 +15036,13 @@ var findConnectorTraceIndex = (label, traces) => traces.findIndex((trace) => {
|
|
|
14837
15036
|
const first = trace.tracePath[0];
|
|
14838
15037
|
const last = trace.tracePath.at(-1);
|
|
14839
15038
|
return Boolean(
|
|
14840
|
-
first &&
|
|
15039
|
+
first && pointsEqual4(first, label.anchorPoint) || last && pointsEqual4(last, label.anchorPoint)
|
|
14841
15040
|
);
|
|
14842
15041
|
});
|
|
14843
15042
|
var canAddConnectorAtAnchor = (label, traces, pinMap) => {
|
|
14844
15043
|
if (label.pinIds.some((pinId) => {
|
|
14845
15044
|
const pin = pinMap[pinId];
|
|
14846
|
-
return pin &&
|
|
15045
|
+
return pin && pointsEqual4(pin, label.anchorPoint);
|
|
14847
15046
|
})) {
|
|
14848
15047
|
return true;
|
|
14849
15048
|
}
|
|
@@ -14853,8 +15052,8 @@ var canAddConnectorAtAnchor = (label, traces, pinMap) => {
|
|
|
14853
15052
|
};
|
|
14854
15053
|
var moveConnectorEndpoint = (trace, oldAnchor, newAnchor) => {
|
|
14855
15054
|
const tracePath = trace.tracePath.map((point) => ({ ...point }));
|
|
14856
|
-
if (
|
|
14857
|
-
if (
|
|
15055
|
+
if (pointsEqual4(tracePath[0], oldAnchor)) tracePath[0] = newAnchor;
|
|
15056
|
+
if (pointsEqual4(tracePath.at(-1), oldAnchor)) {
|
|
14858
15057
|
tracePath[tracePath.length - 1] = newAnchor;
|
|
14859
15058
|
}
|
|
14860
15059
|
return { ...trace, tracePath };
|
|
@@ -15048,7 +15247,13 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15048
15247
|
label.anchorPoint,
|
|
15049
15248
|
movedLabel.anchorPoint
|
|
15050
15249
|
);
|
|
15051
|
-
const connectorObstructed =
|
|
15250
|
+
const connectorObstructed = outputTraces.some(
|
|
15251
|
+
(trace) => trace.globalConnNetId !== connector.globalConnNetId && findPerpendicularPathCrossings(
|
|
15252
|
+
connector.tracePath,
|
|
15253
|
+
trace.tracePath,
|
|
15254
|
+
{ includeTerminalSegments: true }
|
|
15255
|
+
).length > 0
|
|
15256
|
+
) || inlineBounds.some(
|
|
15052
15257
|
(bounds) => pathIntersectsBounds(connector.tracePath, bounds)
|
|
15053
15258
|
) || inputProblem.chips.some(
|
|
15054
15259
|
(chip) => !ownerChipIds.has(chip.chipId) && pathIntersectsBounds(connector.tracePath, {
|
|
@@ -15315,14 +15520,14 @@ var pathIntersectsRenderedLabel = (path, label) => {
|
|
|
15315
15520
|
|
|
15316
15521
|
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15317
15522
|
var EPS15 = 1e-6;
|
|
15318
|
-
var
|
|
15523
|
+
var getPathLength7 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
|
|
15319
15524
|
const previousPoint = path[pointIndex];
|
|
15320
15525
|
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
15321
15526
|
}, 0);
|
|
15322
15527
|
var pathsEqual = (first, second) => first.length === second.length && first.every(
|
|
15323
15528
|
(point, index) => Math.abs(point.x - second[index].x) <= EPS15 && Math.abs(point.y - second[index].y) <= EPS15
|
|
15324
15529
|
);
|
|
15325
|
-
var isStrictlySimpler = (candidate, current) => candidate.length < current.length &&
|
|
15530
|
+
var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength7(candidate) <= getPathLength7(current) + EPS15;
|
|
15326
15531
|
var getIntersectionKeys = (path, otherPath) => {
|
|
15327
15532
|
const intersections = /* @__PURE__ */ new Set();
|
|
15328
15533
|
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
@@ -16285,22 +16490,22 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
16285
16490
|
|
|
16286
16491
|
// lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict.ts
|
|
16287
16492
|
import { doSegmentsIntersect as doSegmentsIntersect4 } from "@tscircuit/math-utils";
|
|
16288
|
-
var
|
|
16493
|
+
var EPSILON2 = 1e-6;
|
|
16289
16494
|
var isStrictlyBetween2 = ({
|
|
16290
16495
|
coordinate,
|
|
16291
16496
|
segmentStartCoordinate,
|
|
16292
16497
|
segmentEndCoordinate
|
|
16293
|
-
}) => coordinate > Math.min(segmentStartCoordinate, segmentEndCoordinate) +
|
|
16498
|
+
}) => coordinate > Math.min(segmentStartCoordinate, segmentEndCoordinate) + EPSILON2 && coordinate < Math.max(segmentStartCoordinate, segmentEndCoordinate) - EPSILON2;
|
|
16294
16499
|
var isStrictInteriorPerpendicularCrossing = ({
|
|
16295
16500
|
firstSegmentStart,
|
|
16296
16501
|
firstSegmentEnd,
|
|
16297
16502
|
secondSegmentStart,
|
|
16298
16503
|
secondSegmentEnd
|
|
16299
16504
|
}) => {
|
|
16300
|
-
const firstIsHorizontal = Math.abs(firstSegmentStart.y - firstSegmentEnd.y) <=
|
|
16301
|
-
const firstIsVertical = Math.abs(firstSegmentStart.x - firstSegmentEnd.x) <=
|
|
16302
|
-
const secondIsHorizontal = Math.abs(secondSegmentStart.y - secondSegmentEnd.y) <=
|
|
16303
|
-
const secondIsVertical = Math.abs(secondSegmentStart.x - secondSegmentEnd.x) <=
|
|
16505
|
+
const firstIsHorizontal = Math.abs(firstSegmentStart.y - firstSegmentEnd.y) <= EPSILON2;
|
|
16506
|
+
const firstIsVertical = Math.abs(firstSegmentStart.x - firstSegmentEnd.x) <= EPSILON2;
|
|
16507
|
+
const secondIsHorizontal = Math.abs(secondSegmentStart.y - secondSegmentEnd.y) <= EPSILON2;
|
|
16508
|
+
const secondIsVertical = Math.abs(secondSegmentStart.x - secondSegmentEnd.x) <= EPSILON2;
|
|
16304
16509
|
let horizontalStart;
|
|
16305
16510
|
let horizontalEnd;
|
|
16306
16511
|
if (firstIsHorizontal) {
|
|
@@ -16459,7 +16664,7 @@ var reduceTraceCrossings = ({
|
|
|
16459
16664
|
globalConnNetId,
|
|
16460
16665
|
otherTraces
|
|
16461
16666
|
});
|
|
16462
|
-
let bestPathLength =
|
|
16667
|
+
let bestPathLength = getPathLength4(tracePath);
|
|
16463
16668
|
for (const candidate of getEndpointAlignedSegmentCandidates(tracePath)) {
|
|
16464
16669
|
if (!isCandidateValid(candidate)) continue;
|
|
16465
16670
|
const crossingCount = countOtherNetCrossings2({
|
|
@@ -16467,7 +16672,7 @@ var reduceTraceCrossings = ({
|
|
|
16467
16672
|
globalConnNetId,
|
|
16468
16673
|
otherTraces
|
|
16469
16674
|
});
|
|
16470
|
-
const pathLength =
|
|
16675
|
+
const pathLength = getPathLength4(candidate);
|
|
16471
16676
|
if (crossingCount < bestCrossingCount || crossingCount === bestCrossingCount && pathLength < bestPathLength) {
|
|
16472
16677
|
bestPath = candidate;
|
|
16473
16678
|
bestCrossingCount = crossingCount;
|