circuit-json-to-gerber 0.0.59 → 0.0.61

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.
@@ -395,6 +395,35 @@ var getFileFunctionLayerSpan = ({
395
395
  const span = normalizeLayerSpan(requestedLayerSpan, layerCount);
396
396
  return `Plated,${getLayerNumber(span.from_layer, layerCount)},${getLayerNumber(span.to_layer, layerCount)},PTH`;
397
397
  };
398
+ var getTraceRouteViaElements = (circuitJson) => {
399
+ const routeVias = [];
400
+ for (const element of circuitJson) {
401
+ if (element.type !== "pcb_trace") {
402
+ continue;
403
+ }
404
+ for (const [index, point] of element.route.entries()) {
405
+ if (point.route_type !== "via" || typeof point.hole_diameter !== "number" || typeof point.outer_diameter !== "number") {
406
+ continue;
407
+ }
408
+ routeVias.push({
409
+ type: "pcb_via",
410
+ pcb_via_id: `${element.pcb_trace_id}_route_via_${index}`,
411
+ x: point.x,
412
+ y: point.y,
413
+ hole_diameter: point.hole_diameter,
414
+ outer_diameter: point.outer_diameter,
415
+ from_layer: point.from_layer,
416
+ to_layer: point.to_layer,
417
+ layers: [point.from_layer, point.to_layer]
418
+ });
419
+ }
420
+ }
421
+ return routeVias;
422
+ };
423
+ var getDrillableElements = (circuitJson) => [
424
+ ...circuitJson,
425
+ ...getTraceRouteViaElements(circuitJson)
426
+ ];
398
427
  var convertSoupToExcellonDrillCommands = ({
399
428
  circuitJson,
400
429
  is_plated,
@@ -403,6 +432,7 @@ var convertSoupToExcellonDrillCommands = ({
403
432
  }) => {
404
433
  const builder = excellonDrill();
405
434
  const layerCount = getLayerCount(circuitJson);
435
+ const drillableElements = getDrillableElements(circuitJson);
406
436
  builder.add("M48", {});
407
437
  const date_str = (/* @__PURE__ */ new Date()).toISOString();
408
438
  builder.add("header_comment", {
@@ -425,7 +455,7 @@ var convertSoupToExcellonDrillCommands = ({
425
455
  }).add("FMAT", { format: 2 }).add("unit_format", { unit: "METRIC", lz: null });
426
456
  let tool_counter = 10;
427
457
  const diameterToToolNumber = {};
428
- for (const element of circuitJson) {
458
+ for (const element of drillableElements) {
429
459
  if (!shouldIncludeElement({
430
460
  element,
431
461
  is_plated,
@@ -453,7 +483,7 @@ var convertSoupToExcellonDrillCommands = ({
453
483
  builder.add("G05", {});
454
484
  for (let i = 10; i < tool_counter; i++) {
455
485
  builder.add("use_tool", { tool_number: i });
456
- for (const element of circuitJson) {
486
+ for (const element of drillableElements) {
457
487
  if (element.type === "pcb_plated_hole" || element.type === "pcb_hole" || element.type === "pcb_via") {
458
488
  if (!shouldIncludeElement({
459
489
  element,
@@ -540,13 +570,15 @@ var convertSoupToExcellonDrillCommandLayers = ({
540
570
  }) => {
541
571
  const layerCount = getLayerCount(circuitJson);
542
572
  const platedSpans = new Map(
543
- circuitJson.flatMap((element) => {
544
- const span = getPlatedElementLayerSpan(element, layerCount);
545
- if (!span) {
546
- return [];
573
+ getDrillableElements(circuitJson).flatMap(
574
+ (element) => {
575
+ const span = getPlatedElementLayerSpan(element, layerCount);
576
+ if (!span) {
577
+ return [];
578
+ }
579
+ return [[getDrillLayerSpanKey(span, layerCount), span]];
547
580
  }
548
- return [[getDrillLayerSpanKey(span, layerCount), span]];
549
- })
581
+ )
550
582
  );
551
583
  const platedDrillLayers = Object.fromEntries(
552
584
  [...platedSpans.entries()].sort().map(([spanKey, span]) => [
@@ -1347,10 +1379,11 @@ function defineAperturesForLayer({
1347
1379
  }).build()
1348
1380
  );
1349
1381
  }
1350
- const apertureConfigs = getAllApertureTemplateConfigsForLayer(
1382
+ const apertureConfigs = getAllApertureTemplateConfigsForLayer({
1351
1383
  circuitJson,
1352
- layerRef
1353
- );
1384
+ layer: layerRef,
1385
+ glayer_name
1386
+ });
1354
1387
  for (const apertureConfig of apertureConfigs) {
1355
1388
  glayer.push(
1356
1389
  ...gerberBuilder().add("define_aperture_template", {
@@ -1389,6 +1422,36 @@ var getApertureConfigFromPcbSmtpad = (elm) => {
1389
1422
  }
1390
1423
  throw new Error(`Unsupported shape ${elm.shape}`);
1391
1424
  };
1425
+ var getApertureConfigFromPcbSmtpadSoldermask = (elm) => {
1426
+ let soldermaskMargin = 0;
1427
+ if ("soldermask_margin" in elm && typeof elm.soldermask_margin === "number") {
1428
+ soldermaskMargin = elm.soldermask_margin;
1429
+ }
1430
+ if (elm.shape === "rect") {
1431
+ return {
1432
+ standard_template_code: "R",
1433
+ x_size: elm.width + soldermaskMargin * 2,
1434
+ y_size: elm.height + soldermaskMargin * 2
1435
+ };
1436
+ }
1437
+ if (elm.shape === "circle") {
1438
+ return {
1439
+ standard_template_code: "C",
1440
+ diameter: elm.radius * 2 + soldermaskMargin * 2
1441
+ };
1442
+ }
1443
+ if (elm.shape === "rotated_rect") {
1444
+ return {
1445
+ standard_template_code: "R",
1446
+ x_size: elm.width + soldermaskMargin * 2,
1447
+ y_size: elm.height + soldermaskMargin * 2
1448
+ };
1449
+ }
1450
+ if (elm.shape === "polygon") {
1451
+ throw new Error("Polygon SMT pads are drawn as regions, not apertures");
1452
+ }
1453
+ throw new Error(`Unsupported shape ${elm.shape}`);
1454
+ };
1392
1455
  var getApertureConfigFromPcbSilkscreenPath = (elm) => {
1393
1456
  if ("stroke_width" in elm) {
1394
1457
  return {
@@ -1527,10 +1590,10 @@ var getApertureConfigFromCirclePcbHole = (elm) => {
1527
1590
  diameter: elm.hole_diameter
1528
1591
  };
1529
1592
  };
1530
- var getApertureConfigFromPcbVia = (elm) => {
1531
- if (!("outer_diameter" in elm)) {
1593
+ var getApertureConfigFromOuterDiameter = (elm) => {
1594
+ if (typeof elm.outer_diameter !== "number") {
1532
1595
  throw new Error(
1533
- "outer_diameter not specified in getApertureConfigFromPcbVia"
1596
+ "outer_diameter not specified in getApertureConfigFromOuterDiameter"
1534
1597
  );
1535
1598
  }
1536
1599
  return {
@@ -1538,9 +1601,14 @@ var getApertureConfigFromPcbVia = (elm) => {
1538
1601
  diameter: elm.outer_diameter
1539
1602
  };
1540
1603
  };
1541
- function getAllApertureTemplateConfigsForLayer(circuitJson, layer) {
1604
+ function getAllApertureTemplateConfigsForLayer({
1605
+ circuitJson,
1606
+ layer,
1607
+ glayer_name
1608
+ }) {
1542
1609
  const configs = [];
1543
1610
  const configHashMap = /* @__PURE__ */ new Set();
1611
+ const isSoldermaskLayer = glayer_name.endsWith("_Mask");
1544
1612
  const addConfigIfNew = (config) => {
1545
1613
  const hash = stableStringify(config);
1546
1614
  if (!configHashMap.has(hash)) {
@@ -1551,7 +1619,11 @@ function getAllApertureTemplateConfigsForLayer(circuitJson, layer) {
1551
1619
  for (const elm of circuitJson) {
1552
1620
  if (elm.type === "pcb_smtpad") {
1553
1621
  if (elm.layer === layer && elm.shape !== "polygon") {
1554
- addConfigIfNew(getApertureConfigFromPcbSmtpad(elm));
1622
+ if (isSoldermaskLayer) {
1623
+ addConfigIfNew(getApertureConfigFromPcbSmtpadSoldermask(elm));
1624
+ } else {
1625
+ addConfigIfNew(getApertureConfigFromPcbSmtpad(elm));
1626
+ }
1555
1627
  }
1556
1628
  } else if (elm.type === "pcb_solder_paste") {
1557
1629
  if (elm.layer === layer) {
@@ -1568,14 +1640,26 @@ function getAllApertureTemplateConfigsForLayer(circuitJson, layer) {
1568
1640
  }
1569
1641
  } else if (elm.type === "pcb_plated_hole") {
1570
1642
  if (elm.layers.includes(layer)) {
1643
+ if (glayer_name.endsWith("_Mask") && elm.is_covered_with_solder_mask === true) {
1644
+ continue;
1645
+ }
1571
1646
  addConfigIfNew(getApertureConfigFromPcbPlatedHole(elm));
1572
1647
  }
1573
1648
  } else if (elm.type === "pcb_hole") {
1649
+ if (glayer_name.endsWith("_Mask") && elm.is_covered_with_solder_mask === true) {
1650
+ continue;
1651
+ }
1574
1652
  if (elm.hole_shape === "circle")
1575
1653
  addConfigIfNew(getApertureConfigFromCirclePcbHole(elm));
1576
1654
  else console.warn("NOT IMPLEMENTED: drawing gerber for non circle holes");
1577
1655
  } else if (elm.type === "pcb_via") {
1578
- addConfigIfNew(getApertureConfigFromPcbVia(elm));
1656
+ addConfigIfNew(getApertureConfigFromOuterDiameter(elm));
1657
+ } else if (elm.type === "pcb_trace") {
1658
+ for (const point of elm.route) {
1659
+ if (point.route_type === "via" && typeof point.outer_diameter === "number" && (point.from_layer === layer || point.to_layer === layer)) {
1660
+ addConfigIfNew(getApertureConfigFromOuterDiameter(point));
1661
+ }
1662
+ }
1579
1663
  } else if (elm.type === "pcb_silkscreen_path")
1580
1664
  addConfigIfNew(getApertureConfigFromPcbSilkscreenPath(elm));
1581
1665
  else if (elm.type === "pcb_silkscreen_text")
@@ -1614,7 +1698,7 @@ var findApertureNumber = (glayer, search_params) => {
1614
1698
  // package.json
1615
1699
  var package_default = {
1616
1700
  name: "circuit-json-to-gerber",
1617
- version: "0.0.58",
1701
+ version: "0.0.60",
1618
1702
  main: "dist/index.js",
1619
1703
  type: "module",
1620
1704
  scripts: {
@@ -2194,6 +2278,30 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2194
2278
  }).add("move_operation", { x: a.x, y: mfy(a.y) }).add("plot_operation", { x: b.x, y: mfy(b.y) }).build()
2195
2279
  );
2196
2280
  }
2281
+ } else if (a.route_type === "via" && b.route_type === "wire") {
2282
+ if (b.layer === layer) {
2283
+ const glayer = glayers[getGerberLayerName(layer, "copper")];
2284
+ glayer.push(
2285
+ ...gerberBuilder().add("select_aperture", {
2286
+ aperture_number: findApertureNumber(glayer, {
2287
+ trace_width: b.width
2288
+ })
2289
+ }).add("move_operation", { x: a.x, y: mfy(a.y) }).add("plot_operation", { x: b.x, y: mfy(b.y) }).build()
2290
+ );
2291
+ }
2292
+ }
2293
+ }
2294
+ for (const point of route) {
2295
+ if (point.route_type === "via" && typeof point.outer_diameter === "number" && (point.from_layer === layer || point.to_layer === layer)) {
2296
+ const glayer = glayers[getGerberLayerName(layer, "copper")];
2297
+ glayer.push(
2298
+ ...gerberBuilder().add("select_aperture", {
2299
+ aperture_number: findApertureNumber(
2300
+ glayer,
2301
+ getApertureConfigFromOuterDiameter(point)
2302
+ )
2303
+ }).add("flash_operation", { x: point.x, y: mfy(point.y) }).build()
2304
+ );
2197
2305
  }
2198
2306
  }
2199
2307
  } else if (element.type === "pcb_silkscreen_path" && outerLayerRefs.includes(layer)) {
@@ -2233,11 +2341,16 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2233
2341
  );
2234
2342
  } else if (element.type === "pcb_smtpad" && element.shape !== "polygon") {
2235
2343
  if (element.layer === layer && outerLayerRefs.includes(layer)) {
2236
- for (const glayer of [
2237
- glayers[getGerberLayerName(layer, "copper")],
2238
- glayers[getGerberLayerName(layer, "soldermask")]
2344
+ for (const { glayer, apertureConfig } of [
2345
+ {
2346
+ glayer: glayers[getGerberLayerName(layer, "copper")],
2347
+ apertureConfig: getApertureConfigFromPcbSmtpad(element)
2348
+ },
2349
+ {
2350
+ glayer: glayers[getGerberLayerName(layer, "soldermask")],
2351
+ apertureConfig: getApertureConfigFromPcbSmtpadSoldermask(element)
2352
+ }
2239
2353
  ]) {
2240
- const apertureConfig = getApertureConfigFromPcbSmtpad(element);
2241
2354
  const apertureNumber = findApertureNumber(glayer, apertureConfig);
2242
2355
  const gb = gerberBuilder().add("select_aperture", {
2243
2356
  aperture_number: apertureNumber
@@ -2330,7 +2443,7 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2330
2443
  const layersToAddTo = [
2331
2444
  glayers[getGerberLayerName(layer, "copper")]
2332
2445
  ];
2333
- if (outerLayerRefs.includes(layer)) {
2446
+ if (outerLayerRefs.includes(layer) && element.is_covered_with_solder_mask !== true) {
2334
2447
  layersToAddTo.push(glayers[getGerberLayerName(layer, "soldermask")]);
2335
2448
  }
2336
2449
  for (const glayer of layersToAddTo) {
@@ -2438,7 +2551,7 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2438
2551
  }
2439
2552
  }
2440
2553
  } else if (element.type === "pcb_hole") {
2441
- if (outerLayerRefs.includes(layer)) {
2554
+ if (outerLayerRefs.includes(layer) && element.is_covered_with_solder_mask !== true) {
2442
2555
  for (const glayer of [
2443
2556
  glayers[getGerberLayerName(layer, "soldermask")]
2444
2557
  ]) {
@@ -2471,7 +2584,7 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
2471
2584
  ...gerberBuilder().add("select_aperture", {
2472
2585
  aperture_number: findApertureNumber(
2473
2586
  glayer,
2474
- getApertureConfigFromPcbVia(element)
2587
+ getApertureConfigFromOuterDiameter(element)
2475
2588
  )
2476
2589
  }).add("flash_operation", { x: element.x, y: mfy(element.y) }).build()
2477
2590
  );
@@ -2706,4 +2819,4 @@ export {
2706
2819
  stringifyGerberCommands,
2707
2820
  convertSoupToGerberCommands
2708
2821
  };
2709
- //# sourceMappingURL=chunk-GEJL7TY6.js.map
2822
+ //# sourceMappingURL=chunk-KJYUL256.js.map