circuit-to-canvas 0.0.50 → 0.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +10 -4
- package/dist/index.js +2911 -2719
- package/lib/drawer/CircuitToCanvasDrawer.ts +317 -366
- package/lib/drawer/elements/helper-functions/draw-pill.ts +39 -0
- package/lib/drawer/elements/helper-functions/draw-polygon.ts +25 -0
- package/lib/drawer/elements/helper-functions/draw-rounded-rect.ts +34 -0
- package/lib/drawer/elements/helper-functions/index.ts +3 -0
- package/lib/drawer/elements/pcb-board.ts +28 -13
- package/lib/drawer/elements/pcb-hole.ts +56 -338
- package/lib/drawer/elements/pcb-plated-hole.ts +154 -442
- package/lib/drawer/elements/pcb-smtpad.ts +3 -292
- package/lib/drawer/elements/pcb-soldermask/board.ts +44 -0
- package/lib/drawer/elements/pcb-soldermask/cutout.ts +74 -0
- package/lib/drawer/elements/pcb-soldermask/hole.ts +288 -0
- package/lib/drawer/elements/pcb-soldermask/index.ts +140 -0
- package/lib/drawer/elements/pcb-soldermask/plated-hole.ts +365 -0
- package/lib/drawer/elements/pcb-soldermask/smt-pad.ts +354 -0
- package/lib/drawer/elements/pcb-soldermask/via.ts +27 -0
- package/package.json +1 -1
- package/tests/board-snapshot/__snapshots__/usb-c-flashlight-board.snap.png +0 -0
- package/tests/board-snapshot/usb-c-flashlight-board.test.ts +1 -0
- package/tests/elements/__snapshots__/board-with-elements.snap.png +0 -0
- package/tests/elements/__snapshots__/brep-copper-pours.snap.png +0 -0
- package/tests/elements/__snapshots__/custom-outline-board.snap.png +0 -0
- package/tests/elements/__snapshots__/oval-plated-hole.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-board.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-comprehensive-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-fabrication-note-dimension.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-hole-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-keepout-layer-filter.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-keepout-multiple-layers.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-keepout-rect-and-circle.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-keepout-with-group-id.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-no-soldermask.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-plated-hole-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-plated-hole.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-silkscreen-on-component.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-silkscreen-oval.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-smtpad-asymmetric-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-smtpad-soldermask-coverage.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-smtpad-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pill-plated-hole.snap.png +0 -0
- package/tests/elements/pcb-board.test.ts +2 -2
- package/tests/elements/pcb-comprehensive-soldermask-margin.test.ts +2 -2
- package/tests/elements/pcb-hole-soldermask-margin.test.ts +155 -2
- package/tests/elements/pcb-keepout-with-group-id.test.ts +1 -1
- package/tests/elements/pcb-no-soldermask.test.ts +1281 -0
- package/tests/elements/pcb-plated-hole-soldermask-margin.test.ts +1 -1
- package/tests/elements/pcb-plated-hole.test.ts +40 -4
- package/tests/elements/pcb-smtpad-asymmetric-soldermask-margin.test.ts +1 -1
- package/tests/elements/pcb-smtpad-soldermask-coverage.test.ts +1 -1
- package/tests/elements/pcb-smtpad-soldermask-margin.test.ts +1 -1
- package/tests/fixtures/getStackedPngSvgComparison.ts +10 -4
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PcbVia } from "circuit-json"
|
|
2
|
+
import type { Matrix } from "transformation-matrix"
|
|
3
|
+
import { applyToPoint } from "transformation-matrix"
|
|
4
|
+
import type { CanvasContext, PcbColorMap } from "../../types"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Process soldermask for a via.
|
|
8
|
+
* Vias typically have soldermask openings to expose the copper ring.
|
|
9
|
+
*/
|
|
10
|
+
export function processViaSoldermask(params: {
|
|
11
|
+
ctx: CanvasContext
|
|
12
|
+
via: PcbVia
|
|
13
|
+
realToCanvasMat: Matrix
|
|
14
|
+
colorMap: PcbColorMap
|
|
15
|
+
}): void {
|
|
16
|
+
const { ctx, via, realToCanvasMat, colorMap } = params
|
|
17
|
+
// Vias typically have soldermask openings to expose the copper ring
|
|
18
|
+
// Draw substrate color to simulate the cutout
|
|
19
|
+
const [cx, cy] = applyToPoint(realToCanvasMat, [via.x, via.y])
|
|
20
|
+
const scaledRadius = (via.outer_diameter / 2) * Math.abs(realToCanvasMat.a)
|
|
21
|
+
|
|
22
|
+
ctx.fillStyle = colorMap.substrate
|
|
23
|
+
ctx.beginPath()
|
|
24
|
+
ctx.arc(cx, cy, scaledRadius, 0, Math.PI * 2)
|
|
25
|
+
ctx.closePath()
|
|
26
|
+
ctx.fill()
|
|
27
|
+
}
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -9,6 +9,7 @@ test("USB-C flashlight - comprehensive comparison (circuit-to-canvas vs circuit-
|
|
|
9
9
|
const stackedPng = await getStackedPngSvgComparison(circuitElements, {
|
|
10
10
|
width: 400,
|
|
11
11
|
height: 800,
|
|
12
|
+
drawSoldermask: true,
|
|
12
13
|
})
|
|
13
14
|
|
|
14
15
|
await expect(stackedPng).toMatchPngSnapshot(import.meta.path)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -22,7 +22,7 @@ test("draw rectangular board", async () => {
|
|
|
22
22
|
material: "fr4",
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
drawer.drawElements([board])
|
|
25
|
+
drawer.drawElements([board], { drawBoardMaterial: true })
|
|
26
26
|
|
|
27
27
|
await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
|
|
28
28
|
import.meta.path,
|
|
@@ -57,7 +57,7 @@ test("draw board with custom outline", async () => {
|
|
|
57
57
|
],
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
drawer.drawElements([board])
|
|
60
|
+
drawer.drawElements([board], { drawBoardMaterial: true })
|
|
61
61
|
|
|
62
62
|
await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
|
|
63
63
|
import.meta.path,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expect, test } from "bun:test"
|
|
2
2
|
import { createCanvas } from "@napi-rs/canvas"
|
|
3
|
-
import { CircuitToCanvasDrawer } from "../../lib/drawer"
|
|
4
3
|
import type { AnyCircuitElement } from "circuit-json"
|
|
4
|
+
import { CircuitToCanvasDrawer } from "../../lib/drawer"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Comprehensive test for soldermask margin functionality:
|
|
@@ -1273,7 +1273,7 @@ test("comprehensive soldermask margin test", async () => {
|
|
|
1273
1273
|
]
|
|
1274
1274
|
|
|
1275
1275
|
drawer.setCameraBounds({ minX: -95, maxX: 90, minY: -22, maxY: 22 })
|
|
1276
|
-
drawer.drawElements(circuit)
|
|
1276
|
+
drawer.drawElements(circuit, { drawSoldermask: true })
|
|
1277
1277
|
|
|
1278
1278
|
await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
|
|
1279
1279
|
import.meta.path,
|
|
@@ -2,7 +2,7 @@ import { expect, test } from "bun:test"
|
|
|
2
2
|
import { createCanvas } from "@napi-rs/canvas"
|
|
3
3
|
import { CircuitToCanvasDrawer } from "../../lib/drawer"
|
|
4
4
|
|
|
5
|
-
test("draw holes with positive soldermask margins", async () => {
|
|
5
|
+
test("draw holes with positive and negative soldermask margins", async () => {
|
|
6
6
|
const canvas = createCanvas(800, 600)
|
|
7
7
|
const ctx = canvas.getContext("2d")
|
|
8
8
|
const drawer = new CircuitToCanvasDrawer(ctx)
|
|
@@ -29,6 +29,122 @@ test("draw holes with positive soldermask margins", async () => {
|
|
|
29
29
|
|
|
30
30
|
soldermask_margin: 0.2,
|
|
31
31
|
},
|
|
32
|
+
// Circle with negative margin
|
|
33
|
+
{
|
|
34
|
+
type: "pcb_hole",
|
|
35
|
+
pcb_hole_id: "hole_circle_negative",
|
|
36
|
+
hole_shape: "circle",
|
|
37
|
+
x: -4,
|
|
38
|
+
y: -2,
|
|
39
|
+
hole_diameter: 1.0,
|
|
40
|
+
|
|
41
|
+
soldermask_margin: -0.15,
|
|
42
|
+
},
|
|
43
|
+
// Square with positive margin
|
|
44
|
+
{
|
|
45
|
+
type: "pcb_hole",
|
|
46
|
+
pcb_hole_id: "hole_square_positive",
|
|
47
|
+
hole_shape: "square",
|
|
48
|
+
x: -1,
|
|
49
|
+
y: 2,
|
|
50
|
+
hole_diameter: 1.0,
|
|
51
|
+
|
|
52
|
+
soldermask_margin: 0.15,
|
|
53
|
+
},
|
|
54
|
+
// Square with negative margin
|
|
55
|
+
{
|
|
56
|
+
type: "pcb_hole",
|
|
57
|
+
pcb_hole_id: "hole_square_negative",
|
|
58
|
+
hole_shape: "square",
|
|
59
|
+
x: -1,
|
|
60
|
+
y: -2,
|
|
61
|
+
hole_diameter: 1.0,
|
|
62
|
+
|
|
63
|
+
soldermask_margin: -0.1,
|
|
64
|
+
},
|
|
65
|
+
// Oval with positive margin
|
|
66
|
+
{
|
|
67
|
+
type: "pcb_hole",
|
|
68
|
+
pcb_hole_id: "hole_oval_positive",
|
|
69
|
+
hole_shape: "oval",
|
|
70
|
+
x: 2,
|
|
71
|
+
y: 2,
|
|
72
|
+
hole_width: 1.5,
|
|
73
|
+
hole_height: 0.8,
|
|
74
|
+
|
|
75
|
+
soldermask_margin: 0.1,
|
|
76
|
+
},
|
|
77
|
+
// Oval with negative margin
|
|
78
|
+
{
|
|
79
|
+
type: "pcb_hole",
|
|
80
|
+
pcb_hole_id: "hole_oval_negative",
|
|
81
|
+
hole_shape: "oval",
|
|
82
|
+
x: 2,
|
|
83
|
+
y: -2,
|
|
84
|
+
hole_width: 1.5,
|
|
85
|
+
hole_height: 0.8,
|
|
86
|
+
|
|
87
|
+
soldermask_margin: -0.12,
|
|
88
|
+
},
|
|
89
|
+
// Rect with positive margin
|
|
90
|
+
{
|
|
91
|
+
type: "pcb_hole",
|
|
92
|
+
pcb_hole_id: "hole_rect_positive",
|
|
93
|
+
hole_shape: "rect",
|
|
94
|
+
x: 5,
|
|
95
|
+
y: 2,
|
|
96
|
+
hole_width: 1.5,
|
|
97
|
+
hole_height: 0.8,
|
|
98
|
+
|
|
99
|
+
soldermask_margin: 0.15,
|
|
100
|
+
},
|
|
101
|
+
// Pill with positive margin
|
|
102
|
+
{
|
|
103
|
+
type: "pcb_hole",
|
|
104
|
+
pcb_hole_id: "hole_pill_positive",
|
|
105
|
+
hole_shape: "pill",
|
|
106
|
+
x: -2.5,
|
|
107
|
+
y: 0,
|
|
108
|
+
hole_width: 1.5,
|
|
109
|
+
hole_height: 0.8,
|
|
110
|
+
|
|
111
|
+
soldermask_margin: 0.1,
|
|
112
|
+
},
|
|
113
|
+
// Pill with negative margin
|
|
114
|
+
{
|
|
115
|
+
type: "pcb_hole",
|
|
116
|
+
pcb_hole_id: "hole_pill_negative",
|
|
117
|
+
hole_shape: "pill",
|
|
118
|
+
x: -2.5,
|
|
119
|
+
y: -4,
|
|
120
|
+
hole_width: 1.5,
|
|
121
|
+
hole_height: 0.8,
|
|
122
|
+
|
|
123
|
+
soldermask_margin: -0.08,
|
|
124
|
+
},
|
|
125
|
+
// Pill with negative margin
|
|
126
|
+
{
|
|
127
|
+
type: "pcb_hole",
|
|
128
|
+
pcb_hole_id: "hole_pill_negative",
|
|
129
|
+
hole_shape: "pill",
|
|
130
|
+
x: -2.5,
|
|
131
|
+
y: -4,
|
|
132
|
+
hole_width: 1.5,
|
|
133
|
+
hole_height: 0.8,
|
|
134
|
+
|
|
135
|
+
soldermask_margin: -0.08,
|
|
136
|
+
},
|
|
137
|
+
// Circle with positive margin (mask extends beyond hole)
|
|
138
|
+
{
|
|
139
|
+
type: "pcb_hole",
|
|
140
|
+
pcb_hole_id: "hole_circle_positive",
|
|
141
|
+
hole_shape: "circle",
|
|
142
|
+
x: -4,
|
|
143
|
+
y: 2,
|
|
144
|
+
hole_diameter: 1.0,
|
|
145
|
+
|
|
146
|
+
soldermask_margin: 0.2,
|
|
147
|
+
},
|
|
32
148
|
// Square with positive margin
|
|
33
149
|
{
|
|
34
150
|
type: "pcb_hole",
|
|
@@ -122,10 +238,47 @@ test("draw holes with positive soldermask margins", async () => {
|
|
|
122
238
|
text: "+0.1mm",
|
|
123
239
|
font_size: 0.4,
|
|
124
240
|
},
|
|
241
|
+
// Labels for negative margin holes (bottom row)
|
|
242
|
+
{
|
|
243
|
+
type: "pcb_silkscreen_text",
|
|
244
|
+
pcb_silkscreen_text_id: "text_circle_neg",
|
|
245
|
+
layer: "top",
|
|
246
|
+
anchor_position: { x: -4, y: -0.8 },
|
|
247
|
+
anchor_alignment: "center",
|
|
248
|
+
text: "-0.15mm",
|
|
249
|
+
font_size: 0.4,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
type: "pcb_silkscreen_text",
|
|
253
|
+
pcb_silkscreen_text_id: "text_square_neg",
|
|
254
|
+
layer: "top",
|
|
255
|
+
anchor_position: { x: -1, y: -0.8 },
|
|
256
|
+
anchor_alignment: "center",
|
|
257
|
+
text: "-0.1mm",
|
|
258
|
+
font_size: 0.4,
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
type: "pcb_silkscreen_text",
|
|
262
|
+
pcb_silkscreen_text_id: "text_oval_neg",
|
|
263
|
+
layer: "top",
|
|
264
|
+
anchor_position: { x: 2, y: -0.8 },
|
|
265
|
+
anchor_alignment: "center",
|
|
266
|
+
text: "-0.12mm",
|
|
267
|
+
font_size: 0.4,
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
type: "pcb_silkscreen_text",
|
|
271
|
+
pcb_silkscreen_text_id: "text_pill_neg",
|
|
272
|
+
layer: "top",
|
|
273
|
+
anchor_position: { x: -2.5, y: -2.8 },
|
|
274
|
+
anchor_alignment: "center",
|
|
275
|
+
text: "-0.08mm",
|
|
276
|
+
font_size: 0.4,
|
|
277
|
+
},
|
|
125
278
|
]
|
|
126
279
|
|
|
127
280
|
drawer.setCameraBounds({ minX: -7, maxX: 7, minY: -5, maxY: 5 })
|
|
128
|
-
drawer.drawElements(circuit)
|
|
281
|
+
drawer.drawElements(circuit, { drawSoldermask: true })
|
|
129
282
|
|
|
130
283
|
await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
|
|
131
284
|
import.meta.path,
|
|
@@ -37,7 +37,7 @@ test("pcb keepout with pcb_group_id and subcircuit_id", async () => {
|
|
|
37
37
|
},
|
|
38
38
|
]
|
|
39
39
|
|
|
40
|
-
drawer.drawElements(elements)
|
|
40
|
+
drawer.drawElements(elements, { drawBoardMaterial: true })
|
|
41
41
|
|
|
42
42
|
await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
|
|
43
43
|
import.meta.path,
|