circuit-to-canvas 0.0.49 → 0.0.51
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 +13 -5
- package/dist/index.js +1450 -1226
- package/lib/drawer/CircuitToCanvasDrawer.ts +262 -312
- 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 +13 -3
- 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 +5 -271
- 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/lib/drawer/elements/soldermask-margin.ts +39 -8
- package/package.json +2 -2
- 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-comprehensive-soldermask-margin.test.ts +2 -2
- package/tests/elements/pcb-hole-soldermask-margin.test.ts +155 -2
- 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 +140 -0
- package/tests/elements/pcb-smtpad-soldermask-coverage.test.ts +1 -1
- package/tests/elements/pcb-smtpad-soldermask-margin.test.ts +18 -2
- package/tests/fixtures/getStackedPngSvgComparison.ts +8 -2
|
@@ -5,13 +5,6 @@ import { drawCircle } from "../shapes/circle"
|
|
|
5
5
|
import { drawRect } from "../shapes/rect"
|
|
6
6
|
import { drawPill } from "../shapes/pill"
|
|
7
7
|
import { drawPolygon } from "../shapes/polygon"
|
|
8
|
-
import {
|
|
9
|
-
drawSoldermaskRingForRect,
|
|
10
|
-
drawSoldermaskRingForCircle,
|
|
11
|
-
drawSoldermaskRingForPill,
|
|
12
|
-
drawSoldermaskRingForPolygon,
|
|
13
|
-
offsetPolygonPoints,
|
|
14
|
-
} from "./soldermask-margin"
|
|
15
8
|
|
|
16
9
|
export interface DrawPcbSmtPadParams {
|
|
17
10
|
ctx: CanvasContext
|
|
@@ -27,53 +20,20 @@ function layerToColor(layer: string, colorMap: PcbColorMap): string {
|
|
|
27
20
|
)
|
|
28
21
|
}
|
|
29
22
|
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function getBorderRadius(pad: PcbSmtPad, margin = 0): number {
|
|
39
|
-
return (
|
|
40
|
-
((pad as { corner_radius?: number }).corner_radius ??
|
|
41
|
-
(pad as { rect_border_radius?: number }).rect_border_radius ??
|
|
42
|
-
0) + margin
|
|
43
|
-
)
|
|
23
|
+
function getBorderRadius(pad: PcbSmtPad): number {
|
|
24
|
+
if (pad.shape === "rect" || pad.shape === "rotated_rect") {
|
|
25
|
+
return pad.corner_radius ?? pad.rect_border_radius ?? 0
|
|
26
|
+
}
|
|
27
|
+
return 0
|
|
44
28
|
}
|
|
45
29
|
|
|
46
30
|
export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
47
31
|
const { ctx, pad, realToCanvasMat, colorMap } = params
|
|
48
32
|
|
|
49
33
|
const color = layerToColor(pad.layer, colorMap)
|
|
50
|
-
const isCoveredWithSoldermask = pad.is_covered_with_solder_mask === true
|
|
51
|
-
// If covered with soldermask, fully covered with no margin; otherwise use soldermask_margin if set
|
|
52
|
-
const margin = isCoveredWithSoldermask ? 0 : (pad.soldermask_margin ?? 0)
|
|
53
|
-
const hasSoldermask =
|
|
54
|
-
!isCoveredWithSoldermask &&
|
|
55
|
-
pad.soldermask_margin !== undefined &&
|
|
56
|
-
pad.soldermask_margin !== 0
|
|
57
|
-
const soldermaskRingColor = getSoldermaskColor(pad.layer, colorMap)
|
|
58
|
-
const positiveMarginColor = colorMap.substrate
|
|
59
|
-
const soldermaskOverlayColor = getSoldermaskColor(pad.layer, colorMap)
|
|
60
34
|
|
|
61
35
|
// Draw the copper pad
|
|
62
36
|
if (pad.shape === "rect") {
|
|
63
|
-
// For positive margins, draw extended mask area first
|
|
64
|
-
if (hasSoldermask && margin > 0) {
|
|
65
|
-
drawRect({
|
|
66
|
-
ctx,
|
|
67
|
-
center: { x: pad.x, y: pad.y },
|
|
68
|
-
width: pad.width + margin * 2,
|
|
69
|
-
height: pad.height + margin * 2,
|
|
70
|
-
fill: positiveMarginColor,
|
|
71
|
-
realToCanvasMat,
|
|
72
|
-
borderRadius: getBorderRadius(pad),
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Draw the pad on top
|
|
77
37
|
drawRect({
|
|
78
38
|
ctx,
|
|
79
39
|
center: { x: pad.x, y: pad.y },
|
|
@@ -83,54 +43,10 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
83
43
|
realToCanvasMat,
|
|
84
44
|
borderRadius: getBorderRadius(pad),
|
|
85
45
|
})
|
|
86
|
-
|
|
87
|
-
// For negative margins, draw soldermask ring on top of the pad
|
|
88
|
-
if (hasSoldermask && margin < 0) {
|
|
89
|
-
drawSoldermaskRingForRect(
|
|
90
|
-
ctx,
|
|
91
|
-
{ x: pad.x, y: pad.y },
|
|
92
|
-
pad.width,
|
|
93
|
-
pad.height,
|
|
94
|
-
margin,
|
|
95
|
-
getBorderRadius(pad),
|
|
96
|
-
0,
|
|
97
|
-
realToCanvasMat,
|
|
98
|
-
soldermaskRingColor,
|
|
99
|
-
color,
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// If covered with soldermask and margin == 0 (treat as 0 positive margin), draw soldermaskOverCopper overlay
|
|
104
|
-
if (isCoveredWithSoldermask && margin === 0) {
|
|
105
|
-
drawRect({
|
|
106
|
-
ctx,
|
|
107
|
-
center: { x: pad.x, y: pad.y },
|
|
108
|
-
width: pad.width,
|
|
109
|
-
height: pad.height,
|
|
110
|
-
fill: soldermaskOverlayColor,
|
|
111
|
-
realToCanvasMat,
|
|
112
|
-
borderRadius: getBorderRadius(pad),
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
46
|
return
|
|
116
47
|
}
|
|
117
48
|
|
|
118
49
|
if (pad.shape === "rotated_rect") {
|
|
119
|
-
// For positive margins, draw extended mask area first
|
|
120
|
-
if (hasSoldermask && margin > 0) {
|
|
121
|
-
drawRect({
|
|
122
|
-
ctx,
|
|
123
|
-
center: { x: pad.x, y: pad.y },
|
|
124
|
-
width: pad.width + margin * 2,
|
|
125
|
-
height: pad.height + margin * 2,
|
|
126
|
-
fill: positiveMarginColor,
|
|
127
|
-
realToCanvasMat,
|
|
128
|
-
borderRadius: getBorderRadius(pad),
|
|
129
|
-
rotation: pad.ccw_rotation ?? 0,
|
|
130
|
-
})
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Draw the pad on top
|
|
134
50
|
drawRect({
|
|
135
51
|
ctx,
|
|
136
52
|
center: { x: pad.x, y: pad.y },
|
|
@@ -141,52 +57,10 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
141
57
|
borderRadius: getBorderRadius(pad),
|
|
142
58
|
rotation: pad.ccw_rotation ?? 0,
|
|
143
59
|
})
|
|
144
|
-
|
|
145
|
-
// For negative margins, draw soldermask ring on top of the pad
|
|
146
|
-
if (hasSoldermask && margin < 0) {
|
|
147
|
-
drawSoldermaskRingForRect(
|
|
148
|
-
ctx,
|
|
149
|
-
{ x: pad.x, y: pad.y },
|
|
150
|
-
pad.width,
|
|
151
|
-
pad.height,
|
|
152
|
-
margin,
|
|
153
|
-
getBorderRadius(pad),
|
|
154
|
-
pad.ccw_rotation ?? 0,
|
|
155
|
-
realToCanvasMat,
|
|
156
|
-
soldermaskRingColor,
|
|
157
|
-
color,
|
|
158
|
-
)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// If covered with soldermask and margin == 0 (treat as 0 positive margin), draw soldermaskOverCopper overlay
|
|
162
|
-
if (isCoveredWithSoldermask && margin === 0) {
|
|
163
|
-
drawRect({
|
|
164
|
-
ctx,
|
|
165
|
-
center: { x: pad.x, y: pad.y },
|
|
166
|
-
width: pad.width,
|
|
167
|
-
height: pad.height,
|
|
168
|
-
fill: soldermaskOverlayColor,
|
|
169
|
-
realToCanvasMat,
|
|
170
|
-
borderRadius: getBorderRadius(pad),
|
|
171
|
-
rotation: pad.ccw_rotation ?? 0,
|
|
172
|
-
})
|
|
173
|
-
}
|
|
174
60
|
return
|
|
175
61
|
}
|
|
176
62
|
|
|
177
63
|
if (pad.shape === "circle") {
|
|
178
|
-
// For positive margins, draw extended mask area first
|
|
179
|
-
if (hasSoldermask && margin > 0) {
|
|
180
|
-
drawCircle({
|
|
181
|
-
ctx,
|
|
182
|
-
center: { x: pad.x, y: pad.y },
|
|
183
|
-
radius: pad.radius + margin,
|
|
184
|
-
fill: positiveMarginColor,
|
|
185
|
-
realToCanvasMat,
|
|
186
|
-
})
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Draw the pad on top
|
|
190
64
|
drawCircle({
|
|
191
65
|
ctx,
|
|
192
66
|
center: { x: pad.x, y: pad.y },
|
|
@@ -194,47 +68,10 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
194
68
|
fill: color,
|
|
195
69
|
realToCanvasMat,
|
|
196
70
|
})
|
|
197
|
-
|
|
198
|
-
// For negative margins, draw soldermask ring on top of the pad
|
|
199
|
-
if (hasSoldermask && margin < 0) {
|
|
200
|
-
drawSoldermaskRingForCircle(
|
|
201
|
-
ctx,
|
|
202
|
-
{ x: pad.x, y: pad.y },
|
|
203
|
-
pad.radius,
|
|
204
|
-
margin,
|
|
205
|
-
realToCanvasMat,
|
|
206
|
-
soldermaskRingColor,
|
|
207
|
-
color,
|
|
208
|
-
)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// If covered with soldermask and margin == 0 (treat as 0 positive margin), draw soldermaskOverCopper overlay
|
|
212
|
-
if (isCoveredWithSoldermask && margin === 0) {
|
|
213
|
-
drawCircle({
|
|
214
|
-
ctx,
|
|
215
|
-
center: { x: pad.x, y: pad.y },
|
|
216
|
-
radius: pad.radius,
|
|
217
|
-
fill: soldermaskOverlayColor,
|
|
218
|
-
realToCanvasMat,
|
|
219
|
-
})
|
|
220
|
-
}
|
|
221
71
|
return
|
|
222
72
|
}
|
|
223
73
|
|
|
224
74
|
if (pad.shape === "pill") {
|
|
225
|
-
// For positive margins, draw extended mask area first
|
|
226
|
-
if (hasSoldermask && margin > 0) {
|
|
227
|
-
drawPill({
|
|
228
|
-
ctx,
|
|
229
|
-
center: { x: pad.x, y: pad.y },
|
|
230
|
-
width: pad.width + margin * 2,
|
|
231
|
-
height: pad.height + margin * 2,
|
|
232
|
-
fill: positiveMarginColor,
|
|
233
|
-
realToCanvasMat,
|
|
234
|
-
})
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Draw the pad on top
|
|
238
75
|
drawPill({
|
|
239
76
|
ctx,
|
|
240
77
|
center: { x: pad.x, y: pad.y },
|
|
@@ -243,51 +80,10 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
243
80
|
fill: color,
|
|
244
81
|
realToCanvasMat,
|
|
245
82
|
})
|
|
246
|
-
|
|
247
|
-
// For negative margins, draw soldermask ring on top of the pad
|
|
248
|
-
if (hasSoldermask && margin < 0) {
|
|
249
|
-
drawSoldermaskRingForPill(
|
|
250
|
-
ctx,
|
|
251
|
-
{ x: pad.x, y: pad.y },
|
|
252
|
-
pad.width,
|
|
253
|
-
pad.height,
|
|
254
|
-
margin,
|
|
255
|
-
0,
|
|
256
|
-
realToCanvasMat,
|
|
257
|
-
soldermaskRingColor,
|
|
258
|
-
color,
|
|
259
|
-
)
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// If covered with soldermask and margin == 0 (treat as 0 positive margin), draw soldermaskOverCopper overlay
|
|
263
|
-
if (isCoveredWithSoldermask && margin === 0) {
|
|
264
|
-
drawPill({
|
|
265
|
-
ctx,
|
|
266
|
-
center: { x: pad.x, y: pad.y },
|
|
267
|
-
width: pad.width,
|
|
268
|
-
height: pad.height,
|
|
269
|
-
fill: soldermaskOverlayColor,
|
|
270
|
-
realToCanvasMat,
|
|
271
|
-
})
|
|
272
|
-
}
|
|
273
83
|
return
|
|
274
84
|
}
|
|
275
85
|
|
|
276
86
|
if (pad.shape === "rotated_pill") {
|
|
277
|
-
// For positive margins, draw extended mask area first
|
|
278
|
-
if (hasSoldermask && margin > 0) {
|
|
279
|
-
drawPill({
|
|
280
|
-
ctx,
|
|
281
|
-
center: { x: pad.x, y: pad.y },
|
|
282
|
-
width: pad.width + margin * 2,
|
|
283
|
-
height: pad.height + margin * 2,
|
|
284
|
-
fill: positiveMarginColor,
|
|
285
|
-
realToCanvasMat,
|
|
286
|
-
rotation: pad.ccw_rotation ?? 0,
|
|
287
|
-
})
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Draw the pad on top
|
|
291
87
|
drawPill({
|
|
292
88
|
ctx,
|
|
293
89
|
center: { x: pad.x, y: pad.y },
|
|
@@ -297,79 +93,17 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
297
93
|
realToCanvasMat,
|
|
298
94
|
rotation: pad.ccw_rotation ?? 0,
|
|
299
95
|
})
|
|
300
|
-
|
|
301
|
-
// For negative margins, draw soldermask ring on top of the pad
|
|
302
|
-
if (hasSoldermask && margin < 0) {
|
|
303
|
-
drawSoldermaskRingForPill(
|
|
304
|
-
ctx,
|
|
305
|
-
{ x: pad.x, y: pad.y },
|
|
306
|
-
pad.width,
|
|
307
|
-
pad.height,
|
|
308
|
-
margin,
|
|
309
|
-
pad.ccw_rotation ?? 0,
|
|
310
|
-
realToCanvasMat,
|
|
311
|
-
soldermaskRingColor,
|
|
312
|
-
color,
|
|
313
|
-
)
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// If covered with soldermask and margin == 0 (treat as 0 positive margin), draw soldermaskOverCopper overlay
|
|
317
|
-
if (isCoveredWithSoldermask && margin === 0) {
|
|
318
|
-
drawPill({
|
|
319
|
-
ctx,
|
|
320
|
-
center: { x: pad.x, y: pad.y },
|
|
321
|
-
width: pad.width,
|
|
322
|
-
height: pad.height,
|
|
323
|
-
fill: soldermaskOverlayColor,
|
|
324
|
-
realToCanvasMat,
|
|
325
|
-
rotation: pad.ccw_rotation ?? 0,
|
|
326
|
-
})
|
|
327
|
-
}
|
|
328
96
|
return
|
|
329
97
|
}
|
|
330
98
|
|
|
331
99
|
if (pad.shape === "polygon") {
|
|
332
100
|
if (pad.points && pad.points.length >= 3) {
|
|
333
|
-
// For positive margins, draw extended mask area first
|
|
334
|
-
if (hasSoldermask && margin > 0) {
|
|
335
|
-
const expandedPoints = offsetPolygonPoints(pad.points, margin)
|
|
336
|
-
drawPolygon({
|
|
337
|
-
ctx,
|
|
338
|
-
points: expandedPoints,
|
|
339
|
-
fill: positiveMarginColor,
|
|
340
|
-
realToCanvasMat,
|
|
341
|
-
})
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Draw the copper pad
|
|
345
101
|
drawPolygon({
|
|
346
102
|
ctx,
|
|
347
103
|
points: pad.points,
|
|
348
104
|
fill: color,
|
|
349
105
|
realToCanvasMat,
|
|
350
106
|
})
|
|
351
|
-
|
|
352
|
-
// For negative margins, draw soldermask ring on top of the pad
|
|
353
|
-
if (hasSoldermask && margin < 0) {
|
|
354
|
-
drawSoldermaskRingForPolygon(
|
|
355
|
-
ctx,
|
|
356
|
-
pad.points,
|
|
357
|
-
margin,
|
|
358
|
-
realToCanvasMat,
|
|
359
|
-
soldermaskRingColor,
|
|
360
|
-
color,
|
|
361
|
-
)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// If covered with soldermask and margin == 0 (treat as 0 positive margin), draw soldermaskOverCopper overlay
|
|
365
|
-
if (isCoveredWithSoldermask && margin === 0) {
|
|
366
|
-
drawPolygon({
|
|
367
|
-
ctx,
|
|
368
|
-
points: pad.points,
|
|
369
|
-
fill: soldermaskOverlayColor,
|
|
370
|
-
realToCanvasMat,
|
|
371
|
-
})
|
|
372
|
-
}
|
|
373
107
|
}
|
|
374
108
|
return
|
|
375
109
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { PcbBoard } from "circuit-json"
|
|
2
|
+
import type { Matrix } from "transformation-matrix"
|
|
3
|
+
import { applyToPoint } from "transformation-matrix"
|
|
4
|
+
import type { CanvasContext } from "../../types"
|
|
5
|
+
import { drawPolygonPath } from "../helper-functions/draw-polygon"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Draws the base soldermask layer covering the entire board.
|
|
9
|
+
*/
|
|
10
|
+
export function drawBoardSoldermask(params: {
|
|
11
|
+
ctx: CanvasContext
|
|
12
|
+
board: PcbBoard
|
|
13
|
+
realToCanvasMat: Matrix
|
|
14
|
+
soldermaskColor: string
|
|
15
|
+
}): void {
|
|
16
|
+
const { ctx, board, realToCanvasMat, soldermaskColor } = params
|
|
17
|
+
const { width, height, center, outline } = board
|
|
18
|
+
|
|
19
|
+
if (outline && Array.isArray(outline) && outline.length >= 3) {
|
|
20
|
+
// Draw filled polygon for custom outline
|
|
21
|
+
const canvasPoints = outline.map((p) => {
|
|
22
|
+
const [x, y] = applyToPoint(realToCanvasMat, [p.x, p.y])
|
|
23
|
+
return { x, y }
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
ctx.beginPath()
|
|
27
|
+
drawPolygonPath({ ctx, points: canvasPoints })
|
|
28
|
+
ctx.fillStyle = soldermaskColor
|
|
29
|
+
ctx.fill()
|
|
30
|
+
} else if (width !== undefined && height !== undefined && center) {
|
|
31
|
+
// Draw filled rectangle
|
|
32
|
+
const [cx, cy] = applyToPoint(realToCanvasMat, [center.x, center.y])
|
|
33
|
+
const scaledWidth = width * Math.abs(realToCanvasMat.a)
|
|
34
|
+
const scaledHeight = height * Math.abs(realToCanvasMat.a)
|
|
35
|
+
|
|
36
|
+
ctx.fillStyle = soldermaskColor
|
|
37
|
+
ctx.fillRect(
|
|
38
|
+
cx - scaledWidth / 2,
|
|
39
|
+
cy - scaledHeight / 2,
|
|
40
|
+
scaledWidth,
|
|
41
|
+
scaledHeight,
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { PcbCutout } from "circuit-json"
|
|
2
|
+
import type { Matrix } from "transformation-matrix"
|
|
3
|
+
import { applyToPoint } from "transformation-matrix"
|
|
4
|
+
import type { CanvasContext, PcbColorMap } from "../../types"
|
|
5
|
+
import { drawPolygonPath } from "../helper-functions/draw-polygon"
|
|
6
|
+
import { drawRoundedRectPath } from "../helper-functions/draw-rounded-rect"
|
|
7
|
+
/**
|
|
8
|
+
* Process soldermask for a board cutout.
|
|
9
|
+
* Cutouts go through the entire board, so they cut through soldermask too.
|
|
10
|
+
*/
|
|
11
|
+
export function processCutoutSoldermask(params: {
|
|
12
|
+
ctx: CanvasContext
|
|
13
|
+
cutout: PcbCutout
|
|
14
|
+
realToCanvasMat: Matrix
|
|
15
|
+
colorMap: PcbColorMap
|
|
16
|
+
}): void {
|
|
17
|
+
const { ctx, cutout, realToCanvasMat, colorMap } = params
|
|
18
|
+
// Cutouts go through the entire board, so they cut through soldermask too
|
|
19
|
+
// Use drill color to indicate the cutout
|
|
20
|
+
ctx.fillStyle = colorMap.drill
|
|
21
|
+
|
|
22
|
+
if (cutout.shape === "rect") {
|
|
23
|
+
const [cx, cy] = applyToPoint(realToCanvasMat, [
|
|
24
|
+
cutout.center?.x ?? 0,
|
|
25
|
+
cutout.center?.y ?? 0,
|
|
26
|
+
])
|
|
27
|
+
const scaledWidth = cutout.width * Math.abs(realToCanvasMat.a)
|
|
28
|
+
const scaledHeight = cutout.height * Math.abs(realToCanvasMat.a)
|
|
29
|
+
const scaledRadius =
|
|
30
|
+
(cutout.corner_radius ?? 0) * Math.abs(realToCanvasMat.a)
|
|
31
|
+
|
|
32
|
+
ctx.save()
|
|
33
|
+
ctx.translate(cx, cy)
|
|
34
|
+
if (cutout.rotation) {
|
|
35
|
+
ctx.rotate((-cutout.rotation * Math.PI) / 180)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
ctx.beginPath()
|
|
39
|
+
drawRoundedRectPath({
|
|
40
|
+
ctx,
|
|
41
|
+
cx: 0,
|
|
42
|
+
cy: 0,
|
|
43
|
+
width: scaledWidth,
|
|
44
|
+
height: scaledHeight,
|
|
45
|
+
radius: scaledRadius,
|
|
46
|
+
})
|
|
47
|
+
ctx.restore()
|
|
48
|
+
ctx.fill()
|
|
49
|
+
} else if (cutout.shape === "circle") {
|
|
50
|
+
const [cx, cy] = applyToPoint(realToCanvasMat, [
|
|
51
|
+
cutout.center?.x ?? 0,
|
|
52
|
+
cutout.center?.y ?? 0,
|
|
53
|
+
])
|
|
54
|
+
const scaledRadius = cutout.radius * Math.abs(realToCanvasMat.a)
|
|
55
|
+
|
|
56
|
+
ctx.beginPath()
|
|
57
|
+
ctx.arc(cx, cy, scaledRadius, 0, Math.PI * 2)
|
|
58
|
+
ctx.closePath()
|
|
59
|
+
ctx.fill()
|
|
60
|
+
} else if (
|
|
61
|
+
cutout.shape === "polygon" &&
|
|
62
|
+
cutout.points &&
|
|
63
|
+
cutout.points.length >= 3
|
|
64
|
+
) {
|
|
65
|
+
const canvasPoints = cutout.points.map((p) => {
|
|
66
|
+
const [x, y] = applyToPoint(realToCanvasMat, [p.x, p.y])
|
|
67
|
+
return { x, y }
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
ctx.beginPath()
|
|
71
|
+
drawPolygonPath({ ctx, points: canvasPoints })
|
|
72
|
+
ctx.fill()
|
|
73
|
+
}
|
|
74
|
+
}
|