@tscircuit/schematic-trace-solver 0.0.182 → 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 +311 -112
- 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/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +13 -13
- 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
|
@@ -11,6 +11,39 @@ import {
|
|
|
11
11
|
} from "./sameNetRailAlignment/geometry"
|
|
12
12
|
import { shortenExcessiveLabelPaddingDetour } from "./shortenExcessiveLabelPaddingDetour"
|
|
13
13
|
|
|
14
|
+
const PATH_LENGTH_EPSILON = 1e-9
|
|
15
|
+
type ObstacleBounds = {
|
|
16
|
+
minX: number
|
|
17
|
+
minY: number
|
|
18
|
+
maxX: number
|
|
19
|
+
maxY: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const getPathLength = (path: SolvedTracePath["tracePath"]): number =>
|
|
23
|
+
path.slice(1).reduce((length, point, pointIndex) => {
|
|
24
|
+
const previousPoint = path[pointIndex]!
|
|
25
|
+
return (
|
|
26
|
+
length +
|
|
27
|
+
Math.abs(point.x - previousPoint.x) +
|
|
28
|
+
Math.abs(point.y - previousPoint.y)
|
|
29
|
+
)
|
|
30
|
+
}, 0)
|
|
31
|
+
|
|
32
|
+
const chooseLengthPreservingBoundaryRoute = ({
|
|
33
|
+
strictPath,
|
|
34
|
+
boundaryPath,
|
|
35
|
+
}: {
|
|
36
|
+
strictPath: SolvedTracePath["tracePath"]
|
|
37
|
+
boundaryPath: SolvedTracePath["tracePath"]
|
|
38
|
+
}) => {
|
|
39
|
+
const doesNotAddTurns = countTurns(boundaryPath) <= countTurns(strictPath)
|
|
40
|
+
const preservesLength =
|
|
41
|
+
Math.abs(getPathLength(boundaryPath) - getPathLength(strictPath)) <=
|
|
42
|
+
PATH_LENGTH_EPSILON
|
|
43
|
+
|
|
44
|
+
return doesNotAddTurns && preservesLength ? boundaryPath : strictPath
|
|
45
|
+
}
|
|
46
|
+
|
|
14
47
|
/**
|
|
15
48
|
* Minimizes turns with a strict pass that treats every other trace as an
|
|
16
49
|
* obstacle and a relaxed pass that permits joining endpoint-sharing same-net
|
|
@@ -95,22 +128,36 @@ export const minimizeTurnsWithFilteredLabels = ({
|
|
|
95
128
|
maxY: nl.center.y + nl.height / 2 + paddingBuffer,
|
|
96
129
|
}))
|
|
97
130
|
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
131
|
+
const minimizeForObstacles = (obstacles: ObstacleBounds[]) => {
|
|
132
|
+
const strictPath = minimizeTurns({
|
|
133
|
+
path: originalPath,
|
|
134
|
+
obstacles,
|
|
135
|
+
labelBounds,
|
|
136
|
+
originalPath,
|
|
137
|
+
})
|
|
138
|
+
const boundaryPath = minimizeTurns({
|
|
139
|
+
path: originalPath,
|
|
140
|
+
obstacles,
|
|
141
|
+
labelBounds,
|
|
142
|
+
originalPath,
|
|
143
|
+
allowLabelBoundaryExtension: true,
|
|
144
|
+
})
|
|
104
145
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
146
|
+
return chooseLengthPreservingBoundaryRoute({
|
|
147
|
+
strictPath,
|
|
148
|
+
boundaryPath,
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const strictPath = minimizeForObstacles([
|
|
153
|
+
...staticObstacles,
|
|
154
|
+
...getTraceObstacles(otherTraces),
|
|
155
|
+
])
|
|
156
|
+
|
|
157
|
+
const relaxedPath = minimizeForObstacles([
|
|
158
|
+
...staticObstacles,
|
|
159
|
+
...getTraceObstacles(relaxedObstacleTraces),
|
|
160
|
+
])
|
|
114
161
|
|
|
115
162
|
const sameNetTraces = otherTraces.filter(
|
|
116
163
|
(trace) => trace.globalConnNetId === targetTrace.globalConnNetId,
|
|
@@ -20,11 +20,13 @@ export const minimizeTurns = ({
|
|
|
20
20
|
obstacles,
|
|
21
21
|
labelBounds,
|
|
22
22
|
originalPath,
|
|
23
|
+
allowLabelBoundaryExtension = false,
|
|
23
24
|
}: {
|
|
24
25
|
path: Point[]
|
|
25
26
|
obstacles: any[]
|
|
26
27
|
labelBounds: any[]
|
|
27
28
|
originalPath: Point[]
|
|
29
|
+
allowLabelBoundaryExtension?: boolean
|
|
28
30
|
}): Point[] => {
|
|
29
31
|
if (path.length <= 2) {
|
|
30
32
|
return path
|
|
@@ -73,6 +75,7 @@ export const minimizeTurns = ({
|
|
|
73
75
|
const collidesWithLabels = hasCollisionsWithLabels(
|
|
74
76
|
connection,
|
|
75
77
|
labelBounds,
|
|
78
|
+
allowLabelBoundaryExtension ? { originalPath } : {},
|
|
76
79
|
)
|
|
77
80
|
|
|
78
81
|
if (!collidesWithObstacles && !collidesWithLabels) {
|
|
@@ -136,6 +139,7 @@ export const minimizeTurns = ({
|
|
|
136
139
|
const collidesWithLabels = hasCollisionsWithLabels(
|
|
137
140
|
connectionSegments,
|
|
138
141
|
labelBounds,
|
|
142
|
+
allowLabelBoundaryExtension ? { originalPath } : {},
|
|
139
143
|
)
|
|
140
144
|
|
|
141
145
|
if (!collidesWithObstacles && !collidesWithLabels) {
|
|
@@ -186,6 +190,7 @@ export const minimizeTurns = ({
|
|
|
186
190
|
const collidesWithLabels = hasCollisionsWithLabels(
|
|
187
191
|
[p1, p3],
|
|
188
192
|
labelBounds,
|
|
193
|
+
allowLabelBoundaryExtension ? { originalPath } : {},
|
|
189
194
|
)
|
|
190
195
|
|
|
191
196
|
if (!collidesWithObstacles && !collidesWithLabels) {
|