@tscircuit/schematic-trace-solver 0.0.29 → 0.0.30
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 +56 -30
- 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/package.json +1 -1
- package/tests/examples/example14.test.tsx +0 -1
- package/tests/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver01.test.ts +1 -2
package/dist/index.js
CHANGED
|
@@ -1494,10 +1494,11 @@ function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex)
|
|
|
1494
1494
|
const pts = solved.tracePath;
|
|
1495
1495
|
for (let i = 0; i < pts.length - 1; i++) {
|
|
1496
1496
|
if (pairId === hostPathId && i === hostSegIndex) continue;
|
|
1497
|
-
if (segmentIntersectsRect(pts[i], pts[i + 1], bounds))
|
|
1497
|
+
if (segmentIntersectsRect(pts[i], pts[i + 1], bounds))
|
|
1498
|
+
return { hasIntersection: true, mspPairId: pairId, segIndex: i };
|
|
1498
1499
|
}
|
|
1499
1500
|
}
|
|
1500
|
-
return false;
|
|
1501
|
+
return { hasIntersection: false };
|
|
1501
1502
|
}
|
|
1502
1503
|
|
|
1503
1504
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/host.ts
|
|
@@ -1582,14 +1583,16 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1582
1583
|
};
|
|
1583
1584
|
}
|
|
1584
1585
|
let pin = null;
|
|
1586
|
+
let pinFacingDirection = null;
|
|
1585
1587
|
for (const chip of inputProblem.chips) {
|
|
1586
1588
|
const p = chip.pins.find((pp) => pp.pinId === pinId);
|
|
1587
1589
|
if (p) {
|
|
1588
1590
|
pin = { x: p.x, y: p.y };
|
|
1591
|
+
pinFacingDirection = p._facingDirection || getPinDirection(p, chip);
|
|
1589
1592
|
break;
|
|
1590
1593
|
}
|
|
1591
1594
|
}
|
|
1592
|
-
if (!pin) {
|
|
1595
|
+
if (!pin || !pinFacingDirection) {
|
|
1593
1596
|
return {
|
|
1594
1597
|
placement: null,
|
|
1595
1598
|
testedCandidates: [],
|
|
@@ -1601,21 +1604,21 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1601
1604
|
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
1605
|
const testedCandidates = [];
|
|
1603
1606
|
for (const orientation of orientations) {
|
|
1604
|
-
const { width, height } = getDimsForOrientation(orientation);
|
|
1605
|
-
const
|
|
1606
|
-
const
|
|
1607
|
-
const
|
|
1607
|
+
const { width: width2, height: height2 } = getDimsForOrientation(orientation);
|
|
1608
|
+
const baseCenter2 = getCenterFromAnchor(anchor, orientation, width2, height2);
|
|
1609
|
+
const outward2 = outwardOf(orientation);
|
|
1610
|
+
const offset2 = 1e-3;
|
|
1608
1611
|
const center = {
|
|
1609
|
-
x:
|
|
1610
|
-
y:
|
|
1612
|
+
x: baseCenter2.x + outward2.x * offset2,
|
|
1613
|
+
y: baseCenter2.y + outward2.y * offset2
|
|
1611
1614
|
};
|
|
1612
|
-
const bounds = getRectBounds(center,
|
|
1615
|
+
const bounds = getRectBounds(center, width2, height2);
|
|
1613
1616
|
const chips = chipObstacleSpatialIndex.getChipsInBounds(bounds);
|
|
1614
1617
|
if (chips.length > 0) {
|
|
1615
1618
|
testedCandidates.push({
|
|
1616
1619
|
center,
|
|
1617
|
-
width,
|
|
1618
|
-
height,
|
|
1620
|
+
width: width2,
|
|
1621
|
+
height: height2,
|
|
1619
1622
|
bounds,
|
|
1620
1623
|
anchor,
|
|
1621
1624
|
orientation,
|
|
@@ -1624,16 +1627,17 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1624
1627
|
});
|
|
1625
1628
|
continue;
|
|
1626
1629
|
}
|
|
1627
|
-
|
|
1630
|
+
const traceIntersectionResult = rectIntersectsAnyTrace(
|
|
1628
1631
|
bounds,
|
|
1629
1632
|
inputTraceMap,
|
|
1630
1633
|
"",
|
|
1631
1634
|
-1
|
|
1632
|
-
)
|
|
1635
|
+
);
|
|
1636
|
+
if (traceIntersectionResult.hasIntersection) {
|
|
1633
1637
|
testedCandidates.push({
|
|
1634
1638
|
center,
|
|
1635
|
-
width,
|
|
1636
|
-
height,
|
|
1639
|
+
width: width2,
|
|
1640
|
+
height: height2,
|
|
1637
1641
|
bounds,
|
|
1638
1642
|
anchor,
|
|
1639
1643
|
orientation,
|
|
@@ -1644,8 +1648,8 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1644
1648
|
}
|
|
1645
1649
|
testedCandidates.push({
|
|
1646
1650
|
center,
|
|
1647
|
-
width,
|
|
1648
|
-
height,
|
|
1651
|
+
width: width2,
|
|
1652
|
+
height: height2,
|
|
1649
1653
|
bounds,
|
|
1650
1654
|
anchor,
|
|
1651
1655
|
orientation,
|
|
@@ -1660,17 +1664,39 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1660
1664
|
pinIds: [pinId],
|
|
1661
1665
|
orientation,
|
|
1662
1666
|
anchorPoint: anchor,
|
|
1663
|
-
width,
|
|
1664
|
-
height,
|
|
1667
|
+
width: width2,
|
|
1668
|
+
height: height2,
|
|
1665
1669
|
center
|
|
1666
1670
|
};
|
|
1667
1671
|
return { placement, testedCandidates };
|
|
1668
1672
|
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
+
const fallbackOrientation = pinFacingDirection;
|
|
1674
|
+
const { width, height } = getDimsForOrientation(fallbackOrientation);
|
|
1675
|
+
const baseCenter = getCenterFromAnchor(
|
|
1676
|
+
anchor,
|
|
1677
|
+
fallbackOrientation,
|
|
1678
|
+
width,
|
|
1679
|
+
height
|
|
1680
|
+
);
|
|
1681
|
+
const outward = outwardOf(fallbackOrientation);
|
|
1682
|
+
const offset = 1e-3;
|
|
1683
|
+
const fallbackCenter = {
|
|
1684
|
+
x: baseCenter.x + outward.x * offset,
|
|
1685
|
+
y: baseCenter.y + outward.y * offset
|
|
1686
|
+
};
|
|
1687
|
+
const fallbackPlacement = {
|
|
1688
|
+
globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
|
|
1689
|
+
dcConnNetId: void 0,
|
|
1690
|
+
netId: overlappingSameNetTraceGroup.netId,
|
|
1691
|
+
mspConnectionPairIds: [],
|
|
1692
|
+
pinIds: [pinId],
|
|
1693
|
+
orientation: fallbackOrientation,
|
|
1694
|
+
anchorPoint: anchor,
|
|
1695
|
+
width,
|
|
1696
|
+
height,
|
|
1697
|
+
center: fallbackCenter
|
|
1673
1698
|
};
|
|
1699
|
+
return { placement: fallbackPlacement, testedCandidates };
|
|
1674
1700
|
}
|
|
1675
1701
|
|
|
1676
1702
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver_visualize.ts
|
|
@@ -1686,12 +1712,11 @@ function visualizeSingleNetLabelPlacementSolver(solver) {
|
|
|
1686
1712
|
const groupStroke = getColorFromString(groupId, 0.9);
|
|
1687
1713
|
const groupFill = getColorFromString(groupId, 0.5);
|
|
1688
1714
|
for (const trace of Object.values(solver.inputTraceMap)) {
|
|
1689
|
-
if (trace.globalConnNetId !== groupId) continue;
|
|
1690
1715
|
const isHost = host ? trace.mspPairId === host.mspPairId : false;
|
|
1691
1716
|
graphics.lines.push({
|
|
1692
|
-
points: trace.tracePath
|
|
1693
|
-
strokeColor: isHost ? groupStroke : groupFill,
|
|
1694
|
-
strokeDash: isHost ?
|
|
1717
|
+
points: trace.tracePath
|
|
1718
|
+
// strokeColor: isHost ? groupStroke : groupFill,
|
|
1719
|
+
// strokeDash: isHost ? undefined : "4 2",
|
|
1695
1720
|
});
|
|
1696
1721
|
}
|
|
1697
1722
|
for (const c of solver.testedCandidates) {
|
|
@@ -1863,12 +1888,13 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1863
1888
|
});
|
|
1864
1889
|
continue;
|
|
1865
1890
|
}
|
|
1866
|
-
|
|
1891
|
+
const traceIntersectionResult = rectIntersectsAnyTrace(
|
|
1867
1892
|
bounds,
|
|
1868
1893
|
this.inputTraceMap,
|
|
1869
1894
|
curr.mspPairId,
|
|
1870
1895
|
si
|
|
1871
|
-
)
|
|
1896
|
+
);
|
|
1897
|
+
if (traceIntersectionResult.hasIntersection) {
|
|
1872
1898
|
this.testedCandidates.push({
|
|
1873
1899
|
center: testCenter,
|
|
1874
1900
|
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/package.json
CHANGED
|
@@ -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)
|
|
@@ -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
|
})
|