circuit-json-to-gerber 0.0.74 → 0.0.76

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.
@@ -1892,7 +1892,7 @@ var findApertureNumber = (glayer, search_params) => {
1892
1892
  // package.json
1893
1893
  var package_default = {
1894
1894
  name: "circuit-json-to-gerber",
1895
- version: "0.0.73",
1895
+ version: "0.0.75",
1896
1896
  main: "dist/index.js",
1897
1897
  type: "module",
1898
1898
  scripts: {
@@ -2021,6 +2021,82 @@ var getGerberLayerName = (layer_ref, layer_type) => {
2021
2021
  return `${layerRefToGerberPrefix[layer_ref]}${layerTypeToGerberSuffix[layer_type]}`;
2022
2022
  };
2023
2023
 
2024
+ // src/gerber/convert-soup-to-gerber-commands/offsetPolygonOutline.ts
2025
+ var getSignedPolygonArea = (points) => {
2026
+ let area = 0;
2027
+ for (let i = 0; i < points.length; i++) {
2028
+ const current = points[i];
2029
+ const next = points[(i + 1) % points.length];
2030
+ area += current.x * next.y - next.x * current.y;
2031
+ }
2032
+ return area / 2;
2033
+ };
2034
+ var getLineIntersection = (lineA, lineB) => {
2035
+ const ax = lineA.end.x - lineA.start.x;
2036
+ const ay = lineA.end.y - lineA.start.y;
2037
+ const bx = lineB.end.x - lineB.start.x;
2038
+ const by = lineB.end.y - lineB.start.y;
2039
+ const denominator = ax * by - ay * bx;
2040
+ if (Math.abs(denominator) < 1e-9) {
2041
+ return null;
2042
+ }
2043
+ const cx = lineB.start.x - lineA.start.x;
2044
+ const cy = lineB.start.y - lineA.start.y;
2045
+ const t = (cx * by - cy * bx) / denominator;
2046
+ return {
2047
+ x: lineA.start.x + ax * t,
2048
+ y: lineA.start.y + ay * t
2049
+ };
2050
+ };
2051
+ var offsetPolygonOutline = (points, offset) => {
2052
+ if (points.length < 3 || offset === 0) {
2053
+ return points;
2054
+ }
2055
+ const isCounterClockwise = getSignedPolygonArea(points) > 0;
2056
+ const shiftedEdges = [];
2057
+ for (let i = 0; i < points.length; i++) {
2058
+ const start = points[i];
2059
+ const end = points[(i + 1) % points.length];
2060
+ const dx = end.x - start.x;
2061
+ const dy = end.y - start.y;
2062
+ const length = Math.sqrt(dx * dx + dy * dy);
2063
+ if (length < 1e-9) {
2064
+ continue;
2065
+ }
2066
+ let normalX = -dy / length;
2067
+ let normalY = dx / length;
2068
+ if (isCounterClockwise) {
2069
+ normalX = dy / length;
2070
+ normalY = -dx / length;
2071
+ }
2072
+ shiftedEdges.push({
2073
+ start: {
2074
+ x: start.x + normalX * offset,
2075
+ y: start.y + normalY * offset
2076
+ },
2077
+ end: {
2078
+ x: end.x + normalX * offset,
2079
+ y: end.y + normalY * offset
2080
+ }
2081
+ });
2082
+ }
2083
+ if (shiftedEdges.length < 3) {
2084
+ return points;
2085
+ }
2086
+ const offsetPoints = [];
2087
+ for (let i = 0; i < shiftedEdges.length; i++) {
2088
+ const previousEdge = shiftedEdges[(i - 1 + shiftedEdges.length) % shiftedEdges.length];
2089
+ const currentEdge = shiftedEdges[i];
2090
+ const intersection = getLineIntersection(previousEdge, currentEdge);
2091
+ if (intersection) {
2092
+ offsetPoints.push(intersection);
2093
+ } else {
2094
+ offsetPoints.push(currentEdge.start);
2095
+ }
2096
+ }
2097
+ return offsetPoints;
2098
+ };
2099
+
2024
2100
  // src/gerber/convert-soup-to-gerber-commands/index.ts
2025
2101
  import { lineAlphabet } from "@tscircuit/alphabet";
2026
2102
  import {
@@ -2745,10 +2821,22 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2745
2821
  if (element.shape === "hole_with_polygon_pad") {
2746
2822
  const { pad_outline } = element;
2747
2823
  if (!pad_outline?.length) continue;
2824
+ const soldermaskGlayer2 = glayers[getGerberLayerName(layer, "soldermask")];
2825
+ let points = pad_outline;
2826
+ if (glayer === soldermaskGlayer2 && "soldermask_margin" in element && typeof element.soldermask_margin === "number") {
2827
+ points = offsetPolygonOutline(
2828
+ pad_outline,
2829
+ element.soldermask_margin
2830
+ );
2831
+ }
2832
+ const translatedPoints = points.map((point) => ({
2833
+ x: point.x + element.x,
2834
+ y: point.y + element.y
2835
+ }));
2748
2836
  addClosedRegionFromPoints({
2749
2837
  target: glayer,
2750
2838
  apertureSource: glayer,
2751
- points: pad_outline
2839
+ points: translatedPoints
2752
2840
  });
2753
2841
  continue;
2754
2842
  }
@@ -2770,10 +2858,17 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2770
2858
  padHeightCandidates.push(element.rect_pad_height);
2771
2859
  }
2772
2860
  const padH = Math.max(...padHeightCandidates);
2861
+ const soldermaskGlayer = glayers[getGerberLayerName(layer, "soldermask")];
2862
+ let soldermaskMargin = 0;
2863
+ if (glayer === soldermaskGlayer && "soldermask_margin" in element && typeof element.soldermask_margin === "number") {
2864
+ soldermaskMargin = element.soldermask_margin;
2865
+ }
2866
+ const aperturePadW = padW + soldermaskMargin * 2;
2867
+ const aperturePadH = padH + soldermaskMargin * 2;
2773
2868
  if (element.shape === "pill") {
2774
2869
  const circleApertureConfig = {
2775
2870
  standard_template_code: "C",
2776
- diameter: Math.min(padW, padH)
2871
+ diameter: Math.min(aperturePadW, aperturePadH)
2777
2872
  };
2778
2873
  let aperture_number;
2779
2874
  try {
@@ -2807,8 +2902,8 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2807
2902
  y: element.y + rotatedY
2808
2903
  };
2809
2904
  };
2810
- const isHorizontal = padW >= padH;
2811
- const offset = isHorizontal ? (padW - padH) / 2 : (padH - padW) / 2;
2905
+ const isHorizontal = aperturePadW >= aperturePadH;
2906
+ const offset = isHorizontal ? (aperturePadW - aperturePadH) / 2 : (aperturePadH - aperturePadW) / 2;
2812
2907
  if (offset <= 0) {
2813
2908
  const center = rotateAndTranslate(0, 0);
2814
2909
  gb.add("flash_operation", { x: center.x, y: mfy(center.y) });
@@ -2839,7 +2934,6 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2839
2934
  }
2840
2935
  glayer.push(...gb.build());
2841
2936
  } else {
2842
- const soldermaskGlayer = glayers[getGerberLayerName(layer, "soldermask")];
2843
2937
  let apertureConfig = getApertureConfigFromPcbPlatedHole({
2844
2938
  ...element,
2845
2939
  ...element.shape !== "circle" ? { outer_width: padW, outer_height: padH } : {}
@@ -3131,4 +3225,4 @@ export {
3131
3225
  stringifyGerberCommands,
3132
3226
  convertSoupToGerberCommands
3133
3227
  };
3134
- //# sourceMappingURL=chunk-TZTA23XF.js.map
3228
+ //# sourceMappingURL=chunk-ER5XAENM.js.map