@tscircuit/schematic-trace-solver 0.0.195 → 0.0.197
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 +48 -3
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +42 -1
- package/lib/solvers/NetLabelToTraceSolver/getSimpleElbowPath.ts +31 -0
- package/lib/solvers/UnroutedTraceRecoverySolver/UnroutedTraceRecoverySolver.ts +15 -1
- package/package.json +1 -1
- package/site/bug-reports/enc-scl-hop.page.tsx +6 -0
- package/tests/assets/enc-scl-hop.json +185 -0
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +13 -31
- package/tests/bug-reports/bug-report-20260901T064117Z/__snapshots__/bug-report-20260901T064117Z.snap.svg +25 -61
- package/tests/repros/__snapshots__/repro-core-vertical-passive-ground-label-overlap.snap.svg +3 -3
- package/tests/repros/__snapshots__/repro-mcp73831-charger-traces.snap.svg +5 -23
- package/tests/repros/__snapshots__/repro-trellis-core-gnd-net-label-overlap.snap.svg +25 -61
- package/tests/repros/__snapshots__/rp2040-robot-controller-disconnected-gnd.snap.svg +12 -26
- package/tests/repros/repro-core-vertical-passive-ground-label-overlap.test.ts +3 -3
- package/tests/solvers/SchematicTracePipelineSolver/__snapshots__/enc-scl-hop.snap.svg +101 -0
- package/tests/solvers/SchematicTracePipelineSolver/__snapshots__/explicit-hop.snap.svg +101 -0
- package/tests/solvers/SchematicTracePipelineSolver/enc-scl-hop.test.ts +139 -0
- package/tests/solvers/UnroutedTraceRecoverySolver/endpoint-approach.test.ts +85 -0
package/dist/index.d.ts
CHANGED
|
@@ -1451,6 +1451,7 @@ declare class NetLabelToTraceSolver extends BaseSolver {
|
|
|
1451
1451
|
private isPortOnlyFallbackLabel;
|
|
1452
1452
|
private isDirectConnectionLabel;
|
|
1453
1453
|
private getMultiPinNetConnection;
|
|
1454
|
+
private getTwoPinNetConnection;
|
|
1454
1455
|
private buildCandidatePairs;
|
|
1455
1456
|
private buildRoutedComponentCandidates;
|
|
1456
1457
|
private isSupersededConnectorTrace;
|
package/dist/index.js
CHANGED
|
@@ -13253,6 +13253,16 @@ var pathCollidesWithObstacles = ({
|
|
|
13253
13253
|
const lastPathPin = connectionPair.pins.find(
|
|
13254
13254
|
(pin) => pointsAreEqual(pin, lastPathPoint)
|
|
13255
13255
|
);
|
|
13256
|
+
for (const [pin, neighbor] of [
|
|
13257
|
+
[firstPathPin, path[1]],
|
|
13258
|
+
[lastPathPin, path[path.length - 2]]
|
|
13259
|
+
]) {
|
|
13260
|
+
if (!pin?._facingDirection) continue;
|
|
13261
|
+
const outward = dir(pin._facingDirection);
|
|
13262
|
+
if ((neighbor.x - pin.x) * outward.x + (neighbor.y - pin.y) * outward.y < -COORDINATE_TOLERANCE) {
|
|
13263
|
+
return true;
|
|
13264
|
+
}
|
|
13265
|
+
}
|
|
13256
13266
|
const pathConnectsPairPins = firstPathPin !== void 0 && lastPathPin !== void 0;
|
|
13257
13267
|
const firstChipObstacle = obstacles.find(
|
|
13258
13268
|
(obstacle) => obstacle.kind === "chip" && obstacle.chipId === firstPathPin?.chipId
|
|
@@ -17890,6 +17900,23 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
|
17890
17900
|
return { chipMap, pinMap };
|
|
17891
17901
|
};
|
|
17892
17902
|
|
|
17903
|
+
// lib/solvers/NetLabelToTraceSolver/getSimpleElbowPath.ts
|
|
17904
|
+
var getSimpleElbowPath = (first, second) => {
|
|
17905
|
+
const firstDirection = dir(first._facingDirection);
|
|
17906
|
+
const secondDirection = dir(second._facingDirection);
|
|
17907
|
+
if (firstDirection.x * secondDirection.x || firstDirection.y * secondDirection.y)
|
|
17908
|
+
return void 0;
|
|
17909
|
+
const elbow = firstDirection.x ? { x: second.x, y: first.y } : { x: first.x, y: second.y };
|
|
17910
|
+
for (const [pin, direction] of [
|
|
17911
|
+
[first, firstDirection],
|
|
17912
|
+
[second, secondDirection]
|
|
17913
|
+
]) {
|
|
17914
|
+
if ((elbow.x - pin.x) * direction.x + (elbow.y - pin.y) * direction.y <= 1e-6)
|
|
17915
|
+
return void 0;
|
|
17916
|
+
}
|
|
17917
|
+
return [{ x: first.x, y: first.y }, elbow, { x: second.x, y: second.y }];
|
|
17918
|
+
};
|
|
17919
|
+
|
|
17893
17920
|
// lib/solvers/NetLabelToTraceSolver/reduceTraceCrossings.ts
|
|
17894
17921
|
var EPS18 = 1e-9;
|
|
17895
17922
|
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS18;
|
|
@@ -18064,6 +18091,11 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18064
18091
|
(connection) => connection.isGround === false && connection.pinIds.length > 2 && connection.netId === label.netId && connection.pinIds.includes(pinId)
|
|
18065
18092
|
);
|
|
18066
18093
|
}
|
|
18094
|
+
getTwoPinNetConnection(label) {
|
|
18095
|
+
return this.inputProblem.netConnections.find(
|
|
18096
|
+
(connection) => !connection.isGround && connection.pinIds.length === 2 && connection.netId === label.netId && connection.pinIds.includes(label.pinIds[0])
|
|
18097
|
+
);
|
|
18098
|
+
}
|
|
18067
18099
|
buildCandidatePairs() {
|
|
18068
18100
|
const { netConnMap } = getConnectivityMapsFromInputProblem(
|
|
18069
18101
|
this.inputProblem
|
|
@@ -18076,7 +18108,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18076
18108
|
}
|
|
18077
18109
|
const labelsByGlobalNet = /* @__PURE__ */ new Map();
|
|
18078
18110
|
for (const label of this.input.netLabelPlacements) {
|
|
18079
|
-
if (!this.isPortOnlyFallbackLabel(label, groundGlobalConnNetIds) || !this.isDirectConnectionLabel(label) && !this.getMultiPinNetConnection(label)) {
|
|
18111
|
+
if (!this.isPortOnlyFallbackLabel(label, groundGlobalConnNetIds) || !this.isDirectConnectionLabel(label) && !this.getMultiPinNetConnection(label) && !this.getTwoPinNetConnection(label)) {
|
|
18080
18112
|
continue;
|
|
18081
18113
|
}
|
|
18082
18114
|
const labels = labelsByGlobalNet.get(label.globalConnNetId) ?? [];
|
|
@@ -18100,7 +18132,9 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18100
18132
|
const bothLabelsBelongToDirectConnections = this.isDirectConnectionLabel(firstLabel) && this.isDirectConnectionLabel(secondLabel);
|
|
18101
18133
|
const firstMultiPinNetConnection = this.getMultiPinNetConnection(firstLabel);
|
|
18102
18134
|
const secondMultiPinNetConnection = this.getMultiPinNetConnection(secondLabel);
|
|
18103
|
-
|
|
18135
|
+
const twoPinNetConnection = this.getTwoPinNetConnection(firstLabel);
|
|
18136
|
+
const simpleElbowPath = !bothLabelsBelongToDirectConnections && twoPinNetConnection && firstPin.chipId !== secondPin.chipId && twoPinNetConnection === this.getTwoPinNetConnection(secondLabel) ? getSimpleElbowPath(firstPin, secondPin) : void 0;
|
|
18137
|
+
if (!simpleElbowPath && !bothLabelsBelongToDirectConnections && (!firstMultiPinNetConnection || firstMultiPinNetConnection !== secondMultiPinNetConnection || perpendicularOffset > MAX_NAMED_NET_RECOVERY_PERPENDICULAR_OFFSET)) {
|
|
18104
18138
|
continue;
|
|
18105
18139
|
}
|
|
18106
18140
|
if (arePinsInDifferentSchematicSections(
|
|
@@ -18126,7 +18160,8 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18126
18160
|
perpendicularOffset,
|
|
18127
18161
|
routeDistance: Math.abs(firstPin.x - secondPin.x) + Math.abs(firstPin.y - secondPin.y),
|
|
18128
18162
|
key: getCanonicalPairKey(firstPin.pinId, secondPin.pinId),
|
|
18129
|
-
recoveryMode: "fallback_labels"
|
|
18163
|
+
recoveryMode: "fallback_labels",
|
|
18164
|
+
simpleElbowPath
|
|
18130
18165
|
});
|
|
18131
18166
|
}
|
|
18132
18167
|
}
|
|
@@ -18288,6 +18323,16 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18288
18323
|
(trace) => trace.globalConnNetId !== candidate.firstLabel.globalConnNetId
|
|
18289
18324
|
);
|
|
18290
18325
|
}
|
|
18326
|
+
if (candidate.simpleElbowPath) {
|
|
18327
|
+
tracePath = candidate.simpleElbowPath;
|
|
18328
|
+
if (findFirstCollision(tracePath, this.activeSubSolver.obstacles) || collisionTraces.reduce(
|
|
18329
|
+
(count, trace) => count + findPerpendicularPathCrossings(tracePath, trace.tracePath, {
|
|
18330
|
+
includeTerminalSegments: true
|
|
18331
|
+
}).length,
|
|
18332
|
+
0
|
|
18333
|
+
) > 1)
|
|
18334
|
+
return;
|
|
18335
|
+
}
|
|
18291
18336
|
if (doesTraceRecoveryPathConflict(tracePath, collisionTraces) || this.routeIntersectsRemainingLabels(tracePath, candidate)) {
|
|
18292
18337
|
return;
|
|
18293
18338
|
}
|
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
type InlineNetLabelPlacement,
|
|
28
28
|
visualizeInlineNetLabelOutput,
|
|
29
29
|
} from "../InlineNetLabelSolver/InlineNetLabelSolver"
|
|
30
|
+
import { getSimpleElbowPath } from "./getSimpleElbowPath"
|
|
31
|
+
import { findPerpendicularPathCrossings } from "../TraceCleanupSolver/sub-solver/findIntersectionsWithObstacles"
|
|
30
32
|
import { reduceTraceCrossings } from "./reduceTraceCrossings"
|
|
31
33
|
|
|
32
34
|
type GlobalConnNetId = NetLabelPlacement["globalConnNetId"]
|
|
@@ -43,6 +45,7 @@ interface CandidatePair {
|
|
|
43
45
|
| "routed_components"
|
|
44
46
|
| "routed_direct_connection"
|
|
45
47
|
netConnectionPinIds?: PinId[]
|
|
48
|
+
simpleElbowPath?: Point[]
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
const RECOVERED_TRACE_PREFIX = "net-label-to-trace-"
|
|
@@ -153,6 +156,16 @@ export class NetLabelToTraceSolver extends BaseSolver {
|
|
|
153
156
|
)
|
|
154
157
|
}
|
|
155
158
|
|
|
159
|
+
private getTwoPinNetConnection(label: NetLabelPlacement) {
|
|
160
|
+
return this.inputProblem.netConnections.find(
|
|
161
|
+
(connection) =>
|
|
162
|
+
!connection.isGround &&
|
|
163
|
+
connection.pinIds.length === 2 &&
|
|
164
|
+
connection.netId === label.netId &&
|
|
165
|
+
connection.pinIds.includes(label.pinIds[0]!),
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
156
169
|
private buildCandidatePairs() {
|
|
157
170
|
const { netConnMap } = getConnectivityMapsFromInputProblem(
|
|
158
171
|
this.inputProblem,
|
|
@@ -169,7 +182,8 @@ export class NetLabelToTraceSolver extends BaseSolver {
|
|
|
169
182
|
if (
|
|
170
183
|
!this.isPortOnlyFallbackLabel(label, groundGlobalConnNetIds) ||
|
|
171
184
|
(!this.isDirectConnectionLabel(label) &&
|
|
172
|
-
!this.getMultiPinNetConnection(label)
|
|
185
|
+
!this.getMultiPinNetConnection(label) &&
|
|
186
|
+
!this.getTwoPinNetConnection(label))
|
|
173
187
|
) {
|
|
174
188
|
continue
|
|
175
189
|
}
|
|
@@ -203,7 +217,16 @@ export class NetLabelToTraceSolver extends BaseSolver {
|
|
|
203
217
|
this.getMultiPinNetConnection(firstLabel)
|
|
204
218
|
const secondMultiPinNetConnection =
|
|
205
219
|
this.getMultiPinNetConnection(secondLabel)
|
|
220
|
+
const twoPinNetConnection = this.getTwoPinNetConnection(firstLabel)
|
|
221
|
+
const simpleElbowPath =
|
|
222
|
+
!bothLabelsBelongToDirectConnections &&
|
|
223
|
+
twoPinNetConnection &&
|
|
224
|
+
firstPin.chipId !== secondPin.chipId &&
|
|
225
|
+
twoPinNetConnection === this.getTwoPinNetConnection(secondLabel)
|
|
226
|
+
? getSimpleElbowPath(firstPin, secondPin)
|
|
227
|
+
: undefined
|
|
206
228
|
if (
|
|
229
|
+
!simpleElbowPath &&
|
|
207
230
|
!bothLabelsBelongToDirectConnections &&
|
|
208
231
|
(!firstMultiPinNetConnection ||
|
|
209
232
|
firstMultiPinNetConnection !== secondMultiPinNetConnection ||
|
|
@@ -242,6 +265,7 @@ export class NetLabelToTraceSolver extends BaseSolver {
|
|
|
242
265
|
Math.abs(firstPin.y - secondPin.y),
|
|
243
266
|
key: getCanonicalPairKey(firstPin.pinId, secondPin.pinId),
|
|
244
267
|
recoveryMode: "fallback_labels",
|
|
268
|
+
simpleElbowPath,
|
|
245
269
|
})
|
|
246
270
|
}
|
|
247
271
|
}
|
|
@@ -474,6 +498,23 @@ export class NetLabelToTraceSolver extends BaseSolver {
|
|
|
474
498
|
trace.globalConnNetId !== candidate.firstLabel.globalConnNetId,
|
|
475
499
|
)
|
|
476
500
|
}
|
|
501
|
+
// Only recover a named two-pin elbow when the shortest, direction-respecting
|
|
502
|
+
// path is clear. Do not replace labels with obstacle detours or many hops.
|
|
503
|
+
if (candidate.simpleElbowPath) {
|
|
504
|
+
tracePath = candidate.simpleElbowPath
|
|
505
|
+
if (
|
|
506
|
+
findFirstCollision(tracePath, this.activeSubSolver!.obstacles) ||
|
|
507
|
+
collisionTraces.reduce(
|
|
508
|
+
(count, trace) =>
|
|
509
|
+
count +
|
|
510
|
+
findPerpendicularPathCrossings(tracePath!, trace.tracePath, {
|
|
511
|
+
includeTerminalSegments: true,
|
|
512
|
+
}).length,
|
|
513
|
+
0,
|
|
514
|
+
) > 1
|
|
515
|
+
)
|
|
516
|
+
return
|
|
517
|
+
}
|
|
477
518
|
if (
|
|
478
519
|
doesTraceRecoveryPathConflict(tracePath, collisionTraces) ||
|
|
479
520
|
this.routeIntersectsRemainingLabels(tracePath, candidate)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
2
|
+
import type { TraceRecoveryPin } from "lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps"
|
|
3
|
+
import { dir } from "lib/utils/dir"
|
|
4
|
+
|
|
5
|
+
/** The single elbow reached by extending both pins outwards, if it exists. */
|
|
6
|
+
export const getSimpleElbowPath = (
|
|
7
|
+
first: TraceRecoveryPin,
|
|
8
|
+
second: TraceRecoveryPin,
|
|
9
|
+
): Point[] | undefined => {
|
|
10
|
+
const firstDirection = dir(first._facingDirection)
|
|
11
|
+
const secondDirection = dir(second._facingDirection)
|
|
12
|
+
if (
|
|
13
|
+
firstDirection.x * secondDirection.x ||
|
|
14
|
+
firstDirection.y * secondDirection.y
|
|
15
|
+
)
|
|
16
|
+
return undefined
|
|
17
|
+
const elbow = firstDirection.x
|
|
18
|
+
? { x: second.x, y: first.y }
|
|
19
|
+
: { x: first.x, y: second.y }
|
|
20
|
+
for (const [pin, direction] of [
|
|
21
|
+
[first, firstDirection],
|
|
22
|
+
[second, secondDirection],
|
|
23
|
+
] as const) {
|
|
24
|
+
if (
|
|
25
|
+
(elbow.x - pin.x) * direction.x + (elbow.y - pin.y) * direction.y <=
|
|
26
|
+
1e-6
|
|
27
|
+
)
|
|
28
|
+
return undefined
|
|
29
|
+
}
|
|
30
|
+
return [{ x: first.x, y: first.y }, elbow, { x: second.x, y: second.y }]
|
|
31
|
+
}
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
21
21
|
import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
|
|
22
22
|
import type { InputProblem, PinId } from "lib/types/InputProblem"
|
|
23
|
-
import type
|
|
23
|
+
import { dir, type FacingDirection } from "lib/utils/dir"
|
|
24
24
|
|
|
25
25
|
const ROUTE_CLEARANCE = 0.2
|
|
26
26
|
const COORDINATE_TOLERANCE = 1e-9
|
|
@@ -306,6 +306,20 @@ const pathCollidesWithObstacles = ({
|
|
|
306
306
|
const lastPathPin = connectionPair.pins.find((pin) =>
|
|
307
307
|
pointsAreEqual(pin, lastPathPoint),
|
|
308
308
|
)
|
|
309
|
+
// Endpoint exemptions must not allow a route through the back of a component.
|
|
310
|
+
for (const [pin, neighbor] of [
|
|
311
|
+
[firstPathPin, path[1]!],
|
|
312
|
+
[lastPathPin, path[path.length - 2]!],
|
|
313
|
+
] as const) {
|
|
314
|
+
if (!pin?._facingDirection) continue
|
|
315
|
+
const outward = dir(pin._facingDirection)
|
|
316
|
+
if (
|
|
317
|
+
(neighbor.x - pin.x) * outward.x + (neighbor.y - pin.y) * outward.y <
|
|
318
|
+
-COORDINATE_TOLERANCE
|
|
319
|
+
) {
|
|
320
|
+
return true
|
|
321
|
+
}
|
|
322
|
+
}
|
|
309
323
|
const pathConnectsPairPins =
|
|
310
324
|
firstPathPin !== undefined && lastPathPin !== undefined
|
|
311
325
|
const firstChipObstacle = obstacles.find(
|
package/package.json
CHANGED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chips": [
|
|
3
|
+
{
|
|
4
|
+
"chipId": "R_ENC_SDA",
|
|
5
|
+
"center": {
|
|
6
|
+
"x": 0.0,
|
|
7
|
+
"y": 1.8
|
|
8
|
+
},
|
|
9
|
+
"width": 0.16000000000000003,
|
|
10
|
+
"height": 0.4,
|
|
11
|
+
"pins": [
|
|
12
|
+
{
|
|
13
|
+
"pinId": "R_ENC_SDA.1",
|
|
14
|
+
"x": 0.0,
|
|
15
|
+
"y": 2.1,
|
|
16
|
+
"_facingDirection": "y+"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"pinId": "R_ENC_SDA.2",
|
|
20
|
+
"x": 0.0,
|
|
21
|
+
"y": 1.5,
|
|
22
|
+
"_facingDirection": "y-"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"chipId": "R_ENC_SCL",
|
|
28
|
+
"center": {
|
|
29
|
+
"x": 2.0,
|
|
30
|
+
"y": 1.8
|
|
31
|
+
},
|
|
32
|
+
"width": 0.16000000000000003,
|
|
33
|
+
"height": 0.4,
|
|
34
|
+
"pins": [
|
|
35
|
+
{
|
|
36
|
+
"pinId": "R_ENC_SCL.1",
|
|
37
|
+
"x": 2.0,
|
|
38
|
+
"y": 2.1,
|
|
39
|
+
"_facingDirection": "y+"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"pinId": "R_ENC_SCL.2",
|
|
43
|
+
"x": 2.0,
|
|
44
|
+
"y": 1.5,
|
|
45
|
+
"_facingDirection": "y-"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"chipId": "U_ENCODER",
|
|
51
|
+
"center": {
|
|
52
|
+
"x": 6.0,
|
|
53
|
+
"y": 0.0
|
|
54
|
+
},
|
|
55
|
+
"width": 1.7600000000000002,
|
|
56
|
+
"height": 1.6,
|
|
57
|
+
"pins": [
|
|
58
|
+
{
|
|
59
|
+
"pinId": "U_ENCODER.6",
|
|
60
|
+
"displayName": "SDA",
|
|
61
|
+
"x": 4.720000000000001,
|
|
62
|
+
"y": 0.1,
|
|
63
|
+
"_facingDirection": "x-"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"pinId": "U_ENCODER.7",
|
|
67
|
+
"displayName": "SCL",
|
|
68
|
+
"x": 4.720000000000001,
|
|
69
|
+
"y": -0.1,
|
|
70
|
+
"_facingDirection": "x-"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"pinId": "U_ENCODER.1",
|
|
74
|
+
"displayName": "VDD5V",
|
|
75
|
+
"x": 5.9,
|
|
76
|
+
"y": 1.2000000000000002,
|
|
77
|
+
"_facingDirection": "y+"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"pinId": "U_ENCODER.2",
|
|
81
|
+
"displayName": "VDD3V3",
|
|
82
|
+
"x": 6.1000000000000005,
|
|
83
|
+
"y": 1.2000000000000002,
|
|
84
|
+
"_facingDirection": "y+"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"pinId": "U_ENCODER.4",
|
|
88
|
+
"displayName": "GND",
|
|
89
|
+
"x": 5.9,
|
|
90
|
+
"y": -1.2000000000000002,
|
|
91
|
+
"_facingDirection": "y-"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"pinId": "U_ENCODER.8",
|
|
95
|
+
"displayName": "DIR",
|
|
96
|
+
"x": 6.1000000000000005,
|
|
97
|
+
"y": -1.2000000000000002,
|
|
98
|
+
"_facingDirection": "y-"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"pinId": "U_ENCODER.3",
|
|
102
|
+
"displayName": "OUT",
|
|
103
|
+
"x": 7.28,
|
|
104
|
+
"y": 0.1,
|
|
105
|
+
"_facingDirection": "x+"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"pinId": "U_ENCODER.5",
|
|
109
|
+
"displayName": "PGO",
|
|
110
|
+
"x": 7.28,
|
|
111
|
+
"y": -0.1,
|
|
112
|
+
"_facingDirection": "x+"
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"directConnections": [
|
|
118
|
+
{
|
|
119
|
+
"netId": "ENC_SDA",
|
|
120
|
+
"netLabelText": "ENC_SDA",
|
|
121
|
+
"pinIds": [
|
|
122
|
+
"R_ENC_SDA.2",
|
|
123
|
+
"U_ENCODER.6"
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"pinIds": [
|
|
128
|
+
"R_ENC_SDA.1",
|
|
129
|
+
"R_ENC_SCL.1"
|
|
130
|
+
],
|
|
131
|
+
"netId": "V3V3"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"pinIds": [
|
|
135
|
+
"U_ENCODER.1",
|
|
136
|
+
"U_ENCODER.2"
|
|
137
|
+
],
|
|
138
|
+
"netId": "V3V3"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"netConnections": [
|
|
142
|
+
{
|
|
143
|
+
"netId": "ENC_SDA",
|
|
144
|
+
"netLabelText": "ENC_SDA",
|
|
145
|
+
"pinIds": [
|
|
146
|
+
"R_ENC_SDA.2",
|
|
147
|
+
"U_ENCODER.6"
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"netId": "ENC_SCL",
|
|
152
|
+
"netLabelText": "ENC_SCL",
|
|
153
|
+
"pinIds": [
|
|
154
|
+
"R_ENC_SCL.2",
|
|
155
|
+
"U_ENCODER.7"
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"netId": "V3V3",
|
|
160
|
+
"netLabelText": "V3V3",
|
|
161
|
+
"pinIds": [
|
|
162
|
+
"R_ENC_SDA.1",
|
|
163
|
+
"R_ENC_SCL.1",
|
|
164
|
+
"U_ENCODER.1",
|
|
165
|
+
"U_ENCODER.2"
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"netId": "GND",
|
|
170
|
+
"netLabelText": "GND",
|
|
171
|
+
"pinIds": [
|
|
172
|
+
"U_ENCODER.4",
|
|
173
|
+
"U_ENCODER.8"
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"availableNetLabelOrientations": {
|
|
178
|
+
"V3V3": [
|
|
179
|
+
"y+"
|
|
180
|
+
],
|
|
181
|
+
"GND": [
|
|
182
|
+
"y-"
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
}
|