circuit-json-to-kicad 0.0.15 → 0.0.17

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.
Files changed (2) hide show
  1. package/dist/index.js +197 -50
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -823,7 +823,8 @@ import {
823
823
  SymbolInstancePath as SymbolInstancePath2,
824
824
  TextEffects as TextEffects3,
825
825
  TextEffectsFont as TextEffectsFont3,
826
- Label
826
+ TextEffectsJustify as TextEffectsJustify2,
827
+ GlobalLabel
827
828
  } from "kicadts";
828
829
  import { applyToPoint as applyToPoint3 } from "transformation-matrix";
829
830
  var AddSchematicNetLabelsStage = class extends ConverterStage {
@@ -839,7 +840,7 @@ var AddSchematicNetLabelsStage = class extends ConverterStage {
839
840
  return;
840
841
  }
841
842
  const symbols3 = [];
842
- const labels = [];
843
+ const globalLabels = [];
843
844
  for (const netLabel of netLabels) {
844
845
  const labelText = netLabel.text || "";
845
846
  const symbolName = netLabel.symbol_name;
@@ -853,9 +854,9 @@ var AddSchematicNetLabelsStage = class extends ConverterStage {
853
854
  symbols3.push(symbol);
854
855
  }
855
856
  } else {
856
- const label = this.createLabel(netLabel, labelText);
857
+ const label = this.createGlobalLabel(netLabel, labelText);
857
858
  if (label) {
858
- labels.push(label);
859
+ globalLabels.push(label);
859
860
  }
860
861
  }
861
862
  }
@@ -863,20 +864,24 @@ var AddSchematicNetLabelsStage = class extends ConverterStage {
863
864
  const existingSymbols = kicadSch.symbols || [];
864
865
  kicadSch.symbols = [...existingSymbols, ...symbols3];
865
866
  }
866
- if (kicadSch && labels.length > 0) {
867
- kicadSch.labels = [...kicadSch.labels || [], ...labels];
867
+ if (kicadSch && globalLabels.length > 0) {
868
+ kicadSch.globalLabels = [
869
+ ...kicadSch.globalLabels || [],
870
+ ...globalLabels
871
+ ];
868
872
  }
869
873
  this.finished = true;
870
874
  }
871
875
  /**
872
876
  * Create a KiCad symbol instance from a net label with a symbol_name
873
- * These are treated like regular components (e.g., rail_up, rail_down, vcc_up, ground_down)
877
+ * These are treated like power/ground symbols (e.g., vcc_up, ground_down)
878
+ * Uses anchor_position as the primary coordinate source
874
879
  */
875
880
  createSymbolFromNetLabel(netLabel, labelText, symbolName) {
876
881
  if (!this.ctx.c2kMatSch) return null;
877
882
  const { x, y } = applyToPoint3(this.ctx.c2kMatSch, {
878
- x: netLabel.center?.x || netLabel.anchor_position?.x || 0,
879
- y: netLabel.center?.y || netLabel.anchor_position?.y || 0
883
+ x: netLabel.anchor_position?.x ?? netLabel.center?.x ?? 0,
884
+ y: netLabel.anchor_position?.y ?? netLabel.center?.y ?? 0
880
885
  });
881
886
  const uuid = crypto.randomUUID();
882
887
  const symbol = new SchematicSymbol3({
@@ -954,21 +959,50 @@ var AddSchematicNetLabelsStage = class extends ConverterStage {
954
959
  return symbol;
955
960
  }
956
961
  /**
957
- * Create a KiCad label from a schematic_net_label without a symbol
962
+ * Create a KiCad global label from a schematic_net_label without a symbol_name
963
+ * Uses anchor_position as the primary coordinate source for the arrow anchor point
958
964
  */
959
- createLabel(netLabel, labelText) {
960
- if (!this.ctx.c2kMatSch) return null;
965
+ createGlobalLabel(netLabel, labelText) {
966
+ if (!this.ctx.c2kMatSch || !this.ctx.kicadSch) return null;
961
967
  const { x, y } = applyToPoint3(this.ctx.c2kMatSch, {
962
- x: netLabel.center?.x || netLabel.anchor_position?.x || 0,
963
- y: netLabel.center?.y || netLabel.anchor_position?.y || 0
968
+ x: netLabel.anchor_position?.x ?? netLabel.center?.x ?? 0,
969
+ y: netLabel.anchor_position?.y ?? netLabel.center?.y ?? 0
964
970
  });
965
- const label = new Label({
971
+ const anchorSide = netLabel.anchor_side || "left";
972
+ const angleMap = {
973
+ left: 0,
974
+ // Anchor on left, arrow points right
975
+ right: 180,
976
+ // Anchor on right, arrow points left
977
+ top: 270,
978
+ // Anchor on top, arrow points down
979
+ bottom: 90
980
+ // Anchor on bottom, arrow points up
981
+ };
982
+ const angle = angleMap[anchorSide] || 0;
983
+ const justifyMap = {
984
+ left: { horizontal: "left" },
985
+ // Anchor on left, text on left
986
+ right: { horizontal: "right" },
987
+ // Anchor on right, text on right
988
+ top: { vertical: "top" },
989
+ // Anchor on top, text on top
990
+ bottom: { vertical: "bottom" }
991
+ // Anchor on bottom, text on bottom
992
+ };
993
+ const justify = justifyMap[anchorSide] || {};
994
+ const effects = this.createTextEffects(1.27, false);
995
+ if (Object.keys(justify).length > 0) {
996
+ effects.justify = new TextEffectsJustify2(justify);
997
+ }
998
+ const globalLabel = new GlobalLabel({
966
999
  value: labelText,
967
- at: [x, y, 0],
968
- effects: this.createTextEffects(1.27, false),
969
- uuid: crypto.randomUUID()
1000
+ at: [x, y, angle],
1001
+ effects,
1002
+ uuid: crypto.randomUUID(),
1003
+ fieldsAutoplaced: true
970
1004
  });
971
- return label;
1005
+ return globalLabel;
972
1006
  }
973
1007
  /**
974
1008
  * Creates text effects for properties and labels
@@ -1315,8 +1349,133 @@ var AddNetsStage = class extends ConverterStage {
1315
1349
  };
1316
1350
 
1317
1351
  // lib/pcb/stages/AddFootprintsStage.ts
1318
- import { Footprint, FpText, FootprintPad } from "kicadts";
1352
+ import { Footprint, FpText } from "kicadts";
1319
1353
  import { applyToPoint as applyToPoint5 } from "transformation-matrix";
1354
+
1355
+ // lib/pcb/stages/utils/CreateSmdPadFromCircuitJson.ts
1356
+ import { FootprintPad } from "kicadts";
1357
+ function createSmdPadFromCircuitJson({
1358
+ pcbPad,
1359
+ componentCenter,
1360
+ padNumber
1361
+ }) {
1362
+ if (!("x" in pcbPad && "y" in pcbPad)) {
1363
+ throw new Error("no support for polygon pads (or any pads w/o X/Y) yet");
1364
+ }
1365
+ const relativeX = pcbPad.x - componentCenter.x;
1366
+ const relativeY = pcbPad.y - componentCenter.y;
1367
+ const layerMap = {
1368
+ top: "F.Cu",
1369
+ bottom: "B.Cu"
1370
+ };
1371
+ const padLayer = layerMap[pcbPad.layer] || "F.Cu";
1372
+ const padShape = pcbPad.shape === "circle" ? "circle" : "rect";
1373
+ const padSize = pcbPad.shape === "circle" ? [
1374
+ "radius" in pcbPad ? pcbPad.radius * 2 : 0.5,
1375
+ "radius" in pcbPad ? pcbPad.radius * 2 : 0.5
1376
+ ] : [
1377
+ "width" in pcbPad ? pcbPad.width : 0.5,
1378
+ "height" in pcbPad ? pcbPad.height : 0.5
1379
+ ];
1380
+ return new FootprintPad({
1381
+ number: String(padNumber),
1382
+ padType: "smd",
1383
+ shape: padShape,
1384
+ at: [relativeX, relativeY, 0],
1385
+ size: padSize,
1386
+ layers: [
1387
+ `${padLayer}`,
1388
+ `${padLayer === "F.Cu" ? "F" : "B"}.Paste`,
1389
+ `${padLayer === "F.Cu" ? "F" : "B"}.Mask`
1390
+ ],
1391
+ uuid: crypto.randomUUID()
1392
+ });
1393
+ }
1394
+
1395
+ // lib/pcb/stages/utils/CreateThruHolePadFromCircuitJson.ts
1396
+ import { FootprintPad as FootprintPad2, PadDrill } from "kicadts";
1397
+ function createThruHolePadFromCircuitJson({
1398
+ platedHole,
1399
+ componentCenter,
1400
+ padNumber
1401
+ }) {
1402
+ if (!("x" in platedHole && "y" in platedHole)) {
1403
+ return null;
1404
+ }
1405
+ const relativeX = platedHole.x - componentCenter.x;
1406
+ const relativeY = platedHole.y - componentCenter.y;
1407
+ let padShape = "circle";
1408
+ let padSize;
1409
+ let drill;
1410
+ let rotation = 0;
1411
+ if (platedHole.shape === "circle") {
1412
+ padShape = "circle";
1413
+ padSize = [platedHole.outer_diameter, platedHole.outer_diameter];
1414
+ drill = new PadDrill({
1415
+ diameter: platedHole.hole_diameter
1416
+ });
1417
+ } else if (platedHole.shape === "pill" || platedHole.shape === "oval") {
1418
+ padShape = "oval";
1419
+ padSize = [
1420
+ platedHole.outer_width,
1421
+ platedHole.outer_height
1422
+ ];
1423
+ drill = new PadDrill({
1424
+ oval: true,
1425
+ diameter: platedHole.hole_width,
1426
+ width: platedHole.hole_height
1427
+ });
1428
+ } else if (platedHole.shape === "pill_hole_with_rect_pad") {
1429
+ padShape = "rect";
1430
+ padSize = [
1431
+ platedHole.rect_pad_width,
1432
+ platedHole.rect_pad_height
1433
+ ];
1434
+ drill = new PadDrill({
1435
+ oval: true,
1436
+ diameter: platedHole.hole_width,
1437
+ width: platedHole.hole_height
1438
+ });
1439
+ } else if (platedHole.shape === "circular_hole_with_rect_pad") {
1440
+ padShape = "rect";
1441
+ padSize = [
1442
+ platedHole.rect_pad_width,
1443
+ platedHole.rect_pad_height
1444
+ ];
1445
+ drill = new PadDrill({
1446
+ diameter: platedHole.hole_diameter
1447
+ });
1448
+ } else if (platedHole.shape === "rotated_pill_hole_with_rect_pad") {
1449
+ padShape = "rect";
1450
+ padSize = [
1451
+ platedHole.rect_pad_width,
1452
+ platedHole.rect_pad_height
1453
+ ];
1454
+ drill = new PadDrill({
1455
+ oval: true,
1456
+ diameter: platedHole.hole_width,
1457
+ width: platedHole.hole_height
1458
+ });
1459
+ rotation = platedHole.rect_ccw_rotation || 0;
1460
+ } else {
1461
+ padShape = "circle";
1462
+ padSize = [1.6, 1.6];
1463
+ drill = new PadDrill({ diameter: 0.8 });
1464
+ }
1465
+ return new FootprintPad2({
1466
+ number: String(padNumber),
1467
+ padType: "thru_hole",
1468
+ shape: padShape,
1469
+ at: [relativeX, relativeY, rotation],
1470
+ size: padSize,
1471
+ drill,
1472
+ layers: ["*.Cu", "*.Mask"],
1473
+ removeUnusedLayers: false,
1474
+ uuid: crypto.randomUUID()
1475
+ });
1476
+ }
1477
+
1478
+ // lib/pcb/stages/AddFootprintsStage.ts
1320
1479
  var AddFootprintsStage = class extends ConverterStage {
1321
1480
  componentsProcessed = 0;
1322
1481
  pcbComponents = [];
@@ -1374,40 +1533,28 @@ var AddFootprintsStage = class extends ConverterStage {
1374
1533
  const fpPads = footprint.fpPads;
1375
1534
  let padNumber = 1;
1376
1535
  for (const pcbPad of pcbPads) {
1377
- if (!("x" in pcbPad && "y" in pcbPad)) {
1378
- throw new Error("no support for polygon pads (or any pads w/o X/Y) yet");
1379
- }
1380
- const relativeX = pcbPad.x - component.center.x;
1381
- const relativeY = pcbPad.y - component.center.y;
1382
- const layerMap = {
1383
- top: "F.Cu",
1384
- bottom: "B.Cu"
1385
- };
1386
- const padLayer = layerMap[pcbPad.layer] || "F.Cu";
1387
- const padShape = pcbPad.shape === "circle" ? "circle" : "rect";
1388
- const padSize = pcbPad.shape === "circle" ? [
1389
- "radius" in pcbPad ? pcbPad.radius * 2 : 0.5,
1390
- "radius" in pcbPad ? pcbPad.radius * 2 : 0.5
1391
- ] : [
1392
- "width" in pcbPad ? pcbPad.width : 0.5,
1393
- "height" in pcbPad ? pcbPad.height : 0.5
1394
- ];
1395
- const pad = new FootprintPad({
1396
- number: String(padNumber),
1397
- padType: "smd",
1398
- shape: padShape,
1399
- at: [relativeX, relativeY, 0],
1400
- size: padSize,
1401
- layers: [
1402
- `${padLayer}`,
1403
- `${padLayer === "F.Cu" ? "F" : "B"}.Paste`,
1404
- `${padLayer === "F.Cu" ? "F" : "B"}.Mask`
1405
- ],
1406
- uuid: crypto.randomUUID()
1536
+ const pad = createSmdPadFromCircuitJson({
1537
+ pcbPad,
1538
+ componentCenter: component.center,
1539
+ padNumber
1407
1540
  });
1408
1541
  fpPads.push(pad);
1409
1542
  padNumber++;
1410
1543
  }
1544
+ const pcbPlatedHoles = this.ctx.db.pcb_plated_hole?.list().filter(
1545
+ (hole) => hole.pcb_component_id === component.pcb_component_id
1546
+ ) || [];
1547
+ for (const platedHole of pcbPlatedHoles) {
1548
+ const pad = createThruHolePadFromCircuitJson({
1549
+ platedHole,
1550
+ componentCenter: component.center,
1551
+ padNumber
1552
+ });
1553
+ if (pad) {
1554
+ fpPads.push(pad);
1555
+ padNumber++;
1556
+ }
1557
+ }
1411
1558
  footprint.fpPads = fpPads;
1412
1559
  const footprints = kicadPcb.footprints;
1413
1560
  footprints.push(footprint);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "circuit-json-to-kicad",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.15",
4
+ "version": "0.0.17",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -20,7 +20,7 @@
20
20
  "@types/bun": "latest",
21
21
  "circuit-json": "^0.0.267",
22
22
  "circuit-to-svg": "^0.0.208",
23
- "kicadts": "^0.0.9",
23
+ "kicadts": "^0.0.10",
24
24
  "schematic-symbols": "^0.0.202",
25
25
  "sharp": "^0.34.4",
26
26
  "transformation-matrix": "^3.1.0",