circuit-to-svg 0.0.132 → 0.0.134
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/README.md +6 -0
- package/dist/index.d.ts +11 -3
- package/dist/index.js +162 -89
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,12 @@ Converts a schematic circuit description to an SVG string.
|
|
|
50
50
|
|
|
51
51
|
Converts a PCB layout description to an SVG string.
|
|
52
52
|
|
|
53
|
+
#### Options
|
|
54
|
+
|
|
55
|
+
- `width` and `height` – dimensions of the output SVG. Defaults to `800x600`.
|
|
56
|
+
- `matchBoardAspectRatio` – if `true`, adjust the SVG dimensions so the
|
|
57
|
+
resulting aspect ratio matches the `pcb_board` found in the circuit JSON.
|
|
58
|
+
|
|
53
59
|
## Contributing
|
|
54
60
|
|
|
55
61
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { AnyCircuitElement } from 'circuit-json';
|
|
2
|
+
import { Matrix } from 'transformation-matrix';
|
|
2
3
|
|
|
3
4
|
interface Options$3 {
|
|
4
5
|
width?: number;
|
|
5
6
|
height?: number;
|
|
6
7
|
shouldDrawErrors?: boolean;
|
|
7
8
|
shouldDrawRatsNest?: boolean;
|
|
9
|
+
layer?: "top" | "bottom";
|
|
10
|
+
matchBoardAspectRatio?: boolean;
|
|
8
11
|
}
|
|
9
|
-
|
|
12
|
+
interface PcbContext {
|
|
13
|
+
transform: Matrix;
|
|
14
|
+
layer?: "top" | "bottom";
|
|
15
|
+
shouldDrawErrors?: boolean;
|
|
16
|
+
}
|
|
17
|
+
declare function convertCircuitJsonToPcbSvg(circuitJson: AnyCircuitElement[], options?: Options$3): string;
|
|
10
18
|
/**
|
|
11
19
|
* @deprecated use `convertCircuitJsonToPcbSvg` instead
|
|
12
20
|
*/
|
|
@@ -206,6 +214,6 @@ interface Options {
|
|
|
206
214
|
width?: number;
|
|
207
215
|
height?: number;
|
|
208
216
|
}
|
|
209
|
-
declare function convertCircuitJsonToSolderPasteMask(
|
|
217
|
+
declare function convertCircuitJsonToSolderPasteMask(circuitJson: AnyCircuitElement[], options: Options): string;
|
|
210
218
|
|
|
211
|
-
export { type ColorMap, type ColorOverrides, circuitJsonToPcbSvg, circuitJsonToSchematicSvg, convertCircuitJsonToAssemblySvg, convertCircuitJsonToPcbSvg, convertCircuitJsonToSchematicSvg, convertCircuitJsonToSolderPasteMask };
|
|
219
|
+
export { type ColorMap, type ColorOverrides, type PcbContext, circuitJsonToPcbSvg, circuitJsonToSchematicSvg, convertCircuitJsonToAssemblySvg, convertCircuitJsonToPcbSvg, convertCircuitJsonToSchematicSvg, convertCircuitJsonToSolderPasteMask };
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
|
|
10
10
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-trace-error.ts
|
|
11
11
|
import { applyToPoint } from "transformation-matrix";
|
|
12
|
-
function createSvgObjectsFromPcbTraceError(pcbTraceError,
|
|
12
|
+
function createSvgObjectsFromPcbTraceError(pcbTraceError, circuitJson, ctx) {
|
|
13
|
+
const { transform, shouldDrawErrors } = ctx;
|
|
13
14
|
if (!shouldDrawErrors) return [];
|
|
14
15
|
const { pcb_port_ids } = pcbTraceError;
|
|
15
16
|
const port1 = circuitJson.find(
|
|
@@ -27,7 +28,7 @@ function createSvgObjectsFromPcbTraceError(pcbTraceError, transform, circuitJson
|
|
|
27
28
|
(el) => el.type === "pcb_via" && el.pcb_via_id === viaId
|
|
28
29
|
);
|
|
29
30
|
if (via && via.type === "pcb_via") {
|
|
30
|
-
return createSvgObjectsForViaTraceError(pcbTraceError, via,
|
|
31
|
+
return createSvgObjectsForViaTraceError(pcbTraceError, via, ctx);
|
|
31
32
|
}
|
|
32
33
|
if (pcbTraceError.center) {
|
|
33
34
|
const screenCenter = applyToPoint(transform, {
|
|
@@ -159,7 +160,8 @@ function createSvgObjectsFromPcbTraceError(pcbTraceError, transform, circuitJson
|
|
|
159
160
|
];
|
|
160
161
|
return svgObjects;
|
|
161
162
|
}
|
|
162
|
-
function createSvgObjectsForViaTraceError(pcbTraceError, via,
|
|
163
|
+
function createSvgObjectsForViaTraceError(pcbTraceError, via, ctx) {
|
|
164
|
+
const { transform } = ctx;
|
|
163
165
|
if (pcbTraceError.center && via) {
|
|
164
166
|
const screenCenter = applyToPoint(transform, {
|
|
165
167
|
x: pcbTraceError.center.x,
|
|
@@ -242,7 +244,8 @@ function createSvgObjectsForViaTraceError(pcbTraceError, via, transform) {
|
|
|
242
244
|
|
|
243
245
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path.ts
|
|
244
246
|
import { applyToPoint as applyToPoint2 } from "transformation-matrix";
|
|
245
|
-
function createSvgObjectsFromPcbFabricationNotePath(fabNotePath,
|
|
247
|
+
function createSvgObjectsFromPcbFabricationNotePath(fabNotePath, ctx) {
|
|
248
|
+
const { transform, layer: layerFilter } = ctx;
|
|
246
249
|
if (!fabNotePath.route || !Array.isArray(fabNotePath.route)) return [];
|
|
247
250
|
const firstPoint = fabNotePath.route[0];
|
|
248
251
|
const lastPoint = fabNotePath.route[fabNotePath.route.length - 1];
|
|
@@ -272,13 +275,9 @@ function createSvgObjectsFromPcbFabricationNotePath(fabNotePath, transform) {
|
|
|
272
275
|
|
|
273
276
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-text.ts
|
|
274
277
|
import { toString as matrixToString } from "transformation-matrix";
|
|
275
|
-
import {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
rotate,
|
|
279
|
-
translate
|
|
280
|
-
} from "transformation-matrix";
|
|
281
|
-
function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
|
|
278
|
+
import { applyToPoint as applyToPoint3, compose, rotate, translate } from "transformation-matrix";
|
|
279
|
+
function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, ctx) {
|
|
280
|
+
const { transform, layer: layerFilter } = ctx;
|
|
282
281
|
const {
|
|
283
282
|
anchor_position,
|
|
284
283
|
anchor_alignment,
|
|
@@ -287,6 +286,7 @@ function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
|
|
|
287
286
|
layer = "top",
|
|
288
287
|
color
|
|
289
288
|
} = pcbFabNoteText;
|
|
289
|
+
if (layerFilter && layer !== layerFilter) return [];
|
|
290
290
|
if (!anchor_position || typeof anchor_position.x !== "number" || typeof anchor_position.y !== "number") {
|
|
291
291
|
console.error("Invalid anchor_position:", anchor_position);
|
|
292
292
|
return [];
|
|
@@ -332,7 +332,8 @@ function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
|
|
|
332
332
|
|
|
333
333
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-plated-hole.ts
|
|
334
334
|
import { applyToPoint as applyToPoint4 } from "transformation-matrix";
|
|
335
|
-
function createSvgObjectsFromPcbPlatedHole(hole,
|
|
335
|
+
function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
|
|
336
|
+
const { transform } = ctx;
|
|
336
337
|
const [x, y] = applyToPoint4(transform, [hole.x, hole.y]);
|
|
337
338
|
if (hole.shape === "pill") {
|
|
338
339
|
const scaledOuterWidth = hole.outer_width * Math.abs(transform.a);
|
|
@@ -529,7 +530,8 @@ var SILKSCREEN_TOP_COLOR = "#f2eda1";
|
|
|
529
530
|
var SILKSCREEN_BOTTOM_COLOR = "#5da9e9";
|
|
530
531
|
|
|
531
532
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-silkscreen-path.ts
|
|
532
|
-
function createSvgObjectsFromPcbSilkscreenPath(silkscreenPath,
|
|
533
|
+
function createSvgObjectsFromPcbSilkscreenPath(silkscreenPath, ctx) {
|
|
534
|
+
const { transform, layer: layerFilter } = ctx;
|
|
533
535
|
if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return [];
|
|
534
536
|
let path = silkscreenPath.route.map((point, index) => {
|
|
535
537
|
const [x, y] = applyToPoint5(transform, [point.x, point.y]);
|
|
@@ -541,6 +543,7 @@ function createSvgObjectsFromPcbSilkscreenPath(silkscreenPath, transform) {
|
|
|
541
543
|
path += " Z";
|
|
542
544
|
}
|
|
543
545
|
const layer = silkscreenPath.layer || "top";
|
|
546
|
+
if (layerFilter && layer !== layerFilter) return [];
|
|
544
547
|
const color = layer === "bottom" ? SILKSCREEN_BOTTOM_COLOR : SILKSCREEN_TOP_COLOR;
|
|
545
548
|
return [
|
|
546
549
|
{
|
|
@@ -572,7 +575,8 @@ import {
|
|
|
572
575
|
scale,
|
|
573
576
|
toString as matrixToString2
|
|
574
577
|
} from "transformation-matrix";
|
|
575
|
-
function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText,
|
|
578
|
+
function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, ctx) {
|
|
579
|
+
const { transform, layer: layerFilter } = ctx;
|
|
576
580
|
const {
|
|
577
581
|
anchor_position,
|
|
578
582
|
text,
|
|
@@ -581,6 +585,7 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
|
|
|
581
585
|
ccw_rotation = 0,
|
|
582
586
|
anchor_alignment = "center"
|
|
583
587
|
} = pcbSilkscreenText;
|
|
588
|
+
if (layerFilter && layer !== layerFilter) return [];
|
|
584
589
|
if (!anchor_position || typeof anchor_position.x !== "number" || typeof anchor_position.y !== "number") {
|
|
585
590
|
console.error("Invalid anchor_position:", anchor_position);
|
|
586
591
|
return [];
|
|
@@ -672,10 +677,9 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
|
|
|
672
677
|
}
|
|
673
678
|
|
|
674
679
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-silkscreen-rect.ts
|
|
675
|
-
import {
|
|
676
|
-
|
|
677
|
-
}
|
|
678
|
-
function createSvgObjectsFromPcbSilkscreenRect(pcbSilkscreenRect, transform) {
|
|
680
|
+
import { applyToPoint as applyToPoint7 } from "transformation-matrix";
|
|
681
|
+
function createSvgObjectsFromPcbSilkscreenRect(pcbSilkscreenRect, ctx) {
|
|
682
|
+
const { transform, layer: layerFilter } = ctx;
|
|
679
683
|
const {
|
|
680
684
|
center,
|
|
681
685
|
width,
|
|
@@ -684,6 +688,7 @@ function createSvgObjectsFromPcbSilkscreenRect(pcbSilkscreenRect, transform) {
|
|
|
684
688
|
pcb_silkscreen_rect_id,
|
|
685
689
|
stroke_width = 1
|
|
686
690
|
} = pcbSilkscreenRect;
|
|
691
|
+
if (layerFilter && layer !== layerFilter) return [];
|
|
687
692
|
if (!center || typeof center.x !== "number" || typeof center.y !== "number" || typeof width !== "number" || typeof height !== "number") {
|
|
688
693
|
console.error("Invalid rectangle data:", { center, width, height });
|
|
689
694
|
return [];
|
|
@@ -717,10 +722,9 @@ function createSvgObjectsFromPcbSilkscreenRect(pcbSilkscreenRect, transform) {
|
|
|
717
722
|
}
|
|
718
723
|
|
|
719
724
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-silkscreen-circle.ts
|
|
720
|
-
import {
|
|
721
|
-
|
|
722
|
-
}
|
|
723
|
-
function createSvgObjectsFromPcbSilkscreenCircle(pcbSilkscreenCircle, transform) {
|
|
725
|
+
import { applyToPoint as applyToPoint8 } from "transformation-matrix";
|
|
726
|
+
function createSvgObjectsFromPcbSilkscreenCircle(pcbSilkscreenCircle, ctx) {
|
|
727
|
+
const { transform, layer: layerFilter } = ctx;
|
|
724
728
|
const {
|
|
725
729
|
center,
|
|
726
730
|
radius,
|
|
@@ -728,6 +732,7 @@ function createSvgObjectsFromPcbSilkscreenCircle(pcbSilkscreenCircle, transform)
|
|
|
728
732
|
pcb_silkscreen_circle_id,
|
|
729
733
|
stroke_width = 1
|
|
730
734
|
} = pcbSilkscreenCircle;
|
|
735
|
+
if (layerFilter && layer !== layerFilter) return [];
|
|
731
736
|
if (!center || typeof center.x !== "number" || typeof center.y !== "number" || typeof radius !== "number") {
|
|
732
737
|
console.error("Invalid PCB Silkscreen Circle data:", { center, radius });
|
|
733
738
|
return [];
|
|
@@ -758,10 +763,9 @@ function createSvgObjectsFromPcbSilkscreenCircle(pcbSilkscreenCircle, transform)
|
|
|
758
763
|
}
|
|
759
764
|
|
|
760
765
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-silkscreen-line.ts
|
|
761
|
-
import {
|
|
762
|
-
|
|
763
|
-
}
|
|
764
|
-
function createSvgObjectsFromPcbSilkscreenLine(pcbSilkscreenLine, transform) {
|
|
766
|
+
import { applyToPoint as applyToPoint9 } from "transformation-matrix";
|
|
767
|
+
function createSvgObjectsFromPcbSilkscreenLine(pcbSilkscreenLine, ctx) {
|
|
768
|
+
const { transform, layer: layerFilter } = ctx;
|
|
765
769
|
const {
|
|
766
770
|
x1,
|
|
767
771
|
y1,
|
|
@@ -771,6 +775,7 @@ function createSvgObjectsFromPcbSilkscreenLine(pcbSilkscreenLine, transform) {
|
|
|
771
775
|
layer = "top",
|
|
772
776
|
pcb_silkscreen_line_id
|
|
773
777
|
} = pcbSilkscreenLine;
|
|
778
|
+
if (layerFilter && layer !== layerFilter) return [];
|
|
774
779
|
if (typeof x1 !== "number" || typeof y1 !== "number" || typeof x2 !== "number" || typeof y2 !== "number") {
|
|
775
780
|
console.error("Invalid coordinates:", { x1, y1, x2, y2 });
|
|
776
781
|
return [];
|
|
@@ -828,7 +833,8 @@ function solderPasteLayerNameToColor(layerName) {
|
|
|
828
833
|
}
|
|
829
834
|
|
|
830
835
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-trace.ts
|
|
831
|
-
function createSvgObjectsFromPcbTrace(trace,
|
|
836
|
+
function createSvgObjectsFromPcbTrace(trace, ctx) {
|
|
837
|
+
const { transform, layer: layerFilter } = ctx;
|
|
832
838
|
if (!trace.route || !Array.isArray(trace.route) || trace.route.length < 2)
|
|
833
839
|
return [];
|
|
834
840
|
const segments = pairs(trace.route);
|
|
@@ -838,6 +844,7 @@ function createSvgObjectsFromPcbTrace(trace, transform) {
|
|
|
838
844
|
const endPoint = applyToPoint10(transform, [end.x, end.y]);
|
|
839
845
|
const layer = "layer" in start ? start.layer : "layer" in end ? end.layer : null;
|
|
840
846
|
if (!layer) continue;
|
|
847
|
+
if (layerFilter && layer !== layerFilter) continue;
|
|
841
848
|
const layerColor = LAYER_NAME_TO_COLOR[layer] ?? "white";
|
|
842
849
|
const traceWidth = "width" in start ? start.width : "width" in end ? end.width : null;
|
|
843
850
|
const svgObject = {
|
|
@@ -875,8 +882,10 @@ function createSvgObjectsFromPcbTrace(trace, transform) {
|
|
|
875
882
|
|
|
876
883
|
// lib/pcb/svg-object-fns/create-svg-objects-from-smt-pads.ts
|
|
877
884
|
import { applyToPoint as applyToPoint11 } from "transformation-matrix";
|
|
878
|
-
function createSvgObjectsFromSmtPad(pad,
|
|
885
|
+
function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
886
|
+
const { transform, layer: layerFilter } = ctx;
|
|
879
887
|
const [x, y] = applyToPoint11(transform, [pad.x, pad.y]);
|
|
888
|
+
if (layerFilter && pad.layer !== layerFilter) return [];
|
|
880
889
|
if (pad.shape === "rect" || pad.shape === "rotated_rect") {
|
|
881
890
|
const width = pad.width * Math.abs(transform.a);
|
|
882
891
|
const height = pad.height * Math.abs(transform.d);
|
|
@@ -938,7 +947,8 @@ function createSvgObjectsFromSmtPad(pad, transform) {
|
|
|
938
947
|
|
|
939
948
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-board.ts
|
|
940
949
|
import { applyToPoint as applyToPoint12 } from "transformation-matrix";
|
|
941
|
-
function createSvgObjectsFromPcbBoard(pcbBoard,
|
|
950
|
+
function createSvgObjectsFromPcbBoard(pcbBoard, ctx) {
|
|
951
|
+
const { transform } = ctx;
|
|
942
952
|
const { width, height, center, outline } = pcbBoard;
|
|
943
953
|
let path;
|
|
944
954
|
if (outline && Array.isArray(outline) && outline.length >= 3) {
|
|
@@ -987,7 +997,8 @@ function createSvgObjectsFromPcbBoard(pcbBoard, transform) {
|
|
|
987
997
|
|
|
988
998
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-via.ts
|
|
989
999
|
import { applyToPoint as applyToPoint13 } from "transformation-matrix";
|
|
990
|
-
function createSvgObjectsFromPcbVia(hole,
|
|
1000
|
+
function createSvgObjectsFromPcbVia(hole, ctx) {
|
|
1001
|
+
const { transform } = ctx;
|
|
991
1002
|
const [x, y] = applyToPoint13(transform, [hole.x, hole.y]);
|
|
992
1003
|
const scaledOuterWidth = hole.outer_diameter * Math.abs(transform.a);
|
|
993
1004
|
const scaledOuterHeight = hole.outer_diameter * Math.abs(transform.a);
|
|
@@ -1027,7 +1038,8 @@ function createSvgObjectsFromPcbVia(hole, transform) {
|
|
|
1027
1038
|
|
|
1028
1039
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-hole.ts
|
|
1029
1040
|
import { applyToPoint as applyToPoint14 } from "transformation-matrix";
|
|
1030
|
-
function createSvgObjectsFromPcbHole(hole,
|
|
1041
|
+
function createSvgObjectsFromPcbHole(hole, ctx) {
|
|
1042
|
+
const { transform } = ctx;
|
|
1031
1043
|
const [x, y] = applyToPoint14(transform, [hole.x, hole.y]);
|
|
1032
1044
|
if (hole.hole_shape === "circle" || hole.hole_shape === "square") {
|
|
1033
1045
|
const scaledDiameter = hole.hole_diameter * Math.abs(transform.a);
|
|
@@ -1135,7 +1147,8 @@ var findNearestPointInNet = (sourcePoint, netId, connectivity, circuitJson) => {
|
|
|
1135
1147
|
|
|
1136
1148
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-rats-nests.ts
|
|
1137
1149
|
import { su as su2 } from "@tscircuit/circuit-json-util";
|
|
1138
|
-
function createSvgObjectsForRatsNest(circuitJson,
|
|
1150
|
+
function createSvgObjectsForRatsNest(circuitJson, ctx) {
|
|
1151
|
+
const { transform } = ctx;
|
|
1139
1152
|
const connectivity = getFullConnectivityMapFromCircuitJson(circuitJson);
|
|
1140
1153
|
const pcbPorts = circuitJson.filter((elm) => elm.type === "pcb_port");
|
|
1141
1154
|
const sourceTraces = circuitJson.filter((elm) => elm.type === "source_trace");
|
|
@@ -1211,7 +1224,8 @@ import {
|
|
|
1211
1224
|
translate as translate3,
|
|
1212
1225
|
toString as matrixToString6
|
|
1213
1226
|
} from "transformation-matrix";
|
|
1214
|
-
function createSvgObjectsFromPcbCutout(cutout,
|
|
1227
|
+
function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
1228
|
+
const { transform } = ctx;
|
|
1215
1229
|
if (cutout.shape === "rect") {
|
|
1216
1230
|
const rectCutout = cutout;
|
|
1217
1231
|
const [cx, cy] = applyToPoint16(transform, [
|
|
@@ -1303,34 +1317,64 @@ var OBJECT_ORDER = [
|
|
|
1303
1317
|
"pcb_component",
|
|
1304
1318
|
"pcb_board"
|
|
1305
1319
|
];
|
|
1306
|
-
function convertCircuitJsonToPcbSvg(
|
|
1320
|
+
function convertCircuitJsonToPcbSvg(circuitJson, options) {
|
|
1321
|
+
const layer = options?.layer;
|
|
1307
1322
|
let minX = Number.POSITIVE_INFINITY;
|
|
1308
1323
|
let minY = Number.POSITIVE_INFINITY;
|
|
1309
1324
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
1310
1325
|
let maxY = Number.NEGATIVE_INFINITY;
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1326
|
+
let boardMinX = Number.POSITIVE_INFINITY;
|
|
1327
|
+
let boardMinY = Number.POSITIVE_INFINITY;
|
|
1328
|
+
let boardMaxX = Number.NEGATIVE_INFINITY;
|
|
1329
|
+
let boardMaxY = Number.NEGATIVE_INFINITY;
|
|
1330
|
+
for (const circuitJsonElm of circuitJson) {
|
|
1331
|
+
if (circuitJsonElm.type === "pcb_board") {
|
|
1332
|
+
if (circuitJsonElm.outline && Array.isArray(circuitJsonElm.outline) && circuitJsonElm.outline.length >= 3) {
|
|
1333
|
+
updateBoundsToIncludeOutline(circuitJsonElm.outline);
|
|
1334
|
+
updateBoardBoundsToIncludeOutline(circuitJsonElm.outline);
|
|
1335
|
+
} else if ("center" in circuitJsonElm && "width" in circuitJsonElm && "height" in circuitJsonElm) {
|
|
1336
|
+
updateBounds(
|
|
1337
|
+
circuitJsonElm.center,
|
|
1338
|
+
circuitJsonElm.width,
|
|
1339
|
+
circuitJsonElm.height
|
|
1340
|
+
);
|
|
1341
|
+
updateBoardBounds(
|
|
1342
|
+
circuitJsonElm.center,
|
|
1343
|
+
circuitJsonElm.width,
|
|
1344
|
+
circuitJsonElm.height
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
} else if ("x" in circuitJsonElm && "y" in circuitJsonElm) {
|
|
1348
|
+
updateBounds({ x: circuitJsonElm.x, y: circuitJsonElm.y }, 0, 0);
|
|
1349
|
+
} else if ("route" in circuitJsonElm) {
|
|
1350
|
+
updateTraceBounds(circuitJsonElm.route);
|
|
1351
|
+
} else if (circuitJsonElm.type === "pcb_silkscreen_text" || circuitJsonElm.type === "pcb_silkscreen_rect" || circuitJsonElm.type === "pcb_silkscreen_circle" || circuitJsonElm.type === "pcb_silkscreen_line") {
|
|
1352
|
+
updateSilkscreenBounds(circuitJsonElm);
|
|
1323
1353
|
}
|
|
1324
1354
|
}
|
|
1325
1355
|
const padding = 1;
|
|
1326
1356
|
const circuitWidth = maxX - minX + 2 * padding;
|
|
1327
1357
|
const circuitHeight = maxY - minY + 2 * padding;
|
|
1328
|
-
|
|
1329
|
-
|
|
1358
|
+
let svgWidth = options?.width ?? 800;
|
|
1359
|
+
let svgHeight = options?.height ?? 600;
|
|
1360
|
+
if (options?.matchBoardAspectRatio) {
|
|
1361
|
+
const boardWidth = boardMaxX - boardMinX;
|
|
1362
|
+
const boardHeight = boardMaxY - boardMinY;
|
|
1363
|
+
if (boardWidth > 0 && boardHeight > 0) {
|
|
1364
|
+
const aspect = boardWidth / boardHeight;
|
|
1365
|
+
if (options?.width && !options?.height) {
|
|
1366
|
+
svgHeight = options.width / aspect;
|
|
1367
|
+
} else if (options?.height && !options?.width) {
|
|
1368
|
+
svgWidth = options.height * aspect;
|
|
1369
|
+
} else {
|
|
1370
|
+
svgHeight = svgWidth / aspect;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1330
1374
|
const paths = [];
|
|
1331
|
-
for (const
|
|
1332
|
-
if ("route" in
|
|
1333
|
-
paths.push(
|
|
1375
|
+
for (const circuitJsonElm of circuitJson) {
|
|
1376
|
+
if ("route" in circuitJsonElm && circuitJsonElm.route !== void 0) {
|
|
1377
|
+
paths.push(circuitJsonElm.route);
|
|
1334
1378
|
}
|
|
1335
1379
|
}
|
|
1336
1380
|
const scaleX = svgWidth / circuitWidth;
|
|
@@ -1346,20 +1390,23 @@ function convertCircuitJsonToPcbSvg(soup, options) {
|
|
|
1346
1390
|
scale2(scaleFactor, -scaleFactor)
|
|
1347
1391
|
// Flip in y-direction
|
|
1348
1392
|
);
|
|
1349
|
-
|
|
1393
|
+
const ctx = {
|
|
1394
|
+
transform,
|
|
1395
|
+
layer,
|
|
1396
|
+
shouldDrawErrors: options?.shouldDrawErrors
|
|
1397
|
+
};
|
|
1398
|
+
let svgObjects = circuitJson.sort(
|
|
1350
1399
|
(a, b) => (OBJECT_ORDER.indexOf(b.type) ?? 9999) - (OBJECT_ORDER.indexOf(a.type) ?? 9999)
|
|
1351
|
-
).flatMap(
|
|
1352
|
-
(item) => createSvgObjects(item, transform, soup, options?.shouldDrawErrors)
|
|
1353
|
-
);
|
|
1400
|
+
).flatMap((elm) => createSvgObjects({ elm, circuitJson, ctx }));
|
|
1354
1401
|
let strokeWidth = String(0.05 * scaleFactor);
|
|
1355
|
-
for (const element of
|
|
1402
|
+
for (const element of circuitJson) {
|
|
1356
1403
|
if ("stroke_width" in element) {
|
|
1357
1404
|
strokeWidth = String(scaleFactor * element.stroke_width);
|
|
1358
1405
|
break;
|
|
1359
1406
|
}
|
|
1360
1407
|
}
|
|
1361
1408
|
if (options?.shouldDrawRatsNest) {
|
|
1362
|
-
const ratsNestObjects = createSvgObjectsForRatsNest(
|
|
1409
|
+
const ratsNestObjects = createSvgObjectsForRatsNest(circuitJson, ctx);
|
|
1363
1410
|
svgObjects = svgObjects.concat(ratsNestObjects);
|
|
1364
1411
|
}
|
|
1365
1412
|
const svgObject = {
|
|
@@ -1412,6 +1459,14 @@ function convertCircuitJsonToPcbSvg(soup, options) {
|
|
|
1412
1459
|
maxX = Math.max(maxX, center.x + halfWidth);
|
|
1413
1460
|
maxY = Math.max(maxY, center.y + halfHeight);
|
|
1414
1461
|
}
|
|
1462
|
+
function updateBoardBounds(center, width, height) {
|
|
1463
|
+
const halfWidth = width / 2;
|
|
1464
|
+
const halfHeight = height / 2;
|
|
1465
|
+
boardMinX = Math.min(boardMinX, center.x - halfWidth);
|
|
1466
|
+
boardMinY = Math.min(boardMinY, center.y - halfHeight);
|
|
1467
|
+
boardMaxX = Math.max(boardMaxX, center.x + halfWidth);
|
|
1468
|
+
boardMaxY = Math.max(boardMaxY, center.y + halfHeight);
|
|
1469
|
+
}
|
|
1415
1470
|
function updateBoundsToIncludeOutline(outline) {
|
|
1416
1471
|
for (const point of outline) {
|
|
1417
1472
|
minX = Math.min(minX, point.x);
|
|
@@ -1420,6 +1475,14 @@ function convertCircuitJsonToPcbSvg(soup, options) {
|
|
|
1420
1475
|
maxY = Math.max(maxY, point.y);
|
|
1421
1476
|
}
|
|
1422
1477
|
}
|
|
1478
|
+
function updateBoardBoundsToIncludeOutline(outline) {
|
|
1479
|
+
for (const point of outline) {
|
|
1480
|
+
boardMinX = Math.min(boardMinX, point.x);
|
|
1481
|
+
boardMinY = Math.min(boardMinY, point.y);
|
|
1482
|
+
boardMaxX = Math.max(boardMaxX, point.x);
|
|
1483
|
+
boardMaxY = Math.max(boardMaxY, point.y);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1423
1486
|
function updateTraceBounds(route) {
|
|
1424
1487
|
for (const point of route) {
|
|
1425
1488
|
minX = Math.min(minX, point.x);
|
|
@@ -1452,50 +1515,53 @@ function convertCircuitJsonToPcbSvg(soup, options) {
|
|
|
1452
1515
|
}
|
|
1453
1516
|
}
|
|
1454
1517
|
}
|
|
1455
|
-
function createSvgObjects(
|
|
1518
|
+
function createSvgObjects({
|
|
1519
|
+
elm,
|
|
1520
|
+
circuitJson,
|
|
1521
|
+
ctx
|
|
1522
|
+
}) {
|
|
1523
|
+
const { transform, layer: layerFilter, shouldDrawErrors } = ctx;
|
|
1456
1524
|
switch (elm.type) {
|
|
1457
1525
|
case "pcb_trace_error":
|
|
1458
|
-
return createSvgObjectsFromPcbTraceError(
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
soup,
|
|
1462
|
-
shouldDrawErrors
|
|
1463
|
-
).filter(Boolean);
|
|
1526
|
+
return createSvgObjectsFromPcbTraceError(elm, circuitJson, ctx).filter(
|
|
1527
|
+
Boolean
|
|
1528
|
+
);
|
|
1464
1529
|
case "pcb_component":
|
|
1465
|
-
return [createSvgObjectsFromPcbComponent(elm,
|
|
1530
|
+
return [createSvgObjectsFromPcbComponent(elm, ctx)].filter(Boolean);
|
|
1466
1531
|
case "pcb_trace":
|
|
1467
|
-
return createSvgObjectsFromPcbTrace(elm,
|
|
1532
|
+
return createSvgObjectsFromPcbTrace(elm, ctx);
|
|
1468
1533
|
case "pcb_plated_hole":
|
|
1469
|
-
return createSvgObjectsFromPcbPlatedHole(elm,
|
|
1534
|
+
return createSvgObjectsFromPcbPlatedHole(elm, ctx).filter(Boolean);
|
|
1470
1535
|
case "pcb_hole":
|
|
1471
|
-
return createSvgObjectsFromPcbHole(elm,
|
|
1536
|
+
return createSvgObjectsFromPcbHole(elm, ctx);
|
|
1472
1537
|
case "pcb_smtpad":
|
|
1473
|
-
return createSvgObjectsFromSmtPad(elm,
|
|
1538
|
+
return createSvgObjectsFromSmtPad(elm, ctx);
|
|
1474
1539
|
case "pcb_silkscreen_text":
|
|
1475
|
-
return createSvgObjectsFromPcbSilkscreenText(elm,
|
|
1540
|
+
return createSvgObjectsFromPcbSilkscreenText(elm, ctx);
|
|
1476
1541
|
case "pcb_silkscreen_rect":
|
|
1477
|
-
return createSvgObjectsFromPcbSilkscreenRect(elm,
|
|
1542
|
+
return createSvgObjectsFromPcbSilkscreenRect(elm, ctx);
|
|
1478
1543
|
case "pcb_silkscreen_circle":
|
|
1479
|
-
return createSvgObjectsFromPcbSilkscreenCircle(elm,
|
|
1544
|
+
return createSvgObjectsFromPcbSilkscreenCircle(elm, ctx);
|
|
1480
1545
|
case "pcb_silkscreen_line":
|
|
1481
|
-
return createSvgObjectsFromPcbSilkscreenLine(elm,
|
|
1546
|
+
return createSvgObjectsFromPcbSilkscreenLine(elm, ctx);
|
|
1482
1547
|
case "pcb_fabrication_note_path":
|
|
1483
|
-
return createSvgObjectsFromPcbFabricationNotePath(elm,
|
|
1548
|
+
return createSvgObjectsFromPcbFabricationNotePath(elm, ctx);
|
|
1484
1549
|
case "pcb_fabrication_note_text":
|
|
1485
|
-
return createSvgObjectsFromPcbFabricationNoteText(elm,
|
|
1550
|
+
return createSvgObjectsFromPcbFabricationNoteText(elm, ctx);
|
|
1486
1551
|
case "pcb_silkscreen_path":
|
|
1487
|
-
return createSvgObjectsFromPcbSilkscreenPath(elm,
|
|
1552
|
+
return createSvgObjectsFromPcbSilkscreenPath(elm, ctx);
|
|
1488
1553
|
case "pcb_board":
|
|
1489
|
-
return createSvgObjectsFromPcbBoard(elm,
|
|
1554
|
+
return createSvgObjectsFromPcbBoard(elm, ctx);
|
|
1490
1555
|
case "pcb_via":
|
|
1491
|
-
return createSvgObjectsFromPcbVia(elm,
|
|
1556
|
+
return createSvgObjectsFromPcbVia(elm, ctx);
|
|
1492
1557
|
case "pcb_cutout":
|
|
1493
|
-
return createSvgObjectsFromPcbCutout(elm,
|
|
1558
|
+
return createSvgObjectsFromPcbCutout(elm, ctx);
|
|
1494
1559
|
default:
|
|
1495
1560
|
return [];
|
|
1496
1561
|
}
|
|
1497
1562
|
}
|
|
1498
|
-
function createSvgObjectsFromPcbComponent(component,
|
|
1563
|
+
function createSvgObjectsFromPcbComponent(component, ctx) {
|
|
1564
|
+
const { transform } = ctx;
|
|
1499
1565
|
const { center, width, height, rotation = 0 } = component;
|
|
1500
1566
|
const [x, y] = applyToPoint17(transform, [center.x, center.y]);
|
|
1501
1567
|
const scaledWidth = width * Math.abs(transform.a);
|
|
@@ -4842,7 +4908,9 @@ import {
|
|
|
4842
4908
|
|
|
4843
4909
|
// lib/pcb/svg-object-fns/convert-circuit-json-to-solder-paste-mask.ts
|
|
4844
4910
|
import { applyToPoint as applyToPoint38 } from "transformation-matrix";
|
|
4845
|
-
function createSvgObjectsFromSolderPaste(solderPaste,
|
|
4911
|
+
function createSvgObjectsFromSolderPaste(solderPaste, ctx) {
|
|
4912
|
+
const { transform, layer: layerFilter } = ctx;
|
|
4913
|
+
if (layerFilter && solderPaste.layer !== layerFilter) return [];
|
|
4846
4914
|
const [x, y] = applyToPoint38(transform, [solderPaste.x, solderPaste.y]);
|
|
4847
4915
|
if (solderPaste.shape === "rect" || solderPaste.shape === "rotated_rect") {
|
|
4848
4916
|
const width = solderPaste.width * Math.abs(transform.a);
|
|
@@ -4922,15 +4990,15 @@ var OBJECT_ORDER3 = [
|
|
|
4922
4990
|
"pcb_board",
|
|
4923
4991
|
"pcb_solder_paste"
|
|
4924
4992
|
];
|
|
4925
|
-
function convertCircuitJsonToSolderPasteMask(
|
|
4993
|
+
function convertCircuitJsonToSolderPasteMask(circuitJson, options) {
|
|
4926
4994
|
let minX = Number.POSITIVE_INFINITY;
|
|
4927
4995
|
let minY = Number.POSITIVE_INFINITY;
|
|
4928
4996
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
4929
4997
|
let maxY = Number.NEGATIVE_INFINITY;
|
|
4930
|
-
const
|
|
4998
|
+
const filteredCircuitJson = circuitJson.filter(
|
|
4931
4999
|
(elm) => elm.type === "pcb_board" || elm.type === "pcb_solder_paste" && elm.layer === options.layer
|
|
4932
5000
|
);
|
|
4933
|
-
for (const item of
|
|
5001
|
+
for (const item of filteredCircuitJson) {
|
|
4934
5002
|
if (item.type === "pcb_board") {
|
|
4935
5003
|
if (item.outline && Array.isArray(item.outline) && item.outline.length >= 3) {
|
|
4936
5004
|
updateBoundsToIncludeOutline(item.outline);
|
|
@@ -4959,9 +5027,13 @@ function convertCircuitJsonToSolderPasteMask(soup, options) {
|
|
|
4959
5027
|
scale8(scaleFactor, -scaleFactor)
|
|
4960
5028
|
// Flip in y-direction
|
|
4961
5029
|
);
|
|
4962
|
-
const
|
|
5030
|
+
const ctx = {
|
|
5031
|
+
transform,
|
|
5032
|
+
layer: options.layer
|
|
5033
|
+
};
|
|
5034
|
+
const svgObjects = filteredCircuitJson.sort(
|
|
4963
5035
|
(a, b) => (OBJECT_ORDER3.indexOf(b.type) ?? 9999) - (OBJECT_ORDER3.indexOf(a.type) ?? 9999)
|
|
4964
|
-
).flatMap((item) => createSvgObjects3(item,
|
|
5036
|
+
).flatMap((item) => createSvgObjects3({ elm: item, ctx }));
|
|
4965
5037
|
const svgObject = {
|
|
4966
5038
|
name: "svg",
|
|
4967
5039
|
type: "element",
|
|
@@ -5021,12 +5093,13 @@ function convertCircuitJsonToSolderPasteMask(soup, options) {
|
|
|
5021
5093
|
}
|
|
5022
5094
|
}
|
|
5023
5095
|
}
|
|
5024
|
-
function createSvgObjects3(elm,
|
|
5096
|
+
function createSvgObjects3({ elm, ctx }) {
|
|
5097
|
+
const { transform } = ctx;
|
|
5025
5098
|
switch (elm.type) {
|
|
5026
5099
|
case "pcb_board":
|
|
5027
|
-
return createSvgObjectsFromPcbBoard(elm,
|
|
5100
|
+
return createSvgObjectsFromPcbBoard(elm, ctx);
|
|
5028
5101
|
case "pcb_solder_paste":
|
|
5029
|
-
return createSvgObjectsFromSolderPaste(elm,
|
|
5102
|
+
return createSvgObjectsFromSolderPaste(elm, ctx);
|
|
5030
5103
|
default:
|
|
5031
5104
|
return [];
|
|
5032
5105
|
}
|