@tscircuit/schematic-trace-solver 0.0.29 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +134 -53
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts +7 -8
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver_visualize.ts +2 -3
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts +10 -3
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts +41 -14
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts +27 -25
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/applyJogToTrace.ts +76 -0
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.ts +1 -1
- package/package.json +1 -1
- package/site/SchematicTracePipelineSolver/SchematicTracePipelineSolver02.page.tsx +177 -0
- package/tests/examples/__snapshots__/example11.snap.svg +1 -1
- package/tests/examples/__snapshots__/example16.snap.svg +195 -0
- package/tests/examples/example14.test.tsx +0 -1
- package/tests/examples/example16.test.tsx +175 -0
- package/tests/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver01.test.ts +1 -2
package/dist/index.js
CHANGED
|
@@ -1137,6 +1137,64 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
1137
1137
|
}
|
|
1138
1138
|
};
|
|
1139
1139
|
|
|
1140
|
+
// lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/applyJogToTrace.ts
|
|
1141
|
+
var applyJogToTerminalSegment = ({
|
|
1142
|
+
pts,
|
|
1143
|
+
segmentIndex: si,
|
|
1144
|
+
offset,
|
|
1145
|
+
JOG_SIZE,
|
|
1146
|
+
EPS: EPS2 = 1e-6
|
|
1147
|
+
}) => {
|
|
1148
|
+
if (si !== 0 && si !== pts.length - 2) return;
|
|
1149
|
+
const start = pts[si];
|
|
1150
|
+
const end = pts[si + 1];
|
|
1151
|
+
const isVertical = Math.abs(start.x - end.x) < EPS2;
|
|
1152
|
+
const isHorizontal = Math.abs(start.y - end.y) < EPS2;
|
|
1153
|
+
if (!isVertical && !isHorizontal) return;
|
|
1154
|
+
const segDir = isVertical ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
|
|
1155
|
+
if (si === 0) {
|
|
1156
|
+
if (isVertical) {
|
|
1157
|
+
const jogY = start.y + segDir * JOG_SIZE;
|
|
1158
|
+
pts.splice(
|
|
1159
|
+
1,
|
|
1160
|
+
1,
|
|
1161
|
+
{ x: start.x, y: jogY },
|
|
1162
|
+
{ x: start.x + offset, y: jogY },
|
|
1163
|
+
{ x: end.x + offset, y: end.y }
|
|
1164
|
+
);
|
|
1165
|
+
} else {
|
|
1166
|
+
const jogX = start.x + segDir * JOG_SIZE;
|
|
1167
|
+
pts.splice(
|
|
1168
|
+
1,
|
|
1169
|
+
1,
|
|
1170
|
+
{ x: jogX, y: start.y },
|
|
1171
|
+
{ x: jogX, y: start.y + offset },
|
|
1172
|
+
{ x: end.x, y: end.y + offset }
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
} else {
|
|
1176
|
+
if (isVertical) {
|
|
1177
|
+
const jogY = end.y - segDir * JOG_SIZE;
|
|
1178
|
+
pts.splice(
|
|
1179
|
+
si,
|
|
1180
|
+
1,
|
|
1181
|
+
{ x: start.x + offset, y: start.y },
|
|
1182
|
+
{ x: end.x + offset, y: jogY },
|
|
1183
|
+
{ x: end.x, y: jogY }
|
|
1184
|
+
);
|
|
1185
|
+
} else {
|
|
1186
|
+
const jogX = end.x - segDir * JOG_SIZE;
|
|
1187
|
+
pts.splice(
|
|
1188
|
+
si,
|
|
1189
|
+
1,
|
|
1190
|
+
{ x: start.x, y: start.y + offset },
|
|
1191
|
+
{ x: jogX, y: end.y + offset },
|
|
1192
|
+
{ x: jogX, y: end.y }
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1140
1198
|
// lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts
|
|
1141
1199
|
var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
1142
1200
|
overlappingTraceSegments;
|
|
@@ -1180,33 +1238,30 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1180
1238
|
const current = this.correctedTraceMap[original.mspPairId] ?? original;
|
|
1181
1239
|
const pts = current.tracePath.map((p) => ({ ...p }));
|
|
1182
1240
|
const segIdxs = Array.from(segIdxSet).sort((a, b) => a - b);
|
|
1183
|
-
const
|
|
1184
|
-
const
|
|
1185
|
-
for (const si of
|
|
1241
|
+
const segIdxsRev = Array.from(segIdxSet).sort((a, b) => a - b).reverse();
|
|
1242
|
+
const JOG_SIZE = this.SHIFT_DISTANCE;
|
|
1243
|
+
for (const si of segIdxsRev) {
|
|
1186
1244
|
if (si < 0 || si >= pts.length - 1) continue;
|
|
1187
|
-
if (si === 0 || si === pts.length - 2)
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1245
|
+
if (si === 0 || si === pts.length - 2) {
|
|
1246
|
+
applyJogToTerminalSegment({
|
|
1247
|
+
pts,
|
|
1248
|
+
segmentIndex: si,
|
|
1249
|
+
offset,
|
|
1250
|
+
JOG_SIZE,
|
|
1251
|
+
EPS: EPS2
|
|
1252
|
+
});
|
|
1253
|
+
} else {
|
|
1254
|
+
const start = pts[si];
|
|
1255
|
+
const end = pts[si + 1];
|
|
1256
|
+
const isVertical = Math.abs(start.x - end.x) < EPS2;
|
|
1257
|
+
const isHorizontal = Math.abs(start.y - end.y) < EPS2;
|
|
1258
|
+
if (!isVertical && !isHorizontal) continue;
|
|
1259
|
+
if (isVertical) {
|
|
1195
1260
|
start.x += offset;
|
|
1196
|
-
appliedX.add(si);
|
|
1197
|
-
}
|
|
1198
|
-
if (!appliedX.has(si + 1)) {
|
|
1199
1261
|
end.x += offset;
|
|
1200
|
-
|
|
1201
|
-
}
|
|
1202
|
-
} else if (isHorizontal) {
|
|
1203
|
-
if (!appliedY.has(si)) {
|
|
1262
|
+
} else {
|
|
1204
1263
|
start.y += offset;
|
|
1205
|
-
appliedY.add(si);
|
|
1206
|
-
}
|
|
1207
|
-
if (!appliedY.has(si + 1)) {
|
|
1208
1264
|
end.y += offset;
|
|
1209
|
-
appliedY.add(si + 1);
|
|
1210
1265
|
}
|
|
1211
1266
|
}
|
|
1212
1267
|
}
|
|
@@ -1295,7 +1350,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1295
1350
|
return islands;
|
|
1296
1351
|
}
|
|
1297
1352
|
findNextOverlapIssue() {
|
|
1298
|
-
const EPS2 =
|
|
1353
|
+
const EPS2 = 2e-3;
|
|
1299
1354
|
const netIds = Object.keys(this.traceNetIslands);
|
|
1300
1355
|
for (let i = 0; i < netIds.length; i++) {
|
|
1301
1356
|
for (let j = i + 1; j < netIds.length; j++) {
|
|
@@ -1494,10 +1549,11 @@ function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex)
|
|
|
1494
1549
|
const pts = solved.tracePath;
|
|
1495
1550
|
for (let i = 0; i < pts.length - 1; i++) {
|
|
1496
1551
|
if (pairId === hostPathId && i === hostSegIndex) continue;
|
|
1497
|
-
if (segmentIntersectsRect(pts[i], pts[i + 1], bounds))
|
|
1552
|
+
if (segmentIntersectsRect(pts[i], pts[i + 1], bounds))
|
|
1553
|
+
return { hasIntersection: true, mspPairId: pairId, segIndex: i };
|
|
1498
1554
|
}
|
|
1499
1555
|
}
|
|
1500
|
-
return false;
|
|
1556
|
+
return { hasIntersection: false };
|
|
1501
1557
|
}
|
|
1502
1558
|
|
|
1503
1559
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/host.ts
|
|
@@ -1582,14 +1638,16 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1582
1638
|
};
|
|
1583
1639
|
}
|
|
1584
1640
|
let pin = null;
|
|
1641
|
+
let pinFacingDirection = null;
|
|
1585
1642
|
for (const chip of inputProblem.chips) {
|
|
1586
1643
|
const p = chip.pins.find((pp) => pp.pinId === pinId);
|
|
1587
1644
|
if (p) {
|
|
1588
1645
|
pin = { x: p.x, y: p.y };
|
|
1646
|
+
pinFacingDirection = p._facingDirection || getPinDirection(p, chip);
|
|
1589
1647
|
break;
|
|
1590
1648
|
}
|
|
1591
1649
|
}
|
|
1592
|
-
if (!pin) {
|
|
1650
|
+
if (!pin || !pinFacingDirection) {
|
|
1593
1651
|
return {
|
|
1594
1652
|
placement: null,
|
|
1595
1653
|
testedCandidates: [],
|
|
@@ -1601,21 +1659,21 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1601
1659
|
const outwardOf = (o) => o === "x+" ? { x: 1, y: 0 } : o === "x-" ? { x: -1, y: 0 } : o === "y+" ? { x: 0, y: 1 } : { x: 0, y: -1 };
|
|
1602
1660
|
const testedCandidates = [];
|
|
1603
1661
|
for (const orientation of orientations) {
|
|
1604
|
-
const { width, height } = getDimsForOrientation(orientation);
|
|
1605
|
-
const
|
|
1606
|
-
const
|
|
1607
|
-
const
|
|
1662
|
+
const { width: width2, height: height2 } = getDimsForOrientation(orientation);
|
|
1663
|
+
const baseCenter2 = getCenterFromAnchor(anchor, orientation, width2, height2);
|
|
1664
|
+
const outward2 = outwardOf(orientation);
|
|
1665
|
+
const offset2 = 1e-3;
|
|
1608
1666
|
const center = {
|
|
1609
|
-
x:
|
|
1610
|
-
y:
|
|
1667
|
+
x: baseCenter2.x + outward2.x * offset2,
|
|
1668
|
+
y: baseCenter2.y + outward2.y * offset2
|
|
1611
1669
|
};
|
|
1612
|
-
const bounds = getRectBounds(center,
|
|
1670
|
+
const bounds = getRectBounds(center, width2, height2);
|
|
1613
1671
|
const chips = chipObstacleSpatialIndex.getChipsInBounds(bounds);
|
|
1614
1672
|
if (chips.length > 0) {
|
|
1615
1673
|
testedCandidates.push({
|
|
1616
1674
|
center,
|
|
1617
|
-
width,
|
|
1618
|
-
height,
|
|
1675
|
+
width: width2,
|
|
1676
|
+
height: height2,
|
|
1619
1677
|
bounds,
|
|
1620
1678
|
anchor,
|
|
1621
1679
|
orientation,
|
|
@@ -1624,16 +1682,17 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1624
1682
|
});
|
|
1625
1683
|
continue;
|
|
1626
1684
|
}
|
|
1627
|
-
|
|
1685
|
+
const traceIntersectionResult = rectIntersectsAnyTrace(
|
|
1628
1686
|
bounds,
|
|
1629
1687
|
inputTraceMap,
|
|
1630
1688
|
"",
|
|
1631
1689
|
-1
|
|
1632
|
-
)
|
|
1690
|
+
);
|
|
1691
|
+
if (traceIntersectionResult.hasIntersection) {
|
|
1633
1692
|
testedCandidates.push({
|
|
1634
1693
|
center,
|
|
1635
|
-
width,
|
|
1636
|
-
height,
|
|
1694
|
+
width: width2,
|
|
1695
|
+
height: height2,
|
|
1637
1696
|
bounds,
|
|
1638
1697
|
anchor,
|
|
1639
1698
|
orientation,
|
|
@@ -1644,8 +1703,8 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1644
1703
|
}
|
|
1645
1704
|
testedCandidates.push({
|
|
1646
1705
|
center,
|
|
1647
|
-
width,
|
|
1648
|
-
height,
|
|
1706
|
+
width: width2,
|
|
1707
|
+
height: height2,
|
|
1649
1708
|
bounds,
|
|
1650
1709
|
anchor,
|
|
1651
1710
|
orientation,
|
|
@@ -1660,17 +1719,39 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1660
1719
|
pinIds: [pinId],
|
|
1661
1720
|
orientation,
|
|
1662
1721
|
anchorPoint: anchor,
|
|
1663
|
-
width,
|
|
1664
|
-
height,
|
|
1722
|
+
width: width2,
|
|
1723
|
+
height: height2,
|
|
1665
1724
|
center
|
|
1666
1725
|
};
|
|
1667
1726
|
return { placement, testedCandidates };
|
|
1668
1727
|
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1728
|
+
const fallbackOrientation = pinFacingDirection;
|
|
1729
|
+
const { width, height } = getDimsForOrientation(fallbackOrientation);
|
|
1730
|
+
const baseCenter = getCenterFromAnchor(
|
|
1731
|
+
anchor,
|
|
1732
|
+
fallbackOrientation,
|
|
1733
|
+
width,
|
|
1734
|
+
height
|
|
1735
|
+
);
|
|
1736
|
+
const outward = outwardOf(fallbackOrientation);
|
|
1737
|
+
const offset = 1e-3;
|
|
1738
|
+
const fallbackCenter = {
|
|
1739
|
+
x: baseCenter.x + outward.x * offset,
|
|
1740
|
+
y: baseCenter.y + outward.y * offset
|
|
1741
|
+
};
|
|
1742
|
+
const fallbackPlacement = {
|
|
1743
|
+
globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
|
|
1744
|
+
dcConnNetId: void 0,
|
|
1745
|
+
netId: overlappingSameNetTraceGroup.netId,
|
|
1746
|
+
mspConnectionPairIds: [],
|
|
1747
|
+
pinIds: [pinId],
|
|
1748
|
+
orientation: fallbackOrientation,
|
|
1749
|
+
anchorPoint: anchor,
|
|
1750
|
+
width,
|
|
1751
|
+
height,
|
|
1752
|
+
center: fallbackCenter
|
|
1673
1753
|
};
|
|
1754
|
+
return { placement: fallbackPlacement, testedCandidates };
|
|
1674
1755
|
}
|
|
1675
1756
|
|
|
1676
1757
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver_visualize.ts
|
|
@@ -1686,12 +1767,11 @@ function visualizeSingleNetLabelPlacementSolver(solver) {
|
|
|
1686
1767
|
const groupStroke = getColorFromString(groupId, 0.9);
|
|
1687
1768
|
const groupFill = getColorFromString(groupId, 0.5);
|
|
1688
1769
|
for (const trace of Object.values(solver.inputTraceMap)) {
|
|
1689
|
-
if (trace.globalConnNetId !== groupId) continue;
|
|
1690
1770
|
const isHost = host ? trace.mspPairId === host.mspPairId : false;
|
|
1691
1771
|
graphics.lines.push({
|
|
1692
|
-
points: trace.tracePath
|
|
1693
|
-
strokeColor: isHost ? groupStroke : groupFill,
|
|
1694
|
-
strokeDash: isHost ?
|
|
1772
|
+
points: trace.tracePath
|
|
1773
|
+
// strokeColor: isHost ? groupStroke : groupFill,
|
|
1774
|
+
// strokeDash: isHost ? undefined : "4 2",
|
|
1695
1775
|
});
|
|
1696
1776
|
}
|
|
1697
1777
|
for (const c of solver.testedCandidates) {
|
|
@@ -1863,12 +1943,13 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1863
1943
|
});
|
|
1864
1944
|
continue;
|
|
1865
1945
|
}
|
|
1866
|
-
|
|
1946
|
+
const traceIntersectionResult = rectIntersectsAnyTrace(
|
|
1867
1947
|
bounds,
|
|
1868
1948
|
this.inputTraceMap,
|
|
1869
1949
|
curr.mspPairId,
|
|
1870
1950
|
si
|
|
1871
|
-
)
|
|
1951
|
+
);
|
|
1952
|
+
if (traceIntersectionResult.hasIntersection) {
|
|
1872
1953
|
this.testedCandidates.push({
|
|
1873
1954
|
center: testCenter,
|
|
1874
1955
|
width,
|
|
@@ -261,14 +261,13 @@ export class SingleNetLabelPlacementSolver extends BaseSolver {
|
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
// Trace collision check (ignore the host segment)
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
) {
|
|
264
|
+
const traceIntersectionResult = rectIntersectsAnyTrace(
|
|
265
|
+
bounds,
|
|
266
|
+
this.inputTraceMap,
|
|
267
|
+
curr.mspPairId,
|
|
268
|
+
si,
|
|
269
|
+
)
|
|
270
|
+
if (traceIntersectionResult.hasIntersection) {
|
|
272
271
|
this.testedCandidates.push({
|
|
273
272
|
center: testCenter,
|
|
274
273
|
width,
|
|
@@ -21,12 +21,11 @@ export function visualizeSingleNetLabelPlacementSolver(
|
|
|
21
21
|
const groupFill = getColorFromString(groupId, 0.5)
|
|
22
22
|
|
|
23
23
|
for (const trace of Object.values(solver.inputTraceMap)) {
|
|
24
|
-
if (trace.globalConnNetId !== groupId) continue
|
|
25
24
|
const isHost = host ? trace.mspPairId === host.mspPairId : false
|
|
26
25
|
graphics.lines!.push({
|
|
27
26
|
points: trace.tracePath,
|
|
28
|
-
strokeColor: isHost ? groupStroke : groupFill,
|
|
29
|
-
strokeDash: isHost ? undefined : "4 2",
|
|
27
|
+
// strokeColor: isHost ? groupStroke : groupFill,
|
|
28
|
+
// strokeDash: isHost ? undefined : "4 2",
|
|
30
29
|
} as any)
|
|
31
30
|
}
|
|
32
31
|
|
|
@@ -33,13 +33,20 @@ export function rectIntersectsAnyTrace(
|
|
|
33
33
|
inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>,
|
|
34
34
|
hostPathId?: MspConnectionPairId,
|
|
35
35
|
hostSegIndex?: number,
|
|
36
|
-
):
|
|
36
|
+
):
|
|
37
|
+
| {
|
|
38
|
+
hasIntersection: true
|
|
39
|
+
mspPairId: MspConnectionPairId
|
|
40
|
+
segIndex: number
|
|
41
|
+
}
|
|
42
|
+
| { hasIntersection: false } {
|
|
37
43
|
for (const [pairId, solved] of Object.entries(inputTraceMap)) {
|
|
38
44
|
const pts = solved.tracePath
|
|
39
45
|
for (let i = 0; i < pts.length - 1; i++) {
|
|
40
46
|
if (pairId === hostPathId && i === hostSegIndex) continue
|
|
41
|
-
if (segmentIntersectsRect(pts[i]!, pts[i + 1]!, bounds))
|
|
47
|
+
if (segmentIntersectsRect(pts[i]!, pts[i + 1]!, bounds))
|
|
48
|
+
return { hasIntersection: true, mspPairId: pairId, segIndex: i }
|
|
42
49
|
}
|
|
43
50
|
}
|
|
44
|
-
return false
|
|
51
|
+
return { hasIntersection: false }
|
|
45
52
|
}
|
package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { MspConnectionPairId } from "lib/solvers/MspConnectionPairSolver/Ms
|
|
|
3
3
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
4
|
import type { FacingDirection } from "lib/utils/dir"
|
|
5
5
|
import { ChipObstacleSpatialIndex } from "lib/data-structures/ChipObstacleSpatialIndex"
|
|
6
|
+
import { getPinDirection } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getPinDirection"
|
|
6
7
|
import type {
|
|
7
8
|
NetLabelPlacement,
|
|
8
9
|
OverlappingSameNetTraceGroup,
|
|
@@ -51,16 +52,18 @@ export function solveNetLabelPlacementForPortOnlyPin(params: {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
// Find pin coordinates
|
|
55
|
+
// Find pin coordinates and facing direction
|
|
55
56
|
let pin: { x: number; y: number } | null = null
|
|
57
|
+
let pinFacingDirection: FacingDirection | null = null
|
|
56
58
|
for (const chip of inputProblem.chips) {
|
|
57
59
|
const p = chip.pins.find((pp) => pp.pinId === pinId)
|
|
58
60
|
if (p) {
|
|
59
61
|
pin = { x: p.x, y: p.y }
|
|
62
|
+
pinFacingDirection = p._facingDirection || getPinDirection(p, chip)
|
|
60
63
|
break
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
|
-
if (!pin) {
|
|
66
|
+
if (!pin || !pinFacingDirection) {
|
|
64
67
|
return {
|
|
65
68
|
placement: null,
|
|
66
69
|
testedCandidates: [],
|
|
@@ -123,14 +126,13 @@ export function solveNetLabelPlacementForPortOnlyPin(params: {
|
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
// Trace collision check
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
) {
|
|
129
|
+
const traceIntersectionResult = rectIntersectsAnyTrace(
|
|
130
|
+
bounds,
|
|
131
|
+
inputTraceMap,
|
|
132
|
+
"" as MspConnectionPairId,
|
|
133
|
+
-1,
|
|
134
|
+
)
|
|
135
|
+
if (traceIntersectionResult.hasIntersection) {
|
|
134
136
|
testedCandidates.push({
|
|
135
137
|
center,
|
|
136
138
|
width,
|
|
@@ -172,9 +174,34 @@ export function solveNetLabelPlacementForPortOnlyPin(params: {
|
|
|
172
174
|
return { placement, testedCandidates }
|
|
173
175
|
}
|
|
174
176
|
|
|
175
|
-
return
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
// If no valid placements found, return placement using pin's facing direction
|
|
178
|
+
const fallbackOrientation = pinFacingDirection
|
|
179
|
+
const { width, height } = getDimsForOrientation(fallbackOrientation)
|
|
180
|
+
const baseCenter = getCenterFromAnchor(
|
|
181
|
+
anchor,
|
|
182
|
+
fallbackOrientation,
|
|
183
|
+
width,
|
|
184
|
+
height,
|
|
185
|
+
)
|
|
186
|
+
const outward = outwardOf(fallbackOrientation)
|
|
187
|
+
const offset = 1e-3
|
|
188
|
+
const fallbackCenter = {
|
|
189
|
+
x: baseCenter.x + outward.x * offset,
|
|
190
|
+
y: baseCenter.y + outward.y * offset,
|
|
179
191
|
}
|
|
192
|
+
|
|
193
|
+
const fallbackPlacement: NetLabelPlacement = {
|
|
194
|
+
globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
|
|
195
|
+
dcConnNetId: undefined,
|
|
196
|
+
netId: overlappingSameNetTraceGroup.netId,
|
|
197
|
+
mspConnectionPairIds: [],
|
|
198
|
+
pinIds: [pinId],
|
|
199
|
+
orientation: fallbackOrientation,
|
|
200
|
+
anchorPoint: anchor,
|
|
201
|
+
width,
|
|
202
|
+
height,
|
|
203
|
+
center: fallbackCenter,
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return { placement: fallbackPlacement, testedCandidates }
|
|
180
207
|
}
|
package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { GraphicsObject } from "graphics-debug"
|
|
|
2
2
|
import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
|
|
3
3
|
import type { MspConnectionPairId } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
|
|
4
4
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
5
|
+
import { applyJogToTerminalSegment } from "./applyJogToTrace"
|
|
5
6
|
|
|
6
7
|
type ConnNetId = string
|
|
7
8
|
|
|
@@ -83,38 +84,39 @@ export class TraceOverlapIssueSolver extends BaseSolver {
|
|
|
83
84
|
|
|
84
85
|
const segIdxs = Array.from(segIdxSet).sort((a, b) => a - b)
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
const segIdxsRev = Array.from(segIdxSet)
|
|
88
|
+
.sort((a, b) => a - b)
|
|
89
|
+
.reverse()
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
if (si < 0 || si >= pts.length - 1) continue
|
|
92
|
-
// Do not move the first or last segment since they connect directly to pins
|
|
93
|
-
if (si === 0 || si === pts.length - 2) continue
|
|
94
|
-
const start = pts[si]!
|
|
95
|
-
const end = pts[si + 1]!
|
|
96
|
-
const isVertical = Math.abs(start.x - end.x) < EPS
|
|
97
|
-
const isHorizontal = Math.abs(start.y - end.y) < EPS
|
|
91
|
+
const JOG_SIZE = this.SHIFT_DISTANCE
|
|
98
92
|
|
|
99
|
-
|
|
93
|
+
// Process from end to start to keep indices valid after splicing
|
|
94
|
+
for (const si of segIdxsRev) {
|
|
95
|
+
if (si < 0 || si >= pts.length - 1) continue
|
|
100
96
|
|
|
101
|
-
if (
|
|
102
|
-
|
|
97
|
+
if (si === 0 || si === pts.length - 2) {
|
|
98
|
+
applyJogToTerminalSegment({
|
|
99
|
+
pts,
|
|
100
|
+
segmentIndex: si,
|
|
101
|
+
offset,
|
|
102
|
+
JOG_SIZE,
|
|
103
|
+
EPS,
|
|
104
|
+
})
|
|
105
|
+
} else {
|
|
106
|
+
// Internal segment - shift both points
|
|
107
|
+
const start = pts[si]!
|
|
108
|
+
const end = pts[si + 1]!
|
|
109
|
+
const isVertical = Math.abs(start.x - end.x) < EPS
|
|
110
|
+
const isHorizontal = Math.abs(start.y - end.y) < EPS
|
|
111
|
+
if (!isVertical && !isHorizontal) continue
|
|
112
|
+
|
|
113
|
+
if (isVertical) {
|
|
103
114
|
start.x += offset
|
|
104
|
-
appliedX.add(si)
|
|
105
|
-
}
|
|
106
|
-
if (!appliedX.has(si + 1)) {
|
|
107
115
|
end.x += offset
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
} else if (isHorizontal) {
|
|
111
|
-
if (!appliedY.has(si)) {
|
|
116
|
+
} else {
|
|
117
|
+
// Horizontal
|
|
112
118
|
start.y += offset
|
|
113
|
-
appliedY.add(si)
|
|
114
|
-
}
|
|
115
|
-
if (!appliedY.has(si + 1)) {
|
|
116
119
|
end.y += offset
|
|
117
|
-
appliedY.add(si + 1)
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
122
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
2
|
+
|
|
3
|
+
export const applyJogToTerminalSegment = ({
|
|
4
|
+
pts,
|
|
5
|
+
segmentIndex: si,
|
|
6
|
+
offset,
|
|
7
|
+
JOG_SIZE,
|
|
8
|
+
EPS = 1e-6,
|
|
9
|
+
}: {
|
|
10
|
+
pts: Point[]
|
|
11
|
+
segmentIndex: number
|
|
12
|
+
offset: number
|
|
13
|
+
JOG_SIZE: number
|
|
14
|
+
EPS?: number
|
|
15
|
+
}) => {
|
|
16
|
+
if (si !== 0 && si !== pts.length - 2) return
|
|
17
|
+
|
|
18
|
+
const start = pts[si]!
|
|
19
|
+
const end = pts[si + 1]!
|
|
20
|
+
const isVertical = Math.abs(start.x - end.x) < EPS
|
|
21
|
+
const isHorizontal = Math.abs(start.y - end.y) < EPS
|
|
22
|
+
if (!isVertical && !isHorizontal) return
|
|
23
|
+
|
|
24
|
+
const segDir = isVertical
|
|
25
|
+
? end.y > start.y
|
|
26
|
+
? 1
|
|
27
|
+
: -1
|
|
28
|
+
: end.x > start.x
|
|
29
|
+
? 1
|
|
30
|
+
: -1
|
|
31
|
+
|
|
32
|
+
if (si === 0) {
|
|
33
|
+
if (isVertical) {
|
|
34
|
+
const jogY = start.y + segDir * JOG_SIZE
|
|
35
|
+
pts.splice(
|
|
36
|
+
1,
|
|
37
|
+
1,
|
|
38
|
+
{ x: start.x, y: jogY },
|
|
39
|
+
{ x: start.x + offset, y: jogY },
|
|
40
|
+
{ x: end.x + offset, y: end.y },
|
|
41
|
+
)
|
|
42
|
+
} else {
|
|
43
|
+
// Horizontal
|
|
44
|
+
const jogX = start.x + segDir * JOG_SIZE
|
|
45
|
+
pts.splice(
|
|
46
|
+
1,
|
|
47
|
+
1,
|
|
48
|
+
{ x: jogX, y: start.y },
|
|
49
|
+
{ x: jogX, y: start.y + offset },
|
|
50
|
+
{ x: end.x, y: end.y + offset },
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
// si === pts.length - 2
|
|
55
|
+
if (isVertical) {
|
|
56
|
+
const jogY = end.y - segDir * JOG_SIZE
|
|
57
|
+
pts.splice(
|
|
58
|
+
si,
|
|
59
|
+
1,
|
|
60
|
+
{ x: start.x + offset, y: start.y },
|
|
61
|
+
{ x: end.x + offset, y: jogY },
|
|
62
|
+
{ x: end.x, y: jogY },
|
|
63
|
+
)
|
|
64
|
+
} else {
|
|
65
|
+
// Horizontal
|
|
66
|
+
const jogX = end.x - segDir * JOG_SIZE
|
|
67
|
+
pts.splice(
|
|
68
|
+
si,
|
|
69
|
+
1,
|
|
70
|
+
{ x: start.x, y: start.y + offset },
|
|
71
|
+
{ x: jogX, y: end.y + offset },
|
|
72
|
+
{ x: jogX, y: end.y },
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -89,7 +89,7 @@ export class TraceOverlapShiftSolver extends BaseSolver {
|
|
|
89
89
|
overlappingTraceSegments: Array<OverlappingTraceSegmentLocator>
|
|
90
90
|
} | null {
|
|
91
91
|
// Detect the next set of overlapping segments between two different net islands.
|
|
92
|
-
const EPS =
|
|
92
|
+
const EPS = 2e-3
|
|
93
93
|
|
|
94
94
|
const netIds = Object.keys(this.traceNetIslands)
|
|
95
95
|
// Compare each pair of different nets
|
package/package.json
CHANGED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { GenericSolverDebugger } from "site/components/GenericSolverDebugger"
|
|
2
|
+
import { useMemo } from "react"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import { SchematicTracePipelineSolver } from "lib/index"
|
|
5
|
+
|
|
6
|
+
const inputProblem = {
|
|
7
|
+
chips: [
|
|
8
|
+
{
|
|
9
|
+
chipId: "schematic_component_0",
|
|
10
|
+
center: {
|
|
11
|
+
x: 0,
|
|
12
|
+
y: 0,
|
|
13
|
+
},
|
|
14
|
+
width: 0.4,
|
|
15
|
+
height: 0.8,
|
|
16
|
+
pins: [
|
|
17
|
+
{
|
|
18
|
+
pinId: "U1.6",
|
|
19
|
+
x: 0.6000000000000001,
|
|
20
|
+
y: -0.2,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pinId: "U1.8",
|
|
24
|
+
x: 0.6000000000000001,
|
|
25
|
+
y: 0,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pinId: "U1.1",
|
|
29
|
+
x: 0.6000000000000001,
|
|
30
|
+
y: 0.2,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
chipId: "schematic_component_1",
|
|
36
|
+
center: {
|
|
37
|
+
x: 1.4,
|
|
38
|
+
y: 0.55,
|
|
39
|
+
},
|
|
40
|
+
width: 0.5291665999999999,
|
|
41
|
+
height: 1.0583333000000001,
|
|
42
|
+
pins: [
|
|
43
|
+
{
|
|
44
|
+
pinId: "C2.1",
|
|
45
|
+
x: 1.4002733499999995,
|
|
46
|
+
y: -0.0012093000000001908,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
pinId: "C2.2",
|
|
50
|
+
x: 1.3997266500000003,
|
|
51
|
+
y: 1.1012093000000003,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
chipId: "schematic_component_2",
|
|
57
|
+
center: {
|
|
58
|
+
x: 2.7,
|
|
59
|
+
y: 1.3,
|
|
60
|
+
},
|
|
61
|
+
width: 1.0583332999999997,
|
|
62
|
+
height: 0.388910699999999,
|
|
63
|
+
pins: [
|
|
64
|
+
{
|
|
65
|
+
pinId: "R1.1",
|
|
66
|
+
x: 2.1487093,
|
|
67
|
+
y: 1.3002732499999994,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
pinId: "R1.2",
|
|
71
|
+
x: 3.2512907000000006,
|
|
72
|
+
y: 1.2997267500000007,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
chipId: "schematic_component_3",
|
|
78
|
+
center: {
|
|
79
|
+
x: 4.4,
|
|
80
|
+
y: 0,
|
|
81
|
+
},
|
|
82
|
+
width: 0.4,
|
|
83
|
+
height: 0.4,
|
|
84
|
+
pins: [
|
|
85
|
+
{
|
|
86
|
+
pinId: "JP5.1",
|
|
87
|
+
x: 3.8000000000000003,
|
|
88
|
+
y: 0,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
chipId: "schematic_component_4",
|
|
94
|
+
center: {
|
|
95
|
+
x: 4.4,
|
|
96
|
+
y: -0.9,
|
|
97
|
+
},
|
|
98
|
+
width: 0.4,
|
|
99
|
+
height: 0.4,
|
|
100
|
+
pins: [
|
|
101
|
+
{
|
|
102
|
+
pinId: "JP9.1",
|
|
103
|
+
x: 3.8000000000000003,
|
|
104
|
+
y: -0.9,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
chipId: "schematic_component_5",
|
|
110
|
+
center: {
|
|
111
|
+
x: 2,
|
|
112
|
+
y: -1.1,
|
|
113
|
+
},
|
|
114
|
+
width: 0.8843008999999997,
|
|
115
|
+
height: 0.5299361999999987,
|
|
116
|
+
pins: [
|
|
117
|
+
{
|
|
118
|
+
pinId: "JP8.1",
|
|
119
|
+
x: 2.4458007999999998,
|
|
120
|
+
y: -1.2015872704999997,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
pinId: "JP8.2",
|
|
124
|
+
x: 2.0034928,
|
|
125
|
+
y: -0.8474009705000005,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
pinId: "JP8.3",
|
|
129
|
+
x: 1.5541992,
|
|
130
|
+
y: -1.2014628704999997,
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
directConnections: [
|
|
136
|
+
{
|
|
137
|
+
pinIds: ["C2.1", "U1.8"],
|
|
138
|
+
netId: "capacitor.C2 > port.pin1 to .U1 > .pin8",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
pinIds: ["C2.2", "R1.1"],
|
|
142
|
+
netId: "capacitor.C2 > port.pin2 to .R1 > .pin1",
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
pinIds: ["R1.1", "U1.1"],
|
|
146
|
+
netId: "resistor.R1 > port.pin1 to .U1 > .pin1",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
pinIds: ["JP5.1", "R1.2"],
|
|
150
|
+
netId: "pinheader.JP5 > port.pin1 to .R1 > .pin2",
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
pinIds: ["JP9.1", "R1.2"],
|
|
154
|
+
netId: "pinheader.JP9 > port.pin1 to .R1 > .pin2",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
pinIds: ["JP8.2", "U1.6"],
|
|
158
|
+
netId: "solderjumper.JP8 > port.pin2 to .U1 > .pin6",
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
netConnections: [
|
|
162
|
+
{
|
|
163
|
+
netId: "PAD",
|
|
164
|
+
pinIds: ["R1.2", "JP5.1", "JP9.1"],
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
availableNetLabelOrientations: {},
|
|
168
|
+
maxMspPairDistance: 5,
|
|
169
|
+
} as InputProblem
|
|
170
|
+
|
|
171
|
+
export default () => {
|
|
172
|
+
const solver = useMemo(
|
|
173
|
+
() => new SchematicTracePipelineSolver(inputProblem),
|
|
174
|
+
[],
|
|
175
|
+
)
|
|
176
|
+
return <GenericSolverDebugger solver={solver} />
|
|
177
|
+
}
|
|
@@ -70,7 +70,7 @@ x+" data-x="1.48" data-y="-0.665" cx="516.9811320754716" cy="426.7924528301886"
|
|
|
70
70
|
<polyline data-points="0.5800000000000001,-0.665 0.1,-0.665 0.1,0.1 -1.6800000000000002,0.1 -1.6800000000000002,0.765 -1.58,0.765" data-type="line" data-label="" points="381.1320754716981,426.7924528301886 308.6792452830188,426.7924528301886 308.6792452830188,311.3207547169811 39.99999999999997,311.3207547169811 39.99999999999997,210.94339622641508 55.09433962264151,210.94339622641508" fill="none" stroke="purple" stroke-width="1" />
|
|
71
71
|
</g>
|
|
72
72
|
<g>
|
|
73
|
-
<polyline data-points="1.48,-0.665 1.78,-0.665 1.78,0.03527232500000027 0,0.03527232500000027 0,0.765 -0.48,0.765" data-type="line" data-label="" points="516.9811320754716,426.7924528301886 562.2641509433961,426.7924528301886 562.2641509433961,321.0909698113207 293.58490566037733,321.0909698113207 293.58490566037733,210.94339622641508 221.1320754716981,210.94339622641508" fill="none" stroke="purple" stroke-width="1" />
|
|
73
|
+
<polyline data-points="1.48,-0.665 1.78,-0.665 1.78,0.03527232500000027 0,0.03527232500000027 0,0.865 -0.38,0.865 -0.38,0.765 -0.48,0.765" data-type="line" data-label="" points="516.9811320754716,426.7924528301886 562.2641509433961,426.7924528301886 562.2641509433961,321.0909698113207 293.58490566037733,321.0909698113207 293.58490566037733,195.84905660377356 236.2264150943396,195.84905660377356 236.2264150943396,210.94339622641508 221.1320754716981,210.94339622641508" fill="none" stroke="purple" stroke-width="1" />
|
|
74
74
|
</g>
|
|
75
75
|
<g>
|
|
76
76
|
<rect data-type="rect" data-label="schematic_component_0" data-x="-1.03" data-y="0.765" x="55.09433962264151" y="181.59164528301895" width="166.0377358490566" height="58.70350188679228" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006625000000000001" />
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="100%" height="100%" fill="white" />
|
|
3
|
+
<g>
|
|
4
|
+
<circle data-type="point" data-label="U1.6
|
|
5
|
+
x+" data-x="0.6000000000000001" data-y="-0.2" cx="160.00000000000003" cy="359.23793250000006" r="3" fill="hsl(324, 100%, 50%, 0.8)" />
|
|
6
|
+
</g>
|
|
7
|
+
<g>
|
|
8
|
+
<circle data-type="point" data-label="U1.8
|
|
9
|
+
x+" data-x="0.6000000000000001" data-y="0" cx="160.00000000000003" cy="339.23793250000006" r="3" fill="hsl(326, 100%, 50%, 0.8)" />
|
|
10
|
+
</g>
|
|
11
|
+
<g>
|
|
12
|
+
<circle data-type="point" data-label="U1.1
|
|
13
|
+
x+" data-x="0.6000000000000001" data-y="0.2" cx="160.00000000000003" cy="319.23793250000006" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
|
|
14
|
+
</g>
|
|
15
|
+
<g>
|
|
16
|
+
<circle data-type="point" data-label="C2.1
|
|
17
|
+
y-" data-x="1.4002733499999995" data-y="-0.0012093000000001908" cx="240.027335" cy="339.3588625000001" r="3" fill="hsl(2, 100%, 50%, 0.8)" />
|
|
18
|
+
</g>
|
|
19
|
+
<g>
|
|
20
|
+
<circle data-type="point" data-label="C2.2
|
|
21
|
+
y+" data-x="1.3997266500000003" data-y="1.1012093000000003" cx="239.97266500000006" cy="229.1170025" r="3" fill="hsl(3, 100%, 50%, 0.8)" />
|
|
22
|
+
</g>
|
|
23
|
+
<g>
|
|
24
|
+
<circle data-type="point" data-label="R1.1
|
|
25
|
+
x-" data-x="2.1487092999999997" data-y="1.3002732499999994" cx="314.87093" cy="209.21060750000012" r="3" fill="hsl(226, 100%, 50%, 0.8)" />
|
|
26
|
+
</g>
|
|
27
|
+
<g>
|
|
28
|
+
<circle data-type="point" data-label="R1.2
|
|
29
|
+
x+" data-x="3.2512907000000006" data-y="1.2997267500000007" cx="425.12907000000007" cy="209.2652575" r="3" fill="hsl(227, 100%, 50%, 0.8)" />
|
|
30
|
+
</g>
|
|
31
|
+
<g>
|
|
32
|
+
<circle data-type="point" data-label="JP5.1
|
|
33
|
+
x-" data-x="3.8000000000000003" data-y="0" cx="480" cy="339.23793250000006" r="3" fill="hsl(242, 100%, 50%, 0.8)" />
|
|
34
|
+
</g>
|
|
35
|
+
<g>
|
|
36
|
+
<circle data-type="point" data-label="JP9.1
|
|
37
|
+
x-" data-x="3.8000000000000003" data-y="-0.9" cx="480" cy="429.23793250000006" r="3" fill="hsl(126, 100%, 50%, 0.8)" />
|
|
38
|
+
</g>
|
|
39
|
+
<g>
|
|
40
|
+
<circle data-type="point" data-label="JP8.1
|
|
41
|
+
x+" data-x="2.4458007999999998" data-y="-1.2015872704999997" cx="344.58008" cy="459.39665955000004" r="3" fill="hsl(245, 100%, 50%, 0.8)" />
|
|
42
|
+
</g>
|
|
43
|
+
<g>
|
|
44
|
+
<circle data-type="point" data-label="JP8.2
|
|
45
|
+
y+" data-x="2.0034928" data-y="-0.8350319000000007" cx="300.34928" cy="422.74112250000013" r="3" fill="hsl(246, 100%, 50%, 0.8)" />
|
|
46
|
+
</g>
|
|
47
|
+
<g>
|
|
48
|
+
<circle data-type="point" data-label="JP8.3
|
|
49
|
+
x-" data-x="1.5541992" data-y="-1.2014628704999997" cx="255.41992000000002" cy="459.38421955" r="3" fill="hsl(247, 100%, 50%, 0.8)" />
|
|
50
|
+
</g>
|
|
51
|
+
<g>
|
|
52
|
+
<circle data-type="point" data-label="" data-x="1.4002733499999995" data-y="-0.30120930000000024" cx="240.027335" cy="369.3588625000001" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
53
|
+
</g>
|
|
54
|
+
<g>
|
|
55
|
+
<circle data-type="point" data-label="" data-x="0.733854175" data-y="0.2" cx="173.38541750000002" cy="319.23793250000006" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
56
|
+
</g>
|
|
57
|
+
<g>
|
|
58
|
+
<circle data-type="point" data-label="" data-x="3.451290700000001" data-y="1.2997267500000007" cx="445.12907000000007" cy="209.2652575" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
59
|
+
</g>
|
|
60
|
+
<g>
|
|
61
|
+
<circle data-type="point" data-label="" data-x="2.0034928" data-y="-0.46751595000000035" cx="300.34928" cy="385.9895275000001" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
62
|
+
</g>
|
|
63
|
+
<g>
|
|
64
|
+
<polyline data-points="1.4002733499999995,-0.0012093000000001908 0.6000000000000001,0" data-type="line" data-label="" points="240.027335,339.3588625000001 160.00000000000003,339.23793250000006" fill="none" stroke="hsl(256, 100%, 50%, 0.8)" stroke-width="1" />
|
|
65
|
+
</g>
|
|
66
|
+
<g>
|
|
67
|
+
<polyline data-points="1.3997266500000003,1.1012093000000003 2.1487092999999997,1.3002732499999994" data-type="line" data-label="" points="239.97266500000006,229.1170025 314.87093,209.21060750000012" fill="none" stroke="hsl(256, 100%, 50%, 0.8)" stroke-width="1" />
|
|
68
|
+
</g>
|
|
69
|
+
<g>
|
|
70
|
+
<polyline data-points="2.1487092999999997,1.3002732499999994 0.6000000000000001,0.2" data-type="line" data-label="" points="314.87093,209.21060750000012 160.00000000000003,319.23793250000006" fill="none" stroke="hsl(280, 100%, 50%, 0.8)" stroke-width="1" />
|
|
71
|
+
</g>
|
|
72
|
+
<g>
|
|
73
|
+
<polyline data-points="3.8000000000000003,0 3.2512907000000006,1.2997267500000007" data-type="line" data-label="" points="480,339.23793250000006 425.12907000000007,209.2652575" fill="none" stroke="hsl(336, 100%, 50%, 0.8)" stroke-width="1" />
|
|
74
|
+
</g>
|
|
75
|
+
<g>
|
|
76
|
+
<polyline data-points="3.8000000000000003,-0.9 3.2512907000000006,1.2997267500000007" data-type="line" data-label="" points="480,429.23793250000006 425.12907000000007,209.2652575" fill="none" stroke="hsl(336, 100%, 50%, 0.8)" stroke-width="1" />
|
|
77
|
+
</g>
|
|
78
|
+
<g>
|
|
79
|
+
<polyline data-points="2.0034928,-0.8350319000000007 0.6000000000000001,-0.2" data-type="line" data-label="" points="300.34928,422.74112250000013 160.00000000000003,359.23793250000006" fill="none" stroke="hsl(352, 100%, 50%, 0.8)" stroke-width="1" />
|
|
80
|
+
</g>
|
|
81
|
+
<g>
|
|
82
|
+
<polyline data-points="3.2512907000000006,1.2997267500000007 3.8000000000000003,0" data-type="line" data-label="" points="425.12907000000007,209.2652575 480,339.23793250000006" fill="none" stroke="hsl(123, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
83
|
+
</g>
|
|
84
|
+
<g>
|
|
85
|
+
<polyline data-points="3.2512907000000006,1.2997267500000007 3.8000000000000003,-0.9" data-type="line" data-label="" points="425.12907000000007,209.2652575 480,429.23793250000006" fill="none" stroke="hsl(123, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
86
|
+
</g>
|
|
87
|
+
<g>
|
|
88
|
+
<polyline data-points="3.8000000000000003,0 3.8000000000000003,-0.9" data-type="line" data-label="" points="480,339.23793250000006 480,429.23793250000006" fill="none" stroke="hsl(123, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
89
|
+
</g>
|
|
90
|
+
<g>
|
|
91
|
+
<polyline data-points="1.4002733499999995,-0.0012093000000001908 1.4002733499999995,-0.30120930000000024 1.0001366749999998,-0.30120930000000024 1.0001366749999998,0 0.6000000000000001,0" data-type="line" data-label="" points="240.027335,339.3588625000001 240.027335,369.3588625000001 200.0136675,369.3588625000001 200.0136675,339.23793250000006 160.00000000000003,339.23793250000006" fill="none" stroke="purple" stroke-width="1" />
|
|
92
|
+
</g>
|
|
93
|
+
<g>
|
|
94
|
+
<polyline data-points="2.1487092999999997,1.3002732499999994 1.3997266500000003,1.3002732499999994 1.3997266500000003,1.1012093000000003" data-type="line" data-label="" points="314.87093,209.21060750000012 239.97266500000006,209.21060750000012 239.97266500000006,229.1170025" fill="none" stroke="purple" stroke-width="1" />
|
|
95
|
+
</g>
|
|
96
|
+
<g>
|
|
97
|
+
<polyline data-points="0.6000000000000001,0.2 0.86770835,0.2 0.86770835,1.1033769750000004 1.3997266500000003,1.1033769750000004 1.3997266500000003,1.1012093000000003" data-type="line" data-label="" points="160.00000000000003,319.23793250000006 186.77083500000003,319.23793250000006 186.77083500000003,228.900235 239.97266500000006,228.900235 239.97266500000006,229.1170025" fill="none" stroke="purple" stroke-width="1" />
|
|
98
|
+
</g>
|
|
99
|
+
<g>
|
|
100
|
+
<polyline data-points="3.8000000000000003,-0.9 3.6000000000000005,-0.9 3.6000000000000005,0 3.8000000000000003,0" data-type="line" data-label="" points="480,429.23793250000006 460.0000000000001,429.23793250000006 460.0000000000001,339.23793250000006 480,339.23793250000006" fill="none" stroke="purple" stroke-width="1" />
|
|
101
|
+
</g>
|
|
102
|
+
<g>
|
|
103
|
+
<polyline data-points="3.2512907000000006,1.2997267500000007 3.451290700000001,1.2997267500000007 3.5256453500000005,1.2997267500000007 3.5256453500000005,0 3.6,0 3.8000000000000003,0" data-type="line" data-label="" points="425.12907000000007,209.2652575 445.12907000000007,209.2652575 452.5645350000001,209.2652575 452.5645350000001,339.23793250000006 460,339.23793250000006 480,339.23793250000006" fill="none" stroke="purple" stroke-width="1" />
|
|
104
|
+
</g>
|
|
105
|
+
<g>
|
|
106
|
+
<polyline data-points="2.0034928,-0.8350319000000007 2.0034928,-0.1 0.7000000000000001,-0.1 0.7000000000000001,-0.2 0.6000000000000001,-0.2" data-type="line" data-label="" points="300.34928,422.74112250000013 300.34928,349.23793250000006 170.00000000000003,349.23793250000006 170.00000000000003,359.23793250000006 160.00000000000003,359.23793250000006" fill="none" stroke="purple" stroke-width="1" />
|
|
107
|
+
</g>
|
|
108
|
+
<g>
|
|
109
|
+
<rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="40.00000000000002" y="299.23793250000006" width="120" height="80" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.01" />
|
|
110
|
+
</g>
|
|
111
|
+
<g>
|
|
112
|
+
<rect data-type="rect" data-label="schematic_component_1" data-x="1.4" data-y="0.55" x="213.54167" y="229.1170025" width="52.916660000000036" height="110.24186000000009" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.01" />
|
|
113
|
+
</g>
|
|
114
|
+
<g>
|
|
115
|
+
<rect data-type="rect" data-label="schematic_component_2" data-x="2.7" data-y="1.3" x="314.87093" y="189.7923975000001" width="110.25814000000008" height="38.8910699999999" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.01" />
|
|
116
|
+
</g>
|
|
117
|
+
<g>
|
|
118
|
+
<rect data-type="rect" data-label="schematic_component_3" data-x="4.4" data-y="0" x="480" y="319.23793250000006" width="120" height="40" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.01" />
|
|
119
|
+
</g>
|
|
120
|
+
<g>
|
|
121
|
+
<rect data-type="rect" data-label="schematic_component_4" data-x="4.4" data-y="-0.9" x="480" y="409.23793250000006" width="120" height="40" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.01" />
|
|
122
|
+
</g>
|
|
123
|
+
<g>
|
|
124
|
+
<rect data-type="rect" data-label="schematic_component_5" data-x="2" data-y="-1.1" x="255.41992000000002" y="422.74112250000013" width="89.16015999999999" height="52.99361999999991" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.01" />
|
|
125
|
+
</g>
|
|
126
|
+
<g>
|
|
127
|
+
<rect data-type="rect" data-label="" data-x="1.6252733499999996" data-y="-0.30120930000000024" x="240.027335" y="359.3588625000001" width="45" height="20" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.01" />
|
|
128
|
+
</g>
|
|
129
|
+
<g>
|
|
130
|
+
<rect data-type="rect" data-label="" data-x="0.733854175" data-y="0.42500000000000004" x="163.38541750000005" y="274.23793250000006" width="19.99999999999997" height="45" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.01" />
|
|
131
|
+
</g>
|
|
132
|
+
<g>
|
|
133
|
+
<rect data-type="rect" data-label="" data-x="3.451290700000001" data-y="1.5247267500000008" x="435.12907000000007" y="164.26525749999996" width="20" height="45.00000000000003" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.01" />
|
|
134
|
+
</g>
|
|
135
|
+
<g>
|
|
136
|
+
<rect data-type="rect" data-label="" data-x="2.2284928" data-y="-0.46751595000000035" x="300.34928" y="375.9895275000001" width="45" height="19.999999999999943" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.01" />
|
|
137
|
+
</g>
|
|
138
|
+
<g id="crosshair" style="display: none">
|
|
139
|
+
<line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
|
|
140
|
+
<line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5" /><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text>
|
|
141
|
+
</g>
|
|
142
|
+
<script>
|
|
143
|
+
<![CDATA[
|
|
144
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
145
|
+
const svg = e.currentTarget;
|
|
146
|
+
const rect = svg.getBoundingClientRect();
|
|
147
|
+
const x = e.clientX - rect.left;
|
|
148
|
+
const y = e.clientY - rect.top;
|
|
149
|
+
const crosshair = svg.getElementById('crosshair');
|
|
150
|
+
const h = svg.getElementById('crosshair-h');
|
|
151
|
+
const v = svg.getElementById('crosshair-v');
|
|
152
|
+
const coords = svg.getElementById('coordinates');
|
|
153
|
+
|
|
154
|
+
crosshair.style.display = 'block';
|
|
155
|
+
h.setAttribute('x1', '0');
|
|
156
|
+
h.setAttribute('x2', '640');
|
|
157
|
+
h.setAttribute('y1', y);
|
|
158
|
+
h.setAttribute('y2', y);
|
|
159
|
+
v.setAttribute('x1', x);
|
|
160
|
+
v.setAttribute('x2', x);
|
|
161
|
+
v.setAttribute('y1', '0');
|
|
162
|
+
v.setAttribute('y2', '640');
|
|
163
|
+
|
|
164
|
+
// Calculate real coordinates using inverse transformation
|
|
165
|
+
const matrix = {
|
|
166
|
+
"a": 100,
|
|
167
|
+
"c": 0,
|
|
168
|
+
"e": 100.00000000000003,
|
|
169
|
+
"b": 0,
|
|
170
|
+
"d": -100,
|
|
171
|
+
"f": 339.23793250000006
|
|
172
|
+
};
|
|
173
|
+
// Manually invert and apply the affine transform
|
|
174
|
+
// Since we only use translate and scale, we can directly compute:
|
|
175
|
+
// x' = (x - tx) / sx
|
|
176
|
+
// y' = (y - ty) / sy
|
|
177
|
+
const sx = matrix.a;
|
|
178
|
+
const sy = matrix.d;
|
|
179
|
+
const tx = matrix.e;
|
|
180
|
+
const ty = matrix.f;
|
|
181
|
+
const realPoint = {
|
|
182
|
+
x: (x - tx) / sx,
|
|
183
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
187
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
188
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
189
|
+
});
|
|
190
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
191
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
192
|
+
});
|
|
193
|
+
]]>
|
|
194
|
+
</script>
|
|
195
|
+
</svg>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { expect, test } from "bun:test"
|
|
2
2
|
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
3
|
import { inputProblem } from "site/examples/example14.page"
|
|
4
|
-
import "tests/fixtures/matcher"
|
|
5
4
|
|
|
6
5
|
test.skip("example14 - should fail with net label placement collision error", () => {
|
|
7
6
|
const solver = new SchematicTracePipelineSolver(inputProblem)
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { expect } from "bun:test"
|
|
2
|
+
import { test } from "bun:test"
|
|
3
|
+
import { SchematicTracePipelineSolver, type InputProblem } from "lib/index"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
|
|
6
|
+
const inputProblem = {
|
|
7
|
+
chips: [
|
|
8
|
+
{
|
|
9
|
+
chipId: "schematic_component_0",
|
|
10
|
+
center: {
|
|
11
|
+
x: 0,
|
|
12
|
+
y: 0,
|
|
13
|
+
},
|
|
14
|
+
width: 0.4,
|
|
15
|
+
height: 0.8,
|
|
16
|
+
pins: [
|
|
17
|
+
{
|
|
18
|
+
pinId: "U1.6",
|
|
19
|
+
x: 0.6000000000000001,
|
|
20
|
+
y: -0.2,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pinId: "U1.8",
|
|
24
|
+
x: 0.6000000000000001,
|
|
25
|
+
y: 0,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pinId: "U1.1",
|
|
29
|
+
x: 0.6000000000000001,
|
|
30
|
+
y: 0.2,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
chipId: "schematic_component_1",
|
|
36
|
+
center: {
|
|
37
|
+
x: 1.4,
|
|
38
|
+
y: 0.55,
|
|
39
|
+
},
|
|
40
|
+
width: 0.5291665999999999,
|
|
41
|
+
height: 1.0583333000000001,
|
|
42
|
+
pins: [
|
|
43
|
+
{
|
|
44
|
+
pinId: "C2.1",
|
|
45
|
+
x: 1.4002733499999995,
|
|
46
|
+
y: -0.0012093000000001908,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
pinId: "C2.2",
|
|
50
|
+
x: 1.3997266500000003,
|
|
51
|
+
y: 1.1012093000000003,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
chipId: "schematic_component_2",
|
|
57
|
+
center: {
|
|
58
|
+
x: 2.7,
|
|
59
|
+
y: 1.3,
|
|
60
|
+
},
|
|
61
|
+
width: 1.0583332999999997,
|
|
62
|
+
height: 0.388910699999999,
|
|
63
|
+
pins: [
|
|
64
|
+
{
|
|
65
|
+
pinId: "R1.1",
|
|
66
|
+
x: 2.1487093,
|
|
67
|
+
y: 1.3002732499999994,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
pinId: "R1.2",
|
|
71
|
+
x: 3.2512907000000006,
|
|
72
|
+
y: 1.2997267500000007,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
chipId: "schematic_component_3",
|
|
78
|
+
center: {
|
|
79
|
+
x: 4.4,
|
|
80
|
+
y: 0,
|
|
81
|
+
},
|
|
82
|
+
width: 0.4,
|
|
83
|
+
height: 0.4,
|
|
84
|
+
pins: [
|
|
85
|
+
{
|
|
86
|
+
pinId: "JP5.1",
|
|
87
|
+
x: 3.8000000000000003,
|
|
88
|
+
y: 0,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
chipId: "schematic_component_4",
|
|
94
|
+
center: {
|
|
95
|
+
x: 4.4,
|
|
96
|
+
y: -0.9,
|
|
97
|
+
},
|
|
98
|
+
width: 0.4,
|
|
99
|
+
height: 0.4,
|
|
100
|
+
pins: [
|
|
101
|
+
{
|
|
102
|
+
pinId: "JP9.1",
|
|
103
|
+
x: 3.8000000000000003,
|
|
104
|
+
y: -0.9,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
chipId: "schematic_component_5",
|
|
110
|
+
center: {
|
|
111
|
+
x: 2,
|
|
112
|
+
y: -1.1,
|
|
113
|
+
},
|
|
114
|
+
width: 0.8843008999999997,
|
|
115
|
+
height: 0.5299361999999987,
|
|
116
|
+
pins: [
|
|
117
|
+
{
|
|
118
|
+
pinId: "JP8.1",
|
|
119
|
+
x: 2.4458007999999998,
|
|
120
|
+
y: -1.2015872704999997,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
pinId: "JP8.2",
|
|
124
|
+
x: 2.0034928,
|
|
125
|
+
y: -0.8474009705000005,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
pinId: "JP8.3",
|
|
129
|
+
x: 1.5541992,
|
|
130
|
+
y: -1.2014628704999997,
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
directConnections: [
|
|
136
|
+
{
|
|
137
|
+
pinIds: ["C2.1", "U1.8"],
|
|
138
|
+
netId: "capacitor.C2 > port.pin1 to .U1 > .pin8",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
pinIds: ["C2.2", "R1.1"],
|
|
142
|
+
netId: "capacitor.C2 > port.pin2 to .R1 > .pin1",
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
pinIds: ["R1.1", "U1.1"],
|
|
146
|
+
netId: "resistor.R1 > port.pin1 to .U1 > .pin1",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
pinIds: ["JP5.1", "R1.2"],
|
|
150
|
+
netId: "pinheader.JP5 > port.pin1 to .R1 > .pin2",
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
pinIds: ["JP9.1", "R1.2"],
|
|
154
|
+
netId: "pinheader.JP9 > port.pin1 to .R1 > .pin2",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
pinIds: ["JP8.2", "U1.6"],
|
|
158
|
+
netId: "solderjumper.JP8 > port.pin2 to .U1 > .pin6",
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
netConnections: [
|
|
162
|
+
{
|
|
163
|
+
netId: "PAD",
|
|
164
|
+
pinIds: ["R1.2", "JP5.1", "JP9.1"],
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
availableNetLabelOrientations: {},
|
|
168
|
+
maxMspPairDistance: 5,
|
|
169
|
+
} as InputProblem
|
|
170
|
+
|
|
171
|
+
test("example16", () => {
|
|
172
|
+
const solver = new SchematicTracePipelineSolver(inputProblem)
|
|
173
|
+
solver.solve()
|
|
174
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
175
|
+
})
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { expect, test } from "bun:test"
|
|
2
2
|
import { SingleNetLabelPlacementSolver } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver"
|
|
3
3
|
import { input } from "site/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver01.page"
|
|
4
|
-
import "tests/fixtures/matcher"
|
|
5
4
|
|
|
6
5
|
test("SingleNetLabelPlacementSolver01 issue reproduction (should pass)", () => {
|
|
7
6
|
const solver = new SingleNetLabelPlacementSolver(input as any)
|
|
@@ -9,5 +8,5 @@ test("SingleNetLabelPlacementSolver01 issue reproduction (should pass)", () => {
|
|
|
9
8
|
solver.solve()
|
|
10
9
|
|
|
11
10
|
// TODO: Fix the test
|
|
12
|
-
|
|
11
|
+
expect(solver.solved).toBe(true)
|
|
13
12
|
})
|