circuit-json-to-lbrn 0.0.6 → 0.0.8

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.
Files changed (37) hide show
  1. package/dist/index.js +636 -16
  2. package/lib/ConvertContext.ts +1 -0
  3. package/lib/element-handlers/addPcbBoard/index.ts +50 -0
  4. package/lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts +30 -72
  5. package/lib/element-handlers/addPlatedHole/addCircularHoleWithRectPad.ts +44 -3
  6. package/lib/element-handlers/addPlatedHole/addHoleWithPolygonPad.ts +55 -4
  7. package/lib/element-handlers/addPlatedHole/addOvalPlatedHole.ts +49 -4
  8. package/lib/element-handlers/addPlatedHole/addPillHoleWithRectPad.ts +52 -4
  9. package/lib/element-handlers/addPlatedHole/addPillPlatedHole.ts +52 -0
  10. package/lib/element-handlers/addPlatedHole/addRotatedPillHoleWithRectPad.ts +57 -4
  11. package/lib/element-handlers/addPlatedHole/index.ts +4 -1
  12. package/lib/helpers/circleShape.ts +42 -0
  13. package/lib/helpers/ovalShape.ts +51 -0
  14. package/lib/helpers/pathPointUtils.ts +45 -0
  15. package/lib/helpers/pillShape.ts +99 -0
  16. package/lib/helpers/polygonShape.ts +38 -0
  17. package/lib/helpers/roundedRectShape.ts +121 -0
  18. package/lib/index.ts +17 -3
  19. package/package.json +1 -1
  20. package/tests/examples/__snapshots__/board-outline.snap.svg +8 -0
  21. package/tests/examples/__snapshots__/lga-interconnect.snap.svg +2 -2
  22. package/tests/examples/__snapshots__/single-trace.snap.svg +2 -2
  23. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-circle.snap.svg +8 -0
  24. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-circular-hole-with-rect-pad.snap.svg +8 -0
  25. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-oval.snap.svg +8 -0
  26. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-pill-with-rect-pad.snap.svg +8 -0
  27. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-pill.snap.svg +8 -0
  28. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-polygon.snap.svg +8 -0
  29. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-rotated-pill-with-rect-pad.snap.svg +8 -0
  30. package/tests/examples/addPlatedHole/pcb-plated-hole-circle.test.ts +62 -0
  31. package/tests/examples/addPlatedHole/pcb-plated-hole-circular-hole-with-rect-pad.test.ts +54 -0
  32. package/tests/examples/addPlatedHole/pcb-plated-hole-oval.test.ts +101 -0
  33. package/tests/examples/addPlatedHole/pcb-plated-hole-pill-with-rect-pad.test.ts +54 -0
  34. package/tests/examples/addPlatedHole/pcb-plated-hole-pill.test.ts +101 -0
  35. package/tests/examples/addPlatedHole/pcb-plated-hole-polygon.test.ts +59 -0
  36. package/tests/examples/addPlatedHole/pcb-plated-hole-rotated-pill-with-rect-pad.test.ts +56 -0
  37. package/tests/examples/board-outline.test.ts +102 -0
package/dist/index.js CHANGED
@@ -1,10 +1,576 @@
1
1
  // lib/index.ts
2
- import { LightBurnProject, CutSetting, ShapePath as ShapePath3 } from "lbrnts";
2
+ import { LightBurnProject, CutSetting, ShapePath as ShapePath10 } from "lbrnts";
3
3
  import { cju as cju2 } from "@tscircuit/circuit-json-util";
4
4
 
5
5
  // lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts
6
6
  import { ShapePath } from "lbrnts";
7
7
 
8
+ // lib/helpers/circleShape.ts
9
+ var createCirclePath = (centerX, centerY, radius, segments = 64) => {
10
+ const verts = [];
11
+ const prims = [];
12
+ for (let i = 0; i < segments; i++) {
13
+ const angle = i / segments * Math.PI * 2;
14
+ const x = centerX + radius * Math.cos(angle);
15
+ const y = centerY + radius * Math.sin(angle);
16
+ verts.push({ x, y });
17
+ prims.push({ type: 0 });
18
+ }
19
+ if (verts.length > 0) {
20
+ const firstVert = verts[0];
21
+ if (firstVert) {
22
+ verts.push({ ...firstVert });
23
+ prims.push({ type: 0 });
24
+ }
25
+ }
26
+ return { verts, prims };
27
+ };
28
+
29
+ // lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts
30
+ var addCirclePlatedHole = (platedHole, ctx) => {
31
+ const { project, copperCutSetting, throughBoardCutSetting, origin } = ctx;
32
+ const centerX = platedHole.x + origin.x;
33
+ const centerY = platedHole.y + origin.y;
34
+ if (platedHole.outer_diameter > 0) {
35
+ const outerRadius = platedHole.outer_diameter / 2;
36
+ const outer = createCirclePath(centerX, centerY, outerRadius);
37
+ project.children.push(
38
+ new ShapePath({
39
+ cutIndex: copperCutSetting.index,
40
+ verts: outer.verts,
41
+ prims: outer.prims,
42
+ isClosed: true
43
+ })
44
+ );
45
+ }
46
+ if (platedHole.hole_diameter > 0) {
47
+ const innerRadius = platedHole.hole_diameter / 2;
48
+ const inner = createCirclePath(centerX, centerY, innerRadius);
49
+ project.children.push(
50
+ new ShapePath({
51
+ cutIndex: throughBoardCutSetting.index,
52
+ verts: inner.verts,
53
+ prims: inner.prims,
54
+ isClosed: true
55
+ })
56
+ );
57
+ }
58
+ };
59
+
60
+ // lib/element-handlers/addPlatedHole/addOvalPlatedHole.ts
61
+ import { ShapePath as ShapePath2 } from "lbrnts";
62
+
63
+ // lib/helpers/ovalShape.ts
64
+ var createOvalPath = (centerX, centerY, width, height, rotation = 0, segments = 64) => {
65
+ const verts = [];
66
+ const prims = [];
67
+ const radiusX = width / 2;
68
+ const radiusY = height / 2;
69
+ const cosTheta = Math.cos(rotation);
70
+ const sinTheta = Math.sin(rotation);
71
+ for (let i = 0; i < segments; i++) {
72
+ const angle = i / segments * Math.PI * 2;
73
+ const localX = radiusX * Math.cos(angle);
74
+ const localY = radiusY * Math.sin(angle);
75
+ const rotatedX = centerX + localX * cosTheta - localY * sinTheta;
76
+ const rotatedY = centerY + localX * sinTheta + localY * cosTheta;
77
+ verts.push({ x: rotatedX, y: rotatedY });
78
+ prims.push({ type: 0 });
79
+ }
80
+ if (verts.length > 0) {
81
+ const firstVert = verts[0];
82
+ if (firstVert) {
83
+ verts.push({ ...firstVert });
84
+ prims.push({ type: 0 });
85
+ }
86
+ }
87
+ return { verts, prims };
88
+ };
89
+
90
+ // lib/element-handlers/addPlatedHole/addOvalPlatedHole.ts
91
+ var addOvalPlatedHole = (platedHole, ctx) => {
92
+ const { project, copperCutSetting, throughBoardCutSetting, origin } = ctx;
93
+ if (platedHole.outer_width <= 0 || platedHole.outer_height <= 0) {
94
+ return;
95
+ }
96
+ const centerX = platedHole.x + origin.x;
97
+ const centerY = platedHole.y + origin.y;
98
+ const rotation = (platedHole.ccw_rotation ?? 0) * (Math.PI / 180);
99
+ if (platedHole.outer_width > 0 && platedHole.outer_height > 0) {
100
+ const outer = createOvalPath(
101
+ centerX,
102
+ centerY,
103
+ platedHole.outer_width,
104
+ platedHole.outer_height,
105
+ rotation
106
+ );
107
+ project.children.push(
108
+ new ShapePath2({
109
+ cutIndex: copperCutSetting.index,
110
+ verts: outer.verts,
111
+ prims: outer.prims,
112
+ isClosed: true
113
+ })
114
+ );
115
+ }
116
+ if (platedHole.hole_width > 0 && platedHole.hole_height > 0) {
117
+ const inner = createOvalPath(
118
+ centerX,
119
+ centerY,
120
+ platedHole.hole_width,
121
+ platedHole.hole_height,
122
+ rotation
123
+ );
124
+ project.children.push(
125
+ new ShapePath2({
126
+ cutIndex: throughBoardCutSetting.index,
127
+ verts: inner.verts,
128
+ prims: inner.prims,
129
+ isClosed: true
130
+ })
131
+ );
132
+ }
133
+ };
134
+
135
+ // lib/element-handlers/addPlatedHole/addCircularHoleWithRectPad.ts
136
+ import { ShapePath as ShapePath3 } from "lbrnts";
137
+
138
+ // lib/helpers/roundedRectShape.ts
139
+ var createRoundedRectPath = (centerX, centerY, width, height, borderRadius = 0, segments = 4, rotation = 0) => {
140
+ const verts = [];
141
+ const prims = [];
142
+ const halfWidth = width / 2;
143
+ const halfHeight = height / 2;
144
+ const rotatePoint = (x, y) => {
145
+ const cos = Math.cos(rotation);
146
+ const sin = Math.sin(rotation);
147
+ return {
148
+ x: x * cos - y * sin,
149
+ y: x * sin + y * cos
150
+ };
151
+ };
152
+ const addPoint = (x, y) => {
153
+ const rotated = rotation ? rotatePoint(x, y) : { x, y };
154
+ verts.push({ x: centerX + rotated.x, y: centerY + rotated.y });
155
+ prims.push({ type: 0 });
156
+ };
157
+ addPoint(-halfWidth + borderRadius, -halfHeight);
158
+ addPoint(halfWidth - borderRadius, -halfHeight);
159
+ if (borderRadius > 0) {
160
+ for (let i = 0; i <= segments; i++) {
161
+ const angle = Math.PI * 1.5 + i * Math.PI * 0.5 / segments;
162
+ addPoint(
163
+ halfWidth - borderRadius + Math.cos(angle) * borderRadius,
164
+ -halfHeight + borderRadius + Math.sin(angle) * borderRadius
165
+ );
166
+ }
167
+ } else {
168
+ addPoint(halfWidth, -halfHeight);
169
+ }
170
+ addPoint(halfWidth, -halfHeight + borderRadius);
171
+ addPoint(halfWidth, halfHeight - borderRadius);
172
+ if (borderRadius > 0) {
173
+ for (let i = 0; i <= segments; i++) {
174
+ const angle = i * Math.PI * 0.5 / segments;
175
+ addPoint(
176
+ halfWidth - borderRadius + Math.cos(angle) * borderRadius,
177
+ halfHeight - borderRadius + Math.sin(angle) * borderRadius
178
+ );
179
+ }
180
+ } else {
181
+ addPoint(halfWidth, halfHeight);
182
+ }
183
+ addPoint(halfWidth - borderRadius, halfHeight);
184
+ addPoint(-halfWidth + borderRadius, halfHeight);
185
+ if (borderRadius > 0) {
186
+ for (let i = 0; i <= segments; i++) {
187
+ const angle = Math.PI * 0.5 + i * Math.PI * 0.5 / segments;
188
+ addPoint(
189
+ -halfWidth + borderRadius + Math.cos(angle) * borderRadius,
190
+ halfHeight - borderRadius + Math.sin(angle) * borderRadius
191
+ );
192
+ }
193
+ } else {
194
+ addPoint(-halfWidth, halfHeight);
195
+ }
196
+ addPoint(-halfWidth, halfHeight - borderRadius);
197
+ addPoint(-halfWidth, -halfHeight + borderRadius);
198
+ if (borderRadius > 0) {
199
+ for (let i = 0; i <= segments; i++) {
200
+ const angle = Math.PI + i * Math.PI * 0.5 / segments;
201
+ addPoint(
202
+ -halfWidth + borderRadius + Math.cos(angle) * borderRadius,
203
+ -halfHeight + borderRadius + Math.sin(angle) * borderRadius
204
+ );
205
+ }
206
+ } else {
207
+ addPoint(-halfWidth, -halfHeight);
208
+ }
209
+ if (verts.length > 0) {
210
+ const firstVert = verts[0];
211
+ if (firstVert) {
212
+ verts.push({ ...firstVert });
213
+ prims.push({ type: 0 });
214
+ }
215
+ }
216
+ return { verts, prims };
217
+ };
218
+
219
+ // lib/element-handlers/addPlatedHole/addCircularHoleWithRectPad.ts
220
+ var addCircularHoleWithRectPad = (platedHole, ctx) => {
221
+ const { project, copperCutSetting, throughBoardCutSetting, origin } = ctx;
222
+ const centerX = platedHole.x + origin.x;
223
+ const centerY = platedHole.y + origin.y;
224
+ const holeRadius = platedHole.hole_diameter / 2;
225
+ const padWidth = platedHole.rect_pad_width;
226
+ const padHeight = platedHole.rect_pad_height;
227
+ const borderRadius = platedHole.rect_border_radius ?? 0;
228
+ const padPath = createRoundedRectPath(
229
+ centerX,
230
+ centerY,
231
+ padWidth,
232
+ padHeight,
233
+ borderRadius
234
+ );
235
+ project.children.push(
236
+ new ShapePath3({
237
+ cutIndex: copperCutSetting.index,
238
+ verts: padPath.verts,
239
+ prims: padPath.prims,
240
+ isClosed: true
241
+ })
242
+ );
243
+ if (holeRadius > 0) {
244
+ const holeCenterX = centerX + platedHole.hole_offset_x;
245
+ const holeCenterY = centerY + platedHole.hole_offset_y;
246
+ const holePath = createCirclePath(holeCenterX, holeCenterY, holeRadius, 32);
247
+ project.children.push(
248
+ new ShapePath3({
249
+ cutIndex: throughBoardCutSetting.index,
250
+ verts: holePath.verts,
251
+ prims: holePath.prims,
252
+ isClosed: true
253
+ })
254
+ );
255
+ }
256
+ };
257
+
258
+ // lib/element-handlers/addPlatedHole/addPillHoleWithRectPad.ts
259
+ import { ShapePath as ShapePath4 } from "lbrnts";
260
+
261
+ // lib/helpers/pathPointUtils.ts
262
+ var createPointAdder = (verts, prims, options = {}) => {
263
+ const { rotation = 0, rotationCenter, translation } = options;
264
+ const cos = Math.cos(rotation);
265
+ const sin = Math.sin(rotation);
266
+ const effectiveCenter = rotationCenter ?? translation ?? { x: 0, y: 0 };
267
+ return (x, y) => {
268
+ let px = x;
269
+ let py = y;
270
+ if (rotation) {
271
+ const cx = effectiveCenter.x;
272
+ const cy = effectiveCenter.y;
273
+ const dx = px - cx;
274
+ const dy = py - cy;
275
+ px = cx + dx * cos - dy * sin;
276
+ py = cy + dx * sin + dy * cos;
277
+ }
278
+ const tx = translation?.x ?? 0;
279
+ const ty = translation?.y ?? 0;
280
+ verts.push({ x: px + tx, y: py + ty });
281
+ prims.push({ type: 0 });
282
+ };
283
+ };
284
+
285
+ // lib/helpers/pillShape.ts
286
+ var createPillPath = (centerX, centerY, width, height, rotation = 0, segments = 32) => {
287
+ const verts = [];
288
+ const prims = [];
289
+ const halfWidth = width / 2;
290
+ const halfHeight = height / 2;
291
+ const radius = Math.min(halfWidth, halfHeight);
292
+ const isVertical = height > width;
293
+ const addPoint = createPointAdder(verts, prims, {
294
+ rotation,
295
+ rotationCenter: { x: centerX, y: centerY }
296
+ });
297
+ if (isVertical) {
298
+ const capOffset = halfHeight - radius;
299
+ for (let i = 0; i <= segments; i++) {
300
+ const angle = Math.PI + i / segments * Math.PI;
301
+ const x = centerX + radius * Math.cos(angle);
302
+ const y = centerY - capOffset + radius * Math.sin(angle);
303
+ addPoint(x, y);
304
+ }
305
+ addPoint(centerX + radius, centerY + capOffset);
306
+ for (let i = 0; i <= segments; i++) {
307
+ const angle = i / segments * Math.PI;
308
+ const x = centerX + radius * Math.cos(angle);
309
+ const y = centerY + capOffset + radius * Math.sin(angle);
310
+ addPoint(x, y);
311
+ }
312
+ addPoint(centerX - radius, centerY - capOffset);
313
+ } else {
314
+ const capOffset = halfWidth - radius;
315
+ for (let i = 0; i <= segments; i++) {
316
+ const angle = -Math.PI / 2 + i / segments * Math.PI;
317
+ const x = centerX + capOffset + radius * Math.cos(angle);
318
+ const y = centerY + radius * Math.sin(angle);
319
+ addPoint(x, y);
320
+ }
321
+ addPoint(centerX - capOffset, centerY + radius);
322
+ for (let i = 0; i <= segments; i++) {
323
+ const angle = Math.PI / 2 + i / segments * Math.PI;
324
+ const x = centerX - capOffset + radius * Math.cos(angle);
325
+ const y = centerY + radius * Math.sin(angle);
326
+ addPoint(x, y);
327
+ }
328
+ addPoint(centerX + capOffset, centerY - radius);
329
+ }
330
+ if (verts.length > 0) {
331
+ const firstVert = verts[0];
332
+ if (firstVert) {
333
+ verts.push({ ...firstVert });
334
+ prims.push({ type: 0 });
335
+ }
336
+ }
337
+ return { verts, prims };
338
+ };
339
+
340
+ // lib/element-handlers/addPlatedHole/addPillHoleWithRectPad.ts
341
+ var addPillHoleWithRectPad = (platedHole, ctx) => {
342
+ const { project, copperCutSetting, throughBoardCutSetting, origin } = ctx;
343
+ const centerX = platedHole.x + origin.x;
344
+ const centerY = platedHole.y + origin.y;
345
+ const padWidth = platedHole.rect_pad_width;
346
+ const padHeight = platedHole.rect_pad_height;
347
+ const borderRadius = platedHole.rect_border_radius ?? 0;
348
+ if (padWidth > 0 && padHeight > 0) {
349
+ const padPath = createRoundedRectPath(
350
+ centerX,
351
+ centerY,
352
+ padWidth,
353
+ padHeight,
354
+ borderRadius
355
+ );
356
+ project.children.push(
357
+ new ShapePath4({
358
+ cutIndex: copperCutSetting.index,
359
+ verts: padPath.verts,
360
+ prims: padPath.prims,
361
+ isClosed: true
362
+ })
363
+ );
364
+ }
365
+ const holeWidth = platedHole.hole_width;
366
+ const holeHeight = platedHole.hole_height;
367
+ if (holeWidth > 0 && holeHeight > 0) {
368
+ const holeCenterX = centerX + platedHole.hole_offset_x;
369
+ const holeCenterY = centerY + platedHole.hole_offset_y;
370
+ const holePath = createPillPath(
371
+ holeCenterX,
372
+ holeCenterY,
373
+ holeWidth,
374
+ holeHeight
375
+ );
376
+ project.children.push(
377
+ new ShapePath4({
378
+ cutIndex: throughBoardCutSetting.index,
379
+ verts: holePath.verts,
380
+ prims: holePath.prims,
381
+ isClosed: true
382
+ })
383
+ );
384
+ }
385
+ };
386
+
387
+ // lib/element-handlers/addPlatedHole/addRotatedPillHoleWithRectPad.ts
388
+ import { ShapePath as ShapePath5 } from "lbrnts";
389
+ var addRotatedPillHoleWithRectPad = (platedHole, ctx) => {
390
+ const { project, copperCutSetting, throughBoardCutSetting, origin } = ctx;
391
+ const centerX = platedHole.x + origin.x;
392
+ const centerY = platedHole.y + origin.y;
393
+ const padWidth = platedHole.rect_pad_width;
394
+ const padHeight = platedHole.rect_pad_height;
395
+ const borderRadius = platedHole.rect_border_radius ?? 0;
396
+ const padRotation = (platedHole.rect_ccw_rotation ?? 0) * (Math.PI / 180);
397
+ if (padWidth > 0 && padHeight > 0) {
398
+ const padPath = createRoundedRectPath(
399
+ centerX,
400
+ centerY,
401
+ padWidth,
402
+ padHeight,
403
+ borderRadius,
404
+ 4,
405
+ padRotation
406
+ );
407
+ project.children.push(
408
+ new ShapePath5({
409
+ cutIndex: copperCutSetting.index,
410
+ verts: padPath.verts,
411
+ prims: padPath.prims,
412
+ isClosed: true
413
+ })
414
+ );
415
+ }
416
+ const holeWidth = platedHole.hole_width;
417
+ const holeHeight = platedHole.hole_height;
418
+ const holeRotation = (platedHole.hole_ccw_rotation ?? 0) * (Math.PI / 180);
419
+ if (holeWidth > 0 && holeHeight > 0) {
420
+ const holeCenterX = centerX + platedHole.hole_offset_x;
421
+ const holeCenterY = centerY + platedHole.hole_offset_y;
422
+ const holePath = createPillPath(
423
+ holeCenterX,
424
+ holeCenterY,
425
+ holeWidth,
426
+ holeHeight,
427
+ holeRotation
428
+ );
429
+ project.children.push(
430
+ new ShapePath5({
431
+ cutIndex: throughBoardCutSetting.index,
432
+ verts: holePath.verts,
433
+ prims: holePath.prims,
434
+ isClosed: true
435
+ })
436
+ );
437
+ }
438
+ };
439
+
440
+ // lib/element-handlers/addPlatedHole/addHoleWithPolygonPad.ts
441
+ import { ShapePath as ShapePath6 } from "lbrnts";
442
+
443
+ // lib/helpers/polygonShape.ts
444
+ var createPolygonPathFromOutline = (outline, offsetX, offsetY) => {
445
+ const verts = [];
446
+ for (const point2 of outline) {
447
+ const x = (point2.x ?? 0) + offsetX;
448
+ const y = (point2.y ?? 0) + offsetY;
449
+ verts.push({ x, y });
450
+ }
451
+ if (verts.length === 0) {
452
+ return { verts, prims: [] };
453
+ }
454
+ const first = verts[0];
455
+ verts.push({ x: first.x, y: first.y });
456
+ const prims = new Array(verts.length).fill({ type: 0 });
457
+ return { verts, prims };
458
+ };
459
+
460
+ // lib/element-handlers/addPlatedHole/addHoleWithPolygonPad.ts
461
+ var addHoleWithPolygonPad = (platedHole, ctx) => {
462
+ const { project, copperCutSetting, throughBoardCutSetting, origin } = ctx;
463
+ if (platedHole.pad_outline.length >= 3) {
464
+ const pad = createPolygonPathFromOutline(
465
+ platedHole.pad_outline,
466
+ platedHole.x + origin.x,
467
+ platedHole.y + origin.y
468
+ );
469
+ project.children.push(
470
+ new ShapePath6({
471
+ cutIndex: copperCutSetting.index,
472
+ verts: pad.verts,
473
+ prims: pad.prims,
474
+ isClosed: true
475
+ })
476
+ );
477
+ }
478
+ if (platedHole.hole_shape === "circle" && platedHole.hole_diameter) {
479
+ const centerX = platedHole.x + platedHole.hole_offset_x + origin.x;
480
+ const centerY = platedHole.y + platedHole.hole_offset_y + origin.y;
481
+ const radius = platedHole.hole_diameter / 2;
482
+ const hole = createCirclePath(centerX, centerY, radius, 64);
483
+ project.children.push(
484
+ new ShapePath6({
485
+ cutIndex: throughBoardCutSetting.index,
486
+ verts: hole.verts,
487
+ prims: hole.prims,
488
+ isClosed: true
489
+ })
490
+ );
491
+ }
492
+ if (platedHole.hole_shape === "pill" && platedHole.hole_diameter) {
493
+ const centerX = platedHole.x + platedHole.hole_offset_x + origin.x;
494
+ const centerY = platedHole.y + platedHole.hole_offset_y + origin.y;
495
+ const radius = platedHole.hole_diameter / 2;
496
+ const hole = createCirclePath(centerX, centerY, radius, 64);
497
+ project.children.push(
498
+ new ShapePath6({
499
+ cutIndex: throughBoardCutSetting.index,
500
+ verts: hole.verts,
501
+ prims: hole.prims,
502
+ isClosed: true
503
+ })
504
+ );
505
+ }
506
+ };
507
+
508
+ // lib/element-handlers/addPlatedHole/addPillPlatedHole.ts
509
+ import { ShapePath as ShapePath7 } from "lbrnts";
510
+ var addPcbPlatedHolePill = (platedHole, ctx) => {
511
+ const { project, copperCutSetting, throughBoardCutSetting, origin } = ctx;
512
+ const centerX = platedHole.x + origin.x;
513
+ const centerY = platedHole.y + origin.y;
514
+ const rotation = (platedHole.ccw_rotation || 0) * (Math.PI / 180);
515
+ if (platedHole.outer_width > 0 && platedHole.outer_height > 0) {
516
+ const outer = createPillPath(
517
+ centerX,
518
+ centerY,
519
+ platedHole.outer_width,
520
+ platedHole.outer_height,
521
+ rotation
522
+ );
523
+ project.children.push(
524
+ new ShapePath7({
525
+ cutIndex: copperCutSetting.index,
526
+ verts: outer.verts,
527
+ prims: outer.prims,
528
+ isClosed: true
529
+ })
530
+ );
531
+ }
532
+ if (platedHole.hole_width > 0 && platedHole.hole_height > 0) {
533
+ const inner = createPillPath(
534
+ centerX,
535
+ centerY,
536
+ platedHole.hole_width,
537
+ platedHole.hole_height,
538
+ rotation
539
+ );
540
+ project.children.push(
541
+ new ShapePath7({
542
+ cutIndex: throughBoardCutSetting.index,
543
+ verts: inner.verts,
544
+ prims: inner.prims,
545
+ isClosed: true
546
+ })
547
+ );
548
+ }
549
+ };
550
+
551
+ // lib/element-handlers/addPlatedHole/index.ts
552
+ var addPlatedHole = (platedHole, ctx) => {
553
+ switch (platedHole.shape) {
554
+ case "circle":
555
+ return addCirclePlatedHole(platedHole, ctx);
556
+ case "oval":
557
+ return addOvalPlatedHole(platedHole, ctx);
558
+ case "pill":
559
+ return addPcbPlatedHolePill(platedHole, ctx);
560
+ case "circular_hole_with_rect_pad":
561
+ return addCircularHoleWithRectPad(platedHole, ctx);
562
+ case "pill_hole_with_rect_pad":
563
+ return addPillHoleWithRectPad(platedHole, ctx);
564
+ case "rotated_pill_hole_with_rect_pad":
565
+ return addRotatedPillHoleWithRectPad(platedHole, ctx);
566
+ case "hole_with_polygon_pad":
567
+ return addHoleWithPolygonPad(platedHole, ctx);
568
+ default:
569
+ const _exhaustive = platedHole;
570
+ console.warn(`Unknown plated hole shape: ${platedHole.shape}`);
571
+ }
572
+ };
573
+
8
574
  // lib/element-handlers/addSmtPad/addRectSmtPad.ts
9
575
  import { Box } from "@flatten-js/core";
10
576
  import "lbrnts";
@@ -69,7 +635,7 @@ var addPcbTrace = (trace, ctx) => {
69
635
  return;
70
636
  }
71
637
  const { route } = trace;
72
- const traceWidth = route.find((point) => point.route_type === "wire")?.width ?? 0.15;
638
+ const traceWidth = route.find((point2) => point2.route_type === "wire")?.width ?? 0.15;
73
639
  const polygons = [];
74
640
  for (const routePoint of route) {
75
641
  const circle = new Flatten2.Circle(
@@ -117,9 +683,9 @@ var addPcbTrace = (trace, ctx) => {
117
683
  netGeoms.get(netId)?.push(tracePolygon);
118
684
  };
119
685
 
120
- // lib/index.ts
121
- import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map";
122
- import { Polygon, Box as Box2, BooleanOperations as BooleanOperations2 } from "@flatten-js/core";
686
+ // lib/element-handlers/addPcbBoard/index.ts
687
+ import { Polygon, point } from "@flatten-js/core";
688
+ import { ShapePath as ShapePath9 } from "lbrnts";
123
689
 
124
690
  // lib/polygon-to-shape-path.ts
125
691
  function polygonToShapePathData(polygon) {
@@ -148,6 +714,46 @@ function polygonToShapePathData(polygon) {
148
714
  return { verts, prims };
149
715
  }
150
716
 
717
+ // lib/element-handlers/addPcbBoard/index.ts
718
+ var addPcbBoard = (board, ctx) => {
719
+ const { origin, project, throughBoardCutSetting } = ctx;
720
+ let polygon = null;
721
+ if (board.outline?.length) {
722
+ polygon = new Polygon(
723
+ board.outline.map(
724
+ (outlinePoint) => point(outlinePoint.x + origin.x, outlinePoint.y + origin.y)
725
+ )
726
+ );
727
+ } else if (typeof board.width === "number" && typeof board.height === "number" && board.center) {
728
+ const halfWidth = board.width / 2;
729
+ const halfHeight = board.height / 2;
730
+ const minX = board.center.x - halfWidth + origin.x;
731
+ const minY = board.center.y - halfHeight + origin.y;
732
+ const maxX = board.center.x + halfWidth + origin.x;
733
+ const maxY = board.center.y + halfHeight + origin.y;
734
+ polygon = new Polygon([
735
+ point(minX, minY),
736
+ point(maxX, minY),
737
+ point(maxX, maxY),
738
+ point(minX, maxY)
739
+ ]);
740
+ }
741
+ if (!polygon) return;
742
+ const { verts, prims } = polygonToShapePathData(polygon);
743
+ project.children.push(
744
+ new ShapePath9({
745
+ cutIndex: throughBoardCutSetting.index,
746
+ verts,
747
+ prims,
748
+ isClosed: true
749
+ })
750
+ );
751
+ };
752
+
753
+ // lib/index.ts
754
+ import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map";
755
+ import { Polygon as Polygon2, Box as Box2, BooleanOperations as BooleanOperations2 } from "@flatten-js/core";
756
+
151
757
  // lib/calculateBounds.ts
152
758
  import { cju } from "@tscircuit/circuit-json-util";
153
759
  var calculateCircuitBounds = (circuitJson) => {
@@ -173,14 +779,14 @@ var calculateCircuitBounds = (circuitJson) => {
173
779
  }
174
780
  }
175
781
  for (const trace of db.pcb_trace.list()) {
176
- const isWidthPoint = (point) => "width" in point && typeof point.width === "number";
782
+ const isWidthPoint = (point2) => "width" in point2 && typeof point2.width === "number";
177
783
  const halfWidth = trace.route_thickness_mode === "interpolated" ? 0 : (trace.route.find(isWidthPoint)?.width ?? 0) / 2;
178
- for (const point of trace.route) {
179
- const pointWidth = trace.route_thickness_mode === "interpolated" ? isWidthPoint(point) ? point.width / 2 : 0 : halfWidth;
180
- minX = Math.min(minX, point.x - pointWidth);
181
- minY = Math.min(minY, point.y - pointWidth);
182
- maxX = Math.max(maxX, point.x + pointWidth);
183
- maxY = Math.max(maxY, point.y + pointWidth);
784
+ for (const point2 of trace.route) {
785
+ const pointWidth = trace.route_thickness_mode === "interpolated" ? isWidthPoint(point2) ? point2.width / 2 : 0 : halfWidth;
786
+ minX = Math.min(minX, point2.x - pointWidth);
787
+ minY = Math.min(minY, point2.y - pointWidth);
788
+ maxX = Math.max(maxX, point2.x + pointWidth);
789
+ maxY = Math.max(maxY, point2.y + pointWidth);
184
790
  }
185
791
  }
186
792
  for (const hole of db.pcb_plated_hole.list()) {
@@ -218,6 +824,13 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
218
824
  speed: 100
219
825
  });
220
826
  project.children.push(copperCutSetting);
827
+ const throughBoardCutSetting = new CutSetting({
828
+ index: 1,
829
+ name: "Cut Through Board",
830
+ numPasses: 3,
831
+ speed: 50
832
+ });
833
+ project.children.push(throughBoardCutSetting);
221
834
  const connMap = getFullConnectivityMapFromCircuitJson(circuitJson);
222
835
  let origin = options.origin;
223
836
  if (!origin) {
@@ -228,6 +841,7 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
228
841
  db,
229
842
  project,
230
843
  copperCutSetting,
844
+ throughBoardCutSetting,
231
845
  connMap,
232
846
  netGeoms: /* @__PURE__ */ new Map(),
233
847
  origin
@@ -238,9 +852,15 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
238
852
  for (const smtpad of db.pcb_smtpad.list()) {
239
853
  addSmtPad(smtpad, ctx);
240
854
  }
855
+ for (const platedHole of db.pcb_plated_hole.list()) {
856
+ addPlatedHole(platedHole, ctx);
857
+ }
241
858
  for (const trace of db.pcb_trace.list()) {
242
859
  addPcbTrace(trace, ctx);
243
860
  }
861
+ for (const board of db.pcb_board.list()) {
862
+ addPcbBoard(board, ctx);
863
+ }
244
864
  for (const net of Object.keys(connMap.netMap)) {
245
865
  const netGeoms = ctx.netGeoms.get(net);
246
866
  if (netGeoms.length === 0) {
@@ -248,19 +868,19 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
248
868
  }
249
869
  let union = netGeoms[0];
250
870
  if (union instanceof Box2) {
251
- union = new Polygon(union);
871
+ union = new Polygon2(union);
252
872
  }
253
873
  for (const geom of netGeoms.slice(1)) {
254
- if (geom instanceof Polygon) {
874
+ if (geom instanceof Polygon2) {
255
875
  union = BooleanOperations2.unify(union, geom);
256
876
  } else if (geom instanceof Box2) {
257
- union = BooleanOperations2.unify(union, new Polygon(geom));
877
+ union = BooleanOperations2.unify(union, new Polygon2(geom));
258
878
  }
259
879
  }
260
880
  for (const island of union.splitToIslands()) {
261
881
  const { verts, prims } = polygonToShapePathData(island);
262
882
  project.children.push(
263
- new ShapePath3({
883
+ new ShapePath10({
264
884
  cutIndex: copperCutSetting.index,
265
885
  verts,
266
886
  prims,