circuit-json-to-kicad 0.0.22 → 0.0.24
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.
- package/dist/index.d.ts +9 -0
- package/dist/index.js +129 -40
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,13 @@ import { CircuitJsonUtilObjects, cju } from '@tscircuit/circuit-json-util';
|
|
|
3
3
|
import { KicadSch, KicadPcb } from 'kicadts';
|
|
4
4
|
import { Matrix } from 'transformation-matrix';
|
|
5
5
|
|
|
6
|
+
type PaperSize = "A0" | "A1" | "A2" | "A3" | "A4" | "A5";
|
|
7
|
+
interface PaperDimensions {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
name: PaperSize;
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
type SchematicPortId = string;
|
|
7
14
|
type SchematicTraceId = string;
|
|
8
15
|
type PcbPortId = string;
|
|
@@ -15,6 +22,8 @@ interface ConverterContext {
|
|
|
15
22
|
c2kMatSch?: Matrix;
|
|
16
23
|
/** Circuit JSON to KiCad PCB transformation matrix */
|
|
17
24
|
c2kMatPcb?: Matrix;
|
|
25
|
+
/** Selected paper size for schematic */
|
|
26
|
+
schematicPaperSize?: PaperDimensions;
|
|
18
27
|
pinPositions?: Map<SchematicPortId, {
|
|
19
28
|
x: number;
|
|
20
29
|
y: number;
|
package/dist/index.js
CHANGED
|
@@ -38,13 +38,13 @@ import { compose, translate, scale } from "transformation-matrix";
|
|
|
38
38
|
import { Paper, Uuid } from "kicadts";
|
|
39
39
|
var InitializeSchematicStage = class extends ConverterStage {
|
|
40
40
|
_step() {
|
|
41
|
-
const { kicadSch } = this.ctx;
|
|
41
|
+
const { kicadSch, schematicPaperSize } = this.ctx;
|
|
42
42
|
if (!kicadSch) {
|
|
43
43
|
throw new Error("KicadSch instance not initialized in context");
|
|
44
44
|
}
|
|
45
45
|
kicadSch.version = 20250114;
|
|
46
46
|
const paper = new Paper();
|
|
47
|
-
paper.size = "A4";
|
|
47
|
+
paper.size = schematicPaperSize?.name ?? "A4";
|
|
48
48
|
kicadSch.paper = paper;
|
|
49
49
|
kicadSch.uuid = new Uuid(crypto.randomUUID());
|
|
50
50
|
this.finished = true;
|
|
@@ -399,14 +399,14 @@ var AddLibrarySymbolsStage = class extends ConverterStage {
|
|
|
399
399
|
*/
|
|
400
400
|
createPolylineFromPoints({
|
|
401
401
|
points,
|
|
402
|
-
scale:
|
|
402
|
+
scale: scale4,
|
|
403
403
|
center,
|
|
404
404
|
fillType
|
|
405
405
|
}) {
|
|
406
406
|
const polyline = new SymbolPolyline();
|
|
407
407
|
const cx = center?.x ?? 0;
|
|
408
408
|
const cy = center?.y ?? 0;
|
|
409
|
-
const scaleMatrix = createScaleMatrix(
|
|
409
|
+
const scaleMatrix = createScaleMatrix(scale4, scale4);
|
|
410
410
|
const xyPoints = points.map((p) => {
|
|
411
411
|
const translated = applyToPoint(scaleMatrix, { x: p.x - cx, y: p.y - cy });
|
|
412
412
|
return new Xy(translated.x, translated.y);
|
|
@@ -1184,6 +1184,26 @@ function getSchematicBoundsAndCenter(db) {
|
|
|
1184
1184
|
};
|
|
1185
1185
|
}
|
|
1186
1186
|
|
|
1187
|
+
// lib/schematic/selectSchematicPaperSize.ts
|
|
1188
|
+
var PAPER_SIZES = [
|
|
1189
|
+
{ name: "A4", width: 297, height: 210 },
|
|
1190
|
+
{ name: "A3", width: 420, height: 297 },
|
|
1191
|
+
{ name: "A2", width: 594, height: 420 },
|
|
1192
|
+
{ name: "A1", width: 841, height: 594 },
|
|
1193
|
+
{ name: "A0", width: 1189, height: 841 }
|
|
1194
|
+
];
|
|
1195
|
+
function selectSchematicPaperSize(contentWidth, contentHeight, paddingMm = 20) {
|
|
1196
|
+
const requiredWidth = contentWidth + 2 * paddingMm;
|
|
1197
|
+
const requiredHeight = contentHeight + 2 * paddingMm;
|
|
1198
|
+
for (let i = 0; i < PAPER_SIZES.length; i++) {
|
|
1199
|
+
const paperSize = PAPER_SIZES[i];
|
|
1200
|
+
if (requiredWidth <= paperSize.width && requiredHeight <= paperSize.height) {
|
|
1201
|
+
return paperSize;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
return PAPER_SIZES[PAPER_SIZES.length - 1];
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1187
1207
|
// lib/schematic/CircuitJsonToKicadSchConverter.ts
|
|
1188
1208
|
var CircuitJsonToKicadSchConverter = class {
|
|
1189
1209
|
ctx;
|
|
@@ -1195,10 +1215,16 @@ var CircuitJsonToKicadSchConverter = class {
|
|
|
1195
1215
|
}
|
|
1196
1216
|
constructor(circuitJson) {
|
|
1197
1217
|
const CIRCUIT_JSON_SCALE_FACTOR = 15;
|
|
1198
|
-
const KICAD_CENTER_Y = 105;
|
|
1199
|
-
const KICAD_CENTER_X = 148.5;
|
|
1200
1218
|
const db = cju(circuitJson);
|
|
1201
|
-
const { center } = getSchematicBoundsAndCenter(db);
|
|
1219
|
+
const { center, bounds } = getSchematicBoundsAndCenter(db);
|
|
1220
|
+
const schematicWidthMm = (bounds.maxX - bounds.minX) * CIRCUIT_JSON_SCALE_FACTOR;
|
|
1221
|
+
const schematicHeightMm = (bounds.maxY - bounds.minY) * CIRCUIT_JSON_SCALE_FACTOR;
|
|
1222
|
+
const paperSize = selectSchematicPaperSize(
|
|
1223
|
+
schematicWidthMm,
|
|
1224
|
+
schematicHeightMm
|
|
1225
|
+
);
|
|
1226
|
+
const KICAD_CENTER_X = paperSize.width / 2;
|
|
1227
|
+
const KICAD_CENTER_Y = paperSize.height / 2;
|
|
1202
1228
|
this.ctx = {
|
|
1203
1229
|
db,
|
|
1204
1230
|
circuitJson,
|
|
@@ -1206,6 +1232,7 @@ var CircuitJsonToKicadSchConverter = class {
|
|
|
1206
1232
|
generator: "circuit-json-to-kicad",
|
|
1207
1233
|
generatorVersion: "0.0.1"
|
|
1208
1234
|
}),
|
|
1235
|
+
schematicPaperSize: paperSize,
|
|
1209
1236
|
c2kMatSch: compose(
|
|
1210
1237
|
translate(KICAD_CENTER_X, KICAD_CENTER_Y),
|
|
1211
1238
|
scale(CIRCUIT_JSON_SCALE_FACTOR, -CIRCUIT_JSON_SCALE_FACTOR),
|
|
@@ -1250,7 +1277,7 @@ var CircuitJsonToKicadSchConverter = class {
|
|
|
1250
1277
|
// lib/pcb/CircuitJsonToKicadPcbConverter.ts
|
|
1251
1278
|
import { KicadPcb } from "kicadts";
|
|
1252
1279
|
import { cju as cju2 } from "@tscircuit/circuit-json-util";
|
|
1253
|
-
import { compose as
|
|
1280
|
+
import { compose as compose3, translate as translate3, scale as scale3 } from "transformation-matrix";
|
|
1254
1281
|
|
|
1255
1282
|
// lib/pcb/stages/InitializePcbStage.ts
|
|
1256
1283
|
import {
|
|
@@ -1353,38 +1380,93 @@ import { Footprint } from "kicadts";
|
|
|
1353
1380
|
import { applyToPoint as applyToPoint9 } from "transformation-matrix";
|
|
1354
1381
|
|
|
1355
1382
|
// lib/pcb/stages/utils/CreateSmdPadFromCircuitJson.ts
|
|
1356
|
-
import {
|
|
1357
|
-
|
|
1383
|
+
import {
|
|
1384
|
+
FootprintPad,
|
|
1385
|
+
PadPrimitives,
|
|
1386
|
+
PadPrimitiveGrPoly,
|
|
1387
|
+
Pts as Pts3,
|
|
1388
|
+
Xy as Xy3,
|
|
1389
|
+
PadOptions
|
|
1390
|
+
} from "kicadts";
|
|
1391
|
+
import {
|
|
1392
|
+
applyToPoint as applyToPoint5,
|
|
1393
|
+
compose as compose2,
|
|
1394
|
+
translate as translate2,
|
|
1395
|
+
scale as scale2,
|
|
1396
|
+
rotate
|
|
1397
|
+
} from "transformation-matrix";
|
|
1358
1398
|
function createSmdPadFromCircuitJson({
|
|
1359
1399
|
pcbPad,
|
|
1360
1400
|
componentCenter,
|
|
1361
1401
|
padNumber,
|
|
1362
1402
|
componentRotation = 0
|
|
1363
1403
|
}) {
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
x
|
|
1372
|
-
y
|
|
1404
|
+
let padX;
|
|
1405
|
+
let padY;
|
|
1406
|
+
if ("x" in pcbPad && "y" in pcbPad) {
|
|
1407
|
+
padX = pcbPad.x;
|
|
1408
|
+
padY = pcbPad.y;
|
|
1409
|
+
} else if ("points" in pcbPad && Array.isArray(pcbPad.points)) {
|
|
1410
|
+
const points = pcbPad.points;
|
|
1411
|
+
padX = points.reduce((sum, p) => sum + p.x, 0) / points.length;
|
|
1412
|
+
padY = points.reduce((sum, p) => sum + p.y, 0) / points.length;
|
|
1413
|
+
} else {
|
|
1414
|
+
throw new Error("Pad must have either x/y coordinates or points array");
|
|
1415
|
+
}
|
|
1416
|
+
const cj2kicadMatrix = compose2(
|
|
1417
|
+
componentRotation !== 0 ? rotate(componentRotation * Math.PI / 180) : { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 },
|
|
1418
|
+
scale2(1, -1),
|
|
1419
|
+
// Flip Y-axis
|
|
1420
|
+
translate2(-componentCenter.x, -componentCenter.y)
|
|
1421
|
+
);
|
|
1422
|
+
const rotatedPos = applyToPoint5(cj2kicadMatrix, {
|
|
1423
|
+
x: padX,
|
|
1424
|
+
y: padY
|
|
1373
1425
|
});
|
|
1374
1426
|
const layerMap = {
|
|
1375
1427
|
top: "F.Cu",
|
|
1376
1428
|
bottom: "B.Cu"
|
|
1377
1429
|
};
|
|
1378
1430
|
const padLayer = layerMap[pcbPad.layer] || "F.Cu";
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
"
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1431
|
+
let padShape;
|
|
1432
|
+
let padSize;
|
|
1433
|
+
let padOptions;
|
|
1434
|
+
let padPrimitives;
|
|
1435
|
+
if (pcbPad.shape === "circle") {
|
|
1436
|
+
padShape = "circle";
|
|
1437
|
+
padSize = [
|
|
1438
|
+
"radius" in pcbPad ? pcbPad.radius * 2 : 0.5,
|
|
1439
|
+
"radius" in pcbPad ? pcbPad.radius * 2 : 0.5
|
|
1440
|
+
];
|
|
1441
|
+
} else if (pcbPad.shape === "polygon" && "points" in pcbPad) {
|
|
1442
|
+
const points = pcbPad.points;
|
|
1443
|
+
const pointTransformMatrix = compose2(
|
|
1444
|
+
scale2(1, -1),
|
|
1445
|
+
// Flip Y-axis
|
|
1446
|
+
translate2(-padX, -padY)
|
|
1447
|
+
);
|
|
1448
|
+
const relativePoints = points.map((p) => {
|
|
1449
|
+
const transformed = applyToPoint5(pointTransformMatrix, { x: p.x, y: p.y });
|
|
1450
|
+
return new Xy3(transformed.x, transformed.y);
|
|
1451
|
+
});
|
|
1452
|
+
const grPoly = new PadPrimitiveGrPoly();
|
|
1453
|
+
grPoly.contours = [new Pts3(relativePoints)];
|
|
1454
|
+
grPoly.width = 0;
|
|
1455
|
+
grPoly.filled = true;
|
|
1456
|
+
padPrimitives = new PadPrimitives();
|
|
1457
|
+
padPrimitives.addGraphic(grPoly);
|
|
1458
|
+
padShape = "custom";
|
|
1459
|
+
padOptions = new PadOptions();
|
|
1460
|
+
padOptions.anchor = "circle";
|
|
1461
|
+
padSize = [0.2, 0.2];
|
|
1462
|
+
} else {
|
|
1463
|
+
padShape = "rect";
|
|
1464
|
+
padSize = [
|
|
1465
|
+
"width" in pcbPad ? pcbPad.width : 0.5,
|
|
1466
|
+
"height" in pcbPad ? pcbPad.height : 0.5
|
|
1467
|
+
];
|
|
1468
|
+
}
|
|
1469
|
+
const pad = new FootprintPad({
|
|
1388
1470
|
number: String(padNumber),
|
|
1389
1471
|
padType: "smd",
|
|
1390
1472
|
shape: padShape,
|
|
@@ -1397,11 +1479,18 @@ function createSmdPadFromCircuitJson({
|
|
|
1397
1479
|
],
|
|
1398
1480
|
uuid: crypto.randomUUID()
|
|
1399
1481
|
});
|
|
1482
|
+
if (padOptions) {
|
|
1483
|
+
pad.options = padOptions;
|
|
1484
|
+
}
|
|
1485
|
+
if (padPrimitives) {
|
|
1486
|
+
pad.primitives = padPrimitives;
|
|
1487
|
+
}
|
|
1488
|
+
return pad;
|
|
1400
1489
|
}
|
|
1401
1490
|
|
|
1402
1491
|
// lib/pcb/stages/utils/CreateThruHolePadFromCircuitJson.ts
|
|
1403
1492
|
import { FootprintPad as FootprintPad2, PadDrill } from "kicadts";
|
|
1404
|
-
import { applyToPoint as applyToPoint6, rotate as rotate2, identity
|
|
1493
|
+
import { applyToPoint as applyToPoint6, rotate as rotate2, identity } from "transformation-matrix";
|
|
1405
1494
|
function createThruHolePadFromCircuitJson({
|
|
1406
1495
|
platedHole,
|
|
1407
1496
|
componentCenter,
|
|
@@ -1413,7 +1502,7 @@ function createThruHolePadFromCircuitJson({
|
|
|
1413
1502
|
}
|
|
1414
1503
|
const relativeX = platedHole.x - componentCenter.x;
|
|
1415
1504
|
const relativeY = -(platedHole.y - componentCenter.y);
|
|
1416
|
-
const rotationMatrix = componentRotation !== 0 ? rotate2(componentRotation * Math.PI / 180) :
|
|
1505
|
+
const rotationMatrix = componentRotation !== 0 ? rotate2(componentRotation * Math.PI / 180) : identity();
|
|
1417
1506
|
const rotatedPos = applyToPoint6(rotationMatrix, {
|
|
1418
1507
|
x: relativeX,
|
|
1419
1508
|
y: relativeY
|
|
@@ -1491,7 +1580,7 @@ function createThruHolePadFromCircuitJson({
|
|
|
1491
1580
|
|
|
1492
1581
|
// lib/pcb/stages/utils/CreateNpthPadFromCircuitJson.ts
|
|
1493
1582
|
import { FootprintPad as FootprintPad3, PadDrill as PadDrill2 } from "kicadts";
|
|
1494
|
-
import { applyToPoint as applyToPoint7, rotate as rotate3, identity as
|
|
1583
|
+
import { applyToPoint as applyToPoint7, rotate as rotate3, identity as identity2 } from "transformation-matrix";
|
|
1495
1584
|
function createNpthPadFromCircuitJson({
|
|
1496
1585
|
pcbHole,
|
|
1497
1586
|
componentCenter,
|
|
@@ -1502,7 +1591,7 @@ function createNpthPadFromCircuitJson({
|
|
|
1502
1591
|
}
|
|
1503
1592
|
const relativeX = pcbHole.x - componentCenter.x;
|
|
1504
1593
|
const relativeY = -(pcbHole.y - componentCenter.y);
|
|
1505
|
-
const rotationMatrix = componentRotation !== 0 ? rotate3(componentRotation * Math.PI / 180) :
|
|
1594
|
+
const rotationMatrix = componentRotation !== 0 ? rotate3(componentRotation * Math.PI / 180) : identity2();
|
|
1506
1595
|
const rotatedPos = applyToPoint7(rotationMatrix, {
|
|
1507
1596
|
x: relativeX,
|
|
1508
1597
|
y: relativeY
|
|
@@ -1529,7 +1618,7 @@ function createNpthPadFromCircuitJson({
|
|
|
1529
1618
|
});
|
|
1530
1619
|
} else {
|
|
1531
1620
|
padShape = "circle";
|
|
1532
|
-
const diameter = pcbHole.hole_diameter
|
|
1621
|
+
const diameter = "hole_diameter" in pcbHole ? pcbHole.hole_diameter : 1;
|
|
1533
1622
|
padSize = [diameter, diameter];
|
|
1534
1623
|
drill = new PadDrill2({ diameter });
|
|
1535
1624
|
}
|
|
@@ -1549,7 +1638,7 @@ function createNpthPadFromCircuitJson({
|
|
|
1549
1638
|
|
|
1550
1639
|
// lib/pcb/stages/utils/CreateFpTextFromCircuitJson.ts
|
|
1551
1640
|
import { FpText, TextEffects as TextEffects4, TextEffectsFont as TextEffectsFont4 } from "kicadts";
|
|
1552
|
-
import { applyToPoint as applyToPoint8, rotate as rotate4, identity as
|
|
1641
|
+
import { applyToPoint as applyToPoint8, rotate as rotate4, identity as identity3 } from "transformation-matrix";
|
|
1553
1642
|
function createFpTextFromCircuitJson({
|
|
1554
1643
|
textElement,
|
|
1555
1644
|
componentCenter,
|
|
@@ -1560,7 +1649,7 @@ function createFpTextFromCircuitJson({
|
|
|
1560
1649
|
}
|
|
1561
1650
|
const relativeX = textElement.anchor_position.x - componentCenter.x;
|
|
1562
1651
|
const relativeY = -(textElement.anchor_position.y - componentCenter.y);
|
|
1563
|
-
const rotationMatrix = componentRotation !== 0 ? rotate4(componentRotation * Math.PI / 180) :
|
|
1652
|
+
const rotationMatrix = componentRotation !== 0 ? rotate4(componentRotation * Math.PI / 180) : identity3();
|
|
1564
1653
|
const rotatedPos = applyToPoint8(rotationMatrix, {
|
|
1565
1654
|
x: relativeX,
|
|
1566
1655
|
y: relativeY
|
|
@@ -1945,8 +2034,8 @@ var AddGraphicsStage = class extends ConverterStage {
|
|
|
1945
2034
|
if (board.outline && board.outline.length > 0) {
|
|
1946
2035
|
corners = board.outline;
|
|
1947
2036
|
} else {
|
|
1948
|
-
const halfWidth = board.width / 2;
|
|
1949
|
-
const halfHeight = board.height / 2;
|
|
2037
|
+
const halfWidth = board.width ? board.width / 2 : 0;
|
|
2038
|
+
const halfHeight = board.height ? board.height / 2 : 0;
|
|
1950
2039
|
corners = [
|
|
1951
2040
|
{ x: board.center.x - halfWidth, y: board.center.y - halfHeight },
|
|
1952
2041
|
{ x: board.center.x + halfWidth, y: board.center.y - halfHeight },
|
|
@@ -1999,9 +2088,9 @@ var CircuitJsonToKicadPcbConverter = class {
|
|
|
1999
2088
|
generator: "circuit-json-to-kicad",
|
|
2000
2089
|
generatorVersion: "0.0.1"
|
|
2001
2090
|
}),
|
|
2002
|
-
c2kMatPcb:
|
|
2003
|
-
|
|
2004
|
-
|
|
2091
|
+
c2kMatPcb: compose3(
|
|
2092
|
+
translate3(KICAD_PCB_CENTER_X, KICAD_PCB_CENTER_Y),
|
|
2093
|
+
scale3(CIRCUIT_JSON_TO_MM_SCALE, -CIRCUIT_JSON_TO_MM_SCALE)
|
|
2005
2094
|
)
|
|
2006
2095
|
};
|
|
2007
2096
|
this.pipeline = [
|
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.
|
|
4
|
+
"version": "0.0.24",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist"
|
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
"@tscircuit/circuit-json-util": "^0.0.72",
|
|
19
19
|
"@tscircuit/common": "^0.0.5",
|
|
20
20
|
"@types/bun": "latest",
|
|
21
|
-
"circuit-json": "^0.0.
|
|
21
|
+
"circuit-json": "^0.0.302",
|
|
22
22
|
"circuit-to-svg": "^0.0.208",
|
|
23
|
-
"kicadts": "^0.0.
|
|
23
|
+
"kicadts": "^0.0.22",
|
|
24
24
|
"schematic-symbols": "^0.0.202",
|
|
25
25
|
"sharp": "^0.34.4",
|
|
26
26
|
"transformation-matrix": "^3.1.0",
|
|
27
|
-
"tscircuit": "^0.0.
|
|
27
|
+
"tscircuit": "^0.0.866",
|
|
28
28
|
"tsup": "^8.5.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|