@tscircuit/schematic-trace-solver 0.0.133 → 0.0.135
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 +1 -0
- package/dist/index.js +226 -129
- package/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts +140 -6
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +7 -1
- package/package.json +1 -1
- package/site/bug-reports/bug-report-20260815T073240Z.page.tsx +4 -0
- package/tests/bug-reports/bug-report-20260815T073240Z/__snapshots__/bug-report-20260815T073240Z.snap.svg +79 -0
- package/tests/bug-reports/bug-report-20260815T073240Z/bug-report-20260815T073240Z.json +314 -0
- package/tests/bug-reports/bug-report-20260815T073240Z/bug-report-20260815T073240Z.test.ts +12 -0
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +133 -0
- package/tests/repros/__snapshots__/repro-type-c-vbus-led-ground-label.snap.svg +66 -0
- package/tests/repros/board1096-usb-label-overlap-iteration.json +663 -0
- package/tests/repros/board1096-usb-label-overlap-iteration.test.ts +16 -0
- package/tests/repros/repro-type-c-vbus-led-ground-label.test.ts +149 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getConnectivityMapsFromInputProblem } from "lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem"
|
|
2
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
2
3
|
import {
|
|
3
4
|
DEFAULT_MAX_MSP_PAIR_DISTANCE,
|
|
4
5
|
type MspConnectionPair,
|
|
@@ -20,13 +21,118 @@ import { isLabeledPeripheralConnection } from "../MspConnectionPairSolver/isLabe
|
|
|
20
21
|
|
|
21
22
|
const NEAREST_NEIGHBOR_COUNT = 3
|
|
22
23
|
|
|
23
|
-
const distance = (p1:
|
|
24
|
+
const distance = (p1: Point, p2: Point) => {
|
|
24
25
|
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2))
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
const manhattanDistance = (p1: InputPin, p2: InputPin) =>
|
|
28
29
|
Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y)
|
|
29
30
|
|
|
31
|
+
const EPS = 1e-9
|
|
32
|
+
|
|
33
|
+
const between = (value: number, first: number, second: number) =>
|
|
34
|
+
value >= Math.min(first, second) - EPS &&
|
|
35
|
+
value <= Math.max(first, second) + EPS
|
|
36
|
+
|
|
37
|
+
const getAxisAlignedIntersection = (
|
|
38
|
+
firstStart: Point,
|
|
39
|
+
firstEnd: Point,
|
|
40
|
+
secondStart: Point,
|
|
41
|
+
secondEnd: Point,
|
|
42
|
+
) => {
|
|
43
|
+
const firstIsHorizontal = Math.abs(firstStart.y - firstEnd.y) <= EPS
|
|
44
|
+
const firstIsVertical = Math.abs(firstStart.x - firstEnd.x) <= EPS
|
|
45
|
+
const secondIsHorizontal = Math.abs(secondStart.y - secondEnd.y) <= EPS
|
|
46
|
+
const secondIsVertical = Math.abs(secondStart.x - secondEnd.x) <= EPS
|
|
47
|
+
|
|
48
|
+
if (firstIsHorizontal && secondIsVertical) {
|
|
49
|
+
const point = { x: secondStart.x, y: firstStart.y }
|
|
50
|
+
return between(point.x, firstStart.x, firstEnd.x) &&
|
|
51
|
+
between(point.y, secondStart.y, secondEnd.y)
|
|
52
|
+
? point
|
|
53
|
+
: null
|
|
54
|
+
}
|
|
55
|
+
if (firstIsVertical && secondIsHorizontal) {
|
|
56
|
+
const point = { x: firstStart.x, y: secondStart.y }
|
|
57
|
+
return between(point.y, firstStart.y, firstEnd.y) &&
|
|
58
|
+
between(point.x, secondStart.x, secondEnd.x)
|
|
59
|
+
? point
|
|
60
|
+
: null
|
|
61
|
+
}
|
|
62
|
+
if (
|
|
63
|
+
firstIsHorizontal &&
|
|
64
|
+
secondIsHorizontal &&
|
|
65
|
+
Math.abs(firstStart.y - secondStart.y) <= EPS
|
|
66
|
+
) {
|
|
67
|
+
const overlapMin = Math.max(
|
|
68
|
+
Math.min(firstStart.x, firstEnd.x),
|
|
69
|
+
Math.min(secondStart.x, secondEnd.x),
|
|
70
|
+
)
|
|
71
|
+
const overlapMax = Math.min(
|
|
72
|
+
Math.max(firstStart.x, firstEnd.x),
|
|
73
|
+
Math.max(secondStart.x, secondEnd.x),
|
|
74
|
+
)
|
|
75
|
+
if (overlapMin > overlapMax + EPS) return null
|
|
76
|
+
return {
|
|
77
|
+
x: Math.max(overlapMin, Math.min(firstStart.x, overlapMax)),
|
|
78
|
+
y: firstStart.y,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (
|
|
82
|
+
firstIsVertical &&
|
|
83
|
+
secondIsVertical &&
|
|
84
|
+
Math.abs(firstStart.x - secondStart.x) <= EPS
|
|
85
|
+
) {
|
|
86
|
+
const overlapMin = Math.max(
|
|
87
|
+
Math.min(firstStart.y, firstEnd.y),
|
|
88
|
+
Math.min(secondStart.y, secondEnd.y),
|
|
89
|
+
)
|
|
90
|
+
const overlapMax = Math.min(
|
|
91
|
+
Math.max(firstStart.y, firstEnd.y),
|
|
92
|
+
Math.max(secondStart.y, secondEnd.y),
|
|
93
|
+
)
|
|
94
|
+
if (overlapMin > overlapMax + EPS) return null
|
|
95
|
+
return {
|
|
96
|
+
x: firstStart.x,
|
|
97
|
+
y: Math.max(overlapMin, Math.min(firstStart.y, overlapMax)),
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const clipPathAtFirstIntersection = (
|
|
104
|
+
tracePath: SolvedTracePath["tracePath"],
|
|
105
|
+
existingTraces: SolvedTracePath[],
|
|
106
|
+
) => {
|
|
107
|
+
for (let pathIndex = 0; pathIndex < tracePath.length - 1; pathIndex++) {
|
|
108
|
+
const pathStart = tracePath[pathIndex]!
|
|
109
|
+
const pathEnd = tracePath[pathIndex + 1]!
|
|
110
|
+
const intersections = existingTraces.flatMap((trace) =>
|
|
111
|
+
trace.tracePath.slice(0, -1).flatMap((traceStart, traceIndex) => {
|
|
112
|
+
const intersection = getAxisAlignedIntersection(
|
|
113
|
+
pathStart,
|
|
114
|
+
pathEnd,
|
|
115
|
+
traceStart,
|
|
116
|
+
trace.tracePath[traceIndex + 1]!,
|
|
117
|
+
)
|
|
118
|
+
return intersection ? [intersection] : []
|
|
119
|
+
}),
|
|
120
|
+
)
|
|
121
|
+
intersections.sort(
|
|
122
|
+
(first, second) =>
|
|
123
|
+
distance(pathStart, first) - distance(pathStart, second),
|
|
124
|
+
)
|
|
125
|
+
const intersection = intersections[0]
|
|
126
|
+
if (!intersection) continue
|
|
127
|
+
const clippedPath = tracePath.slice(0, pathIndex + 1)
|
|
128
|
+
if (distance(clippedPath.at(-1)!, intersection) > EPS) {
|
|
129
|
+
clippedPath.push(intersection)
|
|
130
|
+
}
|
|
131
|
+
return clippedPath
|
|
132
|
+
}
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
|
|
30
136
|
export class LongDistancePairSolver extends BaseSolver {
|
|
31
137
|
public solvedLongDistanceTraces: SolvedTracePath[] = []
|
|
32
138
|
private queuedCandidatePairs: Array<
|
|
@@ -196,14 +302,42 @@ export class LongDistancePairSolver extends BaseSolver {
|
|
|
196
302
|
} else if (this.subSolver?.solved) {
|
|
197
303
|
const newTracePath = this.subSolver.solvedTracePath
|
|
198
304
|
if (newTracePath && this.currentCandidatePair) {
|
|
305
|
+
const [p1, p2] = this.currentCandidatePair
|
|
306
|
+
const globalConnNetId = this.netConnMap.getNetConnectedToId(p1.pinId)!
|
|
307
|
+
const sameNetTraces = this.allSolvedTraces.filter(
|
|
308
|
+
(trace) => trace.globalConnNetId === globalConnNetId,
|
|
309
|
+
)
|
|
310
|
+
const inputNetConnection = this.inputProblem.netConnections.find(
|
|
311
|
+
(connection) =>
|
|
312
|
+
connection.pinIds.length === 3 &&
|
|
313
|
+
connection.pinIds.includes(p1.pinId) &&
|
|
314
|
+
connection.pinIds.includes(p2.pinId),
|
|
315
|
+
)
|
|
316
|
+
const sourceChip = this.chipMap[p1.chipId]
|
|
317
|
+
const targetRailTrace = sameNetTraces.find(
|
|
318
|
+
(trace) =>
|
|
319
|
+
trace.pinIds.includes(p2.pinId) &&
|
|
320
|
+
trace.pins.every((pin) => pin.chipId === p2.chipId),
|
|
321
|
+
)
|
|
322
|
+
const canJoinThreePinNet =
|
|
323
|
+
inputNetConnection !== undefined &&
|
|
324
|
+
sourceChip?.pins.length === 2 &&
|
|
325
|
+
targetRailTrace !== undefined
|
|
326
|
+
const junctionTracePath = canJoinThreePinNet
|
|
327
|
+
? clipPathAtFirstIntersection(newTracePath, sameNetTraces)
|
|
328
|
+
: null
|
|
329
|
+
const acceptedTracePath = junctionTracePath ?? newTracePath
|
|
330
|
+
const tracesToCheck = junctionTracePath
|
|
331
|
+
? this.allSolvedTraces.filter(
|
|
332
|
+
(trace) => trace.globalConnNetId !== globalConnNetId,
|
|
333
|
+
)
|
|
334
|
+
: this.allSolvedTraces
|
|
199
335
|
const isTraceClear = !doesTraceOverlapWithExistingTraces(
|
|
200
|
-
|
|
201
|
-
|
|
336
|
+
acceptedTracePath,
|
|
337
|
+
tracesToCheck,
|
|
202
338
|
)
|
|
203
339
|
|
|
204
340
|
if (isTraceClear) {
|
|
205
|
-
const [p1, p2] = this.currentCandidatePair
|
|
206
|
-
const globalConnNetId = this.netConnMap.getNetConnectedToId(p1.pinId)!
|
|
207
341
|
const mspPairId = `${p1.pinId}-${p2.pinId}`
|
|
208
342
|
|
|
209
343
|
const newSolvedTrace: SolvedTracePath = {
|
|
@@ -211,7 +345,7 @@ export class LongDistancePairSolver extends BaseSolver {
|
|
|
211
345
|
dcConnNetId: globalConnNetId,
|
|
212
346
|
globalConnNetId,
|
|
213
347
|
pins: [p1, p2],
|
|
214
|
-
tracePath:
|
|
348
|
+
tracePath: acceptedTracePath,
|
|
215
349
|
mspConnectionPairIds: [mspPairId],
|
|
216
350
|
pinIds: [p1.pinId, p2.pinId],
|
|
217
351
|
}
|
|
@@ -43,6 +43,7 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
43
43
|
|
|
44
44
|
public override activeSubSolver: SingleOverlapSolver | null = null
|
|
45
45
|
private overlapQueue: Overlap[] = []
|
|
46
|
+
private activeOverlap: Overlap | null = null
|
|
46
47
|
private recentlyFailed: Set<string> = new Set()
|
|
47
48
|
|
|
48
49
|
private currentlyProcessingOverlap: Overlap | null = null
|
|
@@ -88,11 +89,13 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
91
|
this.activeSubSolver = null
|
|
92
|
+
this.activeOverlap = null
|
|
91
93
|
this.recentlyFailed.clear()
|
|
92
94
|
} else if (this.activeSubSolver.failed) {
|
|
93
|
-
const overlapId = `${this.
|
|
95
|
+
const overlapId = `${this.activeOverlap!.trace.mspPairId}-${this.activeOverlap!.label.globalConnNetId}`
|
|
94
96
|
this.recentlyFailed.add(overlapId)
|
|
95
97
|
this.activeSubSolver = null
|
|
98
|
+
this.activeOverlap = null
|
|
96
99
|
} else {
|
|
97
100
|
}
|
|
98
101
|
return
|
|
@@ -160,6 +163,7 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
160
163
|
detourCount + 1,
|
|
161
164
|
)
|
|
162
165
|
|
|
166
|
+
this.activeOverlap = nextOverlap
|
|
163
167
|
this.activeSubSolver = new SingleOverlapSolver({
|
|
164
168
|
trace: traceToFix,
|
|
165
169
|
label: actualOverlapLabel,
|
|
@@ -204,6 +208,7 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
204
208
|
actualOverlapLabel.globalConnNetId,
|
|
205
209
|
detourCount + 1,
|
|
206
210
|
)
|
|
211
|
+
this.activeOverlap = nextOverlap
|
|
207
212
|
this.activeSubSolver = new SingleOverlapSolver({
|
|
208
213
|
trace: traceToFix,
|
|
209
214
|
label: actualOverlapLabel,
|
|
@@ -225,6 +230,7 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
225
230
|
const detourCount =
|
|
226
231
|
this.detourCounts.get(labelToAvoid.globalConnNetId) ?? 0
|
|
227
232
|
this.detourCounts.set(labelToAvoid.globalConnNetId, detourCount + 1)
|
|
233
|
+
this.activeOverlap = nextOverlap
|
|
228
234
|
this.activeSubSolver = new SingleOverlapSolver({
|
|
229
235
|
trace: traceToFix,
|
|
230
236
|
label: labelToAvoid,
|
package/package.json
CHANGED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="-2.6508333333333325,2.473333333333333 -4.532499999999999,1.8875000000000002" data-type="line" data-label="" points="151.35991186393994,208.0385595262687 64.29250154926669,235.1459064931488" fill="none" stroke="hsl(32, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-4.532499999999999,1.8875000000000002 -1.5208333333333326,2.473333333333333" data-type="line" data-label="" points="64.29250154926669,235.1459064931488 203.64662948426633,208.0385595262687" fill="none" stroke="hsl(170, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.532499999999999,1.8875000000000002 -2.6508333333333325,2.473333333333333" data-type="line" data-label="" points="64.29250154926669,235.1459064931488 151.35991186393994,208.0385595262687" fill="none" stroke="hsl(170, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.5208333333333326,2.473333333333333 -2.6508333333333325,2.473333333333333" data-type="line" data-label="" points="203.64662948426633,208.0385595262687 151.35991186393994,208.0385595262687" fill="none" stroke="hsl(170, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.532499999999999,0.8475000000000001 -1.2850000000000001,0.2" data-type="line" data-label="" points="64.29250154926669,283.2681952764581 214.55897541830194,313.2289471872203" fill="none" stroke="hsl(264, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.532499999999999,0.8475000000000001 -1.2850000000000001,-0.2" data-type="line" data-label="" points="64.29250154926669,283.2681952764581 214.55897541830194,331.7375197961854" fill="none" stroke="hsl(264, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.532499999999999,0.8475000000000001 -2.469999999999999,1.7475" data-type="line" data-label="" points="64.29250154926669,283.2681952764581 159.72732906424295,241.6239069062866" fill="none" stroke="hsl(264, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.2850000000000001,0.2 -1.2850000000000001,-0.2" data-type="line" data-label="" points="214.55897541830194,313.2289471872203 214.55897541830194,331.7375197961854" fill="none" stroke="hsl(264, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.2850000000000001,0.2 -2.469999999999999,1.7475" data-type="line" data-label="" points="214.55897541830194,313.2289471872203 159.72732906424295,241.6239069062866" fill="none" stroke="hsl(264, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.2850000000000001,-0.2 -2.469999999999999,1.7475" data-type="line" data-label="" points="214.55897541830194,331.7375197961854 159.72732906424295,241.6239069062866" fill="none" stroke="hsl(264, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.2850000000000001,0 -2.469999999999999,0.9875000000000003" data-type="line" data-label="" points="214.55897541830194,322.48323349170283 159.72732906424295,276.79019486332027" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.2850000000000001,0 2.6075,-0.78" data-type="line" data-label="" points="214.55897541830194,322.48323349170283 394.6705226192935,358.57495007918476" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.2850000000000001,0 6.245,-2.4050000000000002" data-type="line" data-label="" points="214.55897541830194,322.48323349170283 562.9828547820698,433.76602630310543" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.2850000000000001,0 3.9924999999999997,-0.78" data-type="line" data-label="" points="214.55897541830194,322.48323349170283 458.75645527783513,358.57495007918476" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-2.469999999999999,0.9875000000000003 2.6075,-0.78" data-type="line" data-label="" points="159.72732906424295,276.79019486332027 394.6705226192935,358.57495007918476" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-2.469999999999999,0.9875000000000003 6.245,-2.4050000000000002" data-type="line" data-label="" points="159.72732906424295,276.79019486332027 562.9828547820698,433.76602630310543" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-2.469999999999999,0.9875000000000003 3.9924999999999997,-0.78" data-type="line" data-label="" points="159.72732906424295,276.79019486332027 458.75645527783513,358.57495007918476" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="2.6075,-0.78 6.245,-2.4050000000000002" data-type="line" data-label="" points="394.6705226192935,358.57495007918476 562.9828547820698,433.76602630310543" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="2.6075,-0.78 3.9924999999999997,-0.78" data-type="line" data-label="" points="394.6705226192935,358.57495007918476 458.75645527783513,358.57495007918476" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="6.245,-2.4050000000000002 3.9924999999999997,-0.78" data-type="line" data-label="" points="562.9828547820698,433.76602630310543 458.75645527783513,358.57495007918476" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.2850000000000001,0.1 2.6075,-0.019999999999999907" data-type="line" data-label="" points="333.4765544309027,317.85609033946156 394.6705226192935,323.4086621221511" fill="none" stroke="hsl(154, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.2850000000000001,0.1 6.245,-0.07500000000000018" data-type="line" data-label="" points="333.4765544309027,317.85609033946156 562.9828547820698,325.9535908558838" fill="none" stroke="hsl(154, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.2850000000000001,0.1 3.9924999999999997,-0.019999999999999907" data-type="line" data-label="" points="333.4765544309027,317.85609033946156 458.75645527783513,323.4086621221511" fill="none" stroke="hsl(154, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="2.6075,-0.019999999999999907 6.245,-0.07500000000000018" data-type="line" data-label="" points="394.6705226192935,323.4086621221511 562.9828547820698,325.9535908558838" fill="none" stroke="hsl(154, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="2.6075,-0.019999999999999907 3.9924999999999997,-0.019999999999999907" data-type="line" data-label="" points="394.6705226192935,323.4086621221511 458.75645527783513,323.4086621221511" fill="none" stroke="hsl(154, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="6.245,-0.07500000000000018 3.9924999999999997,-0.019999999999999907" data-type="line" data-label="" points="562.9828547820698,325.9535908558838 458.75645527783513,323.4086621221511" fill="none" stroke="hsl(154, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="6.245,-1.205 6.245,-1.8050000000000006" data-type="line" data-label="" points="562.9828547820698,378.2403084762102 562.9828547820698,406.00316738965785" fill="none" stroke="hsl(187, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.2850000000000001,-0.2 -1.485,-0.2 -1.485,0.2 -1.2850000000000001,0.2" data-type="line" data-label="" points="214.55897541830194,331.7375197961854 205.30468911381942,331.7375197961854 205.30468911381942,313.2289471872203 214.55897541830194,313.2289471872203" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.2850000000000001,0 -2.469999999999999,0 -2.469999999999999,0.9875000000000003" data-type="line" data-label="" points="214.55897541830194,322.48323349170283 159.72732906424295,322.48323349170283 159.72732906424295,276.79019486332027" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="3.9924999999999997,-0.78 3.9924999999999997,-0.9800000000000002 2.6075,-0.9800000000000002 2.6075,-0.78" data-type="line" data-label="" points="458.75645527783513,358.57495007918476 458.75645527783513,367.8292363836673 394.6705226192935,367.8292363836673 394.6705226192935,358.57495007918476" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="3.9924999999999997,-0.019999999999999907 3.9924999999999997,0.18000000000000027 2.6075,0.18000000000000027 2.6075,-0.019999999999999907" data-type="line" data-label="" points="458.75645527783513,323.4086621221511 458.75645527783513,314.15437581766855 394.6705226192935,314.15437581766855 394.6705226192935,323.4086621221511" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.2850000000000001,0.1 2.6075,0.1 2.6075,-0.019999999999999907" data-type="line" data-label="" points="333.4765544309027,317.85609033946156 394.6705226192935,317.85609033946156 394.6705226192935,323.4086621221511" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="6.245,-0.07500000000000007 6.245,0.18000000000000027 3.9924999999999997,0.18000000000000027 3.9924999999999997,-0.019999999999999907" data-type="line" data-label="" points="562.9828547820698,325.9535908558838 562.9828547820698,314.15437581766855 458.75645527783513,314.15437581766855 458.75645527783513,323.4086621221511" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="6.245,-1.205 6.245,-1.8050000000000006" data-type="line" data-label="" points="562.9828547820698,378.2403084762102 562.9828547820698,406.00316738965785" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-4.532499999999999,1.8875000000000002 -4.532499999999999,2.473333333333333 -2.8508333333333327,2.473333333333333" data-type="line" data-label="" points="64.29250154926669,235.1459064931488 64.29250154926669,208.0385595262687 142.1056255594574,208.0385595262687" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-4.532499999999999,0.8475000000000001 -4.532499999999999,-0.20000000000000018 -1.2850000000000001,-0.20000000000000018" data-type="line" data-label="" points="64.29250154926669,283.2681952764581 64.29250154926669,331.7375197961854 214.55897541830194,331.7375197961854" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-2.6508333333333325,2.473333333333333 -2.8508333333333327,2.473333333333333 -2.8508333333333327,1.8933333333333333 -1.3208333333333324,1.8933333333333333 -1.3208333333333324,2.473333333333333 -1.5208333333333326,2.473333333333333" data-type="line" data-label="" points="151.35991186393994,208.0385595262687 142.1056255594574,208.0385595262687 142.1056255594574,234.87598980926808 212.90091578874888,234.87598980926808 212.90091578874888,208.0385595262687 203.64662948426633,208.0385595262687" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-2.469999999999999,1.7475 -2.469999999999999,1.8485 -2.9209999999999985,1.8485" data-type="line" data-label="" points="159.72732906424295,241.6239069062866 159.72732906424295,236.9504923225229 138.85891344763482,236.9504923225229" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.8774999999999995,0 -4.817499999999998,0 -4.817499999999998,-0.051000000000000004" data-type="line" data-label="" points="187.14315224127245,322.48323349170283 51.10514356537911,322.48323349170283 51.10514356537911,324.8430764993459" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-4.432499999999998" data-y="1.3675000000000002" x="51.79921503821528" y="235.1459064931488" width="34.24085932658542" height="48.12228878330927" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="-2.0858333333333325" data-y="2.513333333333333" x="151.35991186393994" y="186.75370102595883" width="52.286717620326385" height="38.868002478826696" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="0" data-y="0" x="214.55897541830194" y="308.601804034979" width="118.91757901260075" height="27.762858913447644" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="-2.397499999999999" data-y="1.3675000000000002" x="138.90518487915722" y="241.6239069062866" width="48.353645940921325" height="35.16628795703366" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="schematic_component_4" data-x="2.6799999999999997" data-y="-0.39999999999999997" x="373.8483784342077" y="323.4086621221511" width="48.35364594092135" height="35.16628795703366" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="schematic_component_5" data-x="6.4825" data-y="-0.6400000000000001" x="547.9446395372856" y="325.9535908558838" width="52.05536046271436" height="52.286717620326385" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="schematic_component_6" data-x="6.4025" data-y="-2.1050000000000004" x="547.9446395372856" y="406.00316738965785" width="44.65193141912823" height="27.762858913447587" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="schematic_component_7" data-x="4.005" data-y="-0.39999999999999997" x="437.93431109274934" y="323.4086621221511" width="42.80107415823181" height="35.16628795703366" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="AP2112K-3.3" data-x="-0.2250000000000001" data-y="-0.43" x="233.06754802726704" y="338.21552020932313" width="61.0782896095848" height="8.328857674034339" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="U2" data-x="-0.765" data-y="0.41500000000000004" x="230.2912621359223" y="297.4966604696" width="16.657715348068564" height="11.567857880603128" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="netId: VBUS
|
|
2
|
+
globalConnNetId: connectivity_net0" data-x="-4.532499999999999" data-y="2.683333333333333" x="50.41107209254287" y="188.60455828685537" width="27.762858913447644" height="19.434001239413334" fill="#ef444466" stroke="#ef4444" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="netId: RAW
|
|
3
|
+
globalConnNetId: connectivity_net1" data-x="-4.772499999999999" data-y="0.32375" x="42.08221441850857" y="302.8757143840804" width="22.210287130758132" height="9.254286304482548" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="netId: RAW
|
|
4
|
+
globalConnNetId: connectivity_net1" data-x="-3.1609999999999987" data-y="1.8485" x="116.64862631687667" y="232.32334917028163" width="22.210287130758132" height="9.254286304482548" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="netId: GND
|
|
5
|
+
globalConnNetId: connectivity_net2" data-x="-4.817499999999998" data-y="-0.261" x="40.00000000000004" y="324.8430764993459" width="22.210287130758132" height="19.434001239413305" fill="#00000066" stroke="#000000" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="netId: GND
|
|
6
|
+
globalConnNetId: connectivity_net2" data-x="3.9924999999999997" data-y="-1.1900000000000002" x="447.65131171245605" y="367.8292363836673" width="22.21028713075816" height="19.434001239413362" fill="#00000066" stroke="#000000" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="netId: GND
|
|
7
|
+
globalConnNetId: connectivity_net2" data-x="6.245" data-y="-2.616" x="551.8777112166907" y="433.8122977346278" width="22.21028713075816" height="19.434001239413362" fill="#00000066" stroke="#000000" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="netId: V3V3
|
|
8
|
+
globalConnNetId: connectivity_net3" data-x="3.9924999999999997" data-y="0.39000000000000024" x="444.8750258211113" y="294.72037457825513" width="27.762858913447644" height="19.434001239413362" fill="#ef444466" stroke="#ef4444" stroke-width="0.02161160714285714"/></g><g><rect data-type="rect" data-label="netId: PWR_LED_K
|
|
9
|
+
globalConnNetId: connectivity_net4" data-x="5.6450000000000005" data-y="-1.5050000000000003" x="507.4571369551745" y="387.49459478069275" width="55.52571782689529" height="9.254286304482548" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.02161160714285714"/></g><g><circle data-type="point" data-label="schematic_port_0
|
|
10
|
+
y+" data-x="-4.532499999999999" data-y="1.8875000000000002" cx="64.29250154926669" cy="235.1459064931488" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_1
|
|
11
|
+
y-" data-x="-4.532499999999999" data-y="0.8475000000000001" cx="64.29250154926669" cy="283.2681952764581" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_2
|
|
12
|
+
x+" data-x="-1.5208333333333326" data-y="2.473333333333333" cx="203.64662948426633" cy="208.0385595262687" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_3
|
|
13
|
+
x-" data-x="-2.6508333333333325" data-y="2.473333333333333" cx="151.35991186393994" cy="208.0385595262687" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_4
|
|
14
|
+
x-" data-x="-1.2850000000000001" data-y="0.2" cx="214.55897541830194" cy="313.2289471872203" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_5
|
|
15
|
+
x-" data-x="-1.2850000000000001" data-y="0" cx="214.55897541830194" cy="322.48323349170283" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_6
|
|
16
|
+
x-" data-x="-1.2850000000000001" data-y="-0.2" cx="214.55897541830194" cy="331.7375197961854" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_7
|
|
17
|
+
x+" data-x="1.2850000000000001" data-y="-0.1" cx="333.4765544309027" cy="327.1103766439441" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_8
|
|
18
|
+
x+" data-x="1.2850000000000001" data-y="0.1" cx="333.4765544309027" cy="317.85609033946156" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_9
|
|
19
|
+
y+" data-x="-2.469999999999999" data-y="1.7475" cx="159.72732906424295" cy="241.6239069062866" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_10
|
|
20
|
+
y-" data-x="-2.469999999999999" data-y="0.9875000000000003" cx="159.72732906424295" cy="276.79019486332027" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_11
|
|
21
|
+
y+" data-x="2.6075" data-y="-0.019999999999999907" cx="394.6705226192935" cy="323.4086621221511" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_12
|
|
22
|
+
y-" data-x="2.6075" data-y="-0.78" cx="394.6705226192935" cy="358.57495007918476" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_13
|
|
23
|
+
y+" data-x="6.245" data-y="-0.07500000000000018" cx="562.9828547820698" cy="325.9535908558838" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_14
|
|
24
|
+
y-" data-x="6.245" data-y="-1.205" cx="562.9828547820698" cy="378.2403084762102" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_15
|
|
25
|
+
y+" data-x="6.245" data-y="-1.8050000000000006" cx="562.9828547820698" cy="406.00316738965785" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_16
|
|
26
|
+
y-" data-x="6.245" data-y="-2.4050000000000002" cx="562.9828547820698" cy="433.76602630310543" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_17
|
|
27
|
+
y+" data-x="3.9924999999999997" data-y="-0.019999999999999907" cx="458.75645527783513" cy="323.4086621221511" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_18
|
|
28
|
+
y-" data-x="3.9924999999999997" data-y="-0.78" cx="458.75645527783513" cy="358.57495007918476" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
29
|
+
orientation: y+" data-x="-4.532499999999999" data-y="2.473333333333333" cx="64.29250154926669" cy="208.0385595262687" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
30
|
+
orientation: x-" data-x="-4.532499999999999" data-y="0.32375" cx="64.29250154926669" cy="307.5028575363217" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
31
|
+
orientation: x-" data-x="-2.9209999999999985" data-y="1.8485" cx="138.85891344763482" cy="236.9504923225229" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
32
|
+
orientation: y-" data-x="-4.817499999999998" data-y="-0.051000000000000004" cx="51.10514356537911" cy="324.8430764993459" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
33
|
+
orientation: y-" data-x="3.9924999999999997" data-y="-0.9800000000000002" cx="458.75645527783513" cy="367.8292363836673" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
34
|
+
orientation: y-" data-x="6.245" data-y="-2.4050000000000002" cx="562.9828547820698" cy="433.76602630310543" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
35
|
+
orientation: y+" data-x="3.9924999999999997" data-y="0.18000000000000027" cx="458.75645527783513" cy="314.15437581766855" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
36
|
+
orientation: x-" data-x="6.245" data-y="-1.5050000000000003" cx="562.9828547820698" cy="392.121737932934" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><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></g><script><![CDATA[
|
|
37
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
38
|
+
const svg = e.currentTarget;
|
|
39
|
+
const rect = svg.getBoundingClientRect();
|
|
40
|
+
const x = e.clientX - rect.left;
|
|
41
|
+
const y = e.clientY - rect.top;
|
|
42
|
+
const crosshair = svg.getElementById('crosshair');
|
|
43
|
+
const h = svg.getElementById('crosshair-h');
|
|
44
|
+
const v = svg.getElementById('crosshair-v');
|
|
45
|
+
const coords = svg.getElementById('coordinates');
|
|
46
|
+
|
|
47
|
+
crosshair.style.display = 'block';
|
|
48
|
+
h.setAttribute('x1', '0');
|
|
49
|
+
h.setAttribute('x2', '640');
|
|
50
|
+
h.setAttribute('y1', y);
|
|
51
|
+
h.setAttribute('y2', y);
|
|
52
|
+
v.setAttribute('x1', x);
|
|
53
|
+
v.setAttribute('x2', x);
|
|
54
|
+
v.setAttribute('y1', '0');
|
|
55
|
+
v.setAttribute('y2', '640');
|
|
56
|
+
|
|
57
|
+
// Calculate real coordinates using inverse transformation
|
|
58
|
+
const matrix = {"a":46.271431522412726,"c":0,"e":274.0177649246023,"b":0,"d":-46.271431522412726,"f":322.48323349170283};
|
|
59
|
+
// Manually invert and apply the affine transform
|
|
60
|
+
// Since we only use translate and scale, we can directly compute:
|
|
61
|
+
// x' = (x - tx) / sx
|
|
62
|
+
// y' = (y - ty) / sy
|
|
63
|
+
const sx = matrix.a;
|
|
64
|
+
const sy = matrix.d;
|
|
65
|
+
const tx = matrix.e;
|
|
66
|
+
const ty = matrix.f;
|
|
67
|
+
const realPoint = {
|
|
68
|
+
x: (x - tx) / sx,
|
|
69
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
73
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
74
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
75
|
+
});
|
|
76
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
77
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
78
|
+
});
|
|
79
|
+
]]></script></svg>
|