circuit-to-svg 0.0.20 → 0.0.22
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.js +123 -123
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -1,33 +1,92 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
// src/lib/circuit-to-pcb-svg.ts
|
|
2
|
+
import { stringify as stringify2 } from "svgson";
|
|
3
|
+
import {
|
|
4
|
+
applyToPoint as applyToPoint3,
|
|
5
|
+
compose,
|
|
6
|
+
scale,
|
|
7
|
+
translate
|
|
8
|
+
} from "transformation-matrix";
|
|
9
|
+
|
|
10
|
+
// src/utils/pairs.ts
|
|
11
|
+
function pairs(arr) {
|
|
12
|
+
const result = [];
|
|
13
|
+
for (let i = 0; i < arr.length - 1; i++) {
|
|
14
|
+
result.push([arr[i], arr[i + 1]]);
|
|
15
15
|
}
|
|
16
|
-
return
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/lib/svg-object-fns/create-svg-objects-from-pcb-trace.ts
|
|
20
|
+
import "svgson";
|
|
21
|
+
import { applyToPoint } from "transformation-matrix";
|
|
22
|
+
|
|
23
|
+
// src/lib/layer-name-to-color.ts
|
|
24
|
+
var LAYER_NAME_TO_COLOR = {
|
|
25
|
+
top: "rgb(200, 52, 52)",
|
|
26
|
+
bottom: "rgb(77, 127, 196)"
|
|
17
27
|
};
|
|
18
|
-
|
|
28
|
+
function layerNameToColor(layerName) {
|
|
29
|
+
return LAYER_NAME_TO_COLOR[layerName] ?? "white";
|
|
30
|
+
}
|
|
19
31
|
|
|
20
|
-
// src/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
// src/lib/svg-object-fns/create-svg-objects-from-pcb-trace.ts
|
|
33
|
+
function createSvgObjectsFromPcbTrace(trace, transform) {
|
|
34
|
+
if (!trace.route || !Array.isArray(trace.route) || trace.route.length < 2)
|
|
35
|
+
return [];
|
|
36
|
+
const segments = pairs(trace.route);
|
|
37
|
+
const svgObjects = [];
|
|
38
|
+
for (const [start, end] of segments) {
|
|
39
|
+
const startPoint = applyToPoint(transform, [start.x, start.y]);
|
|
40
|
+
const endPoint = applyToPoint(transform, [end.x, end.y]);
|
|
41
|
+
const layer = "layer" in start ? start.layer : "layer" in end ? end.layer : null;
|
|
42
|
+
if (!layer) continue;
|
|
43
|
+
const layerColor = LAYER_NAME_TO_COLOR[layer] ?? "white";
|
|
44
|
+
const traceWidth = "width" in start ? start.width : "width" in end ? end.width : null;
|
|
45
|
+
svgObjects.push({
|
|
46
|
+
name: "path",
|
|
47
|
+
type: "element",
|
|
48
|
+
value: "",
|
|
49
|
+
children: [],
|
|
50
|
+
attributes: {
|
|
51
|
+
class: "pcb-trace",
|
|
52
|
+
stroke: layerColor,
|
|
53
|
+
d: `M ${startPoint[0]} ${startPoint[1]} L ${endPoint[0]} ${endPoint[1]}`,
|
|
54
|
+
"stroke-width": traceWidth ? (traceWidth * Math.abs(transform.a)).toString() : "0.3",
|
|
55
|
+
"stroke-linecap": "round",
|
|
56
|
+
"stroke-linejoin": "round",
|
|
57
|
+
"shape-rendering": "crispEdges"
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return svgObjects;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/lib/svg-object-fns/create-svg-objects-from-smt-pads.ts
|
|
65
|
+
import { applyToPoint as applyToPoint2 } from "transformation-matrix";
|
|
66
|
+
function createSvgObjectsFromSmtPad(pad, transform) {
|
|
67
|
+
const [x, y] = applyToPoint2(transform, [pad.x, pad.y]);
|
|
68
|
+
if (pad.shape === "rect") {
|
|
69
|
+
const width = pad.width * Math.abs(transform.a);
|
|
70
|
+
const height = pad.height * Math.abs(transform.d);
|
|
71
|
+
return [
|
|
72
|
+
{
|
|
73
|
+
name: "rect",
|
|
74
|
+
type: "element",
|
|
75
|
+
attributes: {
|
|
76
|
+
class: "pcb-pad",
|
|
77
|
+
fill: layerNameToColor(pad.layer),
|
|
78
|
+
x: (x - width / 2).toString(),
|
|
79
|
+
y: (y - height / 2).toString(),
|
|
80
|
+
width: width.toString(),
|
|
81
|
+
height: height.toString()
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
27
88
|
|
|
28
89
|
// src/lib/circuit-to-pcb-svg.ts
|
|
29
|
-
var import_svgson = require("svgson");
|
|
30
|
-
var import_transformation_matrix = require("transformation-matrix");
|
|
31
90
|
function circuitJsonToPcbSvg(soup) {
|
|
32
91
|
let minX = Number.POSITIVE_INFINITY;
|
|
33
92
|
let minY = Number.POSITIVE_INFINITY;
|
|
@@ -58,22 +117,22 @@ function circuitJsonToPcbSvg(soup) {
|
|
|
58
117
|
const scaleFactor = Math.min(scaleX, scaleY);
|
|
59
118
|
const offsetX = (svgWidth - circuitWidth * scaleFactor) / 2;
|
|
60
119
|
const offsetY = (svgHeight - circuitHeight * scaleFactor) / 2;
|
|
61
|
-
const transform =
|
|
62
|
-
|
|
120
|
+
const transform = compose(
|
|
121
|
+
translate(
|
|
63
122
|
offsetX - minX * scaleFactor + padding * scaleFactor,
|
|
64
123
|
svgHeight - offsetY + minY * scaleFactor - padding * scaleFactor
|
|
65
124
|
),
|
|
66
|
-
|
|
125
|
+
scale(scaleFactor, -scaleFactor)
|
|
67
126
|
// Flip in y-direction
|
|
68
127
|
);
|
|
69
|
-
const traceElements = soup.filter((
|
|
70
|
-
const holeElements = soup.filter((
|
|
71
|
-
const silkscreenElements = soup.filter((
|
|
128
|
+
const traceElements = soup.filter((elm) => elm.type === "pcb_trace").flatMap((elm) => createSvgObjects(elm, transform));
|
|
129
|
+
const holeElements = soup.filter((elm) => elm.type === "pcb_plated_hole").flatMap((elm) => createSvgObjects(elm, transform));
|
|
130
|
+
const silkscreenElements = soup.filter((elm) => elm.type === "pcb_silkscreen_path").flatMap((elm) => createPcbSilkscreenPath(elm, transform));
|
|
72
131
|
const otherElements = soup.filter(
|
|
73
|
-
(
|
|
74
|
-
|
|
132
|
+
(elm) => !["pcb_trace", "pcb_plated_hole", "pcb_silkscreen_path"].includes(
|
|
133
|
+
elm.type
|
|
75
134
|
)
|
|
76
|
-
).
|
|
135
|
+
).flatMap((item) => createSvgObjects(item, transform));
|
|
77
136
|
let strokeWidth = String(0.05 * scaleFactor);
|
|
78
137
|
for (const element of soup) {
|
|
79
138
|
if ("stroke_width" in element) {
|
|
@@ -89,6 +148,7 @@ function circuitJsonToPcbSvg(soup) {
|
|
|
89
148
|
width: svgWidth.toString(),
|
|
90
149
|
height: svgHeight.toString()
|
|
91
150
|
},
|
|
151
|
+
value: "",
|
|
92
152
|
children: [
|
|
93
153
|
{
|
|
94
154
|
name: "style",
|
|
@@ -98,10 +158,10 @@ function circuitJsonToPcbSvg(soup) {
|
|
|
98
158
|
type: "text",
|
|
99
159
|
value: `
|
|
100
160
|
.pcb-board { fill: #000; }
|
|
101
|
-
.pcb-trace {
|
|
161
|
+
.pcb-trace { fill: none; }
|
|
102
162
|
.pcb-hole-outer { fill: rgb(200, 52, 52); }
|
|
103
163
|
.pcb-hole-inner { fill: rgb(255, 38, 226); }
|
|
104
|
-
.pcb-pad {
|
|
164
|
+
.pcb-pad { }
|
|
105
165
|
.pcb-boundary { fill: none; stroke: #fff; stroke-width: 0.3; }
|
|
106
166
|
.pcb-silkscreen { fill: none; }
|
|
107
167
|
.pcb-silkscreen-top { stroke: #f2eda1; }
|
|
@@ -121,7 +181,7 @@ function circuitJsonToPcbSvg(soup) {
|
|
|
121
181
|
height: svgHeight.toString()
|
|
122
182
|
}
|
|
123
183
|
},
|
|
124
|
-
|
|
184
|
+
createSvgObjectFromPcbBoundary(transform, minX, minY, maxX, maxY),
|
|
125
185
|
{
|
|
126
186
|
name: "g",
|
|
127
187
|
type: "element",
|
|
@@ -149,7 +209,7 @@ function circuitJsonToPcbSvg(soup) {
|
|
|
149
209
|
].filter((child) => child !== null)
|
|
150
210
|
};
|
|
151
211
|
try {
|
|
152
|
-
return (
|
|
212
|
+
return stringify2(svgObject);
|
|
153
213
|
} catch (error) {
|
|
154
214
|
console.error("Error stringifying SVG object:", error);
|
|
155
215
|
throw error;
|
|
@@ -171,23 +231,23 @@ function circuitJsonToPcbSvg(soup) {
|
|
|
171
231
|
}
|
|
172
232
|
}
|
|
173
233
|
}
|
|
174
|
-
function
|
|
175
|
-
switch (
|
|
234
|
+
function createSvgObjects(elm, transform) {
|
|
235
|
+
switch (elm.type) {
|
|
176
236
|
case "pcb_component":
|
|
177
|
-
return
|
|
237
|
+
return [createSvgObjectsFromPcbComponent(elm, transform)].filter(Boolean);
|
|
178
238
|
case "pcb_trace":
|
|
179
|
-
return
|
|
239
|
+
return createSvgObjectsFromPcbTrace(elm, transform);
|
|
180
240
|
case "pcb_plated_hole":
|
|
181
|
-
return
|
|
241
|
+
return [createSvgObjectsFromPcbHole(elm, transform)].filter(Boolean);
|
|
182
242
|
case "pcb_smtpad":
|
|
183
|
-
return
|
|
243
|
+
return createSvgObjectsFromSmtPad(elm, transform);
|
|
184
244
|
default:
|
|
185
|
-
return
|
|
245
|
+
return [];
|
|
186
246
|
}
|
|
187
247
|
}
|
|
188
|
-
function
|
|
248
|
+
function createSvgObjectsFromPcbComponent(component, transform) {
|
|
189
249
|
const { center, width, height, rotation = 0 } = component;
|
|
190
|
-
const [x, y] = (
|
|
250
|
+
const [x, y] = applyToPoint3(transform, [center.x, center.y]);
|
|
191
251
|
const scaledWidth = width * Math.abs(transform.a);
|
|
192
252
|
const scaledHeight = height * Math.abs(transform.d);
|
|
193
253
|
const transformStr = `translate(${x}, ${y}) rotate(${-rotation}) scale(1, -1)`;
|
|
@@ -221,8 +281,8 @@ function createPcbComponent(component, transform) {
|
|
|
221
281
|
]
|
|
222
282
|
};
|
|
223
283
|
}
|
|
224
|
-
function
|
|
225
|
-
const [x, y] = (
|
|
284
|
+
function createSvgObjectsFromPcbHole(hole, transform) {
|
|
285
|
+
const [x, y] = applyToPoint3(transform, [hole.x, hole.y]);
|
|
226
286
|
const scaledOuterRadius = hole.outer_diameter / 2 * Math.abs(transform.a);
|
|
227
287
|
const scaledInnerRadius = hole.hole_diameter / 2 * Math.abs(transform.a);
|
|
228
288
|
return {
|
|
@@ -252,71 +312,10 @@ function createPcbHole(hole, transform) {
|
|
|
252
312
|
]
|
|
253
313
|
};
|
|
254
314
|
}
|
|
255
|
-
function createPcbSMTPad(pad, transform) {
|
|
256
|
-
const [x, y] = (0, import_transformation_matrix.applyToPoint)(transform, [pad.x, pad.y]);
|
|
257
|
-
const width = pad.width * Math.abs(transform.a);
|
|
258
|
-
const height = pad.height * Math.abs(transform.d);
|
|
259
|
-
return {
|
|
260
|
-
name: "rect",
|
|
261
|
-
type: "element",
|
|
262
|
-
attributes: {
|
|
263
|
-
class: "pcb-pad",
|
|
264
|
-
x: (x - width / 2).toString(),
|
|
265
|
-
y: (y - height / 2).toString(),
|
|
266
|
-
width: width.toString(),
|
|
267
|
-
height: height.toString()
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
function createPcbTrace(trace, transform) {
|
|
272
|
-
if (!trace.route || !Array.isArray(trace.route) || trace.route.length < 2)
|
|
273
|
-
return null;
|
|
274
|
-
const cornerRadius = 0.2;
|
|
275
|
-
const pathCommands = [];
|
|
276
|
-
const transformedPoints = trace.route.map(
|
|
277
|
-
(point) => (0, import_transformation_matrix.applyToPoint)(transform, [point.x, point.y])
|
|
278
|
-
);
|
|
279
|
-
pathCommands.push(`M ${transformedPoints[0][0]} ${transformedPoints[0][1]}`);
|
|
280
|
-
for (let i = 1; i < transformedPoints.length - 1; i++) {
|
|
281
|
-
const prev = transformedPoints[i - 1];
|
|
282
|
-
const curr = transformedPoints[i];
|
|
283
|
-
const next = transformedPoints[i + 1];
|
|
284
|
-
const v1 = curr && prev ? [curr[0] - prev[0], curr[1] - prev[1]] : [0, 0];
|
|
285
|
-
const v2 = next && curr ? [next[0] - curr[0], next[1] - curr[1]] : [0, 0];
|
|
286
|
-
const l1 = Math.sqrt(v1[0] * v1[0] + v1[1] * v1[1]);
|
|
287
|
-
const l2 = Math.sqrt(v2[0] * v2[0] + v2[1] * v2[1]);
|
|
288
|
-
if (l1 !== 0) {
|
|
289
|
-
v1[0] /= l1;
|
|
290
|
-
v1[1] /= l1;
|
|
291
|
-
}
|
|
292
|
-
if (l2 !== 0) {
|
|
293
|
-
v2[0] /= l2;
|
|
294
|
-
v2[1] /= l2;
|
|
295
|
-
}
|
|
296
|
-
const radius = Math.min(cornerRadius, Math.min(l1, l2) / 2);
|
|
297
|
-
const p1 = [curr[0] - v1[0] * radius, curr[1] - v1[1] * radius];
|
|
298
|
-
const p2 = [curr[0] + v2[0] * radius, curr[1] + v2[1] * radius];
|
|
299
|
-
pathCommands.push(`L ${p1[0]} ${p1[1]}`);
|
|
300
|
-
pathCommands.push(`A ${radius} ${radius} 0 0 1 ${p2[0]} ${p2[1]}`);
|
|
301
|
-
}
|
|
302
|
-
const lastPoint = transformedPoints[transformedPoints.length - 1];
|
|
303
|
-
pathCommands.push(`L ${lastPoint[0]} ${lastPoint[1]}`);
|
|
304
|
-
return {
|
|
305
|
-
name: "path",
|
|
306
|
-
type: "element",
|
|
307
|
-
attributes: {
|
|
308
|
-
class: "pcb-trace",
|
|
309
|
-
d: pathCommands.join(" "),
|
|
310
|
-
"stroke-width": trace.stroke_width ? (trace.stroke_width * Math.abs(transform.a)).toString() : "0.3",
|
|
311
|
-
"stroke-linecap": "round",
|
|
312
|
-
"stroke-linejoin": "round"
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
315
|
function createPcbSilkscreenPath(silkscreenPath, transform) {
|
|
317
316
|
if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return null;
|
|
318
317
|
let path = silkscreenPath.route.map((point, index) => {
|
|
319
|
-
const [x, y] = (
|
|
318
|
+
const [x, y] = applyToPoint3(transform, [point.x, point.y]);
|
|
320
319
|
return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
|
|
321
320
|
}).join(" ");
|
|
322
321
|
const firstPoint = silkscreenPath.route[0];
|
|
@@ -336,9 +335,9 @@ function createPcbSilkscreenPath(silkscreenPath, transform) {
|
|
|
336
335
|
}
|
|
337
336
|
};
|
|
338
337
|
}
|
|
339
|
-
function
|
|
340
|
-
const [x1, y1] = (
|
|
341
|
-
const [x2, y2] = (
|
|
338
|
+
function createSvgObjectFromPcbBoundary(transform, minX, minY, maxX, maxY) {
|
|
339
|
+
const [x1, y1] = applyToPoint3(transform, [minX, minY]);
|
|
340
|
+
const [x2, y2] = applyToPoint3(transform, [maxX, maxY]);
|
|
342
341
|
const width = Math.abs(x2 - x1);
|
|
343
342
|
const height = Math.abs(y2 - y1);
|
|
344
343
|
const x = Math.min(x1, x2);
|
|
@@ -346,6 +345,8 @@ function createPcbBoundary(transform, minX, minY, maxX, maxY) {
|
|
|
346
345
|
return {
|
|
347
346
|
name: "rect",
|
|
348
347
|
type: "element",
|
|
348
|
+
value: "",
|
|
349
|
+
children: [],
|
|
349
350
|
attributes: {
|
|
350
351
|
class: "pcb-boundary",
|
|
351
352
|
x: x.toString(),
|
|
@@ -357,8 +358,8 @@ function createPcbBoundary(transform, minX, minY, maxX, maxY) {
|
|
|
357
358
|
}
|
|
358
359
|
|
|
359
360
|
// src/lib/circuit-to-schematic-svg.ts
|
|
360
|
-
|
|
361
|
-
|
|
361
|
+
import { getSvg, symbols } from "schematic-symbols";
|
|
362
|
+
import { parseSync, stringify as stringify3 } from "svgson";
|
|
362
363
|
function circuitJsonToSchematicSvg(soup) {
|
|
363
364
|
let minX = Number.POSITIVE_INFINITY;
|
|
364
365
|
let minY = Number.POSITIVE_INFINITY;
|
|
@@ -452,7 +453,7 @@ function circuitJsonToSchematicSvg(soup) {
|
|
|
452
453
|
...svgChildren
|
|
453
454
|
]
|
|
454
455
|
};
|
|
455
|
-
return (
|
|
456
|
+
return stringify3({ value: "", ...svgObject });
|
|
456
457
|
function updateBounds(center, size, rotation) {
|
|
457
458
|
const corners = [
|
|
458
459
|
{ x: -size.width / 2, y: -size.height / 2 },
|
|
@@ -473,14 +474,14 @@ function circuitJsonToSchematicSvg(soup) {
|
|
|
473
474
|
function createSchematicComponent(center, size, rotation, symbolName) {
|
|
474
475
|
const transform = `translate(${center.x}, ${center.y}) rotate(${rotation * 180 / Math.PI})`;
|
|
475
476
|
if (symbolName) {
|
|
476
|
-
const symbol =
|
|
477
|
+
const symbol = symbols[symbolName];
|
|
477
478
|
const paths = symbol.primitives.filter((p) => p.type === "path");
|
|
478
479
|
const updatedSymbol = {
|
|
479
480
|
...symbol,
|
|
480
481
|
primitives: paths
|
|
481
482
|
};
|
|
482
|
-
const svg =
|
|
483
|
-
|
|
483
|
+
const svg = parseSync(
|
|
484
|
+
getSvg(updatedSymbol, {
|
|
484
485
|
width: size.width,
|
|
485
486
|
height: size.height
|
|
486
487
|
})
|
|
@@ -656,9 +657,8 @@ function getTextAnchor(anchor) {
|
|
|
656
657
|
return "middle";
|
|
657
658
|
}
|
|
658
659
|
}
|
|
659
|
-
|
|
660
|
-
0 && (module.exports = {
|
|
660
|
+
export {
|
|
661
661
|
circuitJsonToPcbSvg,
|
|
662
662
|
circuitJsonToSchematicSvg
|
|
663
|
-
}
|
|
663
|
+
};
|
|
664
664
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/lib/circuit-to-pcb-svg.ts","../src/lib/circuit-to-schematic-svg.ts"],"sourcesContent":["export * from \"./lib\";\n\n","import type { AnySoupElement } from \"@tscircuit/soup\"\nimport { type INode, stringify } from \"svgson\"\nimport { applyToPoint, compose, scale, translate } from \"transformation-matrix\"\n\ninterface SvgObject {\n name: string\n type: \"element\" | \"text\"\n attributes?: { [key: string]: string }\n children?: SvgObject[]\n value?: string\n}\n\ninterface PointObjectNotation {\n x: number\n y: number\n}\n\nfunction circuitJsonToPcbSvg(soup: AnySoupElement[]): string {\n let minX = Number.POSITIVE_INFINITY\n let minY = Number.POSITIVE_INFINITY\n let maxX = Number.NEGATIVE_INFINITY\n let maxY = Number.NEGATIVE_INFINITY\n\n // Process all elements to determine bounds\n for (const item of soup) {\n if (\"center\" in item && \"width\" in item && \"height\" in item) {\n updateBounds(item.center, item.width, item.height)\n } else if (\"x\" in item && \"y\" in item) {\n updateBounds({ x: item.x, y: item.y }, 0, 0)\n } else if (\"route\" in item) {\n updateTraceBounds(item.route)\n }\n }\n\n const padding = 1 // Reduced padding for tighter boundary\n const circuitWidth = maxX - minX + 2 * padding\n const circuitHeight = maxY - minY + 2 * padding\n\n const svgWidth = 800\n const svgHeight = 600\n const paths: PointObjectNotation[][] = []\n for (const item of soup) {\n if (\"route\" in item && item.route !== undefined) {\n paths.push(item.route as PointObjectNotation[])\n }\n }\n\n // Calculate scale factor to fit the circuit within the SVG, maintaining aspect ratio\n const scaleX = svgWidth / circuitWidth\n const scaleY = svgHeight / circuitHeight\n const scaleFactor = Math.min(scaleX, scaleY)\n\n // Calculate centering offsets\n const offsetX = (svgWidth - circuitWidth * scaleFactor) / 2\n const offsetY = (svgHeight - circuitHeight * scaleFactor) / 2\n\n const transform = compose(\n translate(\n offsetX - minX * scaleFactor + padding * scaleFactor,\n svgHeight - offsetY + minY * scaleFactor - padding * scaleFactor,\n ),\n scale(scaleFactor, -scaleFactor), // Flip in y-direction\n )\n\n const traceElements = soup\n .filter((item) => item.type === \"pcb_trace\")\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n const holeElements = soup\n .filter((item) => item.type === \"pcb_plated_hole\")\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n const silkscreenElements = soup\n .filter((item) => item.type === \"pcb_silkscreen_path\")\n .map((item) => createPcbSilkscreenPath(item, transform))\n .filter((element) => element !== null)\n\n const otherElements = soup\n .filter(\n (item) =>\n ![\"pcb_trace\", \"pcb_plated_hole\", \"pcb_silkscreen_path\"].includes(\n item.type,\n ),\n )\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n let strokeWidth = String(0.05 * scaleFactor)\n\n for (const element of soup) {\n if (\"stroke_width\" in element) {\n strokeWidth = String(scaleFactor * element.stroke_width)\n break\n }\n }\n\n const svgObject: SvgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: svgWidth.toString(),\n height: svgHeight.toString(),\n },\n children: [\n {\n name: \"style\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n .pcb-board { fill: #000; }\n .pcb-trace { stroke: rgb(200, 52, 52); stroke-width: ${strokeWidth}; fill: none; }\n .pcb-hole-outer { fill: rgb(200, 52, 52); }\n .pcb-hole-inner { fill: rgb(255, 38, 226); }\n .pcb-pad { fill: rgb(200, 52, 52); }\n .pcb-boundary { fill: none; stroke: #fff; stroke-width: 0.3; }\n .pcb-silkscreen { fill: none; }\n .pcb-silkscreen-top { stroke: #f2eda1; }\n .pcb-silkscreen-bottom { stroke: #f2eda1; }\n `,\n },\n ],\n },\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-board\",\n x: \"0\",\n y: \"0\",\n width: svgWidth.toString(),\n height: svgHeight.toString(),\n },\n },\n createPcbBoundary(transform, minX, minY, maxX, maxY),\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"other-elements\" },\n children: otherElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"traces\" },\n children: traceElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"holes\" },\n children: holeElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"silkscreen\" },\n children: silkscreenElements,\n },\n ].filter((child) => child !== null),\n }\n\n try {\n return stringify(svgObject as INode)\n } catch (error) {\n console.error(\"Error stringifying SVG object:\", error)\n throw error\n }\n\n function updateBounds(center: any, width: any, height: any) {\n const halfWidth = width / 2\n const halfHeight = height / 2\n minX = Math.min(minX, center.x - halfWidth)\n minY = Math.min(minY, center.y - halfHeight)\n maxX = Math.max(maxX, center.x + halfWidth)\n maxY = Math.max(maxY, center.y + halfHeight)\n }\n\n function updateTraceBounds(route: any[]) {\n for (const point of route) {\n minX = Math.min(minX, point.x)\n minY = Math.min(minY, point.y)\n maxX = Math.max(maxX, point.x)\n maxY = Math.max(maxY, point.y)\n }\n }\n}\n\nfunction createSvgElement(item: AnySoupElement, transform: any): any {\n switch (item.type) {\n case \"pcb_component\":\n return createPcbComponent(item, transform)\n case \"pcb_trace\":\n return createPcbTrace(item, transform)\n case \"pcb_plated_hole\":\n return createPcbHole(item, transform)\n case \"pcb_smtpad\":\n return createPcbSMTPad(item, transform)\n default:\n return null\n }\n}\n\nfunction createPcbComponent(component: any, transform: any): any {\n const { center, width, height, rotation = 0 } = component\n const [x, y] = applyToPoint(transform, [center.x, center.y])\n const scaledWidth = width * Math.abs(transform.a)\n const scaledHeight = height * Math.abs(transform.d)\n const transformStr = `translate(${x}, ${y}) rotate(${-rotation}) scale(1, -1)`\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform: transformStr },\n children: [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-component\",\n x: (-scaledWidth / 2).toString(),\n y: (-scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: scaledHeight.toString(),\n },\n },\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-component-outline\",\n x: (-scaledWidth / 2).toString(),\n y: (-scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: scaledHeight.toString(),\n },\n },\n ],\n }\n}\n\nfunction createPcbHole(hole: any, transform: any): any {\n const [x, y] = applyToPoint(transform, [hole.x, hole.y])\n const scaledOuterRadius = (hole.outer_diameter / 2) * Math.abs(transform.a)\n const scaledInnerRadius = (hole.hole_diameter / 2) * Math.abs(transform.a)\n return {\n name: \"g\",\n type: \"element\",\n children: [\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-outer\",\n cx: x.toString(),\n cy: y.toString(),\n r: scaledOuterRadius.toString(),\n },\n },\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-inner\",\n cx: x.toString(),\n cy: y.toString(),\n r: scaledInnerRadius.toString(),\n },\n },\n ],\n }\n}\n\nfunction createPcbSMTPad(pad: any, transform: any): any {\n const [x, y] = applyToPoint(transform, [pad.x, pad.y])\n const width = pad.width * Math.abs(transform.a)\n const height = pad.height * Math.abs(transform.d)\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-pad\",\n x: (x - width / 2).toString(),\n y: (y - height / 2).toString(),\n width: width.toString(),\n height: height.toString(),\n },\n }\n}\n\nfunction createPcbTrace(trace: any, transform: any): any {\n if (!trace.route || !Array.isArray(trace.route) || trace.route.length < 2)\n return null\n\n const cornerRadius = 0.2 // Adjust this value to change the roundness of corners\n const pathCommands: string[] = []\n const transformedPoints = trace.route.map((point: any) =>\n applyToPoint(transform, [point.x, point.y]),\n )\n\n // Start path\n pathCommands.push(`M ${transformedPoints[0][0]} ${transformedPoints[0][1]}`)\n\n for (let i = 1; i < transformedPoints.length - 1; i++) {\n const prev = transformedPoints[i - 1]\n const curr = transformedPoints[i]\n const next = transformedPoints[i + 1]\n\n // Calculate vectors\n const v1 = curr && prev ? [curr[0] - prev[0], curr[1] - prev[1]] : [0, 0]\n const v2 = next && curr ? [next[0] - curr[0], next[1] - curr[1]] : [0, 0]\n\n // Normalize vectors\n const l1 = Math.sqrt((v1[0] as number) * (v1[0] as number) + (v1[1] as number) * (v1[1] as number));\n const l2 = Math.sqrt((v2[0] as number) * (v2[0] as number) + (v2[1] as number) * (v2[1] as number));\n if (l1 !== 0) {\n v1[0]! /= l1;\n v1[1]! /= l1;\n }\n if (l2 !== 0) {\n v2[0]! /= l2;\n v2[1]! /= l2;\n }\n\n // Calculate the corner points\n const radius = Math.min(cornerRadius, Math.min(l1, l2) / 2)\n const p1 = [curr[0] - v1[0]! * radius, curr[1] - v1[1]! * radius] \n const p2 = [curr[0] + v2[0]! * radius, curr[1] + v2[1]! * radius]\n\n // Add line to the start of the corner\n pathCommands.push(`L ${p1[0]} ${p1[1]}`)\n\n // Add the arc\n pathCommands.push(`A ${radius} ${radius} 0 0 1 ${p2[0]} ${p2[1]}`)\n }\n\n // Add final line to last point\n const lastPoint = transformedPoints[transformedPoints.length - 1]\n pathCommands.push(`L ${lastPoint[0]} ${lastPoint[1]}`)\n\n return {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"pcb-trace\",\n d: pathCommands.join(\" \"),\n \"stroke-width\": trace.stroke_width\n ? (trace.stroke_width * Math.abs(transform.a)).toString()\n : \"0.3\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n },\n }\n}\n\nfunction createPcbSilkscreenPath(silkscreenPath: any, transform: any): any {\n if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return null\n\n let path = silkscreenPath.route\n .map((point: any, index: number) => {\n const [x, y] = applyToPoint(transform, [point.x, point.y])\n return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`\n })\n .join(\" \")\n\n // Close the path if it's not already closed\n const firstPoint = silkscreenPath.route[0]\n const lastPoint = silkscreenPath.route[silkscreenPath.route.length - 1]\n if (firstPoint.x !== lastPoint.x || firstPoint.y !== lastPoint.y) {\n path += \" Z\"\n }\n\n return {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: `pcb-silkscreen pcb-silkscreen-${silkscreenPath.layer}`,\n d: path,\n \"stroke-width\": (\n silkscreenPath.stroke_width * Math.abs(transform.a)\n ).toString(),\n \"data-pcb-component-id\": silkscreenPath.pcb_component_id,\n \"data-pcb-silkscreen-path-id\": silkscreenPath.pcb_silkscreen_path_id,\n },\n }\n}\n\nfunction createPcbBoundary(\n transform: any,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): any {\n const [x1, y1] = applyToPoint(transform, [minX, minY])\n const [x2, y2] = applyToPoint(transform, [maxX, maxY])\n const width = Math.abs(x2 - x1)\n const height = Math.abs(y2 - y1)\n const x = Math.min(x1, x2)\n const y = Math.min(y1, y2)\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-boundary\",\n x: x.toString(),\n y: y.toString(),\n width: width.toString(),\n height: height.toString(),\n },\n }\n}\n\nexport { circuitJsonToPcbSvg }\n","import type { AnySoupElement } from \"@tscircuit/soup\";\nimport { getSvg, symbols } from \"schematic-symbols\";\nimport { parseSync, stringify } from \"svgson\";\n\nfunction circuitJsonToSchematicSvg(soup: AnySoupElement[]): string {\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n\n const portSize = 0.2;\n const portPositions = new Map();\n\n // First pass: find the bounds and collect port positions\n for (const item of soup) {\n if (item.type === \"schematic_component\") {\n updateBounds(item.center, item.size, item.rotation || 0);\n } else if (item.type === \"schematic_port\") {\n updateBounds(item.center, { width: portSize, height: portSize }, 0);\n portPositions.set(item.schematic_port_id, item.center);\n } else if (item.type === \"schematic_text\") {\n updateBounds(item.position, { width: 0, height: 0 }, 0);\n }\n }\n\n const height = maxY - minY;\n const flipY = (y: number) => height - (y - minY) + minY;\n\n const svgChildren: any[] = [];\n\n // Process components\n const componentMap = new Map();\n for (const component of soup.filter(\n (item) => item.type === \"schematic_component\"\n )) {\n const flippedCenter = {\n x: component.center.x,\n y: flipY(component.center.y),\n };\n const svg = createSchematicComponent(\n flippedCenter,\n component.size,\n component.rotation || 0,\n component.symbol_name\n );\n svgChildren.push(svg);\n componentMap.set(component.schematic_component_id, component);\n }\n\n // Process ports and add lines to component edges\n for (const port of soup.filter((item) => item.type === \"schematic_port\")) {\n const flippedCenter = { x: port.center.x, y: flipY(port.center.y) };\n const svg = createSchematicPort(flippedCenter);\n svgChildren.push(svg);\n\n const component = componentMap.get(port.schematic_component_id);\n if (component) {\n const line = createPortToComponentLine(\n flippedCenter,\n component,\n port.facing_direction || \"right\"\n );\n svgChildren.push(line);\n }\n }\n\n // Process schematic traces\n for (const trace of soup.filter((item) => item.type === \"schematic_trace\")) {\n const svg = createSchematicTrace(trace, flipY, portPositions);\n if (svg) svgChildren.push(svg);\n }\n\n // Process text\n for (const text of soup.filter((item) => item.type === \"schematic_text\")) {\n const flippedPosition = { x: text.position.x, y: flipY(text.position.y) };\n const svg = createSchematicText(text, flippedPosition);\n svgChildren.push(svg);\n }\n\n const padding = 1;\n const width = maxX - minX + 2 * padding;\n const viewBox = `${minX - padding} ${minY - padding} ${width} ${height + 2 * padding}`;\n\n const svgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox,\n width: \"1200\",\n height: \"600\",\n style: \"background-color: #fff;\",\n },\n children: [\n {\n name: \"style\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n .component { fill: none; stroke: red; stroke-width: 0.03; }\n .component-pin { fill: none; stroke: red; stroke-width: 0.03; }\n .trace { stroke: green; stroke-width: 0.03; fill: none; }\n .text { font-family: Arial, sans-serif; font-size: 0.2px; }\n .port { fill: none; stroke: blue; stroke-width: 0.03; }\n `,\n },\n ],\n },\n ...svgChildren,\n ],\n };\n\n return stringify({ value: \"\", ...svgObject });\n\n function updateBounds(center: any, size: any, rotation: number) {\n const corners = [\n { x: -size.width / 2, y: -size.height / 2 },\n { x: size.width / 2, y: -size.height / 2 },\n { x: size.width / 2, y: size.height / 2 },\n { x: -size.width / 2, y: size.height / 2 },\n ];\n\n for (const corner of corners) {\n const rotatedX =\n corner.x * Math.cos(rotation) -\n corner.y * Math.sin(rotation) +\n center.x;\n const rotatedY =\n corner.x * Math.sin(rotation) +\n corner.y * Math.cos(rotation) +\n center.y;\n minX = Math.min(minX, rotatedX);\n minY = Math.min(minY, rotatedY);\n maxX = Math.max(maxX, rotatedX);\n maxY = Math.max(maxY, rotatedY);\n }\n }\n}\n\nfunction createSchematicComponent(\n center: { x: number; y: number },\n size: { width: number; height: number },\n rotation: number,\n symbolName?: string\n): any {\n const transform = `translate(${center.x}, ${center.y}) rotate(${(rotation * 180) / Math.PI})`;\n\n if (symbolName) {\n const symbol = (symbols as any)[symbolName];\n const paths = symbol.primitives.filter((p: any) => p.type === \"path\");\n const updatedSymbol = {\n ...symbol,\n primitives: paths,\n };\n const svg = parseSync(\n getSvg(updatedSymbol, {\n width: size.width,\n height: size.height,\n })\n );\n\n // Filter out non-path elements and modify path colors\n const pathElements = svg.children\n .filter(\n (child: any) =>\n child.name === \"path\" && child.attributes.fill !== \"green\"\n )\n .map((path: any) => {\n const currentStrokeWidth = Number.parseFloat(\n path.attributes[\"stroke-width\"] || \"0.02\"\n );\n const newStrokeWidth = (currentStrokeWidth * 1.5).toString();\n\n return {\n ...path,\n attributes: {\n ...path.attributes,\n stroke:\n path.attributes.stroke === \"black\"\n ? \"red\"\n : path.attributes.stroke,\n \"stroke-width\": newStrokeWidth,\n },\n };\n });\n\n // Check if viewBox attribute exists\n const viewBoxAttr = svg.attributes.viewBox;\n if (typeof viewBoxAttr === \"undefined\") {\n throw new Error(\"SVG does not have a viewBox attribute.\");\n }\n\n // Extract viewBox values\n const viewBox = viewBoxAttr.split(\" \").map(Number);\n if (viewBox.length < 4) {\n throw new Error(\"Invalid viewBox attribute.\");\n }\n const [minX, minY, width = 0, height = 0] = viewBox;\n\n // Calculate scale factors\n const scaleX = size.width / (width || 1);\n const scaleY = size.height / (height || 1);\n\n const scale = Math.min(scaleX, scaleY);\n\n // Adjust transformation to include scaling and centering\n const adjustedTransform = `${transform} scale(${scale}) translate(${-(minX ?? 0) - width / 2}, ${-(minY ?? 0) - height / 2})`;\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform: adjustedTransform },\n children: pathElements,\n };\n }\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform },\n children: [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"component\",\n x: (-size.width / 2).toString(),\n y: (-size.height / 2).toString(),\n width: size.width.toString(),\n height: size.height.toString(),\n },\n },\n ],\n };\n}\n\nfunction createSchematicPort(center: { x: number; y: number }): any {\n const portSize = 0.2;\n const x = center.x - portSize / 2;\n const y = center.y - portSize / 2;\n\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"port\",\n x: x.toString(),\n y: y.toString(),\n width: portSize.toString(),\n height: portSize.toString(),\n },\n };\n}\n\nfunction createPortToComponentLine(\n portCenter: { x: number; y: number },\n component: any,\n facingDirection: string\n): any {\n const componentCenter = { x: component.center.x, y: portCenter.y };\n const halfWidth = component.size.width / 2;\n const halfHeight = component.size.height / 2;\n\n let endX = portCenter.x;\n let endY = portCenter.y;\n\n switch (facingDirection) {\n case \"left\":\n endX = componentCenter.x - halfWidth;\n break;\n case \"right\":\n endX = componentCenter.x + halfWidth;\n break;\n case \"up\":\n endY = componentCenter.y - halfHeight;\n break;\n case \"down\":\n endY = componentCenter.y + halfHeight;\n break;\n }\n\n return {\n name: \"line\",\n type: \"element\",\n attributes: {\n class: \"component-pin\",\n x1: portCenter.x.toString(),\n y1: portCenter.y.toString(),\n x2: endX.toString(),\n y2: endY.toString(),\n },\n };\n}\n\nfunction createSchematicTrace(\n trace: any,\n flipY: (y: number) => number,\n portPositions: Map<string, { x: number; y: number }>\n): any {\n const edges = trace.edges;\n if (edges.length === 0) return null;\n\n let path = \"\";\n\n // Process all edges\n edges.forEach((edge: any, index: number) => {\n const fromPoint =\n edge.from.ti !== undefined ? portPositions.get(edge.from.ti) : edge.from;\n const toPoint =\n edge.to.ti !== undefined ? portPositions.get(edge.to.ti) : edge.to;\n\n if (!fromPoint || !toPoint) {\n return;\n }\n\n const fromCoord = `${fromPoint.x} ${flipY(fromPoint.y)}`;\n const toCoord = `${toPoint.x} ${flipY(toPoint.y)}`;\n\n if (index === 0) {\n path += `M ${fromCoord} L ${toCoord}`;\n } else {\n path += ` L ${toCoord}`;\n }\n });\n\n // Handle connection to final port if needed\n if (trace.to_schematic_port_id) {\n const finalPort = portPositions.get(trace.to_schematic_port_id);\n if (finalPort) {\n const lastFromPoint = path.split(\"M\")[1]?.split(\"L\")[0];\n const lastEdge = edges[edges.length - 1];\n const lastPoint =\n lastEdge.to.ti !== undefined\n ? portPositions.get(lastEdge.to.ti)\n : lastEdge.to;\n if (lastPoint.x !== finalPort.x || lastPoint.y !== finalPort.y) {\n const finalCoord = `${finalPort.x} ${flipY(finalPort.y)}`;\n path += ` M ${lastFromPoint} L ${finalCoord}`;\n }\n }\n }\n\n return path\n ? {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"trace\",\n d: path,\n },\n }\n : null;\n}\n\nfunction createSchematicText(\n text: any,\n position: { x: number; y: number }\n): any {\n return {\n name: \"text\",\n type: \"element\",\n attributes: {\n class: \"text\",\n x: position.x.toString(),\n y: position.y.toString(),\n \"text-anchor\": getTextAnchor(text.anchor),\n \"dominant-baseline\": \"middle\",\n },\n children: [\n {\n type: \"text\",\n value: text.text ? text.text : \"\",\n },\n ],\n };\n}\n\nfunction getTextAnchor(anchor: string): string {\n switch (anchor) {\n case \"left\":\n return \"start\";\n case \"right\":\n return \"end\";\n default:\n return \"middle\";\n }\n}\n\nexport { circuitJsonToSchematicSvg };\n"],"mappings":"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","names":["import_svgson","scale"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/circuit-to-pcb-svg.ts","../src/utils/pairs.ts","../src/lib/svg-object-fns/create-svg-objects-from-pcb-trace.ts","../src/lib/layer-name-to-color.ts","../src/lib/svg-object-fns/create-svg-objects-from-smt-pads.ts","../src/lib/circuit-to-schematic-svg.ts"],"sourcesContent":["import type { AnySoupElement, PCBTrace } from \"@tscircuit/soup\"\nimport { type INode as SvgObject, stringify } from \"svgson\"\nimport {\n applyToPoint,\n compose,\n scale,\n translate,\n type Matrix,\n} from \"transformation-matrix\"\nimport { createSvgObjectsFromPcbTrace } from \"./svg-object-fns/create-svg-objects-from-pcb-trace\"\nimport { createSvgObjectsFromSmtPad } from \"./svg-object-fns/create-svg-objects-from-smt-pads\"\n\ninterface PointObjectNotation {\n x: number\n y: number\n}\n\nfunction circuitJsonToPcbSvg(soup: AnySoupElement[]): string {\n let minX = Number.POSITIVE_INFINITY\n let minY = Number.POSITIVE_INFINITY\n let maxX = Number.NEGATIVE_INFINITY\n let maxY = Number.NEGATIVE_INFINITY\n\n // Process all elements to determine bounds\n for (const item of soup) {\n if (\"center\" in item && \"width\" in item && \"height\" in item) {\n updateBounds(item.center, item.width, item.height)\n } else if (\"x\" in item && \"y\" in item) {\n updateBounds({ x: item.x, y: item.y }, 0, 0)\n } else if (\"route\" in item) {\n updateTraceBounds(item.route)\n }\n }\n\n const padding = 1 // Reduced padding for tighter boundary\n const circuitWidth = maxX - minX + 2 * padding\n const circuitHeight = maxY - minY + 2 * padding\n\n const svgWidth = 800\n const svgHeight = 600\n const paths: PointObjectNotation[][] = []\n for (const item of soup) {\n if (\"route\" in item && item.route !== undefined) {\n paths.push(item.route as PointObjectNotation[])\n }\n }\n\n // Calculate scale factor to fit the circuit within the SVG, maintaining aspect ratio\n const scaleX = svgWidth / circuitWidth\n const scaleY = svgHeight / circuitHeight\n const scaleFactor = Math.min(scaleX, scaleY)\n\n // Calculate centering offsets\n const offsetX = (svgWidth - circuitWidth * scaleFactor) / 2\n const offsetY = (svgHeight - circuitHeight * scaleFactor) / 2\n\n const transform = compose(\n translate(\n offsetX - minX * scaleFactor + padding * scaleFactor,\n svgHeight - offsetY + minY * scaleFactor - padding * scaleFactor,\n ),\n scale(scaleFactor, -scaleFactor), // Flip in y-direction\n )\n\n const traceElements = soup\n .filter((elm) => elm.type === \"pcb_trace\")\n .flatMap((elm) => createSvgObjects(elm, transform))\n\n const holeElements = soup\n .filter((elm) => elm.type === \"pcb_plated_hole\")\n .flatMap((elm) => createSvgObjects(elm, transform))\n\n const silkscreenElements = soup\n .filter((elm) => elm.type === \"pcb_silkscreen_path\")\n .flatMap((elm) => createPcbSilkscreenPath(elm, transform))\n\n const otherElements = soup\n .filter(\n (elm) =>\n ![\"pcb_trace\", \"pcb_plated_hole\", \"pcb_silkscreen_path\"].includes(\n elm.type,\n ),\n )\n .flatMap((item) => createSvgObjects(item, transform))\n\n let strokeWidth = String(0.05 * scaleFactor)\n\n for (const element of soup) {\n if (\"stroke_width\" in element) {\n strokeWidth = String(scaleFactor * element.stroke_width)\n break\n }\n }\n\n const svgObject: SvgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: svgWidth.toString(),\n height: svgHeight.toString(),\n },\n value: \"\",\n children: [\n {\n name: \"style\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n .pcb-board { fill: #000; }\n .pcb-trace { fill: none; }\n .pcb-hole-outer { fill: rgb(200, 52, 52); }\n .pcb-hole-inner { fill: rgb(255, 38, 226); }\n .pcb-pad { }\n .pcb-boundary { fill: none; stroke: #fff; stroke-width: 0.3; }\n .pcb-silkscreen { fill: none; }\n .pcb-silkscreen-top { stroke: #f2eda1; }\n .pcb-silkscreen-bottom { stroke: #f2eda1; }\n `,\n },\n ],\n },\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-board\",\n x: \"0\",\n y: \"0\",\n width: svgWidth.toString(),\n height: svgHeight.toString(),\n },\n },\n createSvgObjectFromPcbBoundary(transform, minX, minY, maxX, maxY),\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"other-elements\" },\n children: otherElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"traces\" },\n children: traceElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"holes\" },\n children: holeElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"silkscreen\" },\n children: silkscreenElements,\n },\n ].filter((child): child is SvgObject => child !== null),\n }\n\n try {\n return stringify(svgObject as SvgObject)\n } catch (error) {\n console.error(\"Error stringifying SVG object:\", error)\n throw error\n }\n\n function updateBounds(center: any, width: any, height: any) {\n const halfWidth = width / 2\n const halfHeight = height / 2\n minX = Math.min(minX, center.x - halfWidth)\n minY = Math.min(minY, center.y - halfHeight)\n maxX = Math.max(maxX, center.x + halfWidth)\n maxY = Math.max(maxY, center.y + halfHeight)\n }\n\n function updateTraceBounds(route: any[]) {\n for (const point of route) {\n minX = Math.min(minX, point.x)\n minY = Math.min(minY, point.y)\n maxX = Math.max(maxX, point.x)\n maxY = Math.max(maxY, point.y)\n }\n }\n}\n\nfunction createSvgObjects(elm: AnySoupElement, transform: Matrix): SvgObject[] {\n switch (elm.type) {\n case \"pcb_component\":\n return [createSvgObjectsFromPcbComponent(elm, transform)].filter(Boolean)\n case \"pcb_trace\":\n return createSvgObjectsFromPcbTrace(elm, transform)\n case \"pcb_plated_hole\":\n return [createSvgObjectsFromPcbHole(elm, transform)].filter(Boolean)\n case \"pcb_smtpad\":\n return createSvgObjectsFromSmtPad(elm, transform)\n default:\n return []\n }\n}\n\nfunction createSvgObjectsFromPcbComponent(component: any, transform: any): any {\n const { center, width, height, rotation = 0 } = component\n const [x, y] = applyToPoint(transform, [center.x, center.y])\n const scaledWidth = width * Math.abs(transform.a)\n const scaledHeight = height * Math.abs(transform.d)\n const transformStr = `translate(${x}, ${y}) rotate(${-rotation}) scale(1, -1)`\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform: transformStr },\n children: [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-component\",\n x: (-scaledWidth / 2).toString(),\n y: (-scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: scaledHeight.toString(),\n },\n },\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-component-outline\",\n x: (-scaledWidth / 2).toString(),\n y: (-scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: scaledHeight.toString(),\n },\n },\n ],\n }\n}\n\nfunction createSvgObjectsFromPcbHole(hole: any, transform: any): any {\n const [x, y] = applyToPoint(transform, [hole.x, hole.y])\n const scaledOuterRadius = (hole.outer_diameter / 2) * Math.abs(transform.a)\n const scaledInnerRadius = (hole.hole_diameter / 2) * Math.abs(transform.a)\n return {\n name: \"g\",\n type: \"element\",\n children: [\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-outer\",\n cx: x.toString(),\n cy: y.toString(),\n r: scaledOuterRadius.toString(),\n },\n },\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-inner\",\n cx: x.toString(),\n cy: y.toString(),\n r: scaledInnerRadius.toString(),\n },\n },\n ],\n }\n}\n\nfunction createPcbSilkscreenPath(silkscreenPath: any, transform: any): any {\n if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return null\n\n let path = silkscreenPath.route\n .map((point: any, index: number) => {\n const [x, y] = applyToPoint(transform, [point.x, point.y])\n return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`\n })\n .join(\" \")\n\n // Close the path if it's not already closed\n const firstPoint = silkscreenPath.route[0]\n const lastPoint = silkscreenPath.route[silkscreenPath.route.length - 1]\n if (firstPoint.x !== lastPoint.x || firstPoint.y !== lastPoint.y) {\n path += \" Z\"\n }\n\n return {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: `pcb-silkscreen pcb-silkscreen-${silkscreenPath.layer}`,\n d: path,\n \"stroke-width\": (\n silkscreenPath.stroke_width * Math.abs(transform.a)\n ).toString(),\n \"data-pcb-component-id\": silkscreenPath.pcb_component_id,\n \"data-pcb-silkscreen-path-id\": silkscreenPath.pcb_silkscreen_path_id,\n },\n }\n}\n\nfunction createSvgObjectFromPcbBoundary(\n transform: any,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): SvgObject {\n const [x1, y1] = applyToPoint(transform, [minX, minY])\n const [x2, y2] = applyToPoint(transform, [maxX, maxY])\n const width = Math.abs(x2 - x1)\n const height = Math.abs(y2 - y1)\n const x = Math.min(x1, x2)\n const y = Math.min(y1, y2)\n return {\n name: \"rect\",\n type: \"element\",\n value: \"\",\n children: [],\n attributes: {\n class: \"pcb-boundary\",\n x: x.toString(),\n y: y.toString(),\n width: width.toString(),\n height: height.toString(),\n },\n }\n}\n\nexport { circuitJsonToPcbSvg }\n","/**\n * Return pairs of adjacent elements in an array.\n */\nexport function pairs<T>(arr: Array<T>): Array<[T, T]> {\n const result: Array<[T, T]> = []\n for (let i = 0; i < arr.length - 1; i++) {\n result.push([arr[i]!, arr[i + 1]!])\n }\n return result\n}\n","import type { AnySoupElement, PCBTrace } from \"@tscircuit/soup\"\nimport { pairs } from \"src/utils/pairs\"\nimport { type INode as SvgObject, stringify } from \"svgson\"\nimport { applyToPoint } from \"transformation-matrix\"\nimport { LAYER_NAME_TO_COLOR } from \"../layer-name-to-color\"\n\nexport function createSvgObjectsFromPcbTrace(\n trace: PCBTrace,\n transform: any,\n): SvgObject[] {\n if (!trace.route || !Array.isArray(trace.route) || trace.route.length < 2)\n return []\n\n const segments = pairs(trace.route)\n const svgObjects: SvgObject[] = []\n\n for (const [start, end] of segments) {\n const startPoint = applyToPoint(transform, [start.x, start.y])\n const endPoint = applyToPoint(transform, [end.x, end.y])\n\n const layer =\n \"layer\" in start ? start.layer : \"layer\" in end ? end.layer : null\n if (!layer) continue\n\n const layerColor =\n LAYER_NAME_TO_COLOR[layer as keyof typeof LAYER_NAME_TO_COLOR] ?? \"white\"\n\n const traceWidth =\n \"width\" in start ? start.width : \"width\" in end ? end.width : null\n\n svgObjects.push({\n name: \"path\",\n type: \"element\",\n value: \"\",\n children: [],\n attributes: {\n class: \"pcb-trace\",\n stroke: layerColor,\n d: `M ${startPoint[0]} ${startPoint[1]} L ${endPoint[0]} ${endPoint[1]}`,\n \"stroke-width\": traceWidth\n ? (traceWidth * Math.abs(transform.a)).toString()\n : \"0.3\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n \"shape-rendering\": \"crispEdges\",\n },\n })\n }\n return svgObjects\n}\n","/**\n * TODO use @tscircuit/pcb-colors when it's published\n */\nexport const LAYER_NAME_TO_COLOR = {\n top: \"rgb(200, 52, 52)\",\n bottom: \"rgb(77, 127, 196)\",\n}\n\nexport function layerNameToColor(layerName: string) {\n return (\n LAYER_NAME_TO_COLOR[layerName as keyof typeof LAYER_NAME_TO_COLOR] ??\n \"white\"\n )\n}\n","import type { PCBSMTPad } from \"@tscircuit/soup\"\nimport { applyToPoint, type Matrix } from \"transformation-matrix\"\nimport { layerNameToColor } from \"../layer-name-to-color\"\n\nexport function createSvgObjectsFromSmtPad(\n pad: PCBSMTPad,\n transform: Matrix,\n): any {\n const [x, y] = applyToPoint(transform, [pad.x, pad.y])\n\n if (pad.shape === \"rect\") {\n const width = pad.width * Math.abs(transform.a)\n const height = pad.height * Math.abs(transform.d)\n return [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-pad\",\n fill: layerNameToColor(pad.layer),\n x: (x - width / 2).toString(),\n y: (y - height / 2).toString(),\n width: width.toString(),\n height: height.toString(),\n },\n },\n ]\n }\n // TODO implement smtpad circles/ovals etc.\n return []\n}\n","import type { AnySoupElement } from \"@tscircuit/soup\"\nimport { getSvg, symbols } from \"schematic-symbols\"\nimport { parseSync, stringify } from \"svgson\"\n\nfunction circuitJsonToSchematicSvg(soup: AnySoupElement[]): string {\n let minX = Number.POSITIVE_INFINITY\n let minY = Number.POSITIVE_INFINITY\n let maxX = Number.NEGATIVE_INFINITY\n let maxY = Number.NEGATIVE_INFINITY\n\n const portSize = 0.2\n const portPositions = new Map()\n\n // First pass: find the bounds and collect port positions\n for (const item of soup) {\n if (item.type === \"schematic_component\") {\n updateBounds(item.center, item.size, item.rotation || 0)\n } else if (item.type === \"schematic_port\") {\n updateBounds(item.center, { width: portSize, height: portSize }, 0)\n portPositions.set(item.schematic_port_id, item.center)\n } else if (item.type === \"schematic_text\") {\n updateBounds(item.position, { width: 0, height: 0 }, 0)\n }\n }\n\n const height = maxY - minY\n const flipY = (y: number) => height - (y - minY) + minY\n\n const svgChildren: any[] = []\n\n // Process components\n const componentMap = new Map()\n for (const component of soup.filter(\n (item) => item.type === \"schematic_component\",\n )) {\n const flippedCenter = {\n x: component.center.x,\n y: flipY(component.center.y),\n }\n const svg = createSchematicComponent(\n flippedCenter,\n component.size,\n component.rotation || 0,\n (component as any).symbol_name,\n )\n svgChildren.push(svg)\n componentMap.set(component.schematic_component_id, component)\n }\n\n // Process ports and add lines to component edges\n for (const port of soup.filter((item) => item.type === \"schematic_port\")) {\n const flippedCenter = { x: port.center.x, y: flipY(port.center.y) }\n const svg = createSchematicPort(flippedCenter)\n svgChildren.push(svg)\n\n const component = componentMap.get(port.schematic_component_id)\n if (component) {\n const line = createPortToComponentLine(\n flippedCenter,\n component,\n port.facing_direction || \"right\",\n )\n svgChildren.push(line)\n }\n }\n\n // Process schematic traces\n for (const trace of soup.filter((item) => item.type === \"schematic_trace\")) {\n const svg = createSchematicTrace(trace, flipY, portPositions)\n if (svg) svgChildren.push(svg)\n }\n\n // Process text\n for (const text of soup.filter((item) => item.type === \"schematic_text\")) {\n const flippedPosition = { x: text.position.x, y: flipY(text.position.y) }\n const svg = createSchematicText(text, flippedPosition)\n svgChildren.push(svg)\n }\n\n const padding = 1\n const width = maxX - minX + 2 * padding\n const viewBox = `${minX - padding} ${minY - padding} ${width} ${height + 2 * padding}`\n\n const svgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox,\n width: \"1200\",\n height: \"600\",\n style: \"background-color: #fff;\",\n },\n children: [\n {\n name: \"style\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n .component { fill: none; stroke: red; stroke-width: 0.03; }\n .component-pin { fill: none; stroke: red; stroke-width: 0.03; }\n .trace { stroke: green; stroke-width: 0.03; fill: none; }\n .text { font-family: Arial, sans-serif; font-size: 0.2px; }\n .port { fill: none; stroke: blue; stroke-width: 0.03; }\n `,\n },\n ],\n },\n ...svgChildren,\n ],\n }\n\n return stringify({ value: \"\", ...svgObject })\n\n function updateBounds(center: any, size: any, rotation: number) {\n const corners = [\n { x: -size.width / 2, y: -size.height / 2 },\n { x: size.width / 2, y: -size.height / 2 },\n { x: size.width / 2, y: size.height / 2 },\n { x: -size.width / 2, y: size.height / 2 },\n ]\n\n for (const corner of corners) {\n const rotatedX =\n corner.x * Math.cos(rotation) - corner.y * Math.sin(rotation) + center.x\n const rotatedY =\n corner.x * Math.sin(rotation) + corner.y * Math.cos(rotation) + center.y\n minX = Math.min(minX, rotatedX)\n minY = Math.min(minY, rotatedY)\n maxX = Math.max(maxX, rotatedX)\n maxY = Math.max(maxY, rotatedY)\n }\n }\n}\n\nfunction createSchematicComponent(\n center: { x: number; y: number },\n size: { width: number; height: number },\n rotation: number,\n symbolName?: string,\n): any {\n const transform = `translate(${center.x}, ${center.y}) rotate(${(rotation * 180) / Math.PI})`\n\n if (symbolName) {\n const symbol = (symbols as any)[symbolName]\n const paths = symbol.primitives.filter((p: any) => p.type === \"path\")\n const updatedSymbol = {\n ...symbol,\n primitives: paths,\n }\n const svg = parseSync(\n getSvg(updatedSymbol, {\n width: size.width,\n height: size.height,\n }),\n )\n\n // Filter out non-path elements and modify path colors\n const pathElements = svg.children\n .filter(\n (child: any) =>\n child.name === \"path\" && child.attributes.fill !== \"green\",\n )\n .map((path: any) => {\n const currentStrokeWidth = Number.parseFloat(\n path.attributes[\"stroke-width\"] || \"0.02\",\n )\n const newStrokeWidth = (currentStrokeWidth * 1.5).toString()\n\n return {\n ...path,\n attributes: {\n ...path.attributes,\n stroke:\n path.attributes.stroke === \"black\"\n ? \"red\"\n : path.attributes.stroke,\n \"stroke-width\": newStrokeWidth,\n },\n }\n })\n\n // Check if viewBox attribute exists\n const viewBoxAttr = svg.attributes.viewBox\n if (typeof viewBoxAttr === \"undefined\") {\n throw new Error(\"SVG does not have a viewBox attribute.\")\n }\n\n // Extract viewBox values\n const viewBox = viewBoxAttr.split(\" \").map(Number)\n if (viewBox.length < 4) {\n throw new Error(\"Invalid viewBox attribute.\")\n }\n const [minX, minY, width = 0, height = 0] = viewBox\n\n // Calculate scale factors\n const scaleX = size.width / (width || 1)\n const scaleY = size.height / (height || 1)\n\n const scale = Math.min(scaleX, scaleY)\n\n // Adjust transformation to include scaling and centering\n const adjustedTransform = `${transform} scale(${scale}) translate(${-(minX ?? 0) - width / 2}, ${-(minY ?? 0) - height / 2})`\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform: adjustedTransform },\n children: pathElements,\n }\n }\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform },\n children: [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"component\",\n x: (-size.width / 2).toString(),\n y: (-size.height / 2).toString(),\n width: size.width.toString(),\n height: size.height.toString(),\n },\n },\n ],\n }\n}\n\nfunction createSchematicPort(center: { x: number; y: number }): any {\n const portSize = 0.2\n const x = center.x - portSize / 2\n const y = center.y - portSize / 2\n\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"port\",\n x: x.toString(),\n y: y.toString(),\n width: portSize.toString(),\n height: portSize.toString(),\n },\n }\n}\n\nfunction createPortToComponentLine(\n portCenter: { x: number; y: number },\n component: any,\n facingDirection: string,\n): any {\n const componentCenter = { x: component.center.x, y: portCenter.y }\n const halfWidth = component.size.width / 2\n const halfHeight = component.size.height / 2\n\n let endX = portCenter.x\n let endY = portCenter.y\n\n switch (facingDirection) {\n case \"left\":\n endX = componentCenter.x - halfWidth\n break\n case \"right\":\n endX = componentCenter.x + halfWidth\n break\n case \"up\":\n endY = componentCenter.y - halfHeight\n break\n case \"down\":\n endY = componentCenter.y + halfHeight\n break\n }\n\n return {\n name: \"line\",\n type: \"element\",\n attributes: {\n class: \"component-pin\",\n x1: portCenter.x.toString(),\n y1: portCenter.y.toString(),\n x2: endX.toString(),\n y2: endY.toString(),\n },\n }\n}\n\nfunction createSchematicTrace(\n trace: any,\n flipY: (y: number) => number,\n portPositions: Map<string, { x: number; y: number }>,\n): any {\n const edges = trace.edges\n if (edges.length === 0) return null\n\n let path = \"\"\n\n // Process all edges\n edges.forEach((edge: any, index: number) => {\n const fromPoint =\n edge.from.ti !== undefined ? portPositions.get(edge.from.ti) : edge.from\n const toPoint =\n edge.to.ti !== undefined ? portPositions.get(edge.to.ti) : edge.to\n\n if (!fromPoint || !toPoint) {\n return\n }\n\n const fromCoord = `${fromPoint.x} ${flipY(fromPoint.y)}`\n const toCoord = `${toPoint.x} ${flipY(toPoint.y)}`\n\n if (index === 0) {\n path += `M ${fromCoord} L ${toCoord}`\n } else {\n path += ` L ${toCoord}`\n }\n })\n\n // Handle connection to final port if needed\n if (trace.to_schematic_port_id) {\n const finalPort = portPositions.get(trace.to_schematic_port_id)\n if (finalPort) {\n const lastFromPoint = path.split(\"M\")[1]?.split(\"L\")[0]\n const lastEdge = edges[edges.length - 1]\n const lastPoint =\n lastEdge.to.ti !== undefined\n ? portPositions.get(lastEdge.to.ti)\n : lastEdge.to\n if (lastPoint.x !== finalPort.x || lastPoint.y !== finalPort.y) {\n const finalCoord = `${finalPort.x} ${flipY(finalPort.y)}`\n path += ` M ${lastFromPoint} L ${finalCoord}`\n }\n }\n }\n\n return path\n ? {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"trace\",\n d: path,\n },\n }\n : null\n}\n\nfunction createSchematicText(\n text: any,\n position: { x: number; y: number },\n): any {\n return {\n name: \"text\",\n type: \"element\",\n attributes: {\n class: \"text\",\n x: position.x.toString(),\n y: position.y.toString(),\n \"text-anchor\": getTextAnchor(text.anchor),\n \"dominant-baseline\": \"middle\",\n },\n children: [\n {\n type: \"text\",\n value: text.text ? text.text : \"\",\n },\n ],\n }\n}\n\nfunction getTextAnchor(anchor: string): string {\n switch (anchor) {\n case \"left\":\n return \"start\"\n case \"right\":\n return \"end\"\n default:\n return \"middle\"\n }\n}\n\nexport { circuitJsonToSchematicSvg }\n"],"mappings":"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","names":["stringify","applyToPoint","applyToPoint","applyToPoint","stringify","applyToPoint","stringify","scale"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circuit-to-svg",
|
|
3
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.22",
|
|
4
5
|
"description": "Convert Circuit JSON to SVG",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"files": [
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
],
|
|
9
10
|
"scripts": {
|
|
10
11
|
"prepublish": "npm run build",
|
|
11
|
-
"build": "tsup ./src/index.ts --dts --sourcemap",
|
|
12
|
+
"build": "tsup-node ./src/index.ts --format esm --dts --sourcemap",
|
|
12
13
|
"format": "biome format . --write",
|
|
13
14
|
"storybook": "storybook dev -p 6006",
|
|
14
15
|
"build-storybook": "storybook build"
|
|
@@ -26,10 +27,12 @@
|
|
|
26
27
|
"@storybook/react-vite": "^8.2.5",
|
|
27
28
|
"@storybook/test": "^8.2.5",
|
|
28
29
|
"@tscircuit/plop": "^0.0.10",
|
|
30
|
+
"bun-match-svg": "^0.0.3",
|
|
29
31
|
"esbuild": "^0.20.2",
|
|
30
32
|
"storybook": "^8.2.5",
|
|
31
33
|
"tsup": "^8.0.2",
|
|
32
|
-
"typescript": "^5.4.5"
|
|
34
|
+
"typescript": "^5.4.5",
|
|
35
|
+
"vite-tsconfig-paths": "^5.0.1"
|
|
33
36
|
},
|
|
34
37
|
"peerDependencies": {
|
|
35
38
|
"@tscircuit/soup": "^0.0.55"
|