circuit-to-svg 0.0.26 → 0.0.27
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 +205 -161
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,111 +1,63 @@
|
|
|
1
1
|
// src/lib/circuit-to-pcb-svg.ts
|
|
2
2
|
import { stringify as stringify2 } from "svgson";
|
|
3
3
|
import {
|
|
4
|
-
applyToPoint as
|
|
4
|
+
applyToPoint as applyToPoint8,
|
|
5
5
|
compose as compose3,
|
|
6
6
|
scale,
|
|
7
7
|
translate as translate3
|
|
8
8
|
} from "transformation-matrix";
|
|
9
9
|
|
|
10
|
-
// src/
|
|
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
|
-
}
|
|
16
|
-
return result;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// src/lib/svg-object-fns/create-svg-objects-from-pcb-trace.ts
|
|
20
|
-
import "svgson";
|
|
10
|
+
// src/lib/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path.ts
|
|
21
11
|
import { applyToPoint } from "transformation-matrix";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
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({
|
|
12
|
+
function createSvgObjectsFromPcbFabricationNotePath(fabNotePath, transform) {
|
|
13
|
+
if (!fabNotePath.route || !Array.isArray(fabNotePath.route)) return [];
|
|
14
|
+
const firstPoint = fabNotePath.route[0];
|
|
15
|
+
const lastPoint = fabNotePath.route[fabNotePath.route.length - 1];
|
|
16
|
+
const isClosed = firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y;
|
|
17
|
+
const path = fabNotePath.route.slice(0, isClosed ? -1 : void 0).map((point, index) => {
|
|
18
|
+
const [x, y] = applyToPoint(transform, [point.x, point.y]);
|
|
19
|
+
return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
|
|
20
|
+
}).join(" ") + (isClosed ? " Z" : "");
|
|
21
|
+
return [
|
|
22
|
+
{
|
|
46
23
|
name: "path",
|
|
47
24
|
type: "element",
|
|
48
|
-
value: "",
|
|
49
|
-
children: [],
|
|
50
25
|
attributes: {
|
|
51
|
-
class: "pcb-
|
|
52
|
-
stroke:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"stroke-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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 [];
|
|
26
|
+
class: "pcb-fabrication-note-path",
|
|
27
|
+
stroke: "rgba(255,255,255,0.5)",
|
|
28
|
+
fill: "none",
|
|
29
|
+
d: path,
|
|
30
|
+
"stroke-width": (fabNotePath.stroke_width * Math.abs(transform.a)).toString(),
|
|
31
|
+
"data-pcb-component-id": fabNotePath.pcb_component_id,
|
|
32
|
+
"data-pcb-fabrication-note-path-id": fabNotePath.fabrication_note_path_id
|
|
33
|
+
},
|
|
34
|
+
value: "",
|
|
35
|
+
children: []
|
|
36
|
+
}
|
|
37
|
+
];
|
|
87
38
|
}
|
|
88
39
|
|
|
89
|
-
// src/lib/svg-object-fns/create-svg-objects-from-pcb-
|
|
40
|
+
// src/lib/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-text.ts
|
|
41
|
+
import { toString as matrixToString } from "transformation-matrix";
|
|
90
42
|
import {
|
|
91
|
-
applyToPoint as
|
|
43
|
+
applyToPoint as applyToPoint2,
|
|
92
44
|
compose,
|
|
93
45
|
rotate,
|
|
94
|
-
translate
|
|
95
|
-
toString as matrixToString
|
|
46
|
+
translate
|
|
96
47
|
} from "transformation-matrix";
|
|
97
|
-
function
|
|
48
|
+
function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
|
|
98
49
|
const {
|
|
99
50
|
anchor_position,
|
|
51
|
+
anchor_alignment,
|
|
100
52
|
text,
|
|
101
53
|
font_size = 1,
|
|
102
54
|
layer = "top"
|
|
103
|
-
} =
|
|
55
|
+
} = pcbFabNoteText;
|
|
104
56
|
if (!anchor_position || typeof anchor_position.x !== "number" || typeof anchor_position.y !== "number") {
|
|
105
57
|
console.error("Invalid anchor_position:", anchor_position);
|
|
106
58
|
return [];
|
|
107
59
|
}
|
|
108
|
-
const [transformedX, transformedY] =
|
|
60
|
+
const [transformedX, transformedY] = applyToPoint2(transform, [
|
|
109
61
|
anchor_position.x,
|
|
110
62
|
anchor_position.y
|
|
111
63
|
]);
|
|
@@ -116,6 +68,7 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
|
|
|
116
68
|
}
|
|
117
69
|
const textTransform = compose(
|
|
118
70
|
translate(transformedX, transformedY),
|
|
71
|
+
// TODO do anchor_alignment
|
|
119
72
|
rotate(Math.PI / 180)
|
|
120
73
|
// Convert degrees to radians
|
|
121
74
|
);
|
|
@@ -130,8 +83,8 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
|
|
|
130
83
|
"text-anchor": "middle",
|
|
131
84
|
"dominant-baseline": "central",
|
|
132
85
|
transform: matrixToString(textTransform),
|
|
133
|
-
class:
|
|
134
|
-
|
|
86
|
+
class: "pcb-fabrication-note-text",
|
|
87
|
+
fill: "rgba(255,255,255,0.5)"
|
|
135
88
|
},
|
|
136
89
|
children: [
|
|
137
90
|
{
|
|
@@ -147,42 +100,12 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
|
|
|
147
100
|
return [svgObject];
|
|
148
101
|
}
|
|
149
102
|
|
|
150
|
-
// src/lib/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path.ts
|
|
151
|
-
import { applyToPoint as applyToPoint4 } from "transformation-matrix";
|
|
152
|
-
function createSvgObjectsFromPcbFabricationNotePath(fabNotePath, transform) {
|
|
153
|
-
if (!fabNotePath.route || !Array.isArray(fabNotePath.route)) return [];
|
|
154
|
-
const firstPoint = fabNotePath.route[0];
|
|
155
|
-
const lastPoint = fabNotePath.route[fabNotePath.route.length - 1];
|
|
156
|
-
const isClosed = firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y;
|
|
157
|
-
const path = fabNotePath.route.slice(0, isClosed ? -1 : void 0).map((point, index) => {
|
|
158
|
-
const [x, y] = applyToPoint4(transform, [point.x, point.y]);
|
|
159
|
-
return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
|
|
160
|
-
}).join(" ") + (isClosed ? " Z" : "");
|
|
161
|
-
return [
|
|
162
|
-
{
|
|
163
|
-
name: "path",
|
|
164
|
-
type: "element",
|
|
165
|
-
attributes: {
|
|
166
|
-
class: "pcb-fabrication-note-path",
|
|
167
|
-
stroke: "rgba(255,255,255,0.5)",
|
|
168
|
-
fill: "none",
|
|
169
|
-
d: path,
|
|
170
|
-
"stroke-width": (fabNotePath.stroke_width * Math.abs(transform.a)).toString(),
|
|
171
|
-
"data-pcb-component-id": fabNotePath.pcb_component_id,
|
|
172
|
-
"data-pcb-fabrication-note-path-id": fabNotePath.fabrication_note_path_id
|
|
173
|
-
},
|
|
174
|
-
value: "",
|
|
175
|
-
children: []
|
|
176
|
-
}
|
|
177
|
-
];
|
|
178
|
-
}
|
|
179
|
-
|
|
180
103
|
// src/lib/svg-object-fns/create-svg-objects-from-pcb-silkscreen-path.ts
|
|
181
|
-
import { applyToPoint as
|
|
104
|
+
import { applyToPoint as applyToPoint3 } from "transformation-matrix";
|
|
182
105
|
function createSvgObjectsFromPcbSilkscreenPath(silkscreenPath, transform) {
|
|
183
106
|
if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return [];
|
|
184
107
|
let path = silkscreenPath.route.map((point, index) => {
|
|
185
|
-
const [x, y] =
|
|
108
|
+
const [x, y] = applyToPoint3(transform, [point.x, point.y]);
|
|
186
109
|
return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
|
|
187
110
|
}).join(" ");
|
|
188
111
|
const firstPoint = silkscreenPath.route[0];
|
|
@@ -207,27 +130,26 @@ function createSvgObjectsFromPcbSilkscreenPath(silkscreenPath, transform) {
|
|
|
207
130
|
];
|
|
208
131
|
}
|
|
209
132
|
|
|
210
|
-
// src/lib/svg-object-fns/create-svg-objects-from-pcb-
|
|
211
|
-
import { toString as matrixToString2 } from "transformation-matrix";
|
|
133
|
+
// src/lib/svg-object-fns/create-svg-objects-from-pcb-silkscreen-text.ts
|
|
212
134
|
import {
|
|
213
|
-
applyToPoint as
|
|
135
|
+
applyToPoint as applyToPoint4,
|
|
214
136
|
compose as compose2,
|
|
215
137
|
rotate as rotate2,
|
|
216
|
-
translate as translate2
|
|
138
|
+
translate as translate2,
|
|
139
|
+
toString as matrixToString2
|
|
217
140
|
} from "transformation-matrix";
|
|
218
|
-
function
|
|
141
|
+
function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
|
|
219
142
|
const {
|
|
220
143
|
anchor_position,
|
|
221
|
-
anchor_alignment,
|
|
222
144
|
text,
|
|
223
145
|
font_size = 1,
|
|
224
146
|
layer = "top"
|
|
225
|
-
} =
|
|
147
|
+
} = pcbSilkscreenText;
|
|
226
148
|
if (!anchor_position || typeof anchor_position.x !== "number" || typeof anchor_position.y !== "number") {
|
|
227
149
|
console.error("Invalid anchor_position:", anchor_position);
|
|
228
150
|
return [];
|
|
229
151
|
}
|
|
230
|
-
const [transformedX, transformedY] =
|
|
152
|
+
const [transformedX, transformedY] = applyToPoint4(transform, [
|
|
231
153
|
anchor_position.x,
|
|
232
154
|
anchor_position.y
|
|
233
155
|
]);
|
|
@@ -238,7 +160,6 @@ function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
|
|
|
238
160
|
}
|
|
239
161
|
const textTransform = compose2(
|
|
240
162
|
translate2(transformedX, transformedY),
|
|
241
|
-
// TODO do anchor_alignment
|
|
242
163
|
rotate2(Math.PI / 180)
|
|
243
164
|
// Convert degrees to radians
|
|
244
165
|
);
|
|
@@ -253,8 +174,8 @@ function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
|
|
|
253
174
|
"text-anchor": "middle",
|
|
254
175
|
"dominant-baseline": "central",
|
|
255
176
|
transform: matrixToString2(textTransform),
|
|
256
|
-
class:
|
|
257
|
-
|
|
177
|
+
class: `pcb-silkscreen-text pcb-silkscreen-${layer}`,
|
|
178
|
+
"data-pcb-silkscreen-text-id": pcbSilkscreenText.pcb_component_id
|
|
258
179
|
},
|
|
259
180
|
children: [
|
|
260
181
|
{
|
|
@@ -270,14 +191,168 @@ function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
|
|
|
270
191
|
return [svgObject];
|
|
271
192
|
}
|
|
272
193
|
|
|
194
|
+
// src/utils/pairs.ts
|
|
195
|
+
function pairs(arr) {
|
|
196
|
+
const result = [];
|
|
197
|
+
for (let i = 0; i < arr.length - 1; i++) {
|
|
198
|
+
result.push([arr[i], arr[i + 1]]);
|
|
199
|
+
}
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/lib/svg-object-fns/create-svg-objects-from-pcb-trace.ts
|
|
204
|
+
import "svgson";
|
|
205
|
+
import { applyToPoint as applyToPoint5 } from "transformation-matrix";
|
|
206
|
+
|
|
207
|
+
// src/lib/layer-name-to-color.ts
|
|
208
|
+
var LAYER_NAME_TO_COLOR = {
|
|
209
|
+
top: "rgb(200, 52, 52)",
|
|
210
|
+
bottom: "rgb(77, 127, 196)"
|
|
211
|
+
};
|
|
212
|
+
function layerNameToColor(layerName) {
|
|
213
|
+
return LAYER_NAME_TO_COLOR[layerName] ?? "white";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/lib/svg-object-fns/create-svg-objects-from-pcb-trace.ts
|
|
217
|
+
function createSvgObjectsFromPcbTrace(trace, transform) {
|
|
218
|
+
if (!trace.route || !Array.isArray(trace.route) || trace.route.length < 2)
|
|
219
|
+
return [];
|
|
220
|
+
const segments = pairs(trace.route);
|
|
221
|
+
const svgObjects = [];
|
|
222
|
+
for (const [start, end] of segments) {
|
|
223
|
+
const startPoint = applyToPoint5(transform, [start.x, start.y]);
|
|
224
|
+
const endPoint = applyToPoint5(transform, [end.x, end.y]);
|
|
225
|
+
const layer = "layer" in start ? start.layer : "layer" in end ? end.layer : null;
|
|
226
|
+
if (!layer) continue;
|
|
227
|
+
const layerColor = LAYER_NAME_TO_COLOR[layer] ?? "white";
|
|
228
|
+
const traceWidth = "width" in start ? start.width : "width" in end ? end.width : null;
|
|
229
|
+
svgObjects.push({
|
|
230
|
+
name: "path",
|
|
231
|
+
type: "element",
|
|
232
|
+
value: "",
|
|
233
|
+
children: [],
|
|
234
|
+
attributes: {
|
|
235
|
+
class: "pcb-trace",
|
|
236
|
+
stroke: layerColor,
|
|
237
|
+
d: `M ${startPoint[0]} ${startPoint[1]} L ${endPoint[0]} ${endPoint[1]}`,
|
|
238
|
+
"stroke-width": traceWidth ? (traceWidth * Math.abs(transform.a)).toString() : "0.3",
|
|
239
|
+
"stroke-linecap": "round",
|
|
240
|
+
"stroke-linejoin": "round",
|
|
241
|
+
"shape-rendering": "crispEdges"
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return svgObjects;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/lib/svg-object-fns/create-svg-objects-from-smt-pads.ts
|
|
249
|
+
import { applyToPoint as applyToPoint6 } from "transformation-matrix";
|
|
250
|
+
function createSvgObjectsFromSmtPad(pad, transform) {
|
|
251
|
+
const [x, y] = applyToPoint6(transform, [pad.x, pad.y]);
|
|
252
|
+
if (pad.shape === "rect") {
|
|
253
|
+
const width = pad.width * Math.abs(transform.a);
|
|
254
|
+
const height = pad.height * Math.abs(transform.d);
|
|
255
|
+
return [
|
|
256
|
+
{
|
|
257
|
+
name: "rect",
|
|
258
|
+
type: "element",
|
|
259
|
+
attributes: {
|
|
260
|
+
class: "pcb-pad",
|
|
261
|
+
fill: layerNameToColor(pad.layer),
|
|
262
|
+
x: (x - width / 2).toString(),
|
|
263
|
+
y: (y - height / 2).toString(),
|
|
264
|
+
width: width.toString(),
|
|
265
|
+
height: height.toString()
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
return [];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/lib/svg-object-fns/create-svg-objects-from-pcb-plated-hole.ts
|
|
274
|
+
import { applyToPoint as applyToPoint7 } from "transformation-matrix";
|
|
275
|
+
function createSvgObjectsFromPcbHole(hole, transform) {
|
|
276
|
+
const [x, y] = applyToPoint7(transform, [hole.x, hole.y]);
|
|
277
|
+
if (hole.shape === "pill") {
|
|
278
|
+
const scaledOuterWidth = hole.outer_width * Math.abs(transform.a);
|
|
279
|
+
const scaledOuterHeight = hole.outer_height * Math.abs(transform.a);
|
|
280
|
+
const scaledHoleWidth = hole.hole_width * Math.abs(transform.a);
|
|
281
|
+
const scaledHoleHeight = hole.hole_height * Math.abs(transform.a);
|
|
282
|
+
const outerRadiusX = scaledOuterWidth / 2;
|
|
283
|
+
const outerRadiusY = scaledOuterHeight / 2;
|
|
284
|
+
const innerRadiusX = scaledHoleWidth / 2;
|
|
285
|
+
const innerRadiusY = scaledHoleHeight / 2;
|
|
286
|
+
const straightLength = scaledOuterHeight - scaledOuterWidth;
|
|
287
|
+
return {
|
|
288
|
+
name: "g",
|
|
289
|
+
type: "element",
|
|
290
|
+
children: [
|
|
291
|
+
// Outer pill shape
|
|
292
|
+
{
|
|
293
|
+
name: "path",
|
|
294
|
+
type: "element",
|
|
295
|
+
attributes: {
|
|
296
|
+
class: "pcb-hole-outer",
|
|
297
|
+
d: `M${x - outerRadiusX},${y - straightLength / 2} v${straightLength} a${outerRadiusX},${outerRadiusX} 0 0 0 ${scaledOuterWidth},0 v-${straightLength} a${outerRadiusX},${outerRadiusX} 0 0 0 -${scaledOuterWidth},0 z`
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
// Inner pill shape
|
|
301
|
+
{
|
|
302
|
+
name: "path",
|
|
303
|
+
type: "element",
|
|
304
|
+
attributes: {
|
|
305
|
+
class: "pcb-hole-inner",
|
|
306
|
+
d: `M${x - innerRadiusX},${y - (scaledHoleHeight - scaledHoleWidth) / 2} v${scaledHoleHeight - scaledHoleWidth} a${innerRadiusX},${innerRadiusX} 0 0 0 ${scaledHoleWidth},0 v-${scaledHoleHeight - scaledHoleWidth} a${innerRadiusX},${innerRadiusX} 0 0 0 -${scaledHoleWidth},0 z`
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
if (hole.shape === "circle") {
|
|
313
|
+
const scaledOuterWidth = hole.outer_diameter * Math.abs(transform.a);
|
|
314
|
+
const scaledOuterHeight = hole.outer_diameter * Math.abs(transform.a);
|
|
315
|
+
const scaledHoleWidth = hole.hole_diameter * Math.abs(transform.a);
|
|
316
|
+
const scaledHoleHeight = hole.hole_diameter * Math.abs(transform.a);
|
|
317
|
+
const outerRadius = Math.min(scaledOuterWidth, scaledOuterHeight) / 2;
|
|
318
|
+
const innerRadius = Math.min(scaledHoleWidth, scaledHoleHeight) / 2;
|
|
319
|
+
return {
|
|
320
|
+
name: "g",
|
|
321
|
+
type: "element",
|
|
322
|
+
children: [
|
|
323
|
+
{
|
|
324
|
+
name: "circle",
|
|
325
|
+
type: "element",
|
|
326
|
+
attributes: {
|
|
327
|
+
class: "pcb-hole-outer",
|
|
328
|
+
cx: x.toString(),
|
|
329
|
+
cy: y.toString(),
|
|
330
|
+
r: outerRadius.toString()
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
name: "circle",
|
|
335
|
+
type: "element",
|
|
336
|
+
attributes: {
|
|
337
|
+
class: "pcb-hole-inner",
|
|
338
|
+
cx: x.toString(),
|
|
339
|
+
cy: y.toString(),
|
|
340
|
+
r: innerRadius.toString()
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
]
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
273
348
|
// src/lib/circuit-to-pcb-svg.ts
|
|
274
349
|
var OBJECT_ORDER = [
|
|
350
|
+
"pcb_plated_hole",
|
|
275
351
|
"pcb_fabrication_note_text",
|
|
276
352
|
"pcb_fabrication_note_path",
|
|
277
353
|
"pcb_silkscreen_text",
|
|
278
354
|
"pcb_silkscreen_path",
|
|
279
355
|
"pcb_trace",
|
|
280
|
-
"pcb_plated_hole",
|
|
281
356
|
"pcb_smtpad",
|
|
282
357
|
"pcb_component"
|
|
283
358
|
];
|
|
@@ -422,7 +497,7 @@ function createSvgObjects(elm, transform) {
|
|
|
422
497
|
}
|
|
423
498
|
function createSvgObjectsFromPcbComponent(component, transform) {
|
|
424
499
|
const { center, width, height, rotation = 0 } = component;
|
|
425
|
-
const [x, y] =
|
|
500
|
+
const [x, y] = applyToPoint8(transform, [center.x, center.y]);
|
|
426
501
|
const scaledWidth = width * Math.abs(transform.a);
|
|
427
502
|
const scaledHeight = height * Math.abs(transform.d);
|
|
428
503
|
const transformStr = `translate(${x}, ${y}) rotate(${-rotation}) scale(1, -1)`;
|
|
@@ -456,40 +531,9 @@ function createSvgObjectsFromPcbComponent(component, transform) {
|
|
|
456
531
|
]
|
|
457
532
|
};
|
|
458
533
|
}
|
|
459
|
-
function createSvgObjectsFromPcbHole(hole, transform) {
|
|
460
|
-
const [x, y] = applyToPoint7(transform, [hole.x, hole.y]);
|
|
461
|
-
const scaledOuterRadius = hole.outer_diameter / 2 * Math.abs(transform.a);
|
|
462
|
-
const scaledInnerRadius = hole.hole_diameter / 2 * Math.abs(transform.a);
|
|
463
|
-
return {
|
|
464
|
-
name: "g",
|
|
465
|
-
type: "element",
|
|
466
|
-
children: [
|
|
467
|
-
{
|
|
468
|
-
name: "circle",
|
|
469
|
-
type: "element",
|
|
470
|
-
attributes: {
|
|
471
|
-
class: "pcb-hole-outer",
|
|
472
|
-
cx: x.toString(),
|
|
473
|
-
cy: y.toString(),
|
|
474
|
-
r: scaledOuterRadius.toString()
|
|
475
|
-
}
|
|
476
|
-
},
|
|
477
|
-
{
|
|
478
|
-
name: "circle",
|
|
479
|
-
type: "element",
|
|
480
|
-
attributes: {
|
|
481
|
-
class: "pcb-hole-inner",
|
|
482
|
-
cx: x.toString(),
|
|
483
|
-
cy: y.toString(),
|
|
484
|
-
r: scaledInnerRadius.toString()
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
]
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
534
|
function createSvgObjectFromPcbBoundary(transform, minX, minY, maxX, maxY) {
|
|
491
|
-
const [x1, y1] =
|
|
492
|
-
const [x2, y2] =
|
|
535
|
+
const [x1, y1] = applyToPoint8(transform, [minX, minY]);
|
|
536
|
+
const [x2, y2] = applyToPoint8(transform, [maxX, maxY]);
|
|
493
537
|
const width = Math.abs(x2 - x1);
|
|
494
538
|
const height = Math.abs(y2 - y1);
|
|
495
539
|
const x = Math.min(x1, x2);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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/svg-object-fns/create-svg-objects-from-pcb-silkscreen-text.ts","../src/lib/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path.ts","../src/lib/svg-object-fns/create-svg-objects-from-pcb-silkscreen-path.ts","../src/lib/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-text.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\"\nimport { createSvgObjectsFromPcbSilkscreenText } from \"./svg-object-fns/create-svg-objects-from-pcb-silkscreen-text\"\nimport { createSvgObjectsFromPcbFabricationNotePath } from \"./svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path\"\nimport { createSvgObjectsFromPcbSilkscreenPath } from \"./svg-object-fns/create-svg-objects-from-pcb-silkscreen-path\"\nimport { createSvgObjectsFromPcbFabricationNoteText } from \"./svg-object-fns/create-svg-objects-from-pcb-fabrication-note-text\"\n\nconst OBJECT_ORDER: AnySoupElement[\"type\"][] = [\n \"pcb_fabrication_note_text\",\n \"pcb_fabrication_note_path\",\n \"pcb_silkscreen_text\",\n \"pcb_silkscreen_path\",\n \"pcb_trace\",\n \"pcb_plated_hole\",\n \"pcb_smtpad\",\n \"pcb_component\",\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 svgObjects = soup\n .sort(\n (a, b) =>\n (OBJECT_ORDER.indexOf(b.type) ?? 9999) -\n (OBJECT_ORDER.indexOf(a.type) ?? 9999),\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 .pcb-silkscreen-text { fill: #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 ...svgObjects,\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 case \"pcb_silkscreen_text\":\n return createSvgObjectsFromPcbSilkscreenText(elm, transform)\n case \"pcb_fabrication_note_path\":\n return createSvgObjectsFromPcbFabricationNotePath(elm, transform)\n case \"pcb_fabrication_note_text\":\n return createSvgObjectsFromPcbFabricationNoteText(elm, transform)\n case \"pcb_silkscreen_path\":\n return createSvgObjectsFromPcbSilkscreenPath(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 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 { PcbSilkscreenText } from \"@tscircuit/soup\"\nimport type { INode as SvgObject } from \"svgson\"\nimport {\n type Matrix,\n applyToPoint,\n compose,\n rotate,\n translate,\n toString as matrixToString,\n} from \"transformation-matrix\"\n\nexport function createSvgObjectsFromPcbSilkscreenText(\n pcbSilkscreenText: PcbSilkscreenText,\n transform: Matrix,\n): SvgObject[] {\n const {\n anchor_position,\n text,\n font_size = 1,\n layer = \"top\",\n } = pcbSilkscreenText\n\n if (\n !anchor_position ||\n typeof anchor_position.x !== \"number\" ||\n typeof anchor_position.y !== \"number\"\n ) {\n console.error(\"Invalid anchor_position:\", anchor_position)\n return []\n }\n\n const [transformedX, transformedY] = applyToPoint(transform, [\n anchor_position.x,\n anchor_position.y,\n ])\n const transformedFontSize = font_size * Math.abs(transform.a)\n\n // Remove ${} from text value and handle undefined text\n const cleanedText = (text || \"\").replace(/\\$\\{|\\}/g, \"\")\n if (!cleanedText) {\n return []\n }\n\n // Create a composite transformation\n const textTransform = compose(\n translate(transformedX, transformedY),\n rotate(Math.PI / 180), // Convert degrees to radians\n )\n\n const svgObject: SvgObject = {\n name: \"text\",\n type: \"element\",\n attributes: {\n x: \"0\",\n y: \"0\",\n \"font-family\": \"Arial, sans-serif\",\n \"font-size\": transformedFontSize.toString(),\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n transform: matrixToString(textTransform),\n class: `pcb-silkscreen-text pcb-silkscreen-${layer}`,\n \"data-pcb-silkscreen-text-id\": pcbSilkscreenText.pcb_component_id,\n },\n children: [\n {\n type: \"text\",\n value: cleanedText,\n name: \"\",\n attributes: {},\n children: [],\n },\n ],\n value: \"\",\n }\n\n return [svgObject]\n}\n","import type { PcbSilkscreenPath, PcbFabricationNotePath } from \"@tscircuit/soup\"\nimport { applyToPoint, type Matrix } from \"transformation-matrix\"\nimport type { SvgObject } from \"../svg-object\"\n\nexport function createSvgObjectsFromPcbFabricationNotePath(\n fabNotePath: PcbFabricationNotePath,\n transform: Matrix,\n): SvgObject[] {\n if (!fabNotePath.route || !Array.isArray(fabNotePath.route)) return []\n\n // Close the path if the first and last points are the same\n const firstPoint = fabNotePath.route[0]\n const lastPoint = fabNotePath.route[fabNotePath.route.length - 1]\n const isClosed =\n firstPoint!.x === lastPoint!.x && firstPoint!.y === lastPoint!.y\n\n const path =\n fabNotePath.route\n .slice(0, isClosed ? -1 : undefined)\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(\" \") + (isClosed ? \" Z\" : \"\")\n\n return [\n {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"pcb-fabrication-note-path\",\n stroke: \"rgba(255,255,255,0.5)\",\n fill: \"none\",\n d: path,\n \"stroke-width\": (\n fabNotePath.stroke_width * Math.abs(transform.a)\n ).toString(),\n \"data-pcb-component-id\": fabNotePath.pcb_component_id,\n \"data-pcb-fabrication-note-path-id\":\n fabNotePath.fabrication_note_path_id,\n },\n value: \"\",\n children: [],\n },\n ]\n}\n","import type { PcbSilkscreenPath } from \"@tscircuit/soup\"\nimport { applyToPoint, type Matrix } from \"transformation-matrix\"\nimport type { SvgObject } from \"../svg-object\"\n\nexport function createSvgObjectsFromPcbSilkscreenPath(\n silkscreenPath: PcbSilkscreenPath,\n transform: Matrix,\n): SvgObject[] {\n if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return []\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 return [\n {\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 value: \"\",\n children: [],\n },\n ]\n}\n","import type { PcbFabricationNoteText } from \"@tscircuit/soup\"\nimport type { INode as SvgObject } from \"svgson\"\nimport { toString as matrixToString } from \"transformation-matrix\"\nimport {\n type Matrix,\n applyToPoint,\n compose,\n rotate,\n translate,\n} from \"transformation-matrix\"\n\nexport function createSvgObjectsFromPcbFabricationNoteText(\n pcbFabNoteText: PcbFabricationNoteText,\n transform: Matrix,\n): SvgObject[] {\n const {\n anchor_position,\n anchor_alignment,\n text,\n font_size = 1,\n layer = \"top\",\n } = pcbFabNoteText\n\n if (\n !anchor_position ||\n typeof anchor_position.x !== \"number\" ||\n typeof anchor_position.y !== \"number\"\n ) {\n console.error(\"Invalid anchor_position:\", anchor_position)\n return []\n }\n\n const [transformedX, transformedY] = applyToPoint(transform, [\n anchor_position.x,\n anchor_position.y,\n ])\n const transformedFontSize = font_size * Math.abs(transform.a)\n\n // Remove ${} from text value and handle undefined text\n const cleanedText = (text || \"\").replace(/\\$\\{|\\}/g, \"\")\n if (!cleanedText) {\n return []\n }\n\n // Create a composite transformation\n const textTransform = compose(\n translate(transformedX, transformedY), // TODO do anchor_alignment\n rotate(Math.PI / 180), // Convert degrees to radians\n )\n\n const svgObject: SvgObject = {\n name: \"text\",\n type: \"element\",\n attributes: {\n x: \"0\",\n y: \"0\",\n \"font-family\": \"Arial, sans-serif\",\n \"font-size\": transformedFontSize.toString(),\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n transform: matrixToString(textTransform),\n class: \"pcb-fabrication-note-text\",\n fill: \"rgba(255,255,255,0.5)\",\n },\n children: [\n {\n type: \"text\",\n value: cleanedText,\n name: \"\",\n attributes: {},\n children: [],\n },\n ],\n value: \"\",\n }\n\n return [svgObject]\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","compose","translate","applyToPoint","applyToPoint","applyToPoint","applyToPoint","applyToPoint","matrixToString","applyToPoint","compose","rotate","translate","compose","translate","stringify","applyToPoint","stringify","scale"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/circuit-to-pcb-svg.ts","../src/lib/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path.ts","../src/lib/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-text.ts","../src/lib/svg-object-fns/create-svg-objects-from-pcb-silkscreen-path.ts","../src/lib/svg-object-fns/create-svg-objects-from-pcb-silkscreen-text.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/svg-object-fns/create-svg-objects-from-pcb-plated-hole.ts","../src/lib/circuit-to-schematic-svg.ts"],"sourcesContent":["import type { AnySoupElement } from \"@tscircuit/soup\"\nimport { type INode as SvgObject, stringify } from \"svgson\"\nimport {\n type Matrix,\n applyToPoint,\n compose,\n scale,\n translate,\n} from \"transformation-matrix\"\nimport { createSvgObjectsFromPcbFabricationNotePath } from \"./svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path\"\nimport { createSvgObjectsFromPcbFabricationNoteText } from \"./svg-object-fns/create-svg-objects-from-pcb-fabrication-note-text\"\nimport { createSvgObjectsFromPcbSilkscreenPath } from \"./svg-object-fns/create-svg-objects-from-pcb-silkscreen-path\"\nimport { createSvgObjectsFromPcbSilkscreenText } from \"./svg-object-fns/create-svg-objects-from-pcb-silkscreen-text\"\nimport { createSvgObjectsFromPcbTrace } from \"./svg-object-fns/create-svg-objects-from-pcb-trace\"\nimport { createSvgObjectsFromSmtPad } from \"./svg-object-fns/create-svg-objects-from-smt-pads\"\nimport { createSvgObjectsFromPcbHole } from \"./svg-object-fns/create-svg-objects-from-pcb-plated-hole\"\n\nconst OBJECT_ORDER: AnySoupElement[\"type\"][] = [\n \"pcb_plated_hole\",\n \"pcb_fabrication_note_text\",\n \"pcb_fabrication_note_path\",\n \"pcb_silkscreen_text\",\n \"pcb_silkscreen_path\",\n \"pcb_trace\",\n \"pcb_smtpad\",\n \"pcb_component\",\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 svgObjects = soup\n .sort(\n (a, b) =>\n (OBJECT_ORDER.indexOf(b.type) ?? 9999) -\n (OBJECT_ORDER.indexOf(a.type) ?? 9999),\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 .pcb-silkscreen-text { fill: #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 ...svgObjects,\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 case \"pcb_silkscreen_text\":\n return createSvgObjectsFromPcbSilkscreenText(elm, transform)\n case \"pcb_fabrication_note_path\":\n return createSvgObjectsFromPcbFabricationNotePath(elm, transform)\n case \"pcb_fabrication_note_text\":\n return createSvgObjectsFromPcbFabricationNoteText(elm, transform)\n case \"pcb_silkscreen_path\":\n return createSvgObjectsFromPcbSilkscreenPath(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 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","import type { PcbSilkscreenPath, PcbFabricationNotePath } from \"@tscircuit/soup\"\nimport { applyToPoint, type Matrix } from \"transformation-matrix\"\nimport type { SvgObject } from \"../svg-object\"\n\nexport function createSvgObjectsFromPcbFabricationNotePath(\n fabNotePath: PcbFabricationNotePath,\n transform: Matrix,\n): SvgObject[] {\n if (!fabNotePath.route || !Array.isArray(fabNotePath.route)) return []\n\n // Close the path if the first and last points are the same\n const firstPoint = fabNotePath.route[0]\n const lastPoint = fabNotePath.route[fabNotePath.route.length - 1]\n const isClosed =\n firstPoint!.x === lastPoint!.x && firstPoint!.y === lastPoint!.y\n\n const path =\n fabNotePath.route\n .slice(0, isClosed ? -1 : undefined)\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(\" \") + (isClosed ? \" Z\" : \"\")\n\n return [\n {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"pcb-fabrication-note-path\",\n stroke: \"rgba(255,255,255,0.5)\",\n fill: \"none\",\n d: path,\n \"stroke-width\": (\n fabNotePath.stroke_width * Math.abs(transform.a)\n ).toString(),\n \"data-pcb-component-id\": fabNotePath.pcb_component_id,\n \"data-pcb-fabrication-note-path-id\":\n fabNotePath.fabrication_note_path_id,\n },\n value: \"\",\n children: [],\n },\n ]\n}\n","import type { PcbFabricationNoteText } from \"@tscircuit/soup\"\nimport type { INode as SvgObject } from \"svgson\"\nimport { toString as matrixToString } from \"transformation-matrix\"\nimport {\n type Matrix,\n applyToPoint,\n compose,\n rotate,\n translate,\n} from \"transformation-matrix\"\n\nexport function createSvgObjectsFromPcbFabricationNoteText(\n pcbFabNoteText: PcbFabricationNoteText,\n transform: Matrix,\n): SvgObject[] {\n const {\n anchor_position,\n anchor_alignment,\n text,\n font_size = 1,\n layer = \"top\",\n } = pcbFabNoteText\n\n if (\n !anchor_position ||\n typeof anchor_position.x !== \"number\" ||\n typeof anchor_position.y !== \"number\"\n ) {\n console.error(\"Invalid anchor_position:\", anchor_position)\n return []\n }\n\n const [transformedX, transformedY] = applyToPoint(transform, [\n anchor_position.x,\n anchor_position.y,\n ])\n const transformedFontSize = font_size * Math.abs(transform.a)\n\n // Remove ${} from text value and handle undefined text\n const cleanedText = (text || \"\").replace(/\\$\\{|\\}/g, \"\")\n if (!cleanedText) {\n return []\n }\n\n // Create a composite transformation\n const textTransform = compose(\n translate(transformedX, transformedY), // TODO do anchor_alignment\n rotate(Math.PI / 180), // Convert degrees to radians\n )\n\n const svgObject: SvgObject = {\n name: \"text\",\n type: \"element\",\n attributes: {\n x: \"0\",\n y: \"0\",\n \"font-family\": \"Arial, sans-serif\",\n \"font-size\": transformedFontSize.toString(),\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n transform: matrixToString(textTransform),\n class: \"pcb-fabrication-note-text\",\n fill: \"rgba(255,255,255,0.5)\",\n },\n children: [\n {\n type: \"text\",\n value: cleanedText,\n name: \"\",\n attributes: {},\n children: [],\n },\n ],\n value: \"\",\n }\n\n return [svgObject]\n}\n","import type { PcbSilkscreenPath } from \"@tscircuit/soup\"\nimport { applyToPoint, type Matrix } from \"transformation-matrix\"\nimport type { SvgObject } from \"../svg-object\"\n\nexport function createSvgObjectsFromPcbSilkscreenPath(\n silkscreenPath: PcbSilkscreenPath,\n transform: Matrix,\n): SvgObject[] {\n if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return []\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 return [\n {\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 value: \"\",\n children: [],\n },\n ]\n}\n","import type { PcbSilkscreenText } from \"@tscircuit/soup\"\nimport type { INode as SvgObject } from \"svgson\"\nimport {\n type Matrix,\n applyToPoint,\n compose,\n rotate,\n translate,\n toString as matrixToString,\n} from \"transformation-matrix\"\n\nexport function createSvgObjectsFromPcbSilkscreenText(\n pcbSilkscreenText: PcbSilkscreenText,\n transform: Matrix,\n): SvgObject[] {\n const {\n anchor_position,\n text,\n font_size = 1,\n layer = \"top\",\n } = pcbSilkscreenText\n\n if (\n !anchor_position ||\n typeof anchor_position.x !== \"number\" ||\n typeof anchor_position.y !== \"number\"\n ) {\n console.error(\"Invalid anchor_position:\", anchor_position)\n return []\n }\n\n const [transformedX, transformedY] = applyToPoint(transform, [\n anchor_position.x,\n anchor_position.y,\n ])\n const transformedFontSize = font_size * Math.abs(transform.a)\n\n // Remove ${} from text value and handle undefined text\n const cleanedText = (text || \"\").replace(/\\$\\{|\\}/g, \"\")\n if (!cleanedText) {\n return []\n }\n\n // Create a composite transformation\n const textTransform = compose(\n translate(transformedX, transformedY),\n rotate(Math.PI / 180), // Convert degrees to radians\n )\n\n const svgObject: SvgObject = {\n name: \"text\",\n type: \"element\",\n attributes: {\n x: \"0\",\n y: \"0\",\n \"font-family\": \"Arial, sans-serif\",\n \"font-size\": transformedFontSize.toString(),\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n transform: matrixToString(textTransform),\n class: `pcb-silkscreen-text pcb-silkscreen-${layer}`,\n \"data-pcb-silkscreen-text-id\": pcbSilkscreenText.pcb_component_id,\n },\n children: [\n {\n type: \"text\",\n value: cleanedText,\n name: \"\",\n attributes: {},\n children: [],\n },\n ],\n value: \"\",\n }\n\n return [svgObject]\n}\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 { PCBPlatedHole } from \"@tscircuit/soup\"\nimport { applyToPoint } from \"transformation-matrix\"\n\nexport function createSvgObjectsFromPcbHole(\n hole: PCBPlatedHole,\n transform: any,\n): any {\n const [x, y] = applyToPoint(transform, [hole.x, hole.y])\n\n if (hole.shape === \"pill\") {\n const scaledOuterWidth = hole.outer_width * Math.abs(transform.a)\n const scaledOuterHeight = hole.outer_height * Math.abs(transform.a)\n const scaledHoleWidth = hole.hole_width * Math.abs(transform.a)\n const scaledHoleHeight = hole.hole_height * Math.abs(transform.a)\n\n const outerRadiusX = scaledOuterWidth / 2\n const outerRadiusY = scaledOuterHeight / 2\n const innerRadiusX = scaledHoleWidth / 2\n const innerRadiusY = scaledHoleHeight / 2\n const straightLength = scaledOuterHeight - scaledOuterWidth\n\n return {\n name: \"g\",\n type: \"element\",\n children: [\n // Outer pill shape\n {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-outer\",\n d:\n `M${x - outerRadiusX},${y - straightLength / 2} ` +\n `v${straightLength} ` +\n `a${outerRadiusX},${outerRadiusX} 0 0 0 ${scaledOuterWidth},0 ` +\n `v-${straightLength} ` +\n `a${outerRadiusX},${outerRadiusX} 0 0 0 -${scaledOuterWidth},0 z`,\n },\n },\n // Inner pill shape\n {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-inner\",\n d:\n `M${x - innerRadiusX},${y - (scaledHoleHeight - scaledHoleWidth) / 2} ` +\n `v${scaledHoleHeight - scaledHoleWidth} ` +\n `a${innerRadiusX},${innerRadiusX} 0 0 0 ${scaledHoleWidth},0 ` +\n `v-${scaledHoleHeight - scaledHoleWidth} ` +\n `a${innerRadiusX},${innerRadiusX} 0 0 0 -${scaledHoleWidth},0 z`,\n },\n },\n ],\n }\n }\n // Fallback to circular hole if not pill-shaped\n if (hole.shape === \"circle\") {\n const scaledOuterWidth = hole.outer_diameter * Math.abs(transform.a)\n const scaledOuterHeight = hole.outer_diameter * Math.abs(transform.a)\n const scaledHoleWidth = hole.hole_diameter * Math.abs(transform.a)\n const scaledHoleHeight = hole.hole_diameter * Math.abs(transform.a)\n\n const outerRadius = Math.min(scaledOuterWidth, scaledOuterHeight) / 2\n const innerRadius = Math.min(scaledHoleWidth, scaledHoleHeight) / 2\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: outerRadius.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: innerRadius.toString(),\n },\n },\n ],\n }\n }\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","compose","translate","applyToPoint","applyToPoint","applyToPoint","compose","rotate","translate","matrixToString","applyToPoint","applyToPoint","applyToPoint","applyToPoint","applyToPoint","compose","translate","stringify","applyToPoint","stringify","scale"]}
|