circuit-json-to-gerber 0.0.75 → 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.74",
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,14 +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;
2748
- const translatedPadOutline = pad_outline.map((point) => ({
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) => ({
2749
2833
  x: point.x + element.x,
2750
2834
  y: point.y + element.y
2751
2835
  }));
2752
2836
  addClosedRegionFromPoints({
2753
2837
  target: glayer,
2754
2838
  apertureSource: glayer,
2755
- points: translatedPadOutline
2839
+ points: translatedPoints
2756
2840
  });
2757
2841
  continue;
2758
2842
  }
@@ -2774,10 +2858,17 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2774
2858
  padHeightCandidates.push(element.rect_pad_height);
2775
2859
  }
2776
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;
2777
2868
  if (element.shape === "pill") {
2778
2869
  const circleApertureConfig = {
2779
2870
  standard_template_code: "C",
2780
- diameter: Math.min(padW, padH)
2871
+ diameter: Math.min(aperturePadW, aperturePadH)
2781
2872
  };
2782
2873
  let aperture_number;
2783
2874
  try {
@@ -2811,8 +2902,8 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2811
2902
  y: element.y + rotatedY
2812
2903
  };
2813
2904
  };
2814
- const isHorizontal = padW >= padH;
2815
- const offset = isHorizontal ? (padW - padH) / 2 : (padH - padW) / 2;
2905
+ const isHorizontal = aperturePadW >= aperturePadH;
2906
+ const offset = isHorizontal ? (aperturePadW - aperturePadH) / 2 : (aperturePadH - aperturePadW) / 2;
2816
2907
  if (offset <= 0) {
2817
2908
  const center = rotateAndTranslate(0, 0);
2818
2909
  gb.add("flash_operation", { x: center.x, y: mfy(center.y) });
@@ -2843,7 +2934,6 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2843
2934
  }
2844
2935
  glayer.push(...gb.build());
2845
2936
  } else {
2846
- const soldermaskGlayer = glayers[getGerberLayerName(layer, "soldermask")];
2847
2937
  let apertureConfig = getApertureConfigFromPcbPlatedHole({
2848
2938
  ...element,
2849
2939
  ...element.shape !== "circle" ? { outer_width: padW, outer_height: padH } : {}
@@ -3135,4 +3225,4 @@ export {
3135
3225
  stringifyGerberCommands,
3136
3226
  convertSoupToGerberCommands
3137
3227
  };
3138
- //# sourceMappingURL=chunk-EM2JSGDL.js.map
3228
+ //# sourceMappingURL=chunk-ER5XAENM.js.map