@tscircuit/cli 0.1.1908 → 0.1.1909

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/cli/main.js CHANGED
@@ -55439,7 +55439,7 @@ var require_fast_json_stable_stringify = __commonJS((exports2, module2) => {
55439
55439
  };
55440
55440
  });
55441
55441
 
55442
- // node_modules/circuit-json-to-gerber/dist/chunk-46NSLLUV.js
55442
+ // node_modules/circuit-json-to-gerber/dist/chunk-MJSWOMMX.js
55443
55443
  import { z as z4 } from "zod";
55444
55444
  import { z as z23 } from "zod";
55445
55445
  import { z as z32 } from "zod";
@@ -55491,6 +55491,7 @@ import { z as z47 } from "zod";
55491
55491
  import { z as z48 } from "zod";
55492
55492
  import { z as z49 } from "zod";
55493
55493
  import { z as z50 } from "zod";
55494
+ import { strokeWidthRatio } from "@tscircuit/alphabet";
55494
55495
  import {
55495
55496
  applyToPoint as applyToPoint26,
55496
55497
  compose as compose9,
@@ -55499,13 +55500,19 @@ import {
55499
55500
  translate as translate9
55500
55501
  } from "transformation-matrix";
55501
55502
  import { getBoundFromCenteredRect as getBoundFromCenteredRect2 } from "@tscircuit/math-utils";
55502
- import { lineAlphabet as lineAlphabet2 } from "@tscircuit/alphabet";
55503
55503
  import {
55504
- applyToPoint as applyToPoint42,
55505
- compose as compose42,
55504
+ glyphAdvanceRatio,
55505
+ glyphWidthRatio,
55506
+ letterSpacingRatio,
55507
+ lineAlphabet as lineAlphabet2,
55508
+ spaceWidthRatio
55509
+ } from "@tscircuit/alphabet";
55510
+ import {
55511
+ applyToPoint as applyToPoint52,
55512
+ compose as compose52,
55506
55513
  identity as identity32,
55507
- rotate as rotate42,
55508
- translate as translate42
55514
+ rotate as rotate52,
55515
+ translate as translate52
55509
55516
  } from "transformation-matrix";
55510
55517
  import { getBoundFromCenteredRect as getBoundFromCenteredRect3 } from "@tscircuit/math-utils";
55511
55518
  import { applyToPoint as applyToPoint25, compose as compose22, rotate as rotate22, translate as translate22 } from "transformation-matrix";
@@ -55517,6 +55524,7 @@ import {
55517
55524
  rotate as rotate32,
55518
55525
  translate as translate32
55519
55526
  } from "transformation-matrix";
55527
+ import { applyToPoint as applyToPoint42, compose as compose42, rotate as rotate42, translate as translate42 } from "transformation-matrix";
55520
55528
  function pairs3(arr) {
55521
55529
  const result = [];
55522
55530
  for (let i2 = 0;i2 < arr.length - 1; i2++) {
@@ -55542,16 +55550,10 @@ function getAllTraceWidths(soup) {
55542
55550
  }
55543
55551
  }
55544
55552
  }
55545
- return {
55546
- top: Array.from(widths.top || []),
55547
- inner1: Array.from(widths.inner1 || []),
55548
- inner2: Array.from(widths.inner2 || []),
55549
- inner3: Array.from(widths.inner3 || []),
55550
- inner4: Array.from(widths.inner4 || []),
55551
- inner5: Array.from(widths.inner5 || []),
55552
- inner6: Array.from(widths.inner6 || []),
55553
- bottom: Array.from(widths.bottom || [])
55554
- };
55553
+ return Object.fromEntries(Object.entries(widths).map(([layer, layerWidths]) => [
55554
+ layer,
55555
+ Array.from(layerWidths)
55556
+ ]));
55555
55557
  }
55556
55558
  function defineAperturesForLayer({
55557
55559
  glayer,
@@ -55573,7 +55575,7 @@ function defineAperturesForLayer({
55573
55575
  glayer.push(...gerberBuilder().add("comment", { comment: "aperture START LIST" }).build());
55574
55576
  const traceWidths = getAllTraceWidths(circuitJson);
55575
55577
  const layerRef = getLayerRefFromGerberLayerName(glayer_name);
55576
- for (const width of traceWidths[layerRef]) {
55578
+ for (const width of traceWidths[layerRef] ?? []) {
55577
55579
  glayer.push(...gerberBuilder().add("define_aperture_template", {
55578
55580
  aperture_number: getNextApertureNumber(),
55579
55581
  standard_template_code: "C",
@@ -55603,6 +55605,7 @@ function getAllApertureTemplateConfigsForLayer({
55603
55605
  const isSoldermaskLayer = glayer_name.endsWith("_Mask");
55604
55606
  const isCopperLayer = glayer_name.endsWith("_Cu");
55605
55607
  const isFabricationLayer = glayer_name.endsWith("_Fab");
55608
+ const hasCopperPourForLayer = circuitJson.some((element) => element.type === "pcb_copper_pour" && element.layer === layer);
55606
55609
  const addConfigIfNew = (config) => {
55607
55610
  const hash = import_fast_json_stable_stringify.default(config);
55608
55611
  if (!configHashMap.has(hash)) {
@@ -55625,6 +55628,10 @@ function getAllApertureTemplateConfigsForLayer({
55625
55628
  if (isFabricationLayer)
55626
55629
  continue;
55627
55630
  if (elm.layer === layer) {
55631
+ if (elm.shape === "oval") {
55632
+ addConfigIfNew(REGION_APERTURE_CONFIG);
55633
+ continue;
55634
+ }
55628
55635
  addConfigIfNew(getApertureConfigFromPcbSolderPaste(elm));
55629
55636
  if (elm.shape === "pill") {
55630
55637
  addConfigIfNew(getApertureConfigFromPcbSolderPaste({
@@ -55644,6 +55651,10 @@ function getAllApertureTemplateConfigsForLayer({
55644
55651
  if (glayer_name.endsWith("_Mask") && elm.is_covered_with_solder_mask === true) {
55645
55652
  continue;
55646
55653
  }
55654
+ if (elm.shape === "oval") {
55655
+ addConfigIfNew(REGION_APERTURE_CONFIG);
55656
+ continue;
55657
+ }
55647
55658
  if (isSoldermaskLayer) {
55648
55659
  addConfigIfNew(getApertureConfigFromPcbPlatedHoleSoldermask(elm));
55649
55660
  } else {
@@ -55651,9 +55662,11 @@ function getAllApertureTemplateConfigsForLayer({
55651
55662
  }
55652
55663
  }
55653
55664
  } else if (elm.type === "pcb_hole") {
55654
- if (!isSoldermaskLayer)
55665
+ if (!isCopperLayer && !isSoldermaskLayer)
55666
+ continue;
55667
+ if (isCopperLayer && !hasCopperPourForLayer)
55655
55668
  continue;
55656
- if (glayer_name.endsWith("_Mask") && elm.is_covered_with_solder_mask === true) {
55669
+ if (isSoldermaskLayer && elm.is_covered_with_solder_mask === true) {
55657
55670
  continue;
55658
55671
  }
55659
55672
  if (elm.hole_shape === "circle") {
@@ -55734,6 +55747,11 @@ function getAllApertureTemplateConfigsForLayer({
55734
55747
  return true;
55735
55748
  return isSoldermaskLayer && elm.is_covered_with_solder_mask !== true;
55736
55749
  }
55750
+ if (elm.type === "pcb_smtpad" && elm.shape === "rotated_rect") {
55751
+ if (elm.layer !== layer)
55752
+ return false;
55753
+ return isCopperLayer || isSoldermaskLayer;
55754
+ }
55737
55755
  if (elm.type === "pcb_plated_hole" && elm.shape === "hole_with_polygon_pad") {
55738
55756
  if (!elm.layers.includes(layer))
55739
55757
  return false;
@@ -56362,7 +56380,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
56362
56380
  return "top";
56363
56381
  if (glayer_name.startsWith("B_"))
56364
56382
  return "bottom";
56365
- const innerLayerMatch = glayer_name.match(/^In([1-6])_/);
56383
+ const innerLayerMatch = glayer_name.match(/^In(\d+)_/);
56366
56384
  if (innerLayerMatch)
56367
56385
  return `inner${innerLayerMatch[1]}`;
56368
56386
  throw new Error(`Could not infer layer ref from ${glayer_name}`);
@@ -56485,7 +56503,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
56485
56503
  if ("font_size" in elm) {
56486
56504
  return {
56487
56505
  standard_template_code: "C",
56488
- diameter: elm.font_size / 8
56506
+ diameter: elm.font_size * strokeWidthRatio
56489
56507
  };
56490
56508
  }
56491
56509
  throw new Error(`Provide font_size for: ${elm}`);
@@ -56493,7 +56511,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
56493
56511
  if ("font_size" in elm) {
56494
56512
  return {
56495
56513
  standard_template_code: "C",
56496
- diameter: elm.font_size / 8
56514
+ diameter: elm.font_size * strokeWidthRatio
56497
56515
  };
56498
56516
  }
56499
56517
  throw new Error(`Provide font_size for: ${elm}`);
@@ -56501,7 +56519,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
56501
56519
  if ("font_size" in elm) {
56502
56520
  return {
56503
56521
  standard_template_code: "C",
56504
- diameter: elm.font_size / 8
56522
+ diameter: elm.font_size * strokeWidthRatio
56505
56523
  };
56506
56524
  }
56507
56525
  throw new Error(`Provide font_size for: ${elm}`);
@@ -56542,7 +56560,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
56542
56560
  diameter: elm.radius * 2
56543
56561
  };
56544
56562
  }
56545
- if (elm.shape === "pill") {
56563
+ if (elm.shape === "pill" || elm.shape === "rotated_pill") {
56546
56564
  if (!(("width" in elm) && ("height" in elm))) {
56547
56565
  throw new Error("Invalid pill shape in getApertureConfigFromPcbPlatedHole: missing dimensions");
56548
56566
  }
@@ -56736,13 +56754,14 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
56736
56754
  }).add("set_movement_mode_to_linear", {}).add("set_layer_polarity", {
56737
56755
  polarity: "D"
56738
56756
  }).add("create_arc", {}).build();
56739
- }, layerRefToGerberPrefix, layerTypeToGerberSuffix, getGerberLayerName = (layer_ref2, layer_type) => {
56757
+ }, outerLayerRefToGerberPrefix, layerTypeToGerberSuffix, getGerberLayerName = (layer_ref2, layer_type) => {
56740
56758
  if (layer_ref2 === "edgecut")
56741
56759
  return "Edge_Cuts";
56742
56760
  if (layer_ref2.startsWith("inner") && layer_type !== "copper") {
56743
56761
  throw new Error(`Inner layer ${layer_ref2} only supports copper gerbers`);
56744
56762
  }
56745
- return `${layerRefToGerberPrefix[layer_ref2]}${layerTypeToGerberSuffix[layer_type]}`;
56763
+ const prefix = layer_ref2.startsWith("inner") ? `In${layer_ref2.slice("inner".length)}_` : outerLayerRefToGerberPrefix[layer_ref2];
56764
+ return `${prefix}${layerTypeToGerberSuffix[layer_type]}`;
56746
56765
  }, getSignedPolygonArea = (points) => {
56747
56766
  let area2 = 0;
56748
56767
  for (let i2 = 0;i2 < points.length; i2++) {
@@ -57251,6 +57270,46 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
57251
57270
  builder.add("plot_operation", { x: ordered[i2].x, y: mfy(ordered[i2].y) });
57252
57271
  }
57253
57272
  builder.add("plot_operation", { x: ordered[0].x, y: mfy(ordered[0].y) });
57273
+ }, getRotatedRectPoints = ({
57274
+ center: center2,
57275
+ width,
57276
+ height,
57277
+ ccwRotationDegrees
57278
+ }) => {
57279
+ const halfWidth = width / 2;
57280
+ const halfHeight = height / 2;
57281
+ const ccwRotationRadians = ccwRotationDegrees * Math.PI / 180;
57282
+ const rectToPcbTransform = compose42(translate42(center2.x, center2.y), rotate42(ccwRotationRadians));
57283
+ return [
57284
+ { x: -halfWidth, y: halfHeight },
57285
+ { x: halfWidth, y: halfHeight },
57286
+ { x: halfWidth, y: -halfHeight },
57287
+ { x: -halfWidth, y: -halfHeight }
57288
+ ].map((point9) => applyToPoint42(rectToPcbTransform, point9));
57289
+ }, getEllipsePoints = ({
57290
+ x: x4,
57291
+ y: y4,
57292
+ width,
57293
+ height,
57294
+ rotationDegrees = 0
57295
+ }) => {
57296
+ const rotationRadians = rotationDegrees * Math.PI / 180;
57297
+ const cosRotation = Math.cos(rotationRadians);
57298
+ const sinRotation = Math.sin(rotationRadians);
57299
+ return Array.from({ length: 64 }, (_4, index) => {
57300
+ const angle = index * 2 * Math.PI / 64;
57301
+ const dx3 = width / 2 * Math.cos(angle);
57302
+ const dy3 = height / 2 * Math.sin(angle);
57303
+ return {
57304
+ x: x4 + dx3 * cosRotation - dy3 * sinRotation,
57305
+ y: y4 + dx3 * sinRotation + dy3 * cosRotation
57306
+ };
57307
+ });
57308
+ }, getAlphabetCharacterAdvance = (char, fontSize) => {
57309
+ if (char === " ")
57310
+ return fontSize * spaceWidthRatio;
57311
+ const advanceRatio = glyphAdvanceRatio[char] ?? glyphWidthRatio;
57312
+ return fontSize * advanceRatio;
57254
57313
  }, closeRing = (ring) => {
57255
57314
  const first = ring[0];
57256
57315
  const last = ring[ring.length - 1];
@@ -57278,7 +57337,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
57278
57337
  }, getLayerCount2 = (circuitJson) => {
57279
57338
  const board = circuitJson.find((element) => element.type === "pcb_board");
57280
57339
  const numLayers = board?.num_layers ?? 2;
57281
- return Math.max(2, Math.min(8, numLayers));
57340
+ return Math.max(2, Math.min(10, numLayers));
57282
57341
  }, getInnerLayerRefs = (layerCount) => Array.from({ length: layerCount - 2 }, (_4, i2) => `inner${i2 + 1}`), getGerberInnerLayerName = (layerRef) => {
57283
57342
  if (!layerRef.startsWith("inner")) {
57284
57343
  throw new Error(`Expected inner layer, got ${layerRef}`);
@@ -57468,14 +57527,8 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
57468
57527
  let initialX = element.anchor_position.x;
57469
57528
  let initialY = element.anchor_position.y;
57470
57529
  const fontSize = element.font_size * CAP_HEIGHT_SCALE;
57471
- const letterSpacing = fontSize * 0.4;
57472
- const spaceWidth = fontSize * 0.5;
57473
- const textWidth = element.text.split("").reduce((width, char) => {
57474
- if (char === " ") {
57475
- return width + spaceWidth + letterSpacing;
57476
- }
57477
- return width + fontSize + letterSpacing;
57478
- }, 0) - letterSpacing;
57530
+ const letterSpacing = element.font_size * letterSpacingRatio;
57531
+ const textWidth = element.text.split("").reduce((width, char) => width + getAlphabetCharacterAdvance(char, element.font_size), 0) + Math.max(0, element.text.length - 1) * letterSpacing;
57479
57532
  const textHeight = fontSize;
57480
57533
  const anchorAlignment = element.anchor_alignment || (() => {
57481
57534
  const side = element.anchor_side;
@@ -57532,15 +57585,15 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
57532
57585
  const transforms = [];
57533
57586
  const shouldMirror = element.is_mirrored !== undefined ? element.is_mirrored : element.layer === "bottom";
57534
57587
  if (shouldMirror) {
57535
- transforms.push(translate42(cx3, cy3), { a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 }, translate42(-cx3, -cy3));
57588
+ transforms.push(translate52(cx3, cy3), { a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 }, translate52(-cx3, -cy3));
57536
57589
  rotation11 = -rotation11;
57537
57590
  }
57538
57591
  if (rotation11) {
57539
57592
  const rad = rotation11 * Math.PI / 180;
57540
- transforms.push(translate42(cx3, cy3), rotate42(rad), translate42(-cx3, -cy3));
57593
+ transforms.push(translate52(cx3, cy3), rotate52(rad), translate52(-cx3, -cy3));
57541
57594
  }
57542
- const transformMatrix = transforms.length > 0 ? compose42(...transforms) : undefined;
57543
- const applyTransform = (point9) => transformMatrix ? applyToPoint42(transformMatrix, point9) : point9;
57595
+ const transformMatrix = transforms.length > 0 ? compose52(...transforms) : undefined;
57596
+ const applyTransform = (point9) => transformMatrix ? applyToPoint52(transformMatrix, point9) : point9;
57544
57597
  if (element.is_knockout) {
57545
57598
  const padding = element.knockout_padding ?? {
57546
57599
  left: 0.2,
@@ -57585,7 +57638,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
57585
57638
  }
57586
57639
  for (const char of element.text) {
57587
57640
  if (char === " ") {
57588
- anchoredX += spaceWidth + letterSpacing;
57641
+ anchoredX += getAlphabetCharacterAdvance(char, element.font_size) + letterSpacing;
57589
57642
  continue;
57590
57643
  }
57591
57644
  const letterPaths = lineAlphabet2[char] || [];
@@ -57599,7 +57652,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
57599
57652
  gerber.add("move_operation", { x: p12.x, y: mfy(p12.y) });
57600
57653
  gerber.add("plot_operation", { x: p22.x, y: mfy(p22.y) });
57601
57654
  }
57602
- anchoredX += fontSize + letterSpacing;
57655
+ anchoredX += getAlphabetCharacterAdvance(char, element.font_size) + letterSpacing;
57603
57656
  }
57604
57657
  glayer.push(...gerber.build());
57605
57658
  if (element.is_knockout) {
@@ -57721,10 +57774,10 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
57721
57774
  let transformMatrix = identity32();
57722
57775
  if (rotation11) {
57723
57776
  const angle_rad = rotation11 * Math.PI / 180;
57724
- transformMatrix = rotate42(angle_rad);
57777
+ transformMatrix = rotate52(angle_rad);
57725
57778
  }
57726
- transformMatrix = compose42(translate42(center2.x, center2.y), transformMatrix);
57727
- const transformedPoints = points.map((p3) => applyToPoint42(transformMatrix, p3));
57779
+ transformMatrix = compose52(translate52(center2.x, center2.y), transformMatrix);
57780
+ const transformedPoints = points.map((p3) => applyToPoint52(transformMatrix, p3));
57728
57781
  const regionApertureNumber = getRegionApertureNumber(copper_glayer);
57729
57782
  const rect_builder = gerberBuilder().add("select_aperture", { aperture_number: regionApertureNumber }).add("start_region_statement", {});
57730
57783
  rect_builder.add("move_operation", {
@@ -57963,6 +58016,33 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
57963
58016
  });
57964
58017
  continue;
57965
58018
  }
58019
+ if (element.shape === "rotated_rect" && !element.corner_radius && !element.rect_border_radius) {
58020
+ const soldermaskMargin = element.soldermask_margin ?? 0;
58021
+ for (const { glayer, width, height } of [
58022
+ {
58023
+ glayer: glayers[getGerberLayerName(layer, "copper")],
58024
+ width: element.width,
58025
+ height: element.height
58026
+ },
58027
+ {
58028
+ glayer: glayers[getGerberLayerName(layer, "soldermask")],
58029
+ width: element.width + soldermaskMargin * 2,
58030
+ height: element.height + soldermaskMargin * 2
58031
+ }
58032
+ ]) {
58033
+ addClosedRegionFromPoints({
58034
+ target: glayer,
58035
+ apertureSource: glayer,
58036
+ points: getRotatedRectPoints({
58037
+ center: { x: element.x, y: element.y },
58038
+ width,
58039
+ height,
58040
+ ccwRotationDegrees: element.ccw_rotation
58041
+ })
58042
+ });
58043
+ }
58044
+ continue;
58045
+ }
57966
58046
  const rotation11 = element.shape === "rotated_rect" && typeof element.ccw_rotation === "number" ? element.ccw_rotation : 0;
57967
58047
  for (const { glayer, apertureConfig } of [
57968
58048
  {
@@ -58011,6 +58091,20 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
58011
58091
  }
58012
58092
  } else if (element.type === "pcb_solder_paste") {
58013
58093
  if (element.layer === layer && isOuterLayerRef(layer)) {
58094
+ if (element.shape === "oval") {
58095
+ const glayer2 = glayers[getGerberLayerName(layer, "paste")];
58096
+ addClosedRegionFromPoints({
58097
+ target: glayer2,
58098
+ apertureSource: glayer2,
58099
+ points: getEllipsePoints({
58100
+ x: element.x,
58101
+ y: element.y,
58102
+ width: element.width,
58103
+ height: element.height
58104
+ })
58105
+ });
58106
+ continue;
58107
+ }
58014
58108
  const glayer = glayers[getGerberLayerName(layer, "paste")];
58015
58109
  let rotation11 = 0;
58016
58110
  if ("ccw_rotation" in element && typeof element.ccw_rotation === "number") {
@@ -58058,9 +58152,9 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
58058
58152
  const { pad_outline } = element;
58059
58153
  if (!pad_outline?.length)
58060
58154
  continue;
58061
- const soldermaskGlayer2 = glayers[getGerberLayerName(layer, "soldermask")];
58155
+ const soldermaskGlayer2 = isOuterLayerRef(layer) ? glayers[getGerberLayerName(layer, "soldermask")] : undefined;
58062
58156
  let points = pad_outline;
58063
- if (glayer === soldermaskGlayer2 && "soldermask_margin" in element && typeof element.soldermask_margin === "number") {
58157
+ if (soldermaskGlayer2 && glayer === soldermaskGlayer2 && "soldermask_margin" in element && typeof element.soldermask_margin === "number") {
58064
58158
  points = offsetPolygonOutline(pad_outline, element.soldermask_margin);
58065
58159
  }
58066
58160
  const translatedPoints = points.map((point9) => ({
@@ -58092,14 +58186,26 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
58092
58186
  padHeightCandidates.push(element.rect_pad_height);
58093
58187
  }
58094
58188
  const padH = Math.max(...padHeightCandidates);
58095
- const soldermaskGlayer = glayers[getGerberLayerName(layer, "soldermask")];
58189
+ const soldermaskGlayer = isOuterLayerRef(layer) ? glayers[getGerberLayerName(layer, "soldermask")] : undefined;
58096
58190
  let soldermaskMargin = 0;
58097
- if (glayer === soldermaskGlayer && "soldermask_margin" in element && typeof element.soldermask_margin === "number") {
58191
+ if (soldermaskGlayer && glayer === soldermaskGlayer && "soldermask_margin" in element && typeof element.soldermask_margin === "number") {
58098
58192
  soldermaskMargin = element.soldermask_margin;
58099
58193
  }
58100
58194
  const aperturePadW = padW + soldermaskMargin * 2;
58101
58195
  const aperturePadH = padH + soldermaskMargin * 2;
58102
- if (element.shape === "pill") {
58196
+ if (element.shape === "oval") {
58197
+ addClosedRegionFromPoints({
58198
+ target: glayer,
58199
+ apertureSource: glayer,
58200
+ points: getEllipsePoints({
58201
+ x: element.x,
58202
+ y: element.y,
58203
+ width: aperturePadW,
58204
+ height: aperturePadH,
58205
+ rotationDegrees: element.ccw_rotation
58206
+ })
58207
+ });
58208
+ } else if (element.shape === "pill") {
58103
58209
  const circleApertureConfig = {
58104
58210
  standard_template_code: "C",
58105
58211
  diameter: Math.min(aperturePadW, aperturePadH)
@@ -58158,7 +58264,7 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
58158
58264
  ...element,
58159
58265
  ...element.shape !== "circle" ? { outer_width: padW, outer_height: padH } : {}
58160
58266
  });
58161
- if (glayer === soldermaskGlayer) {
58267
+ if (soldermaskGlayer && glayer === soldermaskGlayer) {
58162
58268
  apertureConfig = getApertureConfigFromPcbPlatedHoleSoldermask({
58163
58269
  ...element,
58164
58270
  ...element.shape !== "circle" ? { outer_width: padW, outer_height: padH } : {}
@@ -58296,12 +58402,26 @@ var import_polygon_clipping, import_fast_json_stable_stringify, import_polygon_c
58296
58402
  }
58297
58403
  }
58298
58404
  }
58405
+ for (const layer of copperLayerRefs) {
58406
+ const hasCopperPour = circuitJson.some((element) => element.type === "pcb_copper_pour" && element.layer === layer);
58407
+ if (!hasCopperPour)
58408
+ continue;
58409
+ const copperGlayer = glayers[getGerberLayerName(layer, "copper")];
58410
+ for (const element of circuitJson) {
58411
+ if (element.type !== "pcb_hole" || element.hole_shape !== "circle") {
58412
+ continue;
58413
+ }
58414
+ copperGlayer.push(...gerberBuilder().add("set_layer_polarity", { polarity: "C" }).add("select_aperture", {
58415
+ aperture_number: findApertureNumber(copperGlayer, getApertureConfigFromCirclePcbHole(element))
58416
+ }).add("flash_operation", { x: element.x, y: mfy(element.y) }).add("set_layer_polarity", { polarity: "D" }).build());
58417
+ }
58418
+ }
58299
58419
  for (const key of Object.keys(glayers)) {
58300
58420
  glayers[key].push(...gerberBuilder().add("end_of_file", {}).build());
58301
58421
  }
58302
58422
  return glayers;
58303
58423
  };
58304
- var init_chunk_46NSLLUV = __esm(() => {
58424
+ var init_chunk_MJSWOMMX = __esm(() => {
58305
58425
  import_polygon_clipping = __toESM2(require_polygon_clipping_cjs(), 1);
58306
58426
  import_fast_json_stable_stringify = __toESM2(require_fast_json_stable_stringify(), 1);
58307
58427
  import_polygon_clipping2 = __toESM2(require_polygon_clipping_cjs(), 1);
@@ -58916,7 +59036,8 @@ ${template_code}%`;
58916
59036
  };
58917
59037
  package_default5 = {
58918
59038
  name: "circuit-json-to-gerber",
58919
- version: "0.0.82",
59039
+ version: "0.0.93",
59040
+ license: "MIT",
58920
59041
  main: "dist/index.js",
58921
59042
  type: "module",
58922
59043
  scripts: {
@@ -58941,13 +59062,13 @@ ${template_code}%`;
58941
59062
  "@types/react-dom": "^19.1.5",
58942
59063
  archiver: "^7.0.1",
58943
59064
  "bun-match-svg": "^0.0.13",
58944
- "circuit-json": "^0.0.426",
59065
+ "circuit-json": "^0.0.456",
58945
59066
  commander: "^12.1.0",
59067
+ "format-si-unit": "^0.0.7",
58946
59068
  "gerber-to-svg": "^4.2.8",
58947
59069
  gerberts: "^0.0.3",
58948
59070
  jszip: "^3.10.1",
58949
59071
  "pcb-stackup": "^4.2.8",
58950
- "polygon-clipping": "^0.15.7",
58951
59072
  react: "^19.2.1",
58952
59073
  "react-dom": "^19.2.1",
58953
59074
  tscircuit: "^0.0.1776",
@@ -58961,6 +59082,7 @@ ${template_code}%`;
58961
59082
  dependencies: {
58962
59083
  "@tscircuit/alphabet": "^0.0.25",
58963
59084
  "fast-json-stable-stringify": "^2.1.0",
59085
+ "polygon-clipping": "^0.15.7",
58964
59086
  "transformation-matrix": "^3.0.0"
58965
59087
  }
58966
59088
  };
@@ -58976,15 +59098,9 @@ ${template_code}%`;
58976
59098
  "bottom-paste": "Paste,Bot",
58977
59099
  edgecut: "Profile,NP"
58978
59100
  };
58979
- layerRefToGerberPrefix = {
59101
+ outerLayerRefToGerberPrefix = {
58980
59102
  top: "F_",
58981
- bottom: "B_",
58982
- inner1: "In1_",
58983
- inner2: "In2_",
58984
- inner3: "In3_",
58985
- inner4: "In4_",
58986
- inner5: "In5_",
58987
- inner6: "In6_"
59103
+ bottom: "B_"
58988
59104
  };
58989
59105
  layerTypeToGerberSuffix = {
58990
59106
  copper: "Cu",
@@ -58999,7 +59115,7 @@ ${template_code}%`;
58999
59115
 
59000
59116
  // node_modules/circuit-json-to-gerber/dist/index.js
59001
59117
  var init_dist = __esm(() => {
59002
- init_chunk_46NSLLUV();
59118
+ init_chunk_MJSWOMMX();
59003
59119
  });
59004
59120
 
59005
59121
  // node_modules/@tracespace/xml-id/index.js
@@ -71993,9 +72109,9 @@ import { applyToPoint as applyToPoint28 } from "transformation-matrix";
71993
72109
  import { applyToPoint as applyToPoint43 } from "transformation-matrix";
71994
72110
  import { applyToPoint as applyToPoint33 } from "transformation-matrix";
71995
72111
  import { glyphLineAlphabet } from "@tscircuit/alphabet";
71996
- import { applyToPoint as applyToPoint52 } from "transformation-matrix";
72112
+ import { applyToPoint as applyToPoint53 } from "transformation-matrix";
71997
72113
  import {
71998
- glyphAdvanceRatio,
72114
+ glyphAdvanceRatio as glyphAdvanceRatio2,
71999
72115
  kerningRatio,
72000
72116
  textMetrics
72001
72117
  } from "@tscircuit/alphabet";
@@ -72414,9 +72530,9 @@ function addPolygonToPath(ctx, points) {
72414
72530
  }
72415
72531
  function getAlphabetAdvanceWidth(char, nextChar, fontSize) {
72416
72532
  const advanceRatio = getAdvanceRatio(char);
72417
- const letterSpacingRatio = nextChar ? textMetrics.letterSpacingRatio : 0;
72533
+ const letterSpacingRatio2 = nextChar ? textMetrics.letterSpacingRatio : 0;
72418
72534
  const kerningAdjustmentRatio = nextChar ? kerningRatio[char]?.[nextChar] ?? 0 : 0;
72419
- return fontSize * (advanceRatio + letterSpacingRatio + kerningAdjustmentRatio);
72535
+ return fontSize * (advanceRatio + letterSpacingRatio2 + kerningAdjustmentRatio);
72420
72536
  }
72421
72537
  function getAlphabetLayout(text, fontSize) {
72422
72538
  const glyphWidth = fontSize * textMetrics.glyphWidthRatio;
@@ -72647,7 +72763,7 @@ function drawText(params2) {
72647
72763
  } = params2;
72648
72764
  if (!text)
72649
72765
  return;
72650
- const [canvasX, canvasY] = applyToPoint52(realToCanvasMat, [x4, y4]);
72766
+ const [canvasX, canvasY] = applyToPoint53(realToCanvasMat, [x4, y4]);
72651
72767
  const scale22 = Math.abs(realToCanvasMat.a);
72652
72768
  const scaledFontSize = fontSize * scale22;
72653
72769
  const layout = getAlphabetLayout(text, scaledFontSize);
@@ -76879,7 +76995,7 @@ function getCopperLayer(layers) {
76879
76995
  const renderLayer = layers.find((candidate) => candidate.endsWith("_copper")) ?? layers[0] ?? "top_copper";
76880
76996
  return renderLayer.split("_")[0];
76881
76997
  }
76882
- var getAdvanceRatio = (char) => glyphAdvanceRatio[char] ?? (char === " " ? textMetrics.spaceWidthRatio : textMetrics.glyphWidthRatio), getGlyphLines = (char) => glyphLineAlphabet[char], DEFAULT_KNOCKOUT_PADDING, TEXT_OFFSET_MULTIPLIER2 = 1.5, CHARACTER_WIDTH_MULTIPLIER2 = 0.6, TEXT_INTERSECTION_PADDING_MULTIPLIER2 = 0.3, DEFAULT_NOTE_COLOR = "rgba(255,255,255,0.5)", DEFAULT_NOTE_TEXT_COLOR = "rgb(89, 148, 220)", SOLDER_PASTE_COLOR = "rgb(105, 105, 105)", CUTOUT_MASK_COLOR = "rgba(255, 255, 255, 1)", COORD_EPSILON = 0.000001, DEFAULT_PCB_COLOR_MAP2, isOnCopperLayer = (element, layer) => element.layers?.includes(layer) ?? true, CircuitToCanvasDrawer = class _CircuitToCanvasDrawer {
76998
+ var getAdvanceRatio = (char) => glyphAdvanceRatio2[char] ?? (char === " " ? textMetrics.spaceWidthRatio : textMetrics.glyphWidthRatio), getGlyphLines = (char) => glyphLineAlphabet[char], DEFAULT_KNOCKOUT_PADDING, TEXT_OFFSET_MULTIPLIER2 = 1.5, CHARACTER_WIDTH_MULTIPLIER2 = 0.6, TEXT_INTERSECTION_PADDING_MULTIPLIER2 = 0.3, DEFAULT_NOTE_COLOR = "rgba(255,255,255,0.5)", DEFAULT_NOTE_TEXT_COLOR = "rgb(89, 148, 220)", SOLDER_PASTE_COLOR = "rgb(105, 105, 105)", CUTOUT_MASK_COLOR = "rgba(255, 255, 255, 1)", COORD_EPSILON = 0.000001, DEFAULT_PCB_COLOR_MAP2, isOnCopperLayer = (element, layer) => element.layers?.includes(layer) ?? true, CircuitToCanvasDrawer = class _CircuitToCanvasDrawer {
76883
76999
  ctx;
76884
77000
  colorMap;
76885
77001
  realToCanvasMat;
@@ -77472,10 +77588,10 @@ import { applyToPoint as applyToPoint29, identity as identity10 } from "transfor
77472
77588
  import { convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg22 } from "circuit-to-svg";
77473
77589
  import { deflateSync } from "node:zlib";
77474
77590
  import {
77475
- glyphAdvanceRatio as glyphAdvanceRatio2,
77476
- glyphWidthRatio,
77477
- spaceWidthRatio,
77478
- strokeWidthRatio,
77591
+ glyphAdvanceRatio as glyphAdvanceRatio3,
77592
+ glyphWidthRatio as glyphWidthRatio2,
77593
+ spaceWidthRatio as spaceWidthRatio2,
77594
+ strokeWidthRatio as strokeWidthRatio2,
77479
77595
  svgAlphabet as svgAlphabet2
77480
77596
  } from "@tscircuit/alphabet";
77481
77597
 
@@ -78671,10 +78787,10 @@ var import_gerber_to_svg, renderTscircuitRepro = async (tsx, options = {}) => {
78671
78787
  if (path49) {
78672
78788
  paths.push(`<path d="${path49}" transform="translate(${cursorX} 0)"/>`);
78673
78789
  }
78674
- cursorX += glyphAdvanceRatio2[character] ?? (character === " " ? spaceWidthRatio : glyphWidthRatio);
78790
+ cursorX += glyphAdvanceRatio3[character] ?? (character === " " ? spaceWidthRatio2 : glyphWidthRatio2);
78675
78791
  }
78676
78792
  const renderedSize = maxWidth === undefined || cursorX === 0 ? size : Math.min(size, maxWidth / cursorX);
78677
- return `<g fill="none" stroke="#111" stroke-width="${strokeWidthRatio}" stroke-linecap="round" stroke-linejoin="round" transform="translate(${x4} ${top - 0.24 * renderedSize}) scale(${renderedSize})">${paths.join("")}</g>`;
78793
+ return `<g fill="none" stroke="#111" stroke-width="${strokeWidthRatio2}" stroke-linecap="round" stroke-linejoin="round" transform="translate(${x4} ${top - 0.24 * renderedSize}) scale(${renderedSize})">${paths.join("")}</g>`;
78678
78794
  }, createBitmapLegendSvg = ({
78679
78795
  width,
78680
78796
  height,
@@ -135485,7 +135601,7 @@ var package_default = {
135485
135601
  "circuit-json-to-bom-csv": "^0.0.7",
135486
135602
  "circuit-json-to-connectivity-map": "^0.0.25",
135487
135603
  "circuit-json-to-footprinter": "^0.0.15",
135488
- "circuit-json-to-gerber": "^0.0.83",
135604
+ "circuit-json-to-gerber": "^0.0.94",
135489
135605
  "circuit-json-to-kicad": "0.0.157",
135490
135606
  "circuit-json-to-pnp-csv": "^0.0.9",
135491
135607
  "circuit-json-to-readable-netlist": "^0.0.15",
@@ -310515,7 +310631,7 @@ import Debug32 from "debug";
310515
310631
  import { applyToPoint as applyToPoint44 } from "transformation-matrix";
310516
310632
  import Debug6 from "debug";
310517
310633
  import"transformation-matrix";
310518
- import { applyToPoint as applyToPoint53 } from "transformation-matrix";
310634
+ import { applyToPoint as applyToPoint54 } from "transformation-matrix";
310519
310635
  import Debug42 from "debug";
310520
310636
  import { applyToPoint as applyToPoint63 } from "transformation-matrix";
310521
310637
  import Debug5 from "debug";
package/dist/lib/index.js CHANGED
@@ -65800,7 +65800,7 @@ var package_default = {
65800
65800
  "circuit-json-to-bom-csv": "^0.0.7",
65801
65801
  "circuit-json-to-connectivity-map": "^0.0.25",
65802
65802
  "circuit-json-to-footprinter": "^0.0.15",
65803
- "circuit-json-to-gerber": "^0.0.83",
65803
+ "circuit-json-to-gerber": "^0.0.94",
65804
65804
  "circuit-json-to-kicad": "0.0.157",
65805
65805
  "circuit-json-to-pnp-csv": "^0.0.9",
65806
65806
  "circuit-json-to-readable-netlist": "^0.0.15",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.1908",
3
+ "version": "0.1.1909",
4
4
  "main": "dist/cli/main.js",
5
5
  "exports": {
6
6
  ".": "./dist/cli/main.js",
@@ -40,7 +40,7 @@
40
40
  "circuit-json-to-bom-csv": "^0.0.7",
41
41
  "circuit-json-to-connectivity-map": "^0.0.25",
42
42
  "circuit-json-to-footprinter": "^0.0.15",
43
- "circuit-json-to-gerber": "^0.0.83",
43
+ "circuit-json-to-gerber": "^0.0.94",
44
44
  "circuit-json-to-kicad": "0.0.157",
45
45
  "circuit-json-to-pnp-csv": "^0.0.9",
46
46
  "circuit-json-to-readable-netlist": "^0.0.15",