@tscircuit/schematic-trace-solver 0.0.196 → 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 +38 -3
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +42 -1
- package/lib/solvers/NetLabelToTraceSolver/getSimpleElbowPath.ts +31 -0
- 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-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/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/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
|
@@ -17900,6 +17900,23 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
|
17900
17900
|
return { chipMap, pinMap };
|
|
17901
17901
|
};
|
|
17902
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
|
+
|
|
17903
17920
|
// lib/solvers/NetLabelToTraceSolver/reduceTraceCrossings.ts
|
|
17904
17921
|
var EPS18 = 1e-9;
|
|
17905
17922
|
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS18;
|
|
@@ -18074,6 +18091,11 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18074
18091
|
(connection) => connection.isGround === false && connection.pinIds.length > 2 && connection.netId === label.netId && connection.pinIds.includes(pinId)
|
|
18075
18092
|
);
|
|
18076
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
|
+
}
|
|
18077
18099
|
buildCandidatePairs() {
|
|
18078
18100
|
const { netConnMap } = getConnectivityMapsFromInputProblem(
|
|
18079
18101
|
this.inputProblem
|
|
@@ -18086,7 +18108,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18086
18108
|
}
|
|
18087
18109
|
const labelsByGlobalNet = /* @__PURE__ */ new Map();
|
|
18088
18110
|
for (const label of this.input.netLabelPlacements) {
|
|
18089
|
-
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)) {
|
|
18090
18112
|
continue;
|
|
18091
18113
|
}
|
|
18092
18114
|
const labels = labelsByGlobalNet.get(label.globalConnNetId) ?? [];
|
|
@@ -18110,7 +18132,9 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18110
18132
|
const bothLabelsBelongToDirectConnections = this.isDirectConnectionLabel(firstLabel) && this.isDirectConnectionLabel(secondLabel);
|
|
18111
18133
|
const firstMultiPinNetConnection = this.getMultiPinNetConnection(firstLabel);
|
|
18112
18134
|
const secondMultiPinNetConnection = this.getMultiPinNetConnection(secondLabel);
|
|
18113
|
-
|
|
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)) {
|
|
18114
18138
|
continue;
|
|
18115
18139
|
}
|
|
18116
18140
|
if (arePinsInDifferentSchematicSections(
|
|
@@ -18136,7 +18160,8 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18136
18160
|
perpendicularOffset,
|
|
18137
18161
|
routeDistance: Math.abs(firstPin.x - secondPin.x) + Math.abs(firstPin.y - secondPin.y),
|
|
18138
18162
|
key: getCanonicalPairKey(firstPin.pinId, secondPin.pinId),
|
|
18139
|
-
recoveryMode: "fallback_labels"
|
|
18163
|
+
recoveryMode: "fallback_labels",
|
|
18164
|
+
simpleElbowPath
|
|
18140
18165
|
});
|
|
18141
18166
|
}
|
|
18142
18167
|
}
|
|
@@ -18298,6 +18323,16 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
18298
18323
|
(trace) => trace.globalConnNetId !== candidate.firstLabel.globalConnNetId
|
|
18299
18324
|
);
|
|
18300
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
|
+
}
|
|
18301
18336
|
if (doesTraceRecoveryPathConflict(tracePath, collisionTraces) || this.routeIntersectsRemainingLabels(tracePath, candidate)) {
|
|
18302
18337
|
return;
|
|
18303
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
|
+
}
|
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
|
+
}
|