@tscircuit/schematic-trace-solver 0.0.78 → 0.0.79

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 CHANGED
@@ -901,6 +901,11 @@ declare class NetLabelTraceCollisionSolver extends BaseSolver {
901
901
  constructor(params: NetLabelTraceCollisionSolverParams);
902
902
  getConstructorParams(): ConstructorParameters<typeof NetLabelTraceCollisionSolver>[0];
903
903
  _step(): void;
904
+ /**
905
+ * When a trace is rerouted, net labels that were anchored on the old path
906
+ * can be left floating in space. Snap their anchor back onto the new path.
907
+ */
908
+ private reanchorLabelsOnMovedTrace;
904
909
  getOutput(): {
905
910
  traces: SolvedTracePath[];
906
911
  netLabelPlacements: NetLabelPlacement[];
package/dist/index.js CHANGED
@@ -7815,6 +7815,43 @@ var TraceAnchoredNetLabelOverlapSolver = class extends BaseSolver {
7815
7815
  };
7816
7816
 
7817
7817
  // lib/solvers/NetLabelTraceCollisionSolver/NetLabelTraceCollisionSolver.ts
7818
+ var ON_PATH_EPS = 1e-6;
7819
+ function getClosestPointOnSegment(params) {
7820
+ const { point, segmentStart, segmentEnd } = params;
7821
+ const dx = segmentEnd.x - segmentStart.x;
7822
+ const dy = segmentEnd.y - segmentStart.y;
7823
+ const segmentLengthSq = dx * dx + dy * dy;
7824
+ if (segmentLengthSq === 0) return { x: segmentStart.x, y: segmentStart.y };
7825
+ const projection = ((point.x - segmentStart.x) * dx + (point.y - segmentStart.y) * dy) / segmentLengthSq;
7826
+ const clampedProjection = Math.max(0, Math.min(1, projection));
7827
+ return {
7828
+ x: segmentStart.x + clampedProjection * dx,
7829
+ y: segmentStart.y + clampedProjection * dy
7830
+ };
7831
+ }
7832
+ function getClosestPointOnPath(point, path) {
7833
+ let closestPoint = path[0];
7834
+ let closestDistSq = Infinity;
7835
+ for (let i = 0; i < path.length - 1; i++) {
7836
+ const candidatePoint = getClosestPointOnSegment({
7837
+ point,
7838
+ segmentStart: path[i],
7839
+ segmentEnd: path[i + 1]
7840
+ });
7841
+ const dx = candidatePoint.x - point.x;
7842
+ const dy = candidatePoint.y - point.y;
7843
+ const candidateDistSq = dx * dx + dy * dy;
7844
+ if (candidateDistSq < closestDistSq) {
7845
+ closestDistSq = candidateDistSq;
7846
+ closestPoint = candidatePoint;
7847
+ }
7848
+ }
7849
+ return closestPoint;
7850
+ }
7851
+ function isPointOnPath(point, path) {
7852
+ const closestPoint = getClosestPointOnPath(point, path);
7853
+ return Math.hypot(closestPoint.x - point.x, closestPoint.y - point.y) < ON_PATH_EPS;
7854
+ }
7818
7855
  function buildMergedObstacleLabel(seedLabel, allLabels) {
7819
7856
  const TOUCH_MARGIN = 0.01;
7820
7857
  const getBounds3 = (l) => getRectBounds(l.center, l.width, l.height);
@@ -7908,10 +7945,12 @@ var NetLabelTraceCollisionSolver = class extends BaseSolver {
7908
7945
  (t) => t.mspPairId === this.activeSubSolver.initialTrace.mspPairId
7909
7946
  );
7910
7947
  if (idx !== -1) {
7948
+ const oldPath = this.outputTraces[idx].tracePath;
7911
7949
  this.outputTraces[idx] = {
7912
7950
  ...this.outputTraces[idx],
7913
7951
  tracePath: solvedPath
7914
7952
  };
7953
+ this.reanchorLabelsOnMovedTrace(this.outputTraces[idx], oldPath);
7915
7954
  }
7916
7955
  }
7917
7956
  this.activeSubSolver = null;
@@ -7966,6 +8005,32 @@ var NetLabelTraceCollisionSolver = class extends BaseSolver {
7966
8005
  detourCount
7967
8006
  });
7968
8007
  }
8008
+ /**
8009
+ * When a trace is rerouted, net labels that were anchored on the old path
8010
+ * can be left floating in space. Snap their anchor back onto the new path.
8011
+ */
8012
+ reanchorLabelsOnMovedTrace(movedTrace, oldPath) {
8013
+ for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
8014
+ const label = this.outputNetLabelPlacements[i];
8015
+ if (label.globalConnNetId !== movedTrace.globalConnNetId) continue;
8016
+ if (isPointOnPath(label.anchorPoint, movedTrace.tracePath)) continue;
8017
+ if (!isPointOnPath(label.anchorPoint, oldPath)) continue;
8018
+ const newAnchor = getClosestPointOnPath(
8019
+ label.anchorPoint,
8020
+ movedTrace.tracePath
8021
+ );
8022
+ this.outputNetLabelPlacements[i] = {
8023
+ ...label,
8024
+ anchorPoint: newAnchor,
8025
+ center: getCenterFromAnchor(
8026
+ newAnchor,
8027
+ label.orientation,
8028
+ label.width,
8029
+ label.height
8030
+ )
8031
+ };
8032
+ }
8033
+ }
7969
8034
  getOutput() {
7970
8035
  return {
7971
8036
  traces: this.outputTraces,
@@ -1,14 +1,67 @@
1
+ import type { Point } from "@tscircuit/math-utils"
1
2
  import type { GraphicsObject } from "graphics-debug"
2
3
  import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
3
4
  import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
4
5
  import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
5
6
  import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
6
7
  import { SingleOverlapSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver"
7
- import { getRectBounds } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
8
+ import {
9
+ getCenterFromAnchor,
10
+ getRectBounds,
11
+ } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
8
12
  import { segmentIntersectsRect } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions"
9
13
  import { getColorFromString } from "lib/utils/getColorFromString"
10
14
  import type { InputProblem } from "lib/types/InputProblem"
11
15
 
16
+ const ON_PATH_EPS = 1e-6
17
+
18
+ function getClosestPointOnSegment(params: {
19
+ point: Point
20
+ segmentStart: Point
21
+ segmentEnd: Point
22
+ }): Point {
23
+ const { point, segmentStart, segmentEnd } = params
24
+ const dx = segmentEnd.x - segmentStart.x
25
+ const dy = segmentEnd.y - segmentStart.y
26
+ const segmentLengthSq = dx * dx + dy * dy
27
+ if (segmentLengthSq === 0) return { x: segmentStart.x, y: segmentStart.y }
28
+ const projection =
29
+ ((point.x - segmentStart.x) * dx + (point.y - segmentStart.y) * dy) /
30
+ segmentLengthSq
31
+ const clampedProjection = Math.max(0, Math.min(1, projection))
32
+ return {
33
+ x: segmentStart.x + clampedProjection * dx,
34
+ y: segmentStart.y + clampedProjection * dy,
35
+ }
36
+ }
37
+
38
+ function getClosestPointOnPath(point: Point, path: Point[]): Point {
39
+ let closestPoint: Point = path[0]!
40
+ let closestDistSq = Infinity
41
+ for (let i = 0; i < path.length - 1; i++) {
42
+ const candidatePoint = getClosestPointOnSegment({
43
+ point,
44
+ segmentStart: path[i]!,
45
+ segmentEnd: path[i + 1]!,
46
+ })
47
+ const dx = candidatePoint.x - point.x
48
+ const dy = candidatePoint.y - point.y
49
+ const candidateDistSq = dx * dx + dy * dy
50
+ if (candidateDistSq < closestDistSq) {
51
+ closestDistSq = candidateDistSq
52
+ closestPoint = candidatePoint
53
+ }
54
+ }
55
+ return closestPoint
56
+ }
57
+
58
+ function isPointOnPath(point: Point, path: Point[]): boolean {
59
+ const closestPoint = getClosestPointOnPath(point, path)
60
+ return (
61
+ Math.hypot(closestPoint.x - point.x, closestPoint.y - point.y) < ON_PATH_EPS
62
+ )
63
+ }
64
+
12
65
  /**
13
66
  * Merges all labels that touch/overlap with each other (transitively) around
14
67
  * a seed label into a single bounding-box label. This prevents the situation
@@ -159,10 +212,12 @@ export class NetLabelTraceCollisionSolver extends BaseSolver {
159
212
  (t) => t.mspPairId === this.activeSubSolver!.initialTrace.mspPairId,
160
213
  )
161
214
  if (idx !== -1) {
215
+ const oldPath = this.outputTraces[idx]!.tracePath
162
216
  this.outputTraces[idx] = {
163
217
  ...this.outputTraces[idx],
164
218
  tracePath: solvedPath,
165
219
  }
220
+ this.reanchorLabelsOnMovedTrace(this.outputTraces[idx]!, oldPath)
166
221
  }
167
222
  }
168
223
  this.activeSubSolver = null
@@ -229,6 +284,37 @@ export class NetLabelTraceCollisionSolver extends BaseSolver {
229
284
  })
230
285
  }
231
286
 
287
+ /**
288
+ * When a trace is rerouted, net labels that were anchored on the old path
289
+ * can be left floating in space. Snap their anchor back onto the new path.
290
+ */
291
+ private reanchorLabelsOnMovedTrace(
292
+ movedTrace: SolvedTracePath,
293
+ oldPath: Point[],
294
+ ) {
295
+ for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
296
+ const label = this.outputNetLabelPlacements[i]!
297
+ if (label.globalConnNetId !== movedTrace.globalConnNetId) continue
298
+ if (isPointOnPath(label.anchorPoint, movedTrace.tracePath)) continue
299
+ if (!isPointOnPath(label.anchorPoint, oldPath)) continue
300
+
301
+ const newAnchor = getClosestPointOnPath(
302
+ label.anchorPoint,
303
+ movedTrace.tracePath,
304
+ )
305
+ this.outputNetLabelPlacements[i] = {
306
+ ...label,
307
+ anchorPoint: newAnchor,
308
+ center: getCenterFromAnchor(
309
+ newAnchor,
310
+ label.orientation,
311
+ label.width,
312
+ label.height,
313
+ ),
314
+ }
315
+ }
316
+ }
317
+
232
318
  getOutput() {
233
319
  return {
234
320
  traces: this.outputTraces,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.78",
4
+ "version": "0.0.79",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -0,0 +1,4 @@
1
+ import { PipelineDebugger } from "site/components/PipelineDebugger"
2
+ import inputProblem from "../../tests/assets/example46.json"
3
+
4
+ export default () => <PipelineDebugger inputProblem={inputProblem as any} />
@@ -0,0 +1,4 @@
1
+ import { PipelineDebugger } from "site/components/PipelineDebugger"
2
+ import inputProblem from "../../tests/assets/example47.json"
3
+
4
+ export default () => <PipelineDebugger inputProblem={inputProblem as any} />
@@ -0,0 +1,4 @@
1
+ import { PipelineDebugger } from "site/components/PipelineDebugger"
2
+ import inputProblem from "../../tests/assets/example48.json"
3
+
4
+ export default () => <PipelineDebugger inputProblem={inputProblem as any} />
@@ -0,0 +1,4 @@
1
+ import { PipelineDebugger } from "site/components/PipelineDebugger"
2
+ import inputProblem from "../../tests/assets/example49.json"
3
+
4
+ export default () => <PipelineDebugger inputProblem={inputProblem as any} />
@@ -0,0 +1,236 @@
1
+ {
2
+ "chips": [
3
+ {
4
+ "chipId": "schematic_component_0",
5
+ "center": {
6
+ "x": -2.71,
7
+ "y": 0.7199999999999998
8
+ },
9
+ "width": 0.8599999999999999,
10
+ "height": 1.04,
11
+ "pins": [
12
+ {
13
+ "pinId": "DPROT.1",
14
+ "x": -2.87,
15
+ "y": 1.2399999999999998
16
+ },
17
+ {
18
+ "pinId": "DPROT.2",
19
+ "x": -2.87,
20
+ "y": 0.19999999999999973
21
+ }
22
+ ],
23
+ "sectionId": "pwr"
24
+ },
25
+ {
26
+ "chipId": "schematic_component_1",
27
+ "center": {
28
+ "x": -3.25,
29
+ "y": 3.05
30
+ },
31
+ "width": 1.8800000000000003,
32
+ "height": 1.13,
33
+ "pins": [
34
+ {
35
+ "pinId": "F1.1",
36
+ "x": -2.87,
37
+ "y": 3.58
38
+ },
39
+ {
40
+ "pinId": "F1.2",
41
+ "x": -2.87,
42
+ "y": 2.5199999999999996
43
+ }
44
+ ],
45
+ "sectionId": "pwr"
46
+ },
47
+ {
48
+ "chipId": "schematic_component_2",
49
+ "center": {
50
+ "x": 0,
51
+ "y": 0
52
+ },
53
+ "width": 1.77,
54
+ "height": 0.6,
55
+ "pins": [
56
+ {
57
+ "pinId": "U2.1",
58
+ "x": -1.2850000000000001,
59
+ "y": 0.2
60
+ },
61
+ {
62
+ "pinId": "U2.2",
63
+ "x": -1.2850000000000001,
64
+ "y": 0
65
+ },
66
+ {
67
+ "pinId": "U2.3",
68
+ "x": -1.2850000000000001,
69
+ "y": -0.2
70
+ },
71
+ {
72
+ "pinId": "U2.4",
73
+ "x": 1.2850000000000001,
74
+ "y": -0.1
75
+ },
76
+ {
77
+ "pinId": "U2.5",
78
+ "x": 1.2850000000000001,
79
+ "y": 0.1
80
+ }
81
+ ],
82
+ "sectionId": "pwr"
83
+ },
84
+ {
85
+ "chipId": "schematic_component_3",
86
+ "center": {
87
+ "x": -2.755,
88
+ "y": -1.56
89
+ },
90
+ "width": 0.9600000000000004,
91
+ "height": 1.1000000000000003,
92
+ "pins": [
93
+ {
94
+ "pinId": "C1.1",
95
+ "x": -2.97,
96
+ "y": -1.01
97
+ },
98
+ {
99
+ "pinId": "C1.2",
100
+ "x": -2.97,
101
+ "y": -2.1100000000000003
102
+ }
103
+ ],
104
+ "sectionId": "pwr"
105
+ },
106
+ {
107
+ "chipId": "schematic_component_4",
108
+ "center": {
109
+ "x": -0.5950000000000002,
110
+ "y": -2.4550000000000005
111
+ },
112
+ "width": 0.9599999999999999,
113
+ "height": 1.1000000000000003,
114
+ "pins": [
115
+ {
116
+ "pinId": "C4.1",
117
+ "x": -0.8100000000000003,
118
+ "y": -1.9050000000000005
119
+ },
120
+ {
121
+ "pinId": "C4.2",
122
+ "x": -0.8100000000000003,
123
+ "y": -3.005000000000001
124
+ }
125
+ ],
126
+ "sectionId": "pwr"
127
+ },
128
+ {
129
+ "chipId": "schematic_component_5",
130
+ "center": {
131
+ "x": 2.9724999999999997,
132
+ "y": -1.8699999999999997
133
+ },
134
+ "width": 1.245,
135
+ "height": 1.13,
136
+ "pins": [
137
+ {
138
+ "pinId": "DPWR.1",
139
+ "x": 2.675,
140
+ "y": -1.3299999999999996
141
+ },
142
+ {
143
+ "pinId": "DPWR.2",
144
+ "x": 2.675,
145
+ "y": -2.4099999999999997
146
+ }
147
+ ],
148
+ "sectionId": "pwr"
149
+ },
150
+ {
151
+ "chipId": "schematic_component_6",
152
+ "center": {
153
+ "x": 1.5519553499999992,
154
+ "y": -4.1899999999999995
155
+ },
156
+ "width": 0.9739106999999991,
157
+ "height": 1.0999999999999996,
158
+ "pins": [
159
+ {
160
+ "pinId": "R1.1",
161
+ "x": 1.2594553499999992,
162
+ "y": -3.6399999999999997
163
+ },
164
+ {
165
+ "pinId": "R1.2",
166
+ "x": 1.2594553499999992,
167
+ "y": -4.739999999999999
168
+ }
169
+ ],
170
+ "sectionId": "pwr"
171
+ },
172
+ {
173
+ "chipId": "schematic_component_7",
174
+ "center": {
175
+ "x": -0.5950000000000001,
176
+ "y": -4.765000000000001
177
+ },
178
+ "width": 0.8400000000000001,
179
+ "height": 1.0999999999999996,
180
+ "pins": [
181
+ {
182
+ "pinId": "C18.1",
183
+ "x": -0.75,
184
+ "y": -4.215000000000001
185
+ },
186
+ {
187
+ "pinId": "C18.2",
188
+ "x": -0.75,
189
+ "y": -5.315
190
+ }
191
+ ],
192
+ "sectionId": "pwr"
193
+ }
194
+ ],
195
+ "directConnections": [
196
+ {
197
+ "pinIds": ["F1.2", "DPROT.1"],
198
+ "netId": ".F1 > .pin2 to .DPROT > .anode"
199
+ }
200
+ ],
201
+ "netConnections": [
202
+ {
203
+ "netId": "VBUS",
204
+ "pinIds": ["DPROT.1", "F1.1", "F1.2"],
205
+ "netLabelWidth": 0.6
206
+ },
207
+ {
208
+ "netId": "RAW",
209
+ "pinIds": ["DPROT.2", "U2.1", "U2.3", "C1.1"],
210
+ "netLabelWidth": 0.48
211
+ },
212
+ {
213
+ "netId": "GND",
214
+ "pinIds": ["U2.2", "C1.2", "C4.2", "R1.2", "C18.2"],
215
+ "netLabelWidth": 0.48
216
+ },
217
+ {
218
+ "netId": "V3V3",
219
+ "pinIds": ["U2.5", "C4.1", "DPWR.1", "C18.1"],
220
+ "netLabelWidth": 0.6
221
+ },
222
+ {
223
+ "netId": "PWR_LED_K",
224
+ "pinIds": ["DPWR.2", "R1.1"],
225
+ "netLabelWidth": 1.2
226
+ }
227
+ ],
228
+ "availableNetLabelOrientations": {
229
+ "VBUS": ["y+"],
230
+ "RAW": ["x-", "x+", "y+", "y-"],
231
+ "V3V3": ["y+"],
232
+ "GND": ["y-"],
233
+ "PWR_LED_K": ["x-", "x+", "y+", "y-"]
234
+ },
235
+ "maxMspPairDistance": 2.4
236
+ }
@@ -0,0 +1,206 @@
1
+ {
2
+ "chips": [
3
+ {
4
+ "chipId": "schematic_component_0",
5
+ "center": {
6
+ "x": -0.5899999999999996,
7
+ "y": 0.315272325
8
+ },
9
+ "width": 1.6,
10
+ "height": 1,
11
+ "pins": [
12
+ {
13
+ "pinId": "U1.1",
14
+ "x": 0.6100000000000005,
15
+ "y": 0.015272324999999976
16
+ },
17
+ {
18
+ "pinId": "U1.2",
19
+ "x": -1.7899999999999998,
20
+ "y": 0.015272324999999976
21
+ },
22
+ {
23
+ "pinId": "U1.3",
24
+ "x": 0.6100000000000005,
25
+ "y": 0.415272325
26
+ },
27
+ {
28
+ "pinId": "U1.4",
29
+ "x": -1.7899999999999998,
30
+ "y": 0.6152723250000001
31
+ },
32
+ {
33
+ "pinId": "U1.5",
34
+ "x": -1.7899999999999998,
35
+ "y": 0.41527232500000005
36
+ },
37
+ {
38
+ "pinId": "U1.6",
39
+ "x": -1.7899999999999998,
40
+ "y": 0.21527232500000004
41
+ },
42
+ {
43
+ "pinId": "U1.7",
44
+ "x": 0.6100000000000005,
45
+ "y": 0.215272325
46
+ },
47
+ {
48
+ "pinId": "U1.8",
49
+ "x": 0.6100000000000005,
50
+ "y": 0.6152723250000001
51
+ }
52
+ ]
53
+ },
54
+ {
55
+ "chipId": "schematic_component_1",
56
+ "center": {
57
+ "x": 1.88195535,
58
+ "y": 1.8047276749999999
59
+ },
60
+ "width": 0.8539106999999988,
61
+ "height": 1.1,
62
+ "pins": [
63
+ {
64
+ "pinId": "R1.1",
65
+ "x": 1.64945535,
66
+ "y": 2.354727675
67
+ },
68
+ {
69
+ "pinId": "R1.2",
70
+ "x": 1.64945535,
71
+ "y": 1.2547276749999998
72
+ }
73
+ ]
74
+ },
75
+ {
76
+ "chipId": "schematic_component_2",
77
+ "center": {
78
+ "x": 1.8600000000000005,
79
+ "y": 0.21527232500000035
80
+ },
81
+ "width": 1.1,
82
+ "height": 0.7789106999999988,
83
+ "pins": [
84
+ {
85
+ "pinId": "R2.1",
86
+ "x": 1.3100000000000005,
87
+ "y": 0.21527232500000038
88
+ },
89
+ {
90
+ "pinId": "R2.2",
91
+ "x": 2.4100000000000006,
92
+ "y": 0.21527232500000038
93
+ }
94
+ ]
95
+ },
96
+ {
97
+ "chipId": "schematic_component_3",
98
+ "center": {
99
+ "x": -1.8774999999999997,
100
+ "y": 4.109727674999999
101
+ },
102
+ "width": 1.1149999999999998,
103
+ "height": 1.0999999999999996,
104
+ "pins": [
105
+ {
106
+ "pinId": "C1.1",
107
+ "x": -2.0149999999999997,
108
+ "y": 4.659727674999999
109
+ },
110
+ {
111
+ "pinId": "C1.2",
112
+ "x": -2.0149999999999997,
113
+ "y": 3.5597276749999995
114
+ }
115
+ ]
116
+ },
117
+ {
118
+ "chipId": "schematic_component_4",
119
+ "center": {
120
+ "x": -1.6525000000000003,
121
+ "y": -1.804727675
122
+ },
123
+ "width": 1.1150000000000002,
124
+ "height": 1.1000000000000003,
125
+ "pins": [
126
+ {
127
+ "pinId": "C2.1",
128
+ "x": -1.7900000000000003,
129
+ "y": -1.254727675
130
+ },
131
+ {
132
+ "pinId": "C2.2",
133
+ "x": -1.7900000000000003,
134
+ "y": -2.3547276750000004
135
+ }
136
+ ]
137
+ },
138
+ {
139
+ "chipId": "schematic_component_5",
140
+ "center": {
141
+ "x": 0.9100000000000001,
142
+ "y": 4.3547276749999995
143
+ },
144
+ "width": 1.4000000000000004,
145
+ "height": 0.8000000000000003,
146
+ "pins": [
147
+ {
148
+ "pinId": "J1.1",
149
+ "x": -0.18999999999999995,
150
+ "y": 4.554727675
151
+ },
152
+ {
153
+ "pinId": "J1.2",
154
+ "x": -0.18999999999999995,
155
+ "y": 4.3547276749999995
156
+ },
157
+ {
158
+ "pinId": "J1.3",
159
+ "x": -0.18999999999999995,
160
+ "y": 4.154727674999999
161
+ }
162
+ ]
163
+ }
164
+ ],
165
+ "directConnections": [
166
+ {
167
+ "pinIds": ["U1.5", "C2.1"],
168
+ "netId": "U1.CTRL to C2.pin1"
169
+ },
170
+ {
171
+ "pinIds": ["R1.2", "U1.7"],
172
+ "netId": "R1.pin2 to U1.DISCH"
173
+ },
174
+ {
175
+ "pinIds": ["U1.7", "R2.1"],
176
+ "netId": "U1.DISCH to R2.pin1"
177
+ }
178
+ ],
179
+ "netConnections": [
180
+ {
181
+ "netId": "GND",
182
+ "pinIds": ["U1.1", "C1.2", "C2.2", "J1.3"],
183
+ "netLabelWidth": 0.48
184
+ },
185
+ {
186
+ "netId": "NODE",
187
+ "pinIds": ["U1.2", "U1.6", "R2.2", "C1.1"],
188
+ "netLabelWidth": 0.6
189
+ },
190
+ {
191
+ "netId": "OUT",
192
+ "pinIds": ["U1.3", "J1.2"],
193
+ "netLabelWidth": 0.48
194
+ },
195
+ {
196
+ "netId": "VCC",
197
+ "pinIds": ["U1.4", "U1.8", "R1.1", "J1.1"],
198
+ "netLabelWidth": 0.48
199
+ }
200
+ ],
201
+ "availableNetLabelOrientations": {
202
+ "VCC": ["y+"],
203
+ "GND": ["y-"]
204
+ },
205
+ "maxMspPairDistance": 2.4
206
+ }