@tscircuit/copper-pour-solver 0.0.10 → 0.0.11
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 +8 -2
- package/dist/index.js +131 -9
- package/lib/circuit-json/convert-circuit-json-to-input-problem.ts +43 -0
- package/lib/solvers/CopperPourPipelineSolver.ts +1 -0
- package/lib/solvers/copper-pour/process-obstacles.ts +109 -7
- package/lib/types.ts +11 -1
- package/package.json +1 -1
- package/tests/__snapshots__/hole-and-cutouts.snap.svg +1 -0
- package/tests/assets/hole-and-cutouts.json +772 -0
- package/tests/hole-and-cutouts.test.ts +16 -0
- package/tests/utils/run-solver-and-render-to-svg.ts +1 -0
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ interface InputPourRegion {
|
|
|
11
11
|
padMargin: number;
|
|
12
12
|
traceMargin: number;
|
|
13
13
|
board_edge_margin?: number;
|
|
14
|
+
cutout_margin?: number;
|
|
14
15
|
}
|
|
15
16
|
interface BaseInputPad {
|
|
16
17
|
padId: string;
|
|
@@ -32,7 +33,11 @@ interface InputTracePad extends BaseInputPad {
|
|
|
32
33
|
width: number;
|
|
33
34
|
segments: Point[];
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
interface InputPolygonPad extends BaseInputPad {
|
|
37
|
+
shape: "polygon";
|
|
38
|
+
points: Point[];
|
|
39
|
+
}
|
|
40
|
+
type InputPad = InputRectPad | InputCircularPad | InputTracePad | InputPolygonPad;
|
|
36
41
|
interface InputProblem {
|
|
37
42
|
regionsForPour: InputPourRegion[];
|
|
38
43
|
pads: InputPad[];
|
|
@@ -54,6 +59,7 @@ declare const convertCircuitJsonToInputProblem: (circuitJson: AnyCircuitElement[
|
|
|
54
59
|
pad_margin: number;
|
|
55
60
|
trace_margin: number;
|
|
56
61
|
board_edge_margin?: number;
|
|
62
|
+
cutout_margin?: number;
|
|
57
63
|
}) => InputProblem;
|
|
58
64
|
|
|
59
|
-
export { type BaseInputPad, CopperPourPipelineSolver, type InputCircularPad, type InputPad, type InputPourRegion, type InputProblem, type InputRectPad, type InputTracePad, type PipelineOutput, convertCircuitJsonToInputProblem };
|
|
65
|
+
export { type BaseInputPad, CopperPourPipelineSolver, type InputCircularPad, type InputPad, type InputPolygonPad, type InputPourRegion, type InputProblem, type InputRectPad, type InputTracePad, type PipelineOutput, convertCircuitJsonToInputProblem };
|
package/dist/index.js
CHANGED
|
@@ -57,9 +57,10 @@ var circleToPolygon = (circle, numSegments = 32) => {
|
|
|
57
57
|
var isRectPad = (pad) => pad.shape === "rect";
|
|
58
58
|
var isTracePad = (pad) => pad.shape === "trace";
|
|
59
59
|
var isCircularPad = (pad) => pad.shape === "circle";
|
|
60
|
+
var isPolygonPad = (pad) => pad.shape === "polygon";
|
|
60
61
|
var processObstaclesForPour = (pads, pourConnectivityKey, margins, boardOutline) => {
|
|
61
62
|
const polygonsToSubtract = [];
|
|
62
|
-
const { padMargin, traceMargin, board_edge_margin } = margins;
|
|
63
|
+
const { padMargin, traceMargin, board_edge_margin, cutoutMargin } = margins;
|
|
63
64
|
if (boardOutline && boardOutline.length > 0 && board_edge_margin && board_edge_margin > 0) {
|
|
64
65
|
const boardPoly = new Flatten3.Polygon(
|
|
65
66
|
boardOutline.map((p) => Flatten3.point(p.x, p.y))
|
|
@@ -123,9 +124,18 @@ var processObstaclesForPour = (pads, pourConnectivityKey, margins, boardOutline)
|
|
|
123
124
|
if (isOnNet) {
|
|
124
125
|
continue;
|
|
125
126
|
}
|
|
127
|
+
const isHoleOrCutout = pad.connectivityKey.startsWith("hole:") || pad.connectivityKey.startsWith("cutout:");
|
|
126
128
|
if (isCircularPad(pad)) {
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
+
const margin = isHoleOrCutout ? cutoutMargin ?? 0 : padMargin;
|
|
130
|
+
if (isHoleOrCutout) {
|
|
131
|
+
console.log(
|
|
132
|
+
`Applying cutout margin to circular pad/hole/cutout: ${pad.padId}, margin: ${margin}`
|
|
133
|
+
);
|
|
134
|
+
} else {
|
|
135
|
+
console.log(
|
|
136
|
+
`Applying pad margin to circular pad: ${pad.padId}, margin: ${margin}`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
129
139
|
const circle = new Flatten3.Circle(
|
|
130
140
|
new Flatten3.Point(pad.x, pad.y),
|
|
131
141
|
pad.radius + margin
|
|
@@ -134,16 +144,83 @@ var processObstaclesForPour = (pads, pourConnectivityKey, margins, boardOutline)
|
|
|
134
144
|
continue;
|
|
135
145
|
}
|
|
136
146
|
if (isRectPad(pad)) {
|
|
147
|
+
const margin = isHoleOrCutout ? cutoutMargin ?? 0 : padMargin;
|
|
148
|
+
if (isHoleOrCutout) {
|
|
149
|
+
console.log(
|
|
150
|
+
`Applying cutout margin to rect pad/cutout: ${pad.padId}, margin: ${margin}`
|
|
151
|
+
);
|
|
152
|
+
} else {
|
|
153
|
+
console.log(
|
|
154
|
+
`Applying pad margin to rect pad: ${pad.padId}, margin: ${margin}`
|
|
155
|
+
);
|
|
156
|
+
}
|
|
137
157
|
const { bounds } = pad;
|
|
138
158
|
const b = new Flatten3.Box(
|
|
139
|
-
bounds.minX -
|
|
140
|
-
bounds.minY -
|
|
141
|
-
bounds.maxX +
|
|
142
|
-
bounds.maxY +
|
|
159
|
+
bounds.minX - margin,
|
|
160
|
+
bounds.minY - margin,
|
|
161
|
+
bounds.maxX + margin,
|
|
162
|
+
bounds.maxY + margin
|
|
143
163
|
);
|
|
144
164
|
polygonsToSubtract.push(new Flatten3.Polygon(b.toPoints()));
|
|
145
165
|
continue;
|
|
146
166
|
}
|
|
167
|
+
if (isPolygonPad(pad)) {
|
|
168
|
+
const margin = isHoleOrCutout ? cutoutMargin ?? 0 : 0;
|
|
169
|
+
if (isHoleOrCutout) {
|
|
170
|
+
console.log(
|
|
171
|
+
`Applying cutout margin to polygon cutout: ${pad.padId}, margin: ${margin}`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const seen = /* @__PURE__ */ new Set();
|
|
175
|
+
const uniquePoints = pad.points.filter((p) => {
|
|
176
|
+
const key = `${p.x},${p.y}`;
|
|
177
|
+
if (seen.has(key)) {
|
|
178
|
+
console.log(
|
|
179
|
+
`Duplicate point detected and removed for ${pad.padId}: (${p.x}, ${p.y})`
|
|
180
|
+
);
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
seen.add(key);
|
|
184
|
+
return true;
|
|
185
|
+
});
|
|
186
|
+
if (uniquePoints.length < 3) continue;
|
|
187
|
+
const polygon = new Flatten3.Polygon(
|
|
188
|
+
uniquePoints.map((p) => Flatten3.point(p.x, p.y))
|
|
189
|
+
);
|
|
190
|
+
if (Math.abs(polygon.area()) < 1e-9) continue;
|
|
191
|
+
if (margin <= 0) {
|
|
192
|
+
polygonsToSubtract.push(polygon);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (polygon.area() > 0) {
|
|
196
|
+
polygon.reverse();
|
|
197
|
+
}
|
|
198
|
+
const offsetLines = [];
|
|
199
|
+
const polygonVertices = polygon.vertices;
|
|
200
|
+
for (let i = 0; i < polygonVertices.length; i++) {
|
|
201
|
+
const p1 = polygonVertices[i];
|
|
202
|
+
const p2 = polygonVertices[(i + 1) % polygonVertices.length];
|
|
203
|
+
const segment = Flatten3.segment(p1, p2);
|
|
204
|
+
if (segment.length === 0) continue;
|
|
205
|
+
const line = Flatten3.line(segment.start, segment.end);
|
|
206
|
+
const norm = line.norm;
|
|
207
|
+
const offsetLine = line.translate(norm.multiply(-margin));
|
|
208
|
+
offsetLines.push(offsetLine);
|
|
209
|
+
}
|
|
210
|
+
const newPolygonPoints = [];
|
|
211
|
+
for (let i = 0; i < offsetLines.length; i++) {
|
|
212
|
+
const line1 = offsetLines[i];
|
|
213
|
+
const line2 = offsetLines[(i + 1) % offsetLines.length];
|
|
214
|
+
const ip = line1.intersect(line2);
|
|
215
|
+
if (ip.length > 0) {
|
|
216
|
+
newPolygonPoints.push(ip[0]);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (newPolygonPoints.length >= 3) {
|
|
220
|
+
polygonsToSubtract.push(new Flatten3.Polygon(newPolygonPoints));
|
|
221
|
+
}
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
147
224
|
if (isTracePad(pad)) {
|
|
148
225
|
for (const segment of pad.segments) {
|
|
149
226
|
const circle = new Flatten3.Circle(
|
|
@@ -254,7 +331,8 @@ var CopperPourPipelineSolver = class extends BasePipelineSolver {
|
|
|
254
331
|
{
|
|
255
332
|
padMargin: region.padMargin,
|
|
256
333
|
traceMargin: region.traceMargin,
|
|
257
|
-
board_edge_margin: region.board_edge_margin
|
|
334
|
+
board_edge_margin: region.board_edge_margin,
|
|
335
|
+
cutoutMargin: region.cutout_margin
|
|
258
336
|
},
|
|
259
337
|
region.outline
|
|
260
338
|
);
|
|
@@ -410,6 +488,49 @@ var convertCircuitJsonToInputProblem = (circuitJson, options) => {
|
|
|
410
488
|
y: hole.y,
|
|
411
489
|
radius: hole.hole_diameter / 2
|
|
412
490
|
});
|
|
491
|
+
} else if (elm.type === "pcb_cutout") {
|
|
492
|
+
const cutout = elm;
|
|
493
|
+
console.log(
|
|
494
|
+
`Processing cutout: ${cutout.pcb_cutout_id} (shape: ${cutout.shape})`
|
|
495
|
+
);
|
|
496
|
+
if (cutout.shape === "rect") {
|
|
497
|
+
pads.push({
|
|
498
|
+
shape: "rect",
|
|
499
|
+
padId: cutout.pcb_cutout_id,
|
|
500
|
+
layer: options.layer,
|
|
501
|
+
// through-all
|
|
502
|
+
connectivityKey: `cutout:${cutout.pcb_cutout_id}`,
|
|
503
|
+
bounds: {
|
|
504
|
+
minX: cutout.center.x - cutout.width / 2,
|
|
505
|
+
minY: cutout.center.y - cutout.height / 2,
|
|
506
|
+
maxX: cutout.center.x + cutout.width / 2,
|
|
507
|
+
maxY: cutout.center.y + cutout.height / 2
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
} else if (cutout.shape === "circle") {
|
|
511
|
+
pads.push({
|
|
512
|
+
shape: "circle",
|
|
513
|
+
padId: cutout.pcb_cutout_id,
|
|
514
|
+
layer: options.layer,
|
|
515
|
+
// through-all
|
|
516
|
+
connectivityKey: `cutout:${cutout.pcb_cutout_id}`,
|
|
517
|
+
x: cutout.center.x,
|
|
518
|
+
y: cutout.center.y,
|
|
519
|
+
radius: cutout.radius
|
|
520
|
+
});
|
|
521
|
+
} else if (cutout.shape === "polygon") {
|
|
522
|
+
console.log(
|
|
523
|
+
`Polygon cutout points for ${cutout.pcb_cutout_id}: ${JSON.stringify(cutout.points)}`
|
|
524
|
+
);
|
|
525
|
+
pads.push({
|
|
526
|
+
shape: "polygon",
|
|
527
|
+
padId: cutout.pcb_cutout_id,
|
|
528
|
+
layer: options.layer,
|
|
529
|
+
// through-all
|
|
530
|
+
connectivityKey: `cutout:${cutout.pcb_cutout_id}`,
|
|
531
|
+
points: cutout.points
|
|
532
|
+
});
|
|
533
|
+
}
|
|
413
534
|
} else if (elm.type === "pcb_via") {
|
|
414
535
|
const via = elm;
|
|
415
536
|
if (!via.layers.includes(options.layer)) continue;
|
|
@@ -478,7 +599,8 @@ var convertCircuitJsonToInputProblem = (circuitJson, options) => {
|
|
|
478
599
|
connectivityKey: options.pour_connectivity_key,
|
|
479
600
|
padMargin: options.pad_margin,
|
|
480
601
|
traceMargin: options.trace_margin,
|
|
481
|
-
board_edge_margin: options.board_edge_margin ?? 0
|
|
602
|
+
board_edge_margin: options.board_edge_margin ?? 0,
|
|
603
|
+
cutout_margin: options.cutout_margin
|
|
482
604
|
}
|
|
483
605
|
];
|
|
484
606
|
return {
|
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
import type {
|
|
17
17
|
InputCircularPad,
|
|
18
18
|
InputPad,
|
|
19
|
+
InputPolygonPad,
|
|
19
20
|
InputProblem,
|
|
20
21
|
InputRectPad,
|
|
21
22
|
InputTracePad,
|
|
@@ -29,6 +30,7 @@ export const convertCircuitJsonToInputProblem = (
|
|
|
29
30
|
pad_margin: number
|
|
30
31
|
trace_margin: number
|
|
31
32
|
board_edge_margin?: number
|
|
33
|
+
cutout_margin?: number
|
|
32
34
|
},
|
|
33
35
|
): InputProblem => {
|
|
34
36
|
const source_ports = circuitJson.filter(
|
|
@@ -180,6 +182,46 @@ export const convertCircuitJsonToInputProblem = (
|
|
|
180
182
|
y: hole.y,
|
|
181
183
|
radius: hole.hole_diameter / 2,
|
|
182
184
|
} as InputCircularPad)
|
|
185
|
+
} else if (elm.type === "pcb_cutout") {
|
|
186
|
+
const cutout = elm as any
|
|
187
|
+
console.log(
|
|
188
|
+
`Processing cutout: ${cutout.pcb_cutout_id} (shape: ${cutout.shape})`,
|
|
189
|
+
)
|
|
190
|
+
if (cutout.shape === "rect") {
|
|
191
|
+
pads.push({
|
|
192
|
+
shape: "rect",
|
|
193
|
+
padId: cutout.pcb_cutout_id,
|
|
194
|
+
layer: options.layer, // through-all
|
|
195
|
+
connectivityKey: `cutout:${cutout.pcb_cutout_id}`,
|
|
196
|
+
bounds: {
|
|
197
|
+
minX: cutout.center.x - cutout.width / 2,
|
|
198
|
+
minY: cutout.center.y - cutout.height / 2,
|
|
199
|
+
maxX: cutout.center.x + cutout.width / 2,
|
|
200
|
+
maxY: cutout.center.y + cutout.height / 2,
|
|
201
|
+
},
|
|
202
|
+
} as InputRectPad)
|
|
203
|
+
} else if (cutout.shape === "circle") {
|
|
204
|
+
pads.push({
|
|
205
|
+
shape: "circle",
|
|
206
|
+
padId: cutout.pcb_cutout_id,
|
|
207
|
+
layer: options.layer, // through-all
|
|
208
|
+
connectivityKey: `cutout:${cutout.pcb_cutout_id}`,
|
|
209
|
+
x: cutout.center.x,
|
|
210
|
+
y: cutout.center.y,
|
|
211
|
+
radius: cutout.radius,
|
|
212
|
+
} as InputCircularPad)
|
|
213
|
+
} else if (cutout.shape === "polygon") {
|
|
214
|
+
console.log(
|
|
215
|
+
`Polygon cutout points for ${cutout.pcb_cutout_id}: ${JSON.stringify(cutout.points)}`,
|
|
216
|
+
)
|
|
217
|
+
pads.push({
|
|
218
|
+
shape: "polygon",
|
|
219
|
+
padId: cutout.pcb_cutout_id,
|
|
220
|
+
layer: options.layer, // through-all
|
|
221
|
+
connectivityKey: `cutout:${cutout.pcb_cutout_id}`,
|
|
222
|
+
points: cutout.points,
|
|
223
|
+
} as InputPolygonPad)
|
|
224
|
+
}
|
|
183
225
|
} else if (elm.type === "pcb_via") {
|
|
184
226
|
const via = elm as PcbVia
|
|
185
227
|
if (!via.layers.includes(options.layer)) continue
|
|
@@ -257,6 +299,7 @@ export const convertCircuitJsonToInputProblem = (
|
|
|
257
299
|
padMargin: options.pad_margin,
|
|
258
300
|
traceMargin: options.trace_margin,
|
|
259
301
|
board_edge_margin: options.board_edge_margin ?? 0,
|
|
302
|
+
cutout_margin: options.cutout_margin,
|
|
260
303
|
},
|
|
261
304
|
]
|
|
262
305
|
|
|
@@ -29,6 +29,7 @@ export class CopperPourPipelineSolver extends BasePipelineSolver<InputProblem> {
|
|
|
29
29
|
padMargin: region.padMargin,
|
|
30
30
|
traceMargin: region.traceMargin,
|
|
31
31
|
board_edge_margin: region.board_edge_margin,
|
|
32
|
+
cutoutMargin: region.cutout_margin,
|
|
32
33
|
},
|
|
33
34
|
region.outline,
|
|
34
35
|
)
|
|
@@ -3,6 +3,7 @@ import type { Point } from "@tscircuit/math-utils"
|
|
|
3
3
|
import type {
|
|
4
4
|
InputCircularPad,
|
|
5
5
|
InputPad,
|
|
6
|
+
InputPolygonPad,
|
|
6
7
|
InputRectPad,
|
|
7
8
|
InputTracePad,
|
|
8
9
|
} from "lib/types"
|
|
@@ -17,6 +18,8 @@ const isTracePad = (pad: InputPad): pad is InputTracePad =>
|
|
|
17
18
|
pad.shape === "trace"
|
|
18
19
|
const isCircularPad = (pad: InputPad): pad is InputCircularPad =>
|
|
19
20
|
pad.shape === "circle"
|
|
21
|
+
const isPolygonPad = (pad: InputPad): pad is InputPolygonPad =>
|
|
22
|
+
pad.shape === "polygon"
|
|
20
23
|
|
|
21
24
|
export const processObstaclesForPour = (
|
|
22
25
|
pads: InputPad[],
|
|
@@ -25,12 +28,13 @@ export const processObstaclesForPour = (
|
|
|
25
28
|
padMargin: number
|
|
26
29
|
traceMargin: number
|
|
27
30
|
board_edge_margin?: number
|
|
31
|
+
cutoutMargin?: number
|
|
28
32
|
},
|
|
29
33
|
boardOutline?: Point[],
|
|
30
34
|
): ProcessedObstacles => {
|
|
31
35
|
const polygonsToSubtract: Flatten.Polygon[] = []
|
|
32
36
|
|
|
33
|
-
const { padMargin, traceMargin, board_edge_margin } = margins
|
|
37
|
+
const { padMargin, traceMargin, board_edge_margin, cutoutMargin } = margins
|
|
34
38
|
|
|
35
39
|
if (
|
|
36
40
|
boardOutline &&
|
|
@@ -120,9 +124,21 @@ export const processObstaclesForPour = (
|
|
|
120
124
|
continue
|
|
121
125
|
}
|
|
122
126
|
|
|
127
|
+
const isHoleOrCutout =
|
|
128
|
+
pad.connectivityKey.startsWith("hole:") ||
|
|
129
|
+
pad.connectivityKey.startsWith("cutout:")
|
|
130
|
+
|
|
123
131
|
if (isCircularPad(pad)) {
|
|
124
|
-
const
|
|
125
|
-
|
|
132
|
+
const margin = isHoleOrCutout ? (cutoutMargin ?? 0) : padMargin
|
|
133
|
+
if (isHoleOrCutout) {
|
|
134
|
+
console.log(
|
|
135
|
+
`Applying cutout margin to circular pad/hole/cutout: ${pad.padId}, margin: ${margin}`,
|
|
136
|
+
)
|
|
137
|
+
} else {
|
|
138
|
+
console.log(
|
|
139
|
+
`Applying pad margin to circular pad: ${pad.padId}, margin: ${margin}`,
|
|
140
|
+
)
|
|
141
|
+
}
|
|
126
142
|
const circle = new Flatten.Circle(
|
|
127
143
|
new Flatten.Point(pad.x, pad.y),
|
|
128
144
|
pad.radius + margin,
|
|
@@ -132,17 +148,103 @@ export const processObstaclesForPour = (
|
|
|
132
148
|
}
|
|
133
149
|
|
|
134
150
|
if (isRectPad(pad)) {
|
|
151
|
+
const margin = isHoleOrCutout ? (cutoutMargin ?? 0) : padMargin
|
|
152
|
+
if (isHoleOrCutout) {
|
|
153
|
+
console.log(
|
|
154
|
+
`Applying cutout margin to rect pad/cutout: ${pad.padId}, margin: ${margin}`,
|
|
155
|
+
)
|
|
156
|
+
} else {
|
|
157
|
+
console.log(
|
|
158
|
+
`Applying pad margin to rect pad: ${pad.padId}, margin: ${margin}`,
|
|
159
|
+
)
|
|
160
|
+
}
|
|
135
161
|
const { bounds } = pad
|
|
136
162
|
const b = new Flatten.Box(
|
|
137
|
-
bounds.minX -
|
|
138
|
-
bounds.minY -
|
|
139
|
-
bounds.maxX +
|
|
140
|
-
bounds.maxY +
|
|
163
|
+
bounds.minX - margin,
|
|
164
|
+
bounds.minY - margin,
|
|
165
|
+
bounds.maxX + margin,
|
|
166
|
+
bounds.maxY + margin,
|
|
141
167
|
)
|
|
142
168
|
polygonsToSubtract.push(new Flatten.Polygon(b.toPoints()))
|
|
143
169
|
continue
|
|
144
170
|
}
|
|
145
171
|
|
|
172
|
+
if (isPolygonPad(pad)) {
|
|
173
|
+
const margin = isHoleOrCutout ? (cutoutMargin ?? 0) : 0
|
|
174
|
+
if (isHoleOrCutout) {
|
|
175
|
+
console.log(
|
|
176
|
+
`Applying cutout margin to polygon cutout: ${pad.padId}, margin: ${margin}`,
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const seen = new Set<string>()
|
|
181
|
+
const uniquePoints = pad.points.filter((p) => {
|
|
182
|
+
const key = `${p.x},${p.y}`
|
|
183
|
+
if (seen.has(key)) {
|
|
184
|
+
console.log(
|
|
185
|
+
`Duplicate point detected and removed for ${pad.padId}: (${p.x}, ${p.y})`,
|
|
186
|
+
)
|
|
187
|
+
return false
|
|
188
|
+
}
|
|
189
|
+
seen.add(key)
|
|
190
|
+
return true
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
if (uniquePoints.length < 3) continue
|
|
194
|
+
|
|
195
|
+
const polygon = new Flatten.Polygon(
|
|
196
|
+
uniquePoints.map((p) => Flatten.point(p.x, p.y)),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
if (Math.abs(polygon.area()) < 1e-9) continue
|
|
200
|
+
|
|
201
|
+
if (margin <= 0) {
|
|
202
|
+
polygonsToSubtract.push(polygon)
|
|
203
|
+
continue
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Ensure polygon is CCW for consistent normal direction.
|
|
207
|
+
// In flatten-js, CCW corresponds to a negative area.
|
|
208
|
+
if (polygon.area() > 0) {
|
|
209
|
+
polygon.reverse()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const offsetLines: Flatten.Line[] = []
|
|
213
|
+
const polygonVertices = polygon.vertices
|
|
214
|
+
for (let i = 0; i < polygonVertices.length; i++) {
|
|
215
|
+
const p1 = polygonVertices[i]!
|
|
216
|
+
const p2 = polygonVertices[(i + 1) % polygonVertices.length]!
|
|
217
|
+
|
|
218
|
+
const segment = Flatten.segment(p1, p2)
|
|
219
|
+
|
|
220
|
+
if (segment.length === 0) continue
|
|
221
|
+
|
|
222
|
+
const line = Flatten.line(segment.start, segment.end)
|
|
223
|
+
|
|
224
|
+
// For a CCW polygon, the normal (rotated +90deg, i.e. "left") points inward.
|
|
225
|
+
// We must translate outward, so we use a negative margin.
|
|
226
|
+
const norm = line.norm
|
|
227
|
+
const offsetLine = line.translate(norm.multiply(-margin))
|
|
228
|
+
offsetLines.push(offsetLine)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const newPolygonPoints: Flatten.Point[] = []
|
|
232
|
+
for (let i = 0; i < offsetLines.length; i++) {
|
|
233
|
+
const line1 = offsetLines[i]!
|
|
234
|
+
const line2 = offsetLines[(i + 1) % offsetLines.length]!
|
|
235
|
+
|
|
236
|
+
const ip = line1.intersect(line2)
|
|
237
|
+
if (ip.length > 0) {
|
|
238
|
+
newPolygonPoints.push(ip[0]!)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (newPolygonPoints.length >= 3) {
|
|
243
|
+
polygonsToSubtract.push(new Flatten.Polygon(newPolygonPoints))
|
|
244
|
+
}
|
|
245
|
+
continue
|
|
246
|
+
}
|
|
247
|
+
|
|
146
248
|
if (isTracePad(pad)) {
|
|
147
249
|
// Add circles for each vertex
|
|
148
250
|
for (const segment of pad.segments) {
|
package/lib/types.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface InputPourRegion {
|
|
|
10
10
|
padMargin: number
|
|
11
11
|
traceMargin: number
|
|
12
12
|
board_edge_margin?: number
|
|
13
|
+
cutout_margin?: number
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export interface BaseInputPad {
|
|
@@ -36,7 +37,16 @@ export interface InputTracePad extends BaseInputPad {
|
|
|
36
37
|
segments: Point[]
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
export
|
|
40
|
+
export interface InputPolygonPad extends BaseInputPad {
|
|
41
|
+
shape: "polygon"
|
|
42
|
+
points: Point[]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type InputPad =
|
|
46
|
+
| InputRectPad
|
|
47
|
+
| InputCircularPad
|
|
48
|
+
| InputTracePad
|
|
49
|
+
| InputPolygonPad
|
|
40
50
|
|
|
41
51
|
export interface InputProblem {
|
|
42
52
|
regionsForPour: InputPourRegion[]
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.849"><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="150" y="50" width="500" height="500" data-type="pcb_boundary" data-pcb-layer="global"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="284" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="bottom"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="233" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 297.5 300 L 297.5 378.95223661654137" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 297.5 378.95223661654137 L 303.5414925183353 384.99372913487673" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 303.5414925183353 384.99372913487673 L 306.25 393.75" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 306.25 393.75 L 306.25 393.75" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-silkscreen pcb-silkscreen-bottom" d="M 246.5 264 L 321 264 L 321 336 L 246.5 336" fill="none" stroke="#5da9e9" stroke-width="5" 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="bottom"/><text x="0" y="0" dx="0" dy="0" fill="#5da9e9" font-family="Arial, sans-serif" font-size="20" text-anchor="middle" dominant-baseline="central" transform="matrix(-1,0,0,1,272,239)" class="pcb-silkscreen-text pcb-silkscreen-bottom" data-pcb-silkscreen-text-id="pcb_component_1" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="bottom">C1</text><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5" data-type="pcb_board" data-pcb-layer="board"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="361" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="412" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 306.25 393.75 L 306.25 393.75" stroke-width="7.5" 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 306.25 393.75 L 306.25 368.25" stroke-width="7.5" 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 306.25 368.25 L 374.5 300" stroke-width="7.5" 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 150 550 L 150 50 L 650 50 L 650 550 L 150 550 Z M 610 150 L 608.8471168241938 138.29458067903232 L 605.4327719506772 127.03899405809463 L 599.8881767381527 116.66578601882387 L 592.4264068711929 107.57359312880715 L 583.3342139811762 100.11182326184729 L 572.9610059419053 94.56722804932278 L 561.7054193209676 91.15288317580615 L 550 90 L 538.2945806790324 91.15288317580615 L 527.0389940580947 94.56722804932278 L 516.6657860188238 100.11182326184729 L 507.57359312880715 107.57359312880715 L 500.1118232618473 116.66578601882387 L 494.5672280493228 127.0389940580946 L 491.1528831758062 138.2945806790323 L 490 150 L 491.1528831758062 161.70541932096768 L 494.5672280493228 172.96100594190537 L 500.1118232618473 183.3342139811761 L 507.57359312880715 192.42640687119285 L 516.6657860188238 199.8881767381527 L 527.0389940580945 205.4327719506772 L 538.2945806790323 208.84711682419382 L 550 210 L 561.7054193209676 208.84711682419382 L 572.9610059419053 205.4327719506772 L 583.3342139811762 199.8881767381527 L 592.4264068711929 192.42640687119285 L 599.8881767381527 183.33421398117613 L 605.4327719506772 172.96100594190543 L 608.8471168241938 161.7054193209677 L 610 150 Z M 460 450 L 458.84711682419385 438.2945806790323 L 455.4327719506772 427.03899405809466 L 449.8881767381527 416.66578601882384 L 442.42640687119285 407.57359312880715 L 433.33421398117616 400.1118232618473 L 422.9610059419054 394.5672280493228 L 411.7054193209677 391.1528831758062 L 400 390 L 388.2945806790323 391.1528831758062 L 377.0389940580946 394.5672280493228 L 366.6657860188239 400.1118232618473 L 357.57359312880715 407.57359312880715 L 350.1118232618473 416.66578601882384 L 344.5672280493228 427.0389940580946 L 341.15288317580615 438.29458067903226 L 340 450 L 341.15288317580615 461.7054193209677 L 344.5672280493228 472.96100594190534 L 350.1118232618473 483.3342139811761 L 357.57359312880715 492.42640687119285 L 366.66578601882384 499.8881767381527 L 377.0389940580946 505.4327719506772 L 388.29458067903226 508.8471168241938 L 400 510 L 411.7054193209677 508.84711682419385 L 422.9610059419054 505.4327719506772 L 433.3342139811761 499.8881767381527 L 442.42640687119285 492.42640687119285 L 449.8881767381527 483.33421398117616 L 455.4327719506772 472.96100594190546 L 458.8471168241938 461.70541932096774 L 460 450 Z M 490 335 L 610 335 L 610 265 L 490 265 L 490 335 Z M 316.0805385563561 370.7938301144085 L 360.87436867076457 326 L 398 326 L 398 274 L 351 274 L 351 311.12563132923543 L 300.0628156646177 362.0628156646177 L 298.97464089235274 363.3887604610785 L 298.16605409052625 364.9015199668055 L 297.6681287964717 366.54295968235886 L 297.5 368.25 L 297.5 370.40515141679646 L 296.6829141908728 370.6530116872178 L 292.36074417450993 372.9632596924364 L 288.5723304703363 376.0723304703363 L 285.4632596924364 379.86074417450993 L 283.1530116872178 384.18291419087274 L 281.7303679899193 388.8727419495968 L 281.25 393.75 L 281.7303679899193 398.6272580504032 L 283.1530116872178 403.3170858091272 L 285.46325969243634 407.63925582549007 L 288.5723304703363 411.4276695296637 L 292.36074417450993 414.5367403075636 L 296.68291419087274 416.8469883127822 L 301.3727419495968 418.2696320100807 L 306.25 418.75 L 311.1272580504032 418.2696320100807 L 315.81708580912726 416.8469883127822 L 320.13925582549007 414.53674030756366 L 323.9276695296637 411.4276695296637 L 327.0367403075636 407.63925582549007 L 329.3469883127822 403.31708580912726 L 330.7696320100807 398.6272580504032 L 331.25 393.75 L 330.7696320100807 388.8727419495968 L 329.3469883127822 384.1829141908728 L 327.0367403075636 379.86074417450993 L 323.9276695296637 376.0723304703363 L 320.13925582549007 372.9632596924364 L 316.0805385563561 370.7938301144085 Z M 475.85786437626905 460 L 624.142135623731 460 L 550 385.85786437626905 L 475.85786437626905 460 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 425.5 264 L 351 264 L 351 336 L 425.5 336" fill="none" stroke="#f2eda1" stroke-width="5" 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="20" text-anchor="middle" dominant-baseline="central" transform="matrix(1,0,0,1,400,239)" 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><g data-type="pcb_via" data-pcb-layer="through"><circle class="pcb-hole-outer" fill="rgb(200, 52, 52)" cx="306.25" cy="393.75" r="15" data-type="pcb_via" data-pcb-layer="top"/><circle class="pcb-hole-inner" fill="#FF26E2" cx="306.25" cy="393.75" r="7.5" data-type="pcb_via" data-pcb-layer="drill"/></g><rect class="pcb-cutout pcb-cutout-rect" x="-50" y="-25" width="100" height="50" fill="#FF26E2" transform="matrix(1,0,0,1,550,300)" data-type="pcb_cutout" data-pcb-layer="drill"/><circle class="pcb-cutout pcb-cutout-circle" cx="550" cy="150" r="50" fill="#FF26E2" data-type="pcb_cutout" data-pcb-layer="drill"/><polygon class="pcb-cutout pcb-cutout-polygon" points="550,400 550,400 600,450 500,450" fill="#FF26E2" data-type="pcb_cutout" data-pcb-layer="drill"/><circle class="pcb-hole" cx="400" cy="450" r="50" fill="#FF26E2" data-type="pcb_hole" data-pcb-layer="drill"/></svg>
|
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "source_project_metadata",
|
|
4
|
+
"source_project_metadata_id": "source_project_metadata_0",
|
|
5
|
+
"software_used_string": "@tscircuit/core@0.0.849"
|
|
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": "unnamedsubcircuit917_connectivity_net0"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"type": "source_port",
|
|
27
|
+
"source_port_id": "source_port_0",
|
|
28
|
+
"name": "pin1",
|
|
29
|
+
"pin_number": 1,
|
|
30
|
+
"port_hints": ["pin1", "anode", "pos", "left", "1"],
|
|
31
|
+
"source_component_id": "source_component_0",
|
|
32
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
33
|
+
"subcircuit_connectivity_map_key": "unnamedsubcircuit917_connectivity_net1"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"type": "source_port",
|
|
37
|
+
"source_port_id": "source_port_1",
|
|
38
|
+
"name": "pin2",
|
|
39
|
+
"pin_number": 2,
|
|
40
|
+
"port_hints": ["pin2", "cathode", "neg", "right", "2"],
|
|
41
|
+
"source_component_id": "source_component_0",
|
|
42
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
43
|
+
"subcircuit_connectivity_map_key": "unnamedsubcircuit917_connectivity_net0"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"type": "source_component",
|
|
47
|
+
"source_component_id": "source_component_0",
|
|
48
|
+
"ftype": "simple_resistor",
|
|
49
|
+
"name": "R1",
|
|
50
|
+
"supplier_part_numbers": {
|
|
51
|
+
"jlcpcb": ["C11702", "C25543", "C2906864"]
|
|
52
|
+
},
|
|
53
|
+
"resistance": 1000,
|
|
54
|
+
"display_resistance": "1kΩ",
|
|
55
|
+
"are_pins_interchangeable": true,
|
|
56
|
+
"source_group_id": "source_group_0"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"type": "source_port",
|
|
60
|
+
"source_port_id": "source_port_2",
|
|
61
|
+
"name": "pin1",
|
|
62
|
+
"pin_number": 1,
|
|
63
|
+
"port_hints": ["pin1", "pos", "anode", "1"],
|
|
64
|
+
"source_component_id": "source_component_1",
|
|
65
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
66
|
+
"subcircuit_connectivity_map_key": "unnamedsubcircuit917_connectivity_net1"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "source_port",
|
|
70
|
+
"source_port_id": "source_port_3",
|
|
71
|
+
"name": "pin2",
|
|
72
|
+
"pin_number": 2,
|
|
73
|
+
"port_hints": ["pin2", "neg", "cathode", "2"],
|
|
74
|
+
"source_component_id": "source_component_1",
|
|
75
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "source_component",
|
|
79
|
+
"source_component_id": "source_component_1",
|
|
80
|
+
"ftype": "simple_capacitor",
|
|
81
|
+
"name": "C1",
|
|
82
|
+
"supplier_part_numbers": {
|
|
83
|
+
"jlcpcb": ["C1523", "C696907", "C5137470"]
|
|
84
|
+
},
|
|
85
|
+
"capacitance": 1e-9,
|
|
86
|
+
"display_capacitance": "1000pF",
|
|
87
|
+
"are_pins_interchangeable": true,
|
|
88
|
+
"source_group_id": "source_group_0"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"type": "source_net",
|
|
92
|
+
"source_net_id": "source_net_1",
|
|
93
|
+
"name": "VCC",
|
|
94
|
+
"member_source_group_ids": [],
|
|
95
|
+
"is_ground": false,
|
|
96
|
+
"is_power": true,
|
|
97
|
+
"is_positive_voltage_source": true,
|
|
98
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
99
|
+
"subcircuit_connectivity_map_key": "unnamedsubcircuit917_connectivity_net1"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "source_board",
|
|
103
|
+
"source_board_id": "source_board_0",
|
|
104
|
+
"source_group_id": "source_group_0"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"type": "source_trace",
|
|
108
|
+
"source_trace_id": "source_trace_0",
|
|
109
|
+
"connected_source_port_ids": ["source_port_1"],
|
|
110
|
+
"connected_source_net_ids": ["source_net_0"],
|
|
111
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
112
|
+
"display_name": ".R1 > .pin2 to net.GND",
|
|
113
|
+
"subcircuit_connectivity_map_key": "unnamedsubcircuit917_connectivity_net0"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"type": "source_trace",
|
|
117
|
+
"source_trace_id": "source_trace_1",
|
|
118
|
+
"connected_source_port_ids": ["source_port_0"],
|
|
119
|
+
"connected_source_net_ids": ["source_net_1"],
|
|
120
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
121
|
+
"display_name": ".R1 > .pin1 to net.VCC",
|
|
122
|
+
"subcircuit_connectivity_map_key": "unnamedsubcircuit917_connectivity_net1"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"type": "source_trace",
|
|
126
|
+
"source_trace_id": "source_trace_2",
|
|
127
|
+
"connected_source_port_ids": ["source_port_2"],
|
|
128
|
+
"connected_source_net_ids": ["source_net_1"],
|
|
129
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
130
|
+
"max_length": null,
|
|
131
|
+
"display_name": ".C1 > .pin1 to net.VCC",
|
|
132
|
+
"subcircuit_connectivity_map_key": "unnamedsubcircuit917_connectivity_net1"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"type": "source_pin_missing_trace_warning",
|
|
136
|
+
"source_pin_missing_trace_warning_id": "source_pin_missing_trace_warning_0",
|
|
137
|
+
"message": "Port pin2 on C1 is missing a trace",
|
|
138
|
+
"source_component_id": "source_component_1",
|
|
139
|
+
"source_port_id": "source_port_3",
|
|
140
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
141
|
+
"warning_type": "source_pin_missing_trace_warning"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"type": "schematic_component",
|
|
145
|
+
"schematic_component_id": "schematic_component_0",
|
|
146
|
+
"center": {
|
|
147
|
+
"x": 0,
|
|
148
|
+
"y": 0
|
|
149
|
+
},
|
|
150
|
+
"size": {
|
|
151
|
+
"width": 1.1,
|
|
152
|
+
"height": 0.388910699999999
|
|
153
|
+
},
|
|
154
|
+
"source_component_id": "source_component_0",
|
|
155
|
+
"is_box_with_pins": true,
|
|
156
|
+
"symbol_name": "boxresistor_right",
|
|
157
|
+
"symbol_display_value": "1kΩ",
|
|
158
|
+
"schematic_group_id": "schematic_group_0"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"type": "schematic_component",
|
|
162
|
+
"schematic_component_id": "schematic_component_1",
|
|
163
|
+
"center": {
|
|
164
|
+
"x": 0,
|
|
165
|
+
"y": -1.8144553499999994
|
|
166
|
+
},
|
|
167
|
+
"size": {
|
|
168
|
+
"width": 1.1,
|
|
169
|
+
"height": 0.84
|
|
170
|
+
},
|
|
171
|
+
"source_component_id": "source_component_1",
|
|
172
|
+
"is_box_with_pins": true,
|
|
173
|
+
"symbol_name": "capacitor_right",
|
|
174
|
+
"symbol_display_value": "1000pF",
|
|
175
|
+
"schematic_group_id": "schematic_group_0"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"type": "schematic_group",
|
|
179
|
+
"schematic_group_id": "schematic_group_0",
|
|
180
|
+
"is_subcircuit": true,
|
|
181
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
182
|
+
"name": "unnamed_board1",
|
|
183
|
+
"center": {
|
|
184
|
+
"x": 0,
|
|
185
|
+
"y": 0
|
|
186
|
+
},
|
|
187
|
+
"width": 0,
|
|
188
|
+
"height": 0,
|
|
189
|
+
"schematic_component_ids": [],
|
|
190
|
+
"source_group_id": "source_group_0"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"type": "schematic_port",
|
|
194
|
+
"schematic_port_id": "schematic_port_0",
|
|
195
|
+
"schematic_component_id": "schematic_component_0",
|
|
196
|
+
"center": {
|
|
197
|
+
"x": -0.55,
|
|
198
|
+
"y": 0
|
|
199
|
+
},
|
|
200
|
+
"source_port_id": "source_port_0",
|
|
201
|
+
"facing_direction": "left",
|
|
202
|
+
"distance_from_component_edge": 0.4,
|
|
203
|
+
"pin_number": 1,
|
|
204
|
+
"display_pin_label": "anode",
|
|
205
|
+
"is_connected": true
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"type": "schematic_port",
|
|
209
|
+
"schematic_port_id": "schematic_port_1",
|
|
210
|
+
"schematic_component_id": "schematic_component_0",
|
|
211
|
+
"center": {
|
|
212
|
+
"x": 0.55,
|
|
213
|
+
"y": 0
|
|
214
|
+
},
|
|
215
|
+
"source_port_id": "source_port_1",
|
|
216
|
+
"facing_direction": "right",
|
|
217
|
+
"distance_from_component_edge": 0.4,
|
|
218
|
+
"pin_number": 2,
|
|
219
|
+
"display_pin_label": "cathode",
|
|
220
|
+
"is_connected": false
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"type": "schematic_port",
|
|
224
|
+
"schematic_port_id": "schematic_port_2",
|
|
225
|
+
"schematic_component_id": "schematic_component_1",
|
|
226
|
+
"center": {
|
|
227
|
+
"x": -0.55,
|
|
228
|
+
"y": -1.8144553499999994
|
|
229
|
+
},
|
|
230
|
+
"source_port_id": "source_port_2",
|
|
231
|
+
"facing_direction": "left",
|
|
232
|
+
"distance_from_component_edge": 0.4,
|
|
233
|
+
"pin_number": 1,
|
|
234
|
+
"display_pin_label": "pos",
|
|
235
|
+
"is_connected": true
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"type": "schematic_port",
|
|
239
|
+
"schematic_port_id": "schematic_port_3",
|
|
240
|
+
"schematic_component_id": "schematic_component_1",
|
|
241
|
+
"center": {
|
|
242
|
+
"x": 0.55,
|
|
243
|
+
"y": -1.8144553499999994
|
|
244
|
+
},
|
|
245
|
+
"source_port_id": "source_port_3",
|
|
246
|
+
"facing_direction": "right",
|
|
247
|
+
"distance_from_component_edge": 0.4,
|
|
248
|
+
"pin_number": 2,
|
|
249
|
+
"display_pin_label": "neg",
|
|
250
|
+
"is_connected": false
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"type": "schematic_trace",
|
|
254
|
+
"schematic_trace_id": "schematic_trace_0",
|
|
255
|
+
"source_trace_id": "solver_R1.1-C1.1",
|
|
256
|
+
"edges": [
|
|
257
|
+
{
|
|
258
|
+
"from": {
|
|
259
|
+
"x": -0.55,
|
|
260
|
+
"y": 0
|
|
261
|
+
},
|
|
262
|
+
"to": {
|
|
263
|
+
"x": -0.75,
|
|
264
|
+
"y": 0
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"from": {
|
|
269
|
+
"x": -0.75,
|
|
270
|
+
"y": 0
|
|
271
|
+
},
|
|
272
|
+
"to": {
|
|
273
|
+
"x": -0.75,
|
|
274
|
+
"y": -1.8144553499999994
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"from": {
|
|
279
|
+
"x": -0.75,
|
|
280
|
+
"y": -1.8144553499999994
|
|
281
|
+
},
|
|
282
|
+
"to": {
|
|
283
|
+
"x": -0.55,
|
|
284
|
+
"y": -1.8144553499999994
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
],
|
|
288
|
+
"junctions": [],
|
|
289
|
+
"subcircuit_connectivity_map_key": "unnamedsubcircuit917_connectivity_net1"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"type": "schematic_net_label",
|
|
293
|
+
"schematic_net_label_id": "schematic_net_label_0",
|
|
294
|
+
"text": "VCC",
|
|
295
|
+
"anchor_position": {
|
|
296
|
+
"x": -0.75,
|
|
297
|
+
"y": 0
|
|
298
|
+
},
|
|
299
|
+
"center": {
|
|
300
|
+
"x": -0.75,
|
|
301
|
+
"y": 0.09
|
|
302
|
+
},
|
|
303
|
+
"anchor_side": "bottom",
|
|
304
|
+
"source_net_id": "source_net_1",
|
|
305
|
+
"symbol_name": "rail_up"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"type": "schematic_net_label",
|
|
309
|
+
"schematic_net_label_id": "schematic_net_label_1",
|
|
310
|
+
"text": "GND",
|
|
311
|
+
"anchor_position": {
|
|
312
|
+
"x": 0.55,
|
|
313
|
+
"y": 0
|
|
314
|
+
},
|
|
315
|
+
"center": {
|
|
316
|
+
"x": 0.7000000000000001,
|
|
317
|
+
"y": 0
|
|
318
|
+
},
|
|
319
|
+
"anchor_side": "left",
|
|
320
|
+
"source_net_id": "source_net_0"
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"type": "pcb_component",
|
|
324
|
+
"pcb_component_id": "pcb_component_0",
|
|
325
|
+
"center": {
|
|
326
|
+
"x": 0,
|
|
327
|
+
"y": 0
|
|
328
|
+
},
|
|
329
|
+
"width": 1.56,
|
|
330
|
+
"height": 0.64,
|
|
331
|
+
"layer": "top",
|
|
332
|
+
"rotation": 0,
|
|
333
|
+
"source_component_id": "source_component_0",
|
|
334
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
335
|
+
"do_not_place": false,
|
|
336
|
+
"obstructs_within_bounds": true
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"type": "pcb_component",
|
|
340
|
+
"pcb_component_id": "pcb_component_1",
|
|
341
|
+
"center": {
|
|
342
|
+
"x": -2.5600000000000005,
|
|
343
|
+
"y": 0
|
|
344
|
+
},
|
|
345
|
+
"width": 1.56,
|
|
346
|
+
"height": 0.64,
|
|
347
|
+
"layer": "bottom",
|
|
348
|
+
"rotation": 0,
|
|
349
|
+
"source_component_id": "source_component_1",
|
|
350
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
351
|
+
"do_not_place": false,
|
|
352
|
+
"obstructs_within_bounds": true
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"type": "pcb_board",
|
|
356
|
+
"pcb_board_id": "pcb_board_0",
|
|
357
|
+
"center": {
|
|
358
|
+
"x": 0,
|
|
359
|
+
"y": 0
|
|
360
|
+
},
|
|
361
|
+
"thickness": 1.4,
|
|
362
|
+
"num_layers": 2,
|
|
363
|
+
"width": 10,
|
|
364
|
+
"height": 10,
|
|
365
|
+
"material": "fr4"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"type": "pcb_smtpad",
|
|
369
|
+
"pcb_smtpad_id": "pcb_smtpad_0",
|
|
370
|
+
"pcb_component_id": "pcb_component_0",
|
|
371
|
+
"pcb_port_id": "pcb_port_0",
|
|
372
|
+
"layer": "top",
|
|
373
|
+
"shape": "rect",
|
|
374
|
+
"width": 0.54,
|
|
375
|
+
"height": 0.64,
|
|
376
|
+
"port_hints": ["1", "left"],
|
|
377
|
+
"is_covered_with_solder_mask": false,
|
|
378
|
+
"x": -0.51,
|
|
379
|
+
"y": 0,
|
|
380
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"type": "pcb_solder_paste",
|
|
384
|
+
"pcb_solder_paste_id": "pcb_solder_paste_0",
|
|
385
|
+
"layer": "top",
|
|
386
|
+
"shape": "rect",
|
|
387
|
+
"width": 0.378,
|
|
388
|
+
"height": 0.44799999999999995,
|
|
389
|
+
"x": -0.51,
|
|
390
|
+
"y": 0,
|
|
391
|
+
"pcb_component_id": "pcb_component_0",
|
|
392
|
+
"pcb_smtpad_id": "pcb_smtpad_0",
|
|
393
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"type": "pcb_smtpad",
|
|
397
|
+
"pcb_smtpad_id": "pcb_smtpad_1",
|
|
398
|
+
"pcb_component_id": "pcb_component_0",
|
|
399
|
+
"pcb_port_id": "pcb_port_1",
|
|
400
|
+
"layer": "top",
|
|
401
|
+
"shape": "rect",
|
|
402
|
+
"width": 0.54,
|
|
403
|
+
"height": 0.64,
|
|
404
|
+
"port_hints": ["2", "right"],
|
|
405
|
+
"is_covered_with_solder_mask": false,
|
|
406
|
+
"x": 0.51,
|
|
407
|
+
"y": 0,
|
|
408
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"type": "pcb_solder_paste",
|
|
412
|
+
"pcb_solder_paste_id": "pcb_solder_paste_1",
|
|
413
|
+
"layer": "top",
|
|
414
|
+
"shape": "rect",
|
|
415
|
+
"width": 0.378,
|
|
416
|
+
"height": 0.44799999999999995,
|
|
417
|
+
"x": 0.51,
|
|
418
|
+
"y": 0,
|
|
419
|
+
"pcb_component_id": "pcb_component_0",
|
|
420
|
+
"pcb_smtpad_id": "pcb_smtpad_1",
|
|
421
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
"type": "pcb_silkscreen_path",
|
|
425
|
+
"pcb_silkscreen_path_id": "pcb_silkscreen_path_0",
|
|
426
|
+
"pcb_component_id": "pcb_component_0",
|
|
427
|
+
"layer": "top",
|
|
428
|
+
"route": [
|
|
429
|
+
{
|
|
430
|
+
"x": 0.51,
|
|
431
|
+
"y": 0.72
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"x": -0.98,
|
|
435
|
+
"y": 0.72
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"x": -0.98,
|
|
439
|
+
"y": -0.72
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
"x": 0.51,
|
|
443
|
+
"y": -0.72
|
|
444
|
+
}
|
|
445
|
+
],
|
|
446
|
+
"stroke_width": 0.1,
|
|
447
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
"type": "pcb_silkscreen_text",
|
|
451
|
+
"pcb_silkscreen_text_id": "pcb_silkscreen_text_0",
|
|
452
|
+
"anchor_alignment": "center",
|
|
453
|
+
"anchor_position": {
|
|
454
|
+
"x": 0,
|
|
455
|
+
"y": 1.22
|
|
456
|
+
},
|
|
457
|
+
"font": "tscircuit2024",
|
|
458
|
+
"font_size": 0.4,
|
|
459
|
+
"layer": "top",
|
|
460
|
+
"text": "R1",
|
|
461
|
+
"ccw_rotation": 0,
|
|
462
|
+
"pcb_component_id": "pcb_component_0",
|
|
463
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
"type": "pcb_smtpad",
|
|
467
|
+
"pcb_smtpad_id": "pcb_smtpad_2",
|
|
468
|
+
"pcb_component_id": "pcb_component_1",
|
|
469
|
+
"pcb_port_id": "pcb_port_2",
|
|
470
|
+
"layer": "bottom",
|
|
471
|
+
"shape": "rect",
|
|
472
|
+
"width": 0.54,
|
|
473
|
+
"height": 0.64,
|
|
474
|
+
"port_hints": ["1", "left"],
|
|
475
|
+
"is_covered_with_solder_mask": false,
|
|
476
|
+
"x": -2.0500000000000007,
|
|
477
|
+
"y": 0,
|
|
478
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
"type": "pcb_solder_paste",
|
|
482
|
+
"pcb_solder_paste_id": "pcb_solder_paste_2",
|
|
483
|
+
"layer": "bottom",
|
|
484
|
+
"shape": "rect",
|
|
485
|
+
"width": 0.378,
|
|
486
|
+
"height": 0.44799999999999995,
|
|
487
|
+
"x": 0.51,
|
|
488
|
+
"y": 0,
|
|
489
|
+
"pcb_component_id": "pcb_component_1",
|
|
490
|
+
"pcb_smtpad_id": "pcb_smtpad_2",
|
|
491
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"type": "pcb_smtpad",
|
|
495
|
+
"pcb_smtpad_id": "pcb_smtpad_3",
|
|
496
|
+
"pcb_component_id": "pcb_component_1",
|
|
497
|
+
"pcb_port_id": "pcb_port_3",
|
|
498
|
+
"layer": "bottom",
|
|
499
|
+
"shape": "rect",
|
|
500
|
+
"width": 0.54,
|
|
501
|
+
"height": 0.64,
|
|
502
|
+
"port_hints": ["2", "right"],
|
|
503
|
+
"is_covered_with_solder_mask": false,
|
|
504
|
+
"x": -3.0700000000000003,
|
|
505
|
+
"y": 0,
|
|
506
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"type": "pcb_solder_paste",
|
|
510
|
+
"pcb_solder_paste_id": "pcb_solder_paste_3",
|
|
511
|
+
"layer": "bottom",
|
|
512
|
+
"shape": "rect",
|
|
513
|
+
"width": 0.378,
|
|
514
|
+
"height": 0.44799999999999995,
|
|
515
|
+
"x": -0.51,
|
|
516
|
+
"y": 0,
|
|
517
|
+
"pcb_component_id": "pcb_component_1",
|
|
518
|
+
"pcb_smtpad_id": "pcb_smtpad_3",
|
|
519
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
"type": "pcb_silkscreen_path",
|
|
523
|
+
"pcb_silkscreen_path_id": "pcb_silkscreen_path_1",
|
|
524
|
+
"pcb_component_id": "pcb_component_1",
|
|
525
|
+
"layer": "bottom",
|
|
526
|
+
"route": [
|
|
527
|
+
{
|
|
528
|
+
"x": -3.0700000000000003,
|
|
529
|
+
"y": 0.72
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
"x": -1.5800000000000005,
|
|
533
|
+
"y": 0.72
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
"x": -1.5800000000000005,
|
|
537
|
+
"y": -0.72
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
"x": -3.0700000000000003,
|
|
541
|
+
"y": -0.72
|
|
542
|
+
}
|
|
543
|
+
],
|
|
544
|
+
"stroke_width": 0.1,
|
|
545
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"type": "pcb_silkscreen_text",
|
|
549
|
+
"pcb_silkscreen_text_id": "pcb_silkscreen_text_1",
|
|
550
|
+
"anchor_alignment": "center",
|
|
551
|
+
"anchor_position": {
|
|
552
|
+
"x": -2.5600000000000005,
|
|
553
|
+
"y": 1.22
|
|
554
|
+
},
|
|
555
|
+
"font": "tscircuit2024",
|
|
556
|
+
"font_size": 0.4,
|
|
557
|
+
"layer": "bottom",
|
|
558
|
+
"text": "C1",
|
|
559
|
+
"ccw_rotation": 0,
|
|
560
|
+
"pcb_component_id": "pcb_component_1",
|
|
561
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
"type": "pcb_hole",
|
|
565
|
+
"pcb_hole_id": "pcb_hole_0",
|
|
566
|
+
"hole_shape": "circle",
|
|
567
|
+
"hole_diameter": 2,
|
|
568
|
+
"x": 0,
|
|
569
|
+
"y": -3,
|
|
570
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
"type": "pcb_cutout",
|
|
574
|
+
"pcb_cutout_id": "pcb_cutout_0",
|
|
575
|
+
"shape": "rect",
|
|
576
|
+
"center": {
|
|
577
|
+
"x": 3,
|
|
578
|
+
"y": 0
|
|
579
|
+
},
|
|
580
|
+
"width": 2,
|
|
581
|
+
"height": 1,
|
|
582
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
"type": "pcb_cutout",
|
|
586
|
+
"pcb_cutout_id": "pcb_cutout_1",
|
|
587
|
+
"shape": "circle",
|
|
588
|
+
"center": {
|
|
589
|
+
"x": 3,
|
|
590
|
+
"y": 3
|
|
591
|
+
},
|
|
592
|
+
"radius": 1,
|
|
593
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
"type": "pcb_cutout",
|
|
597
|
+
"pcb_cutout_id": "pcb_cutout_2",
|
|
598
|
+
"shape": "polygon",
|
|
599
|
+
"points": [
|
|
600
|
+
{
|
|
601
|
+
"x": 3,
|
|
602
|
+
"y": -2
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
"x": 3,
|
|
606
|
+
"y": -2
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"x": 4,
|
|
610
|
+
"y": -3
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
"x": 2,
|
|
614
|
+
"y": -3
|
|
615
|
+
}
|
|
616
|
+
],
|
|
617
|
+
"subcircuit_id": "subcircuit_source_group_0"
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
"type": "pcb_port",
|
|
621
|
+
"pcb_port_id": "pcb_port_0",
|
|
622
|
+
"pcb_component_id": "pcb_component_0",
|
|
623
|
+
"layers": ["top"],
|
|
624
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
625
|
+
"x": -0.51,
|
|
626
|
+
"y": 0,
|
|
627
|
+
"source_port_id": "source_port_0"
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
"type": "pcb_port",
|
|
631
|
+
"pcb_port_id": "pcb_port_1",
|
|
632
|
+
"pcb_component_id": "pcb_component_0",
|
|
633
|
+
"layers": ["top"],
|
|
634
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
635
|
+
"x": 0.51,
|
|
636
|
+
"y": 0,
|
|
637
|
+
"source_port_id": "source_port_1"
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
"type": "pcb_port",
|
|
641
|
+
"pcb_port_id": "pcb_port_2",
|
|
642
|
+
"pcb_component_id": "pcb_component_1",
|
|
643
|
+
"layers": ["bottom"],
|
|
644
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
645
|
+
"x": -2.0500000000000007,
|
|
646
|
+
"y": 0,
|
|
647
|
+
"source_port_id": "source_port_2"
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
"type": "pcb_port",
|
|
651
|
+
"pcb_port_id": "pcb_port_3",
|
|
652
|
+
"pcb_component_id": "pcb_component_1",
|
|
653
|
+
"layers": ["bottom"],
|
|
654
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
655
|
+
"x": -3.0700000000000003,
|
|
656
|
+
"y": 0,
|
|
657
|
+
"source_port_id": "source_port_3"
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
"type": "cad_component",
|
|
661
|
+
"cad_component_id": "cad_component_0",
|
|
662
|
+
"position": {
|
|
663
|
+
"x": 0,
|
|
664
|
+
"y": 0,
|
|
665
|
+
"z": 0.7
|
|
666
|
+
},
|
|
667
|
+
"rotation": {
|
|
668
|
+
"x": 0,
|
|
669
|
+
"y": 0,
|
|
670
|
+
"z": 0
|
|
671
|
+
},
|
|
672
|
+
"pcb_component_id": "pcb_component_0",
|
|
673
|
+
"source_component_id": "source_component_0",
|
|
674
|
+
"footprinter_string": "0402"
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
"type": "cad_component",
|
|
678
|
+
"cad_component_id": "cad_component_1",
|
|
679
|
+
"position": {
|
|
680
|
+
"x": -2.5600000000000005,
|
|
681
|
+
"y": 0,
|
|
682
|
+
"z": -0.7
|
|
683
|
+
},
|
|
684
|
+
"rotation": {
|
|
685
|
+
"x": 0,
|
|
686
|
+
"y": 180,
|
|
687
|
+
"z": 0
|
|
688
|
+
},
|
|
689
|
+
"pcb_component_id": "pcb_component_1",
|
|
690
|
+
"source_component_id": "source_component_1",
|
|
691
|
+
"footprinter_string": "0402"
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
"type": "pcb_trace",
|
|
695
|
+
"pcb_trace_id": "source_net_1_0",
|
|
696
|
+
"connection_name": "source_net_1",
|
|
697
|
+
"route": [
|
|
698
|
+
{
|
|
699
|
+
"route_type": "wire",
|
|
700
|
+
"x": -2.0500000000000007,
|
|
701
|
+
"y": 0,
|
|
702
|
+
"width": 0.15,
|
|
703
|
+
"layer": "bottom",
|
|
704
|
+
"start_pcb_port_id": "pcb_port_2"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
"route_type": "wire",
|
|
708
|
+
"x": -2.0500000000000007,
|
|
709
|
+
"y": -1.5790447323308274,
|
|
710
|
+
"width": 0.15,
|
|
711
|
+
"layer": "bottom"
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
"route_type": "wire",
|
|
715
|
+
"x": -1.929170149633294,
|
|
716
|
+
"y": -1.699874582697534,
|
|
717
|
+
"width": 0.15,
|
|
718
|
+
"layer": "bottom"
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
"route_type": "wire",
|
|
722
|
+
"x": -1.875,
|
|
723
|
+
"y": -1.875,
|
|
724
|
+
"width": 0.15,
|
|
725
|
+
"layer": "bottom"
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
"route_type": "via",
|
|
729
|
+
"x": -1.875,
|
|
730
|
+
"y": -1.875,
|
|
731
|
+
"from_layer": "bottom",
|
|
732
|
+
"to_layer": "top"
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
"route_type": "wire",
|
|
736
|
+
"x": -1.875,
|
|
737
|
+
"y": -1.875,
|
|
738
|
+
"width": 0.15,
|
|
739
|
+
"layer": "top"
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
"route_type": "wire",
|
|
743
|
+
"x": -1.875,
|
|
744
|
+
"y": -1.365,
|
|
745
|
+
"width": 0.15,
|
|
746
|
+
"layer": "top"
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
"route_type": "wire",
|
|
750
|
+
"x": -0.51,
|
|
751
|
+
"y": 0,
|
|
752
|
+
"width": 0.15,
|
|
753
|
+
"layer": "top",
|
|
754
|
+
"end_pcb_port_id": "pcb_port_0"
|
|
755
|
+
}
|
|
756
|
+
],
|
|
757
|
+
"subcircuit_id": "subcircuit_source_group_0",
|
|
758
|
+
"source_trace_id": "source_net_1"
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
"type": "pcb_via",
|
|
762
|
+
"pcb_via_id": "pcb_via_0",
|
|
763
|
+
"pcb_trace_id": "source_net_1_0",
|
|
764
|
+
"x": -1.875,
|
|
765
|
+
"y": -1.875,
|
|
766
|
+
"hole_diameter": 0.3,
|
|
767
|
+
"outer_diameter": 0.6,
|
|
768
|
+
"layers": ["bottom", "top"],
|
|
769
|
+
"from_layer": "bottom",
|
|
770
|
+
"to_layer": "top"
|
|
771
|
+
}
|
|
772
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import circuitJson from "./assets/hole-and-cutouts.json"
|
|
3
|
+
import { runSolverAndRenderToSvg } from "./utils/run-solver-and-render-to-svg"
|
|
4
|
+
import type { AnyCircuitElement } from "circuit-json"
|
|
5
|
+
|
|
6
|
+
test("hole and cutouts", async () => {
|
|
7
|
+
const svg = runSolverAndRenderToSvg(circuitJson as AnyCircuitElement[], {
|
|
8
|
+
layer: "top",
|
|
9
|
+
net_name: "GND",
|
|
10
|
+
pad_margin: 0.2,
|
|
11
|
+
trace_margin: 0.1,
|
|
12
|
+
cutout_margin: 0.2,
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
await expect(svg).toMatchSvgSnapshot(import.meta.path, "hole-and-cutouts")
|
|
16
|
+
})
|