circuit-json-to-gerber 0.0.46 → 0.0.48

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.
@@ -1422,7 +1422,7 @@ var findApertureNumber = (glayer, search_params) => {
1422
1422
  // package.json
1423
1423
  var package_default = {
1424
1424
  name: "circuit-json-to-gerber",
1425
- version: "0.0.45",
1425
+ version: "0.0.47",
1426
1426
  main: "dist/index.js",
1427
1427
  type: "module",
1428
1428
  scripts: {
@@ -1447,7 +1447,7 @@ var package_default = {
1447
1447
  "@types/react-dom": "^19.1.5",
1448
1448
  archiver: "^7.0.1",
1449
1449
  "bun-match-svg": "^0.0.13",
1450
- "circuit-json": "^0.0.317",
1450
+ "circuit-json": "^0.0.378",
1451
1451
  commander: "^12.1.0",
1452
1452
  "gerber-to-svg": "^4.2.8",
1453
1453
  gerberts: "^0.0.3",
@@ -1542,6 +1542,7 @@ import {
1542
1542
  } from "transformation-matrix";
1543
1543
  var convertSoupToGerberCommands = (soup, opts = {}) => {
1544
1544
  opts.flip_y_axis ??= false;
1545
+ const hasPanel = soup.some((e) => e.type === "pcb_panel");
1545
1546
  const glayers = {
1546
1547
  F_Cu: getCommandHeaders({
1547
1548
  layer: "top",
@@ -1771,6 +1772,179 @@ var convertSoupToGerberCommands = (soup, opts = {}) => {
1771
1772
  );
1772
1773
  }
1773
1774
  };
1775
+ const drawRingToBuilder = (builder, ring) => {
1776
+ if (!ring || ring.vertices.length === 0) return;
1777
+ builder.add("move_operation", {
1778
+ x: ring.vertices[0].x,
1779
+ y: mfy(ring.vertices[0].y)
1780
+ });
1781
+ const vertices_loop = [...ring.vertices, ring.vertices[0]];
1782
+ for (let i = 0; i < vertices_loop.length - 1; i++) {
1783
+ const start = vertices_loop[i];
1784
+ const end = vertices_loop[i + 1];
1785
+ if (start.bulge && Math.abs(start.bulge) > 1e-9) {
1786
+ const bulge = (opts.flip_y_axis ? -1 : 1) * start.bulge;
1787
+ if (bulge > 0) {
1788
+ builder.add("set_movement_mode_to_counterclockwise_circular", {});
1789
+ } else {
1790
+ builder.add("set_movement_mode_to_clockwise_circular", {});
1791
+ }
1792
+ const p1 = { x: start.x, y: start.y };
1793
+ const p2 = { x: end.x, y: end.y };
1794
+ const dx = p2.x - p1.x;
1795
+ const dy = p2.y - p1.y;
1796
+ const d = Math.sqrt(dx * dx + dy * dy);
1797
+ if (d < 1e-9) {
1798
+ builder.add("set_movement_mode_to_linear", {});
1799
+ builder.add("plot_operation", {
1800
+ x: end.x,
1801
+ y: mfy(end.y)
1802
+ });
1803
+ continue;
1804
+ }
1805
+ const abs_b = Math.abs(bulge);
1806
+ const theta = 4 * Math.atan(abs_b);
1807
+ if (Math.abs(Math.sin(theta / 2)) < 1e-9) {
1808
+ builder.add("set_movement_mode_to_linear", {});
1809
+ builder.add("plot_operation", {
1810
+ x: end.x,
1811
+ y: mfy(end.y)
1812
+ });
1813
+ continue;
1814
+ }
1815
+ const R = d / (2 * Math.sin(theta / 2));
1816
+ const alpha = (Math.PI - theta) / 2;
1817
+ const phi = Math.atan2(dy, dx);
1818
+ const delta_angle = bulge > 0 ? alpha : -alpha;
1819
+ const angle_p1_center = phi + delta_angle;
1820
+ const Cx = p1.x + R * Math.cos(angle_p1_center);
1821
+ const Cy = p1.y + R * Math.sin(angle_p1_center);
1822
+ const i_offset = Cx - p1.x;
1823
+ const j_offset = Cy - p1.y;
1824
+ builder.add("plot_operation", {
1825
+ x: end.x,
1826
+ y: mfy(end.y),
1827
+ i: i_offset,
1828
+ j: opts.flip_y_axis ? -j_offset : j_offset
1829
+ });
1830
+ } else {
1831
+ builder.add("set_movement_mode_to_linear", {});
1832
+ builder.add("plot_operation", { x: end.x, y: mfy(end.y) });
1833
+ }
1834
+ }
1835
+ };
1836
+ const reverseRing = (ring) => {
1837
+ const { vertices } = ring;
1838
+ if (!vertices || vertices.length === 0) return { vertices: [] };
1839
+ const n = vertices.length;
1840
+ const reversed_pts = [...vertices].reverse();
1841
+ const new_vertices = reversed_pts.map((pt, i) => {
1842
+ const bulge_v_idx = (n - 2 - i + n) % n;
1843
+ const bulge = vertices[bulge_v_idx].bulge;
1844
+ return { ...pt, bulge: bulge ? -bulge : void 0 };
1845
+ });
1846
+ return { vertices: new_vertices };
1847
+ };
1848
+ for (const layer of ["top", "bottom"]) {
1849
+ for (const element of soup) {
1850
+ if (element.type === "pcb_copper_pour" && layer === element.layer) {
1851
+ const copper_glayer = glayers[getGerberLayerName(layer, "copper")];
1852
+ const all_pour_commands = [];
1853
+ if (element.shape === "brep") {
1854
+ const { brep_shape } = element;
1855
+ if (!brep_shape) continue;
1856
+ const { outer_ring, inner_rings } = brep_shape;
1857
+ const outer_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
1858
+ drawRingToBuilder(outer_builder, reverseRing(outer_ring));
1859
+ outer_builder.add("end_region_statement", {});
1860
+ all_pour_commands.push(...outer_builder.build());
1861
+ if (inner_rings && inner_rings.length > 0) {
1862
+ all_pour_commands.push(
1863
+ ...gerberBuilder().add("set_layer_polarity", { polarity: "C" }).build()
1864
+ );
1865
+ for (const inner_ring of inner_rings) {
1866
+ const inner_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
1867
+ drawRingToBuilder(inner_builder, inner_ring);
1868
+ inner_builder.add("end_region_statement", {});
1869
+ all_pour_commands.push(...inner_builder.build());
1870
+ }
1871
+ all_pour_commands.push(
1872
+ ...gerberBuilder().add("set_layer_polarity", { polarity: "D" }).build()
1873
+ );
1874
+ }
1875
+ } else if (element.shape === "rect") {
1876
+ const { center, width, height, rotation } = element;
1877
+ const w = width / 2;
1878
+ const h = height / 2;
1879
+ const points = [
1880
+ { x: -w, y: h },
1881
+ // Top-left
1882
+ { x: w, y: h },
1883
+ // Top-right
1884
+ { x: w, y: -h },
1885
+ // Bottom-right
1886
+ { x: -w, y: -h }
1887
+ // Bottom-left
1888
+ ];
1889
+ let transformMatrix = identity();
1890
+ if (rotation) {
1891
+ const angle_rad = rotation * Math.PI / 180;
1892
+ transformMatrix = rotate(angle_rad);
1893
+ }
1894
+ transformMatrix = compose(
1895
+ translate(center.x, center.y),
1896
+ transformMatrix
1897
+ );
1898
+ const transformedPoints = points.map(
1899
+ (p) => applyToPoint(transformMatrix, p)
1900
+ );
1901
+ const rect_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
1902
+ rect_builder.add("move_operation", {
1903
+ x: transformedPoints[0].x,
1904
+ y: mfy(transformedPoints[0].y)
1905
+ });
1906
+ for (let i = 1; i < transformedPoints.length; i++) {
1907
+ rect_builder.add("plot_operation", {
1908
+ x: transformedPoints[i].x,
1909
+ y: mfy(transformedPoints[i].y)
1910
+ });
1911
+ }
1912
+ rect_builder.add("plot_operation", {
1913
+ x: transformedPoints[0].x,
1914
+ y: mfy(transformedPoints[0].y)
1915
+ });
1916
+ rect_builder.add("end_region_statement", {});
1917
+ all_pour_commands.push(...rect_builder.build());
1918
+ } else if (element.shape === "polygon") {
1919
+ const { points } = element;
1920
+ if (points.length > 0) {
1921
+ const poly_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
1922
+ poly_builder.add("move_operation", {
1923
+ x: points[0].x,
1924
+ y: mfy(points[0].y)
1925
+ });
1926
+ for (let i = 1; i < points.length; i++) {
1927
+ poly_builder.add("plot_operation", {
1928
+ x: points[i].x,
1929
+ y: mfy(points[i].y)
1930
+ });
1931
+ }
1932
+ poly_builder.add("plot_operation", {
1933
+ x: points[0].x,
1934
+ y: mfy(points[0].y)
1935
+ });
1936
+ poly_builder.add("end_region_statement", {});
1937
+ all_pour_commands.push(...poly_builder.build());
1938
+ }
1939
+ }
1940
+ copper_glayer.push(...all_pour_commands);
1941
+ if (element.covered_with_solder_mask === false) {
1942
+ const mask_layer = glayers[getGerberLayerName(layer, "soldermask")];
1943
+ mask_layer.push(...all_pour_commands);
1944
+ }
1945
+ }
1946
+ }
1947
+ }
1774
1948
  for (const layer of ["top", "bottom", "edgecut"]) {
1775
1949
  for (const element of soup) {
1776
1950
  if (element.type === "pcb_trace") {
@@ -2044,10 +2218,7 @@ var convertSoupToGerberCommands = (soup, opts = {}) => {
2044
2218
  }
2045
2219
  }
2046
2220
  } else if (element.type === "pcb_board" && layer === "edgecut") {
2047
- const board = element;
2048
- if (board.pcb_panel_id) {
2049
- continue;
2050
- }
2221
+ if (hasPanel) continue;
2051
2222
  const glayer = glayers.Edge_Cuts;
2052
2223
  const { width, height, center, outline } = element;
2053
2224
  const gerberBuild = gerberBuilder().add("select_aperture", {
@@ -2253,164 +2424,6 @@ var convertSoupToGerberCommands = (soup, opts = {}) => {
2253
2424
  }
2254
2425
  ec_layer.push(...cutout_builder.build());
2255
2426
  }
2256
- } else if (element.type === "pcb_copper_pour" && layer === element.layer) {
2257
- const copper_glayer = glayers[getGerberLayerName(layer, "copper")];
2258
- const pour_builder = gerberBuilder().add("select_aperture", { aperture_number: 10 }).add("start_region_statement", {});
2259
- if (element.shape === "brep") {
2260
- const { brep_shape } = element;
2261
- if (!brep_shape) continue;
2262
- const { outer_ring, inner_rings } = brep_shape;
2263
- const drawRing = (ring) => {
2264
- if (!ring || ring.vertices.length === 0) return;
2265
- pour_builder.add("move_operation", {
2266
- x: ring.vertices[0].x,
2267
- y: mfy(ring.vertices[0].y)
2268
- });
2269
- const vertices_loop = [...ring.vertices, ring.vertices[0]];
2270
- for (let i = 0; i < vertices_loop.length - 1; i++) {
2271
- const start = vertices_loop[i];
2272
- const end = vertices_loop[i + 1];
2273
- if (start.bulge && Math.abs(start.bulge) > 1e-9) {
2274
- const bulge = (opts.flip_y_axis ? -1 : 1) * start.bulge;
2275
- if (bulge > 0) {
2276
- pour_builder.add(
2277
- "set_movement_mode_to_counterclockwise_circular",
2278
- {}
2279
- );
2280
- } else {
2281
- pour_builder.add(
2282
- "set_movement_mode_to_clockwise_circular",
2283
- {}
2284
- );
2285
- }
2286
- const p1 = { x: start.x, y: start.y };
2287
- const p2 = { x: end.x, y: end.y };
2288
- const dx = p2.x - p1.x;
2289
- const dy = p2.y - p1.y;
2290
- const d = Math.sqrt(dx * dx + dy * dy);
2291
- if (d < 1e-9) {
2292
- pour_builder.add("set_movement_mode_to_linear", {});
2293
- pour_builder.add("plot_operation", {
2294
- x: end.x,
2295
- y: mfy(end.y)
2296
- });
2297
- continue;
2298
- }
2299
- const abs_b = Math.abs(bulge);
2300
- const theta = 4 * Math.atan(abs_b);
2301
- if (Math.abs(Math.sin(theta / 2)) < 1e-9) {
2302
- pour_builder.add("set_movement_mode_to_linear", {});
2303
- pour_builder.add("plot_operation", {
2304
- x: end.x,
2305
- y: mfy(end.y)
2306
- });
2307
- continue;
2308
- }
2309
- const R = d / (2 * Math.sin(theta / 2));
2310
- const alpha = (Math.PI - theta) / 2;
2311
- const phi = Math.atan2(dy, dx);
2312
- const delta_angle = bulge > 0 ? alpha : -alpha;
2313
- const angle_p1_center = phi + delta_angle;
2314
- const Cx = p1.x + R * Math.cos(angle_p1_center);
2315
- const Cy = p1.y + R * Math.sin(angle_p1_center);
2316
- const i_offset = Cx - p1.x;
2317
- const j_offset = Cy - p1.y;
2318
- pour_builder.add("plot_operation", {
2319
- x: end.x,
2320
- y: mfy(end.y),
2321
- i: i_offset,
2322
- j: opts.flip_y_axis ? -j_offset : j_offset
2323
- });
2324
- } else {
2325
- pour_builder.add("set_movement_mode_to_linear", {});
2326
- pour_builder.add("plot_operation", { x: end.x, y: mfy(end.y) });
2327
- }
2328
- }
2329
- };
2330
- const reverseRing = (ring) => {
2331
- const { vertices } = ring;
2332
- if (!vertices || vertices.length === 0) return { vertices: [] };
2333
- const n = vertices.length;
2334
- const reversed_pts = [...vertices].reverse();
2335
- const new_vertices = reversed_pts.map((pt, i) => {
2336
- const bulge_v_idx = (n - 2 - i + n) % n;
2337
- const bulge = vertices[bulge_v_idx].bulge;
2338
- return { ...pt, bulge: bulge ? -bulge : void 0 };
2339
- });
2340
- return { vertices: new_vertices };
2341
- };
2342
- drawRing(reverseRing(outer_ring));
2343
- if (inner_rings) {
2344
- for (const inner_ring of inner_rings) {
2345
- drawRing(reverseRing(inner_ring));
2346
- }
2347
- }
2348
- } else if (element.shape === "rect") {
2349
- const { center, width, height, rotation } = element;
2350
- const w = width / 2;
2351
- const h = height / 2;
2352
- const points = [
2353
- { x: -w, y: h },
2354
- // Top-left
2355
- { x: w, y: h },
2356
- // Top-right
2357
- { x: w, y: -h },
2358
- // Bottom-right
2359
- { x: -w, y: -h }
2360
- // Bottom-left
2361
- ];
2362
- let transformMatrix = identity();
2363
- if (rotation) {
2364
- const angle_rad = rotation * Math.PI / 180;
2365
- transformMatrix = rotate(angle_rad);
2366
- }
2367
- transformMatrix = compose(
2368
- translate(center.x, center.y),
2369
- transformMatrix
2370
- );
2371
- const transformedPoints = points.map(
2372
- (p) => applyToPoint(transformMatrix, p)
2373
- );
2374
- pour_builder.add("move_operation", {
2375
- x: transformedPoints[0].x,
2376
- y: mfy(transformedPoints[0].y)
2377
- });
2378
- for (let i = 1; i < transformedPoints.length; i++) {
2379
- pour_builder.add("plot_operation", {
2380
- x: transformedPoints[i].x,
2381
- y: mfy(transformedPoints[i].y)
2382
- });
2383
- }
2384
- pour_builder.add("plot_operation", {
2385
- x: transformedPoints[0].x,
2386
- y: mfy(transformedPoints[0].y)
2387
- });
2388
- } else if (element.shape === "polygon") {
2389
- const { points } = element;
2390
- if (points.length > 0) {
2391
- pour_builder.add("move_operation", {
2392
- x: points[0].x,
2393
- y: mfy(points[0].y)
2394
- });
2395
- for (let i = 1; i < points.length; i++) {
2396
- pour_builder.add("plot_operation", {
2397
- x: points[i].x,
2398
- y: mfy(points[i].y)
2399
- });
2400
- }
2401
- pour_builder.add("plot_operation", {
2402
- x: points[0].x,
2403
- y: mfy(points[0].y)
2404
- });
2405
- }
2406
- }
2407
- pour_builder.add("end_region_statement", {});
2408
- const pour_commands = pour_builder.build();
2409
- copper_glayer.push(...pour_commands);
2410
- if (element.covered_with_solder_mask === false) {
2411
- const mask_layer = glayers[getGerberLayerName(layer, "soldermask")];
2412
- mask_layer.push(...pour_commands);
2413
- }
2414
2427
  }
2415
2428
  }
2416
2429
  }
@@ -2432,4 +2445,4 @@ export {
2432
2445
  stringifyGerberCommands,
2433
2446
  convertSoupToGerberCommands
2434
2447
  };
2435
- //# sourceMappingURL=chunk-WSRKOLQZ.js.map
2448
+ //# sourceMappingURL=chunk-VM5XFQ53.js.map