@tscircuit/copper-pour-solver 0.0.2 → 0.0.3

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
@@ -10,6 +10,7 @@ interface InputPourRegion {
10
10
  connectivityKey: string;
11
11
  padMargin: number;
12
12
  traceMargin: number;
13
+ boardEdgeMargin?: number;
13
14
  }
14
15
  interface BaseInputPad {
15
16
  padId: string;
@@ -52,6 +53,7 @@ declare const convertCircuitJsonToInputProblem: (circuitJson: AnyCircuitElement[
52
53
  pour_connectivity_key: string;
53
54
  pad_margin: number;
54
55
  trace_margin: number;
56
+ boardEdgeMargin?: number;
55
57
  }) => InputProblem;
56
58
 
57
59
  export { type BaseInputPad, CopperPourPipelineSolver, type InputCircularPad, type InputPad, type InputPourRegion, type InputProblem, type InputRectPad, type InputTracePad, type PipelineOutput, convertCircuitJsonToInputProblem };
package/dist/index.js CHANGED
@@ -4,18 +4,29 @@ import { BasePipelineSolver } from "@tscircuit/solver-utils";
4
4
  // lib/solvers/copper-pour/get-board-polygon.ts
5
5
  import Flatten from "@flatten-js/core";
6
6
  var getBoardPolygon = (region) => {
7
+ const boardEdgeMargin = region.boardEdgeMargin ?? 0;
7
8
  if (region.outline && region.outline.length > 0) {
8
- return new Flatten.Polygon(
9
+ const polygon = new Flatten.Polygon(
9
10
  region.outline.map((p) => Flatten.point(p.x, p.y))
10
11
  );
12
+ return polygon;
11
13
  }
12
14
  const { bounds } = region;
15
+ const newBounds = {
16
+ minX: bounds.minX + boardEdgeMargin,
17
+ minY: bounds.minY + boardEdgeMargin,
18
+ maxX: bounds.maxX - boardEdgeMargin,
19
+ maxY: bounds.maxY - boardEdgeMargin
20
+ };
21
+ if (newBounds.minX >= newBounds.maxX || newBounds.minY >= newBounds.maxY) {
22
+ return new Flatten.Polygon();
23
+ }
13
24
  return new Flatten.Polygon(
14
25
  new Flatten.Box(
15
- bounds.minX,
16
- bounds.minY,
17
- bounds.maxX,
18
- bounds.maxY
26
+ newBounds.minX,
27
+ newBounds.minY,
28
+ newBounds.maxX,
29
+ newBounds.maxY
19
30
  ).toPoints()
20
31
  );
21
32
  };
@@ -46,9 +57,67 @@ var circleToPolygon = (circle, numSegments = 32) => {
46
57
  var isRectPad = (pad) => pad.shape === "rect";
47
58
  var isTracePad = (pad) => pad.shape === "trace";
48
59
  var isCircularPad = (pad) => pad.shape === "circle";
49
- var processObstaclesForPour = (pads, pourConnectivityKey, margins) => {
60
+ var processObstaclesForPour = (pads, pourConnectivityKey, margins, boardOutline) => {
50
61
  const polygonsToSubtract = [];
51
- const { padMargin, traceMargin } = margins;
62
+ const { padMargin, traceMargin, boardEdgeMargin } = margins;
63
+ if (boardOutline && boardOutline.length > 0 && boardEdgeMargin && boardEdgeMargin > 0) {
64
+ const boardPoly = new Flatten3.Polygon(
65
+ boardOutline.map((p) => Flatten3.point(p.x, p.y))
66
+ );
67
+ if (boardPoly.area() < 0) {
68
+ boardPoly.reverse();
69
+ }
70
+ const vertices = boardPoly.vertices;
71
+ for (let i = 0; i < vertices.length; i++) {
72
+ const p1 = vertices[i === 0 ? vertices.length - 1 : i - 1];
73
+ const p2 = vertices[i];
74
+ const p3 = vertices[(i + 1) % vertices.length];
75
+ if (!p1 || !p2 || !p3) continue;
76
+ const v1 = new Flatten3.Vector(p1, p2);
77
+ const v2 = new Flatten3.Vector(p2, p3);
78
+ const crossProduct = v1.cross(v2);
79
+ const circle = new Flatten3.Circle(p2, boardEdgeMargin);
80
+ polygonsToSubtract.push(circleToPolygon(circle));
81
+ if (crossProduct < 0) {
82
+ const box = new Flatten3.Box(
83
+ p2.x - boardEdgeMargin,
84
+ p2.y - boardEdgeMargin,
85
+ p2.x + boardEdgeMargin,
86
+ p2.y + boardEdgeMargin
87
+ );
88
+ polygonsToSubtract.push(new Flatten3.Polygon(box.toPoints()));
89
+ }
90
+ }
91
+ for (let i = 0; i < vertices.length; i++) {
92
+ const p1 = vertices[i];
93
+ const p2 = vertices[(i + 1) % vertices.length];
94
+ if (!p1 || !p2) continue;
95
+ const segmentLength = Math.hypot(p1.x - p2.x, p1.y - p2.y);
96
+ if (segmentLength === 0) continue;
97
+ const enlargedWidth = boardEdgeMargin * 2;
98
+ const centerX = (p1.x + p2.x) / 2;
99
+ const centerY = (p1.y + p2.y) / 2;
100
+ const rotationDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
101
+ const w2 = segmentLength / 2;
102
+ const h2 = enlargedWidth / 2;
103
+ const angleRad = rotationDeg * Math.PI / 180;
104
+ const cosAngle = Math.cos(angleRad);
105
+ const sinAngle = Math.sin(angleRad);
106
+ const corners = [
107
+ { x: -w2, y: -h2 },
108
+ { x: w2, y: -h2 },
109
+ { x: w2, y: h2 },
110
+ { x: -w2, y: h2 }
111
+ ];
112
+ const rotatedCorners = corners.map((p) => ({
113
+ x: centerX + p.x * cosAngle - p.y * sinAngle,
114
+ y: centerY + p.x * sinAngle + p.y * cosAngle
115
+ }));
116
+ polygonsToSubtract.push(
117
+ new Flatten3.Polygon(rotatedCorners.map((p) => Flatten3.point(p.x, p.y)))
118
+ );
119
+ }
120
+ }
52
121
  for (const pad of pads) {
53
122
  const isOnNet = pad.connectivityKey === pourConnectivityKey;
54
123
  if (isOnNet) {
@@ -184,15 +253,26 @@ var CopperPourPipelineSolver = class extends BasePipelineSolver {
184
253
  region.connectivityKey,
185
254
  {
186
255
  padMargin: region.padMargin,
187
- traceMargin: region.traceMargin
188
- }
256
+ traceMargin: region.traceMargin,
257
+ boardEdgeMargin: region.boardEdgeMargin
258
+ },
259
+ region.outline
189
260
  );
190
261
  let pourPolygons = boardPolygon;
191
262
  for (const poly of polygonsToSubtract) {
192
- pourPolygons = Flatten5.BooleanOperations.subtract(
193
- pourPolygons,
194
- poly
195
- );
263
+ const currentPolys = Array.isArray(pourPolygons) ? pourPolygons : [pourPolygons];
264
+ const nextPolys = [];
265
+ for (const p of currentPolys) {
266
+ const result = Flatten5.BooleanOperations.subtract(p, poly);
267
+ if (result) {
268
+ if (Array.isArray(result)) {
269
+ nextPolys.push(...result.filter((r) => !r.isEmpty()));
270
+ } else {
271
+ if (!result.isEmpty()) nextPolys.push(result);
272
+ }
273
+ }
274
+ }
275
+ pourPolygons = nextPolys;
196
276
  }
197
277
  const new_breps = generateBRep(pourPolygons);
198
278
  brep_shapes.push(...new_breps);
@@ -354,7 +434,8 @@ var convertCircuitJsonToInputProblem = (circuitJson, options) => {
354
434
  outline: pcb_board.outline,
355
435
  connectivityKey: options.pour_connectivity_key,
356
436
  padMargin: options.pad_margin,
357
- traceMargin: options.trace_margin
437
+ traceMargin: options.trace_margin,
438
+ boardEdgeMargin: options.boardEdgeMargin ?? 0
358
439
  }
359
440
  ];
360
441
  return {
@@ -26,6 +26,7 @@ export const convertCircuitJsonToInputProblem = (
26
26
  pour_connectivity_key: string
27
27
  pad_margin: number
28
28
  trace_margin: number
29
+ boardEdgeMargin?: number
29
30
  },
30
31
  ): InputProblem => {
31
32
  const source_ports = circuitJson.filter(
@@ -198,6 +199,7 @@ export const convertCircuitJsonToInputProblem = (
198
199
  connectivityKey: options.pour_connectivity_key,
199
200
  padMargin: options.pad_margin,
200
201
  traceMargin: options.trace_margin,
202
+ boardEdgeMargin: options.boardEdgeMargin ?? 0,
201
203
  },
202
204
  ]
203
205
 
@@ -28,16 +28,29 @@ export class CopperPourPipelineSolver extends BasePipelineSolver<InputProblem> {
28
28
  {
29
29
  padMargin: region.padMargin,
30
30
  traceMargin: region.traceMargin,
31
+ boardEdgeMargin: region.boardEdgeMargin,
31
32
  },
33
+ region.outline,
32
34
  )
33
35
 
34
- let pourPolygons: Flatten.Polygon = boardPolygon
36
+ let pourPolygons: Flatten.Polygon | Flatten.Polygon[] = boardPolygon
35
37
 
36
38
  for (const poly of polygonsToSubtract) {
37
- pourPolygons = Flatten.BooleanOperations.subtract(
38
- pourPolygons,
39
- poly,
40
- ) as Flatten.Polygon
39
+ const currentPolys = Array.isArray(pourPolygons)
40
+ ? pourPolygons
41
+ : [pourPolygons]
42
+ const nextPolys: Flatten.Polygon[] = []
43
+ for (const p of currentPolys) {
44
+ const result = Flatten.BooleanOperations.subtract(p, poly)
45
+ if (result) {
46
+ if (Array.isArray(result)) {
47
+ nextPolys.push(...result.filter((r) => !r.isEmpty()))
48
+ } else {
49
+ if (!result.isEmpty()) nextPolys.push(result)
50
+ }
51
+ }
52
+ }
53
+ pourPolygons = nextPolys
41
54
  }
42
55
 
43
56
  const new_breps = generateBRep(pourPolygons)
@@ -2,18 +2,33 @@ import type { InputPourRegion } from "lib/types"
2
2
  import Flatten from "@flatten-js/core"
3
3
 
4
4
  export const getBoardPolygon = (region: InputPourRegion): Flatten.Polygon => {
5
+ const boardEdgeMargin = region.boardEdgeMargin ?? 0
6
+
5
7
  if (region.outline && region.outline.length > 0) {
6
- return new Flatten.Polygon(
8
+ const polygon = new Flatten.Polygon(
7
9
  region.outline.map((p) => Flatten.point(p.x, p.y)),
8
10
  )
11
+ return polygon
9
12
  }
13
+
10
14
  const { bounds } = region
15
+ const newBounds = {
16
+ minX: bounds.minX + boardEdgeMargin,
17
+ minY: bounds.minY + boardEdgeMargin,
18
+ maxX: bounds.maxX - boardEdgeMargin,
19
+ maxY: bounds.maxY - boardEdgeMargin,
20
+ }
21
+
22
+ if (newBounds.minX >= newBounds.maxX || newBounds.minY >= newBounds.maxY) {
23
+ return new Flatten.Polygon()
24
+ }
25
+
11
26
  return new Flatten.Polygon(
12
27
  new Flatten.Box(
13
- bounds.minX,
14
- bounds.minY,
15
- bounds.maxX,
16
- bounds.maxY,
28
+ newBounds.minX,
29
+ newBounds.minY,
30
+ newBounds.maxX,
31
+ newBounds.maxY,
17
32
  ).toPoints(),
18
33
  )
19
34
  }
@@ -1,4 +1,5 @@
1
1
  import Flatten from "@flatten-js/core"
2
+ import type { Point } from "@tscircuit/math-utils"
2
3
  import type {
3
4
  InputCircularPad,
4
5
  InputPad,
@@ -20,11 +21,93 @@ const isCircularPad = (pad: InputPad): pad is InputCircularPad =>
20
21
  export const processObstaclesForPour = (
21
22
  pads: InputPad[],
22
23
  pourConnectivityKey: string,
23
- margins: { padMargin: number; traceMargin: number },
24
+ margins: { padMargin: number; traceMargin: number; boardEdgeMargin?: number },
25
+ boardOutline?: Point[],
24
26
  ): ProcessedObstacles => {
25
27
  const polygonsToSubtract: Flatten.Polygon[] = []
26
28
 
27
- const { padMargin, traceMargin } = margins
29
+ const { padMargin, traceMargin, boardEdgeMargin } = margins
30
+
31
+ if (
32
+ boardOutline &&
33
+ boardOutline.length > 0 &&
34
+ boardEdgeMargin &&
35
+ boardEdgeMargin > 0
36
+ ) {
37
+ const boardPoly = new Flatten.Polygon(
38
+ boardOutline.map((p) => Flatten.point(p.x, p.y)),
39
+ )
40
+ if (boardPoly.area() < 0) {
41
+ boardPoly.reverse()
42
+ }
43
+ const vertices = boardPoly.vertices
44
+
45
+ // Add clearance shapes at vertices
46
+ for (let i = 0; i < vertices.length; i++) {
47
+ const p1 = vertices[i === 0 ? vertices.length - 1 : i - 1]
48
+ const p2 = vertices[i]
49
+ const p3 = vertices[(i + 1) % vertices.length]
50
+
51
+ if (!p1 || !p2 || !p3) continue
52
+
53
+ const v1 = new Flatten.Vector(p1, p2)
54
+ const v2 = new Flatten.Vector(p2, p3)
55
+ const crossProduct = v1.cross(v2)
56
+
57
+ const circle = new Flatten.Circle(p2, boardEdgeMargin)
58
+ polygonsToSubtract.push(circleToPolygon(circle))
59
+
60
+ if (crossProduct < 0) {
61
+ const box = new Flatten.Box(
62
+ p2.x - boardEdgeMargin,
63
+ p2.y - boardEdgeMargin,
64
+ p2.x + boardEdgeMargin,
65
+ p2.y + boardEdgeMargin,
66
+ )
67
+ polygonsToSubtract.push(new Flatten.Polygon(box.toPoints()))
68
+ }
69
+ }
70
+
71
+ // Add rectangles for each segment to create clearance along edges
72
+ for (let i = 0; i < vertices.length; i++) {
73
+ const p1 = vertices[i]
74
+ const p2 = vertices[(i + 1) % vertices.length]
75
+
76
+ if (!p1 || !p2) continue
77
+
78
+ const segmentLength = Math.hypot(p1.x - p2.x, p1.y - p2.y)
79
+ if (segmentLength === 0) continue
80
+
81
+ const enlargedWidth = boardEdgeMargin * 2
82
+
83
+ const centerX = (p1.x + p2.x) / 2
84
+ const centerY = (p1.y + p2.y) / 2
85
+ const rotationDeg = (Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180) / Math.PI
86
+
87
+ const w2 = segmentLength / 2
88
+ const h2 = enlargedWidth / 2
89
+
90
+ const angleRad = (rotationDeg * Math.PI) / 180
91
+ const cosAngle = Math.cos(angleRad)
92
+ const sinAngle = Math.sin(angleRad)
93
+
94
+ const corners = [
95
+ { x: -w2, y: -h2 },
96
+ { x: w2, y: -h2 },
97
+ { x: w2, y: h2 },
98
+ { x: -w2, y: h2 },
99
+ ]
100
+
101
+ const rotatedCorners = corners.map((p) => ({
102
+ x: centerX + p.x * cosAngle - p.y * sinAngle,
103
+ y: centerY + p.x * sinAngle + p.y * cosAngle,
104
+ }))
105
+
106
+ polygonsToSubtract.push(
107
+ new Flatten.Polygon(rotatedCorners.map((p) => Flatten.point(p.x, p.y))),
108
+ )
109
+ }
110
+ }
28
111
 
29
112
  for (const pad of pads) {
30
113
  const isOnNet = pad.connectivityKey === pourConnectivityKey
package/lib/types.ts CHANGED
@@ -9,6 +9,7 @@ export interface InputPourRegion {
9
9
  connectivityKey: string
10
10
  padMargin: number
11
11
  traceMargin: number
12
+ boardEdgeMargin?: number
12
13
  }
13
14
 
14
15
  export interface BaseInputPad {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/copper-pour-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.2",
4
+ "version": "0.0.3",
5
5
  "scripts": {
6
6
  "format": "biome format . --write",
7
7
  "format:check": "biome format .",
@@ -10,7 +10,7 @@
10
10
  "type": "module",
11
11
  "devDependencies": {
12
12
  "@biomejs/biome": "^2.2.4",
13
- "@flatten-js/core": "^1.6.6",
13
+ "@flatten-js/core": "^1.6.2",
14
14
  "@tscircuit/math-utils": "^0.0.25",
15
15
  "@tscircuit/solver-utils": "^0.0.3",
16
16
  "@types/bun": "latest",
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.844"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="127.27272727272725" y="27.272727272727252" width="545.4545454545455" height="545.4545454545455" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 127.27272727272725 572.7272727272727 L 672.7272727272727 572.7272727272727 L 672.7272727272727 27.272727272727252 L 400 27.272727272727252 L 400 300 L 127.27272727272725 300 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="2.7272727272727275" data-type="pcb_board" data-pcb-layer="board"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="224.77272727272728" y="335.4545454545455" width="27.954545454545453" height="38.18181818181818" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="274.5454545454545" y="335.4545454545455" width="27.954545454545453" height="38.18181818181818" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="497.5" y="335.4545454545455" width="27.954545454545453" height="38.18181818181818" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="547.2727272727273" y="335.4545454545455" width="27.954545454545453" height="38.18181818181818" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 511.47727272727275 354.54545454545456 L 561.25 354.54545454545456" stroke-width="4.090909090909091" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 561.25 354.54545454545456 L 561.25 354.54545454545456" stroke-width="4.090909090909091" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 511.47727272727275 354.54545454545456 L 288.52272727272725 354.54545454545456" stroke-width="4.090909090909091" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 288.52272727272725 354.54545454545456 L 288.52272727272725 354.54545454545456" stroke-width="4.090909090909091" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-copper-pour pcb-copper-pour-brep" d="M 313.4090909090909 362.0454545454545 L 486.5909090909091 362.04545454545456 L 486.5909090909091 384.54545454545456 L 536.3636363636364 384.54545454545456 L 586.1363636363636 384.54545454545456 L 586.1363636363636 324.54545454545456 L 536.3636363636364 324.54545454545456 L 486.5909090909091 324.54545454545456 L 486.5909090909091 347.04545454545456 L 313.4090909090909 347.04545454545456 L 313.4090909090909 327.27272727272725 L 372.72727272727275 327.27272727272725 L 400 327.27272727272725 L 427.27272727272725 327.27272727272725 L 427.27272727272725 300 L 427.27272727272725 272.72727272727275 L 427.27272727272725 54.54545454545453 L 645.4545454545455 54.54545454545453 L 645.4545454545455 545.4545454545455 L 154.54545454545453 545.4545454545455 L 154.54545454545453 327.27272727272725 L 263.6363636363636 327.27272727272725 L 263.6363636363636 384.54545454545456 L 313.4090909090909 384.54545454545456 L 313.4090909090909 362.0454545454545 Z" fill="rgb(200, 52, 52)" fill-rule="evenodd" fill-opacity="0.5" data-type="pcb_copper_pour" data-pcb-layer="top"/><path class="pcb-silkscreen pcb-silkscreen-top" d="M 288.52272727272725 324.54545454545456 L 219.3181818181818 324.54545454545456 L 219.3181818181818 384.54545454545456 L 288.52272727272725 384.54545454545456" fill="none" stroke="#f2eda1" stroke-width="2.7272727272727275" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_0" data-pcb-silkscreen-path-id="pcb_silkscreen_path_0" data-type="pcb_silkscreen_path" data-pcb-layer="top"/><text x="0" y="0" dx="0" dy="0" fill="#f2eda1" font-family="Arial, sans-serif" font-size="10.90909090909091" text-anchor="middle" dominant-baseline="central" transform="matrix(1,0,0,1,263.6363636363636,310.9090909090909)" class="pcb-silkscreen-text pcb-silkscreen-top" data-pcb-silkscreen-text-id="pcb_component_0" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="top">R1</text><path class="pcb-silkscreen pcb-silkscreen-top" d="M 561.25 324.54545454545456 L 492.04545454545456 324.54545454545456 L 492.04545454545456 384.54545454545456 L 561.25 384.54545454545456" fill="none" stroke="#f2eda1" stroke-width="2.7272727272727275" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_1" data-pcb-silkscreen-path-id="pcb_silkscreen_path_1" data-type="pcb_silkscreen_path" data-pcb-layer="top"/><text x="0" y="0" dx="0" dy="0" fill="#f2eda1" font-family="Arial, sans-serif" font-size="10.90909090909091" text-anchor="middle" dominant-baseline="central" transform="matrix(1,0,0,1,536.3636363636364,310.9090909090909)" class="pcb-silkscreen-text pcb-silkscreen-top" data-pcb-silkscreen-text-id="pcb_component_1" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="top">R2</text></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.844"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="33.33333333333337" y="22.22222222222223" width="733.3333333333334" height="555.5555555555557" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 144.4444444444445 577.7777777777778 L 700 577.7777777777778 L 744.4444444444445 466.6666666666667 L 766.6666666666667 244.44444444444446 L 744.4444444444445 22.22222222222223 L 700 22.22222222222223 L 588.8888888888889 22.22222222222223 L 588.8888888888889 133.33333333333334 L 477.7777777777778 133.33333333333334 L 477.7777777777778 22.22222222222223 L 144.4444444444445 22.22222222222223 L 33.33333333333337 133.33333333333334 L 144.4444444444445 244.44444444444446 L 255.5555555555556 244.44444444444446 L 255.5555555555556 466.6666666666667 L 144.4444444444445 466.6666666666667 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="2.2222222222222223" data-type="pcb_board" data-pcb-layer="board"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="335" y="273.33333333333337" width="22.777777777777775" height="31.111111111111107" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="375.55555555555554" y="273.33333333333337" width="22.777777777777775" height="31.111111111111107" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="557.2222222222223" y="273.33333333333337" width="22.777777777777775" height="31.111111111111107" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="597.7777777777778" y="273.33333333333337" width="22.777777777777775" height="31.111111111111107" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 568.6111111111112 288.8888888888889 L 609.1666666666667 288.8888888888889" stroke-width="3.333333333333333" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 609.1666666666667 288.8888888888889 L 609.1666666666667 288.8888888888889" stroke-width="3.333333333333333" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 568.6111111111112 288.8888888888889 L 386.94444444444446 288.8888888888889" stroke-width="3.333333333333333" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 386.94444444444446 288.8888888888889 L 386.94444444444446 288.8888888888889" stroke-width="3.333333333333333" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-copper-pour pcb-copper-pour-brep" d="M 166.66666666666674 488.8888888888889 L 233.3333333333334 488.8888888888889 L 255.55555555555597 488.8888888888889 L 277.7777777777778 488.8888888888889 L 277.7777777777778 466.6666666666667 L 277.7777777777778 444.44444444444446 L 277.7777777777778 266.6666666666667 L 277.7777777777778 244.44444444444446 L 277.7777777777778 222.22222222222223 L 255.5555555555556 222.22222222222223 L 233.3333333333334 222.22222222222223 L 153.64919027495773 222.22222222222223 L 64.76030138606876 133.33333333333343 L 153.6491902749578 44.44444444444443 L 455.5555555555556 44.444444444444514 L 455.5555555555556 111.11111111111114 L 455.5555555555556 133.33333333333337 L 455.5555555555556 155.55555555555557 L 477.7777777777778 155.55555555555557 L 500.00000000000006 155.55555555555557 L 566.6666666666667 155.55555555555557 L 588.8888888888889 155.55555555555557 L 611.1111111111111 155.55555555555557 L 611.1111111111111 133.33333333333334 L 611.1111111111111 111.11111111111114 L 611.1111111111111 44.44444444444446 L 700 44.44444444444446 L 724.3336097308425 44.44444444444446 L 744.3336097308425 244.44444444444466 L 722.6450571331745 461.32997042112515 L 684.9548230794022 555.5555555555555 L 166.66666666666674 555.5555555555555 L 166.66666666666674 488.8888888888889 Z M 407.2222222222223 295 L 548.3333333333334 295 L 548.3333333333334 313.33333333333337 L 588.8888888888889 313.33333333333337 L 629.4444444444445 313.33333333333337 L 629.4444444444445 264.44444444444446 L 588.8888888888889 264.44444444444446 L 548.3333333333334 264.44444444444446 L 548.3333333333334 282.7777777777778 L 407.2222222222223 282.77777777777777 L 407.2222222222223 264.44444444444446 L 366.6666666666667 264.44444444444446 L 366.6666666666667 313.33333333333337 L 407.2222222222223 313.33333333333337 L 407.2222222222223 295 Z" fill="rgb(200, 52, 52)" fill-rule="evenodd" fill-opacity="0.5" data-type="pcb_copper_pour" data-pcb-layer="top"/><path class="pcb-silkscreen pcb-silkscreen-top" d="M 386.94444444444446 264.44444444444446 L 330.5555555555556 264.44444444444446 L 330.5555555555556 313.33333333333337 L 386.94444444444446 313.33333333333337" fill="none" stroke="#f2eda1" stroke-width="2.2222222222222223" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_0" data-pcb-silkscreen-path-id="pcb_silkscreen_path_0" data-type="pcb_silkscreen_path" data-pcb-layer="top"/><text x="0" y="0" dx="0" dy="0" fill="#f2eda1" font-family="Arial, sans-serif" font-size="8.88888888888889" text-anchor="middle" dominant-baseline="central" transform="matrix(1,0,0,1,366.66666666666674,253.33333333333334)" class="pcb-silkscreen-text pcb-silkscreen-top" data-pcb-silkscreen-text-id="pcb_component_0" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="top">R1</text><path class="pcb-silkscreen pcb-silkscreen-top" d="M 609.1666666666667 264.44444444444446 L 552.7777777777778 264.44444444444446 L 552.7777777777778 313.33333333333337 L 609.1666666666667 313.33333333333337" fill="none" stroke="#f2eda1" stroke-width="2.2222222222222223" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_1" data-pcb-silkscreen-path-id="pcb_silkscreen_path_1" data-type="pcb_silkscreen_path" data-pcb-layer="top"/><text x="0" y="0" dx="0" dy="0" fill="#f2eda1" font-family="Arial, sans-serif" font-size="8.88888888888889" text-anchor="middle" dominant-baseline="central" transform="matrix(1,0,0,1,588.8888888888889,253.33333333333334)" class="pcb-silkscreen-text pcb-silkscreen-top" data-pcb-silkscreen-text-id="pcb_component_1" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="top">R2</text></svg>
@@ -0,0 +1,846 @@
1
+ [
2
+ {
3
+ "type": "source_project_metadata",
4
+ "source_project_metadata_id": "source_project_metadata_0",
5
+ "software_used_string": "@tscircuit/core@0.0.844"
6
+ },
7
+ {
8
+ "type": "source_group",
9
+ "source_group_id": "source_group_0",
10
+ "is_subcircuit": true,
11
+ "was_automatically_named": true,
12
+ "subcircuit_id": "subcircuit_source_group_0"
13
+ },
14
+ {
15
+ "type": "source_net",
16
+ "source_net_id": "source_net_0",
17
+ "name": "GND",
18
+ "member_source_group_ids": [],
19
+ "is_ground": true,
20
+ "is_power": false,
21
+ "is_positive_voltage_source": false,
22
+ "subcircuit_id": "subcircuit_source_group_0",
23
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net0"
24
+ },
25
+ {
26
+ "type": "source_net",
27
+ "source_net_id": "source_net_1",
28
+ "name": "VCC",
29
+ "member_source_group_ids": [],
30
+ "is_ground": false,
31
+ "is_power": true,
32
+ "is_positive_voltage_source": true,
33
+ "subcircuit_id": "subcircuit_source_group_0",
34
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
35
+ },
36
+ {
37
+ "type": "source_port",
38
+ "source_port_id": "source_port_0",
39
+ "name": "pin1",
40
+ "pin_number": 1,
41
+ "port_hints": ["pin1", "anode", "pos", "left", "1"],
42
+ "source_component_id": "source_component_0",
43
+ "subcircuit_id": "subcircuit_source_group_0",
44
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net0"
45
+ },
46
+ {
47
+ "type": "source_port",
48
+ "source_port_id": "source_port_1",
49
+ "name": "pin2",
50
+ "pin_number": 2,
51
+ "port_hints": ["pin2", "cathode", "neg", "right", "2"],
52
+ "source_component_id": "source_component_0",
53
+ "subcircuit_id": "subcircuit_source_group_0",
54
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
55
+ },
56
+ {
57
+ "type": "source_component",
58
+ "source_component_id": "source_component_0",
59
+ "ftype": "simple_resistor",
60
+ "name": "R1",
61
+ "resistance": 10000,
62
+ "display_resistance": "10kΩ",
63
+ "are_pins_interchangeable": true,
64
+ "source_group_id": "source_group_0"
65
+ },
66
+ {
67
+ "type": "source_port",
68
+ "source_port_id": "source_port_2",
69
+ "name": "pin1",
70
+ "pin_number": 1,
71
+ "port_hints": ["pin1", "anode", "pos", "left", "1"],
72
+ "source_component_id": "source_component_1",
73
+ "subcircuit_id": "subcircuit_source_group_0",
74
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
75
+ },
76
+ {
77
+ "type": "source_port",
78
+ "source_port_id": "source_port_3",
79
+ "name": "pin2",
80
+ "pin_number": 2,
81
+ "port_hints": ["pin2", "cathode", "neg", "right", "2"],
82
+ "source_component_id": "source_component_1",
83
+ "subcircuit_id": "subcircuit_source_group_0",
84
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
85
+ },
86
+ {
87
+ "type": "source_component",
88
+ "source_component_id": "source_component_1",
89
+ "ftype": "simple_resistor",
90
+ "name": "R2",
91
+ "resistance": 1000,
92
+ "display_resistance": "1kΩ",
93
+ "are_pins_interchangeable": true,
94
+ "source_group_id": "source_group_0"
95
+ },
96
+ {
97
+ "type": "source_board",
98
+ "source_board_id": "source_board_0",
99
+ "source_group_id": "source_group_0"
100
+ },
101
+ {
102
+ "type": "source_trace",
103
+ "source_trace_id": "source_trace_0",
104
+ "connected_source_port_ids": ["source_port_0"],
105
+ "connected_source_net_ids": ["source_net_0"],
106
+ "subcircuit_id": "subcircuit_source_group_0",
107
+ "display_name": ".R1 > .pin1 to net.GND",
108
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net0"
109
+ },
110
+ {
111
+ "type": "source_trace",
112
+ "source_trace_id": "source_trace_1",
113
+ "connected_source_port_ids": ["source_port_1"],
114
+ "connected_source_net_ids": ["source_net_1"],
115
+ "subcircuit_id": "subcircuit_source_group_0",
116
+ "display_name": ".R1 > .pin2 to net.VCC",
117
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
118
+ },
119
+ {
120
+ "type": "source_trace",
121
+ "source_trace_id": "source_trace_2",
122
+ "connected_source_port_ids": ["source_port_2"],
123
+ "connected_source_net_ids": ["source_net_1"],
124
+ "subcircuit_id": "subcircuit_source_group_0",
125
+ "display_name": ".R2 > .pin1 to net.VCC",
126
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
127
+ },
128
+ {
129
+ "type": "source_trace",
130
+ "source_trace_id": "source_trace_3",
131
+ "connected_source_port_ids": ["source_port_3"],
132
+ "connected_source_net_ids": ["source_net_1"],
133
+ "subcircuit_id": "subcircuit_source_group_0",
134
+ "display_name": ".R2 > .pin2 to net.VCC",
135
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
136
+ },
137
+ {
138
+ "type": "schematic_component",
139
+ "schematic_component_id": "schematic_component_0",
140
+ "center": {
141
+ "x": 0,
142
+ "y": 0
143
+ },
144
+ "size": {
145
+ "width": 1.1,
146
+ "height": 0.388910699999999
147
+ },
148
+ "source_component_id": "source_component_0",
149
+ "is_box_with_pins": true,
150
+ "symbol_name": "boxresistor_right",
151
+ "symbol_display_value": "10kΩ",
152
+ "schematic_group_id": "schematic_group_0"
153
+ },
154
+ {
155
+ "type": "schematic_component",
156
+ "schematic_component_id": "schematic_component_1",
157
+ "center": {
158
+ "x": 1.0999999999999996,
159
+ "y": -1.588910699999999
160
+ },
161
+ "size": {
162
+ "width": 1.1,
163
+ "height": 0.388910699999999
164
+ },
165
+ "source_component_id": "source_component_1",
166
+ "is_box_with_pins": true,
167
+ "symbol_name": "boxresistor_right",
168
+ "symbol_display_value": "1kΩ",
169
+ "schematic_group_id": "schematic_group_0"
170
+ },
171
+ {
172
+ "type": "schematic_group",
173
+ "schematic_group_id": "schematic_group_0",
174
+ "is_subcircuit": true,
175
+ "subcircuit_id": "subcircuit_source_group_0",
176
+ "name": "unnamed_board1",
177
+ "center": {
178
+ "x": 0,
179
+ "y": 0
180
+ },
181
+ "width": 0,
182
+ "height": 0,
183
+ "schematic_component_ids": [],
184
+ "source_group_id": "source_group_0"
185
+ },
186
+ {
187
+ "type": "schematic_port",
188
+ "schematic_port_id": "schematic_port_0",
189
+ "schematic_component_id": "schematic_component_0",
190
+ "center": {
191
+ "x": -0.55,
192
+ "y": 0
193
+ },
194
+ "source_port_id": "source_port_0",
195
+ "facing_direction": "left",
196
+ "distance_from_component_edge": 0.4,
197
+ "pin_number": 1,
198
+ "display_pin_label": "anode",
199
+ "is_connected": false
200
+ },
201
+ {
202
+ "type": "schematic_port",
203
+ "schematic_port_id": "schematic_port_1",
204
+ "schematic_component_id": "schematic_component_0",
205
+ "center": {
206
+ "x": 0.55,
207
+ "y": 0
208
+ },
209
+ "source_port_id": "source_port_1",
210
+ "facing_direction": "right",
211
+ "distance_from_component_edge": 0.4,
212
+ "pin_number": 2,
213
+ "display_pin_label": "cathode",
214
+ "is_connected": true
215
+ },
216
+ {
217
+ "type": "schematic_port",
218
+ "schematic_port_id": "schematic_port_2",
219
+ "schematic_component_id": "schematic_component_1",
220
+ "center": {
221
+ "x": 0.5499999999999996,
222
+ "y": -1.588910699999999
223
+ },
224
+ "source_port_id": "source_port_2",
225
+ "facing_direction": "left",
226
+ "distance_from_component_edge": 0.4,
227
+ "pin_number": 1,
228
+ "display_pin_label": "anode",
229
+ "is_connected": true
230
+ },
231
+ {
232
+ "type": "schematic_port",
233
+ "schematic_port_id": "schematic_port_3",
234
+ "schematic_component_id": "schematic_component_1",
235
+ "center": {
236
+ "x": 1.6499999999999997,
237
+ "y": -1.588910699999999
238
+ },
239
+ "source_port_id": "source_port_3",
240
+ "facing_direction": "right",
241
+ "distance_from_component_edge": 0.4,
242
+ "pin_number": 2,
243
+ "display_pin_label": "cathode",
244
+ "is_connected": true
245
+ },
246
+ {
247
+ "type": "schematic_trace",
248
+ "schematic_trace_id": "schematic_trace_0",
249
+ "source_trace_id": "solver_R2.1-R1.2",
250
+ "edges": [
251
+ {
252
+ "from": {
253
+ "x": 0.5499999999999996,
254
+ "y": -1.588910699999999
255
+ },
256
+ "to": {
257
+ "x": 0.34999999999999964,
258
+ "y": -1.588910699999999
259
+ }
260
+ },
261
+ {
262
+ "from": {
263
+ "x": 0.34999999999999964,
264
+ "y": -1.588910699999999
265
+ },
266
+ "to": {
267
+ "x": 0.34999999999999964,
268
+ "y": -0.7944553499999994
269
+ }
270
+ },
271
+ {
272
+ "from": {
273
+ "x": 0.34999999999999964,
274
+ "y": -0.7944553499999994
275
+ },
276
+ "to": {
277
+ "x": 0.75,
278
+ "y": -0.7944553499999994
279
+ }
280
+ },
281
+ {
282
+ "from": {
283
+ "x": 0.75,
284
+ "y": -0.7944553499999994
285
+ },
286
+ "to": {
287
+ "x": 0.75,
288
+ "y": 0
289
+ }
290
+ },
291
+ {
292
+ "from": {
293
+ "x": 0.75,
294
+ "y": 0
295
+ },
296
+ "to": {
297
+ "x": 0.55,
298
+ "y": 0
299
+ }
300
+ }
301
+ ],
302
+ "junctions": [
303
+ {
304
+ "x": 0.34999999999999964,
305
+ "y": -1.388910699999999
306
+ }
307
+ ],
308
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
309
+ },
310
+ {
311
+ "type": "schematic_trace",
312
+ "schematic_trace_id": "schematic_trace_1",
313
+ "source_trace_id": "solver_R2.2-R2.1",
314
+ "edges": [
315
+ {
316
+ "from": {
317
+ "x": 1.6499999999999997,
318
+ "y": -1.588910699999999
319
+ },
320
+ "to": {
321
+ "x": 1.8499999999999996,
322
+ "y": -1.588910699999999
323
+ }
324
+ },
325
+ {
326
+ "from": {
327
+ "x": 1.8499999999999996,
328
+ "y": -1.588910699999999
329
+ },
330
+ "to": {
331
+ "x": 1.8499999999999996,
332
+ "y": -1.388910699999999
333
+ }
334
+ },
335
+ {
336
+ "from": {
337
+ "x": 1.8499999999999996,
338
+ "y": -1.388910699999999
339
+ },
340
+ "to": {
341
+ "x": 0.34999999999999964,
342
+ "y": -1.388910699999999
343
+ }
344
+ },
345
+ {
346
+ "from": {
347
+ "x": 0.34999999999999964,
348
+ "y": -1.388910699999999
349
+ },
350
+ "to": {
351
+ "x": 0.34999999999999964,
352
+ "y": -1.588910699999999
353
+ }
354
+ },
355
+ {
356
+ "from": {
357
+ "x": 0.34999999999999964,
358
+ "y": -1.588910699999999
359
+ },
360
+ "to": {
361
+ "x": 0.5499999999999996,
362
+ "y": -1.588910699999999
363
+ }
364
+ }
365
+ ],
366
+ "junctions": [
367
+ {
368
+ "x": 0.34999999999999964,
369
+ "y": -1.388910699999999
370
+ }
371
+ ],
372
+ "subcircuit_connectivity_map_key": "unnamedsubcircuit25_connectivity_net1"
373
+ },
374
+ {
375
+ "type": "schematic_net_label",
376
+ "schematic_net_label_id": "schematic_net_label_0",
377
+ "text": "VCC",
378
+ "anchor_position": {
379
+ "x": 0.75,
380
+ "y": 0
381
+ },
382
+ "center": {
383
+ "x": 0.75,
384
+ "y": 0.09
385
+ },
386
+ "anchor_side": "bottom",
387
+ "source_net_id": "source_net_1",
388
+ "symbol_name": "rail_up"
389
+ },
390
+ {
391
+ "type": "schematic_net_label",
392
+ "schematic_net_label_id": "schematic_net_label_1",
393
+ "text": "GND",
394
+ "anchor_position": {
395
+ "x": -0.55,
396
+ "y": 0
397
+ },
398
+ "center": {
399
+ "x": -0.7000000000000001,
400
+ "y": 0
401
+ },
402
+ "anchor_side": "right",
403
+ "source_net_id": "source_net_0"
404
+ },
405
+ {
406
+ "type": "pcb_component",
407
+ "pcb_component_id": "pcb_component_0",
408
+ "center": {
409
+ "x": -5,
410
+ "y": -2
411
+ },
412
+ "width": 2.8499999999999996,
413
+ "height": 1.4000000000000001,
414
+ "layer": "top",
415
+ "rotation": 0,
416
+ "source_component_id": "source_component_0",
417
+ "subcircuit_id": "subcircuit_source_group_0",
418
+ "do_not_place": false,
419
+ "obstructs_within_bounds": true
420
+ },
421
+ {
422
+ "type": "pcb_component",
423
+ "pcb_component_id": "pcb_component_1",
424
+ "center": {
425
+ "x": 5,
426
+ "y": -2
427
+ },
428
+ "width": 2.8499999999999996,
429
+ "height": 1.4000000000000001,
430
+ "layer": "top",
431
+ "rotation": 0,
432
+ "source_component_id": "source_component_1",
433
+ "subcircuit_id": "subcircuit_source_group_0",
434
+ "do_not_place": false,
435
+ "obstructs_within_bounds": true
436
+ },
437
+ {
438
+ "type": "pcb_board",
439
+ "pcb_board_id": "pcb_board_0",
440
+ "center": {
441
+ "x": 0,
442
+ "y": 0
443
+ },
444
+ "thickness": 1.4,
445
+ "num_layers": 2,
446
+ "width": 33,
447
+ "height": 25,
448
+ "outline": [
449
+ {
450
+ "x": -15,
451
+ "y": -15
452
+ },
453
+ {
454
+ "x": 10,
455
+ "y": -15
456
+ },
457
+ {
458
+ "x": 12,
459
+ "y": -10
460
+ },
461
+ {
462
+ "x": 13,
463
+ "y": 0
464
+ },
465
+ {
466
+ "x": 12,
467
+ "y": 10
468
+ },
469
+ {
470
+ "x": 10,
471
+ "y": 10
472
+ },
473
+ {
474
+ "x": 5,
475
+ "y": 10
476
+ },
477
+ {
478
+ "x": 5,
479
+ "y": 5
480
+ },
481
+ {
482
+ "x": 0,
483
+ "y": 5
484
+ },
485
+ {
486
+ "x": 0,
487
+ "y": 10
488
+ },
489
+ {
490
+ "x": -15,
491
+ "y": 10
492
+ },
493
+ {
494
+ "x": -20,
495
+ "y": 5
496
+ },
497
+ {
498
+ "x": -15,
499
+ "y": 0
500
+ },
501
+ {
502
+ "x": -10,
503
+ "y": 0
504
+ },
505
+ {
506
+ "x": -10,
507
+ "y": -10
508
+ },
509
+ {
510
+ "x": -15,
511
+ "y": -10
512
+ }
513
+ ],
514
+ "material": "fr4"
515
+ },
516
+ {
517
+ "type": "pcb_smtpad",
518
+ "pcb_smtpad_id": "pcb_smtpad_0",
519
+ "pcb_component_id": "pcb_component_0",
520
+ "pcb_port_id": "pcb_port_0",
521
+ "layer": "top",
522
+ "shape": "rect",
523
+ "width": 1.025,
524
+ "height": 1.4,
525
+ "port_hints": ["1", "left"],
526
+ "is_covered_with_solder_mask": false,
527
+ "x": -5.9125,
528
+ "y": -2,
529
+ "subcircuit_id": "subcircuit_source_group_0"
530
+ },
531
+ {
532
+ "type": "pcb_solder_paste",
533
+ "pcb_solder_paste_id": "pcb_solder_paste_0",
534
+ "layer": "top",
535
+ "shape": "rect",
536
+ "width": 0.7174999999999999,
537
+ "height": 0.9799999999999999,
538
+ "x": -5.9125,
539
+ "y": -2,
540
+ "pcb_component_id": "pcb_component_0",
541
+ "pcb_smtpad_id": "pcb_smtpad_0",
542
+ "subcircuit_id": "subcircuit_source_group_0"
543
+ },
544
+ {
545
+ "type": "pcb_smtpad",
546
+ "pcb_smtpad_id": "pcb_smtpad_1",
547
+ "pcb_component_id": "pcb_component_0",
548
+ "pcb_port_id": "pcb_port_1",
549
+ "layer": "top",
550
+ "shape": "rect",
551
+ "width": 1.025,
552
+ "height": 1.4,
553
+ "port_hints": ["2", "right"],
554
+ "is_covered_with_solder_mask": false,
555
+ "x": -4.0875,
556
+ "y": -2,
557
+ "subcircuit_id": "subcircuit_source_group_0"
558
+ },
559
+ {
560
+ "type": "pcb_solder_paste",
561
+ "pcb_solder_paste_id": "pcb_solder_paste_1",
562
+ "layer": "top",
563
+ "shape": "rect",
564
+ "width": 0.7174999999999999,
565
+ "height": 0.9799999999999999,
566
+ "x": -4.0875,
567
+ "y": -2,
568
+ "pcb_component_id": "pcb_component_0",
569
+ "pcb_smtpad_id": "pcb_smtpad_1",
570
+ "subcircuit_id": "subcircuit_source_group_0"
571
+ },
572
+ {
573
+ "type": "pcb_silkscreen_path",
574
+ "pcb_silkscreen_path_id": "pcb_silkscreen_path_0",
575
+ "pcb_component_id": "pcb_component_0",
576
+ "layer": "top",
577
+ "route": [
578
+ {
579
+ "x": -4.0875,
580
+ "y": -0.8999999999999999
581
+ },
582
+ {
583
+ "x": -6.625,
584
+ "y": -0.8999999999999999
585
+ },
586
+ {
587
+ "x": -6.625,
588
+ "y": -3.1
589
+ },
590
+ {
591
+ "x": -4.0875,
592
+ "y": -3.1
593
+ }
594
+ ],
595
+ "stroke_width": 0.1,
596
+ "subcircuit_id": "subcircuit_source_group_0"
597
+ },
598
+ {
599
+ "type": "pcb_silkscreen_text",
600
+ "pcb_silkscreen_text_id": "pcb_silkscreen_text_0",
601
+ "anchor_alignment": "center",
602
+ "anchor_position": {
603
+ "x": -5,
604
+ "y": -0.3999999999999999
605
+ },
606
+ "font": "tscircuit2024",
607
+ "font_size": 0.4,
608
+ "layer": "top",
609
+ "text": "R1",
610
+ "ccw_rotation": 0,
611
+ "pcb_component_id": "pcb_component_0",
612
+ "subcircuit_id": "subcircuit_source_group_0"
613
+ },
614
+ {
615
+ "type": "pcb_smtpad",
616
+ "pcb_smtpad_id": "pcb_smtpad_2",
617
+ "pcb_component_id": "pcb_component_1",
618
+ "pcb_port_id": "pcb_port_2",
619
+ "layer": "top",
620
+ "shape": "rect",
621
+ "width": 1.025,
622
+ "height": 1.4,
623
+ "port_hints": ["1", "left"],
624
+ "is_covered_with_solder_mask": false,
625
+ "x": 4.0875,
626
+ "y": -2,
627
+ "subcircuit_id": "subcircuit_source_group_0"
628
+ },
629
+ {
630
+ "type": "pcb_solder_paste",
631
+ "pcb_solder_paste_id": "pcb_solder_paste_2",
632
+ "layer": "top",
633
+ "shape": "rect",
634
+ "width": 0.7174999999999999,
635
+ "height": 0.9799999999999999,
636
+ "x": 4.0875,
637
+ "y": -2,
638
+ "pcb_component_id": "pcb_component_1",
639
+ "pcb_smtpad_id": "pcb_smtpad_2",
640
+ "subcircuit_id": "subcircuit_source_group_0"
641
+ },
642
+ {
643
+ "type": "pcb_smtpad",
644
+ "pcb_smtpad_id": "pcb_smtpad_3",
645
+ "pcb_component_id": "pcb_component_1",
646
+ "pcb_port_id": "pcb_port_3",
647
+ "layer": "top",
648
+ "shape": "rect",
649
+ "width": 1.025,
650
+ "height": 1.4,
651
+ "port_hints": ["2", "right"],
652
+ "is_covered_with_solder_mask": false,
653
+ "x": 5.9125,
654
+ "y": -2,
655
+ "subcircuit_id": "subcircuit_source_group_0"
656
+ },
657
+ {
658
+ "type": "pcb_solder_paste",
659
+ "pcb_solder_paste_id": "pcb_solder_paste_3",
660
+ "layer": "top",
661
+ "shape": "rect",
662
+ "width": 0.7174999999999999,
663
+ "height": 0.9799999999999999,
664
+ "x": 5.9125,
665
+ "y": -2,
666
+ "pcb_component_id": "pcb_component_1",
667
+ "pcb_smtpad_id": "pcb_smtpad_3",
668
+ "subcircuit_id": "subcircuit_source_group_0"
669
+ },
670
+ {
671
+ "type": "pcb_silkscreen_path",
672
+ "pcb_silkscreen_path_id": "pcb_silkscreen_path_1",
673
+ "pcb_component_id": "pcb_component_1",
674
+ "layer": "top",
675
+ "route": [
676
+ {
677
+ "x": 5.9125,
678
+ "y": -0.8999999999999999
679
+ },
680
+ {
681
+ "x": 3.375,
682
+ "y": -0.8999999999999999
683
+ },
684
+ {
685
+ "x": 3.375,
686
+ "y": -3.1
687
+ },
688
+ {
689
+ "x": 5.9125,
690
+ "y": -3.1
691
+ }
692
+ ],
693
+ "stroke_width": 0.1,
694
+ "subcircuit_id": "subcircuit_source_group_0"
695
+ },
696
+ {
697
+ "type": "pcb_silkscreen_text",
698
+ "pcb_silkscreen_text_id": "pcb_silkscreen_text_1",
699
+ "anchor_alignment": "center",
700
+ "anchor_position": {
701
+ "x": 5,
702
+ "y": -0.3999999999999999
703
+ },
704
+ "font": "tscircuit2024",
705
+ "font_size": 0.4,
706
+ "layer": "top",
707
+ "text": "R2",
708
+ "ccw_rotation": 0,
709
+ "pcb_component_id": "pcb_component_1",
710
+ "subcircuit_id": "subcircuit_source_group_0"
711
+ },
712
+ {
713
+ "type": "pcb_port",
714
+ "pcb_port_id": "pcb_port_0",
715
+ "pcb_component_id": "pcb_component_0",
716
+ "layers": ["top"],
717
+ "subcircuit_id": "subcircuit_source_group_0",
718
+ "x": -5.9125,
719
+ "y": -2,
720
+ "source_port_id": "source_port_0"
721
+ },
722
+ {
723
+ "type": "pcb_port",
724
+ "pcb_port_id": "pcb_port_1",
725
+ "pcb_component_id": "pcb_component_0",
726
+ "layers": ["top"],
727
+ "subcircuit_id": "subcircuit_source_group_0",
728
+ "x": -4.0875,
729
+ "y": -2,
730
+ "source_port_id": "source_port_1"
731
+ },
732
+ {
733
+ "type": "pcb_port",
734
+ "pcb_port_id": "pcb_port_2",
735
+ "pcb_component_id": "pcb_component_1",
736
+ "layers": ["top"],
737
+ "subcircuit_id": "subcircuit_source_group_0",
738
+ "x": 4.0875,
739
+ "y": -2,
740
+ "source_port_id": "source_port_2"
741
+ },
742
+ {
743
+ "type": "pcb_port",
744
+ "pcb_port_id": "pcb_port_3",
745
+ "pcb_component_id": "pcb_component_1",
746
+ "layers": ["top"],
747
+ "subcircuit_id": "subcircuit_source_group_0",
748
+ "x": 5.9125,
749
+ "y": -2,
750
+ "source_port_id": "source_port_3"
751
+ },
752
+ {
753
+ "type": "cad_component",
754
+ "cad_component_id": "cad_component_0",
755
+ "position": {
756
+ "x": -5,
757
+ "y": -2,
758
+ "z": 0.7
759
+ },
760
+ "rotation": {
761
+ "x": 0,
762
+ "y": 0,
763
+ "z": 0
764
+ },
765
+ "pcb_component_id": "pcb_component_0",
766
+ "source_component_id": "source_component_0",
767
+ "footprinter_string": "0805"
768
+ },
769
+ {
770
+ "type": "cad_component",
771
+ "cad_component_id": "cad_component_1",
772
+ "position": {
773
+ "x": 5,
774
+ "y": -2,
775
+ "z": 0.7
776
+ },
777
+ "rotation": {
778
+ "x": 0,
779
+ "y": 0,
780
+ "z": 0
781
+ },
782
+ "pcb_component_id": "pcb_component_1",
783
+ "source_component_id": "source_component_1",
784
+ "footprinter_string": "0805"
785
+ },
786
+ {
787
+ "type": "pcb_trace",
788
+ "pcb_trace_id": "source_net_1_mst0_0",
789
+ "connection_name": "source_net_1",
790
+ "route": [
791
+ {
792
+ "route_type": "wire",
793
+ "x": 4.0875,
794
+ "y": -2,
795
+ "width": 0.15,
796
+ "layer": "top"
797
+ },
798
+ {
799
+ "route_type": "wire",
800
+ "x": 5.9125,
801
+ "y": -2,
802
+ "width": 0.15,
803
+ "layer": "top"
804
+ },
805
+ {
806
+ "route_type": "wire",
807
+ "x": 5.9125,
808
+ "y": -2,
809
+ "width": 0.15,
810
+ "layer": "top"
811
+ }
812
+ ],
813
+ "subcircuit_id": "subcircuit_source_group_0",
814
+ "source_trace_id": "source_net_1"
815
+ },
816
+ {
817
+ "type": "pcb_trace",
818
+ "pcb_trace_id": "source_net_1_mst1_0",
819
+ "connection_name": "source_net_1",
820
+ "route": [
821
+ {
822
+ "route_type": "wire",
823
+ "x": 4.0875,
824
+ "y": -2,
825
+ "width": 0.15,
826
+ "layer": "top"
827
+ },
828
+ {
829
+ "route_type": "wire",
830
+ "x": -4.0875,
831
+ "y": -2,
832
+ "width": 0.15,
833
+ "layer": "top"
834
+ },
835
+ {
836
+ "route_type": "wire",
837
+ "x": -4.0875,
838
+ "y": -2,
839
+ "width": 0.15,
840
+ "layer": "top"
841
+ }
842
+ ],
843
+ "subcircuit_id": "subcircuit_source_group_0",
844
+ "source_trace_id": "source_net_1"
845
+ }
846
+ ]
@@ -0,0 +1,15 @@
1
+ import { expect, test } from "bun:test"
2
+ import circuitJson from "./assets/circuit-6.json"
3
+ import { runSolverAndRenderToSvg } from "./utils/run-solver-and-render-to-svg"
4
+
5
+ test("circuit-7", async () => {
6
+ const svg = runSolverAndRenderToSvg(circuitJson as any, {
7
+ layer: "top",
8
+ net_name: "GND",
9
+ pad_margin: 0.4,
10
+ trace_margin: 0.2,
11
+ boardEdgeMargin: 1,
12
+ })
13
+
14
+ await expect(svg).toMatchSvgSnapshot(import.meta.path, "circuit-7")
15
+ })
@@ -0,0 +1,16 @@
1
+ import { expect, test } from "bun:test"
2
+ import circuitJson from "./assets/circuit-8.json"
3
+ import { runSolverAndRenderToSvg } from "./utils/run-solver-and-render-to-svg"
4
+ import type { AnyCircuitElement } from "circuit-json"
5
+
6
+ test("circuit 8", async () => {
7
+ const svg = runSolverAndRenderToSvg(circuitJson as AnyCircuitElement[], {
8
+ layer: "top",
9
+ net_name: "GND",
10
+ pad_margin: 0.4,
11
+ trace_margin: 0.2,
12
+ boardEdgeMargin: 1,
13
+ })
14
+
15
+ await expect(svg).toMatchSvgSnapshot(import.meta.path, "circuit-8")
16
+ })
@@ -17,6 +17,7 @@ export const runSolverAndRenderToSvg = (
17
17
  net_name: string
18
18
  pad_margin: number
19
19
  trace_margin: number
20
+ boardEdgeMargin?: number
20
21
  },
21
22
  ) => {
22
23
  const source_net = circuitJson.find(