circuit-to-canvas 0.0.45 → 0.0.47
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 +530 -163
- package/lib/drawer/CircuitToCanvasDrawer.ts +1 -5
- package/lib/drawer/elements/pcb-hole.ts +248 -61
- package/lib/drawer/elements/pcb-plated-hole.ts +234 -107
- package/lib/drawer/elements/pcb-smtpad.ts +43 -21
- package/lib/drawer/elements/soldermask-margin.ts +130 -0
- package/package.json +1 -1
- package/tests/board-snapshot/__snapshots__/usb-c-flashlight-board.snap.png +0 -0
- package/tests/elements/__snapshots__/board-with-elements.snap.png +0 -0
- package/tests/elements/__snapshots__/custom-outline-board.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-note-dimension-with-offset.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-plated-hole-soldermask-margin.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-silkscreen-oval.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-smtpad-soldermask-margin.snap.png +0 -0
- package/tests/elements/pcb-comprehensive-soldermask-margin.test.ts +1281 -0
- package/tests/elements/pcb-hole-soldermask-margin.test.ts +5 -5
- package/tests/elements/pcb-plated-hole-soldermask-margin.test.ts +8 -8
- package/tests/elements/pcb-smtpad-soldermask-margin.test.ts +0 -6
- package/tests/shapes/__snapshots__/dimension-line.snap.png +0 -0
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
drawSoldermaskRingForOval,
|
|
12
12
|
drawSoldermaskRingForPill,
|
|
13
13
|
drawSoldermaskRingForRect,
|
|
14
|
+
drawSoldermaskRingForPolygon,
|
|
15
|
+
offsetPolygonPoints,
|
|
14
16
|
} from "./soldermask-margin"
|
|
15
17
|
|
|
16
18
|
export interface DrawPcbPlatedHoleParams {
|
|
@@ -35,11 +37,12 @@ function getSoldermaskColor(
|
|
|
35
37
|
export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
36
38
|
const { ctx, hole, realToCanvasMat, colorMap } = params
|
|
37
39
|
|
|
40
|
+
const isCoveredWithSoldermask = hole.is_covered_with_solder_mask === true
|
|
41
|
+
const margin = isCoveredWithSoldermask ? 0 : (hole.soldermask_margin ?? 0)
|
|
38
42
|
const hasSoldermask =
|
|
39
|
-
|
|
43
|
+
!isCoveredWithSoldermask &&
|
|
40
44
|
hole.soldermask_margin !== undefined &&
|
|
41
45
|
hole.soldermask_margin !== 0
|
|
42
|
-
const margin = hasSoldermask ? hole.soldermask_margin! : 0
|
|
43
46
|
const soldermaskRingColor = getSoldermaskColor(hole.layers, colorMap)
|
|
44
47
|
const positiveMarginColor = colorMap.substrate
|
|
45
48
|
const copperColor = colorMap.copper.top
|
|
@@ -78,14 +81,27 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
78
81
|
)
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
// If fully covered, draw soldermask overlay
|
|
85
|
+
if (isCoveredWithSoldermask) {
|
|
86
|
+
drawCircle({
|
|
87
|
+
ctx,
|
|
88
|
+
center: { x: hole.x, y: hole.y },
|
|
89
|
+
radius: hole.outer_diameter / 2,
|
|
90
|
+
fill: soldermaskRingColor,
|
|
91
|
+
realToCanvasMat,
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Draw inner drill hole (only if not fully covered with soldermask)
|
|
96
|
+
if (!isCoveredWithSoldermask) {
|
|
97
|
+
drawCircle({
|
|
98
|
+
ctx,
|
|
99
|
+
center: { x: hole.x, y: hole.y },
|
|
100
|
+
radius: hole.hole_diameter / 2,
|
|
101
|
+
fill: colorMap.drill,
|
|
102
|
+
realToCanvasMat,
|
|
103
|
+
})
|
|
104
|
+
}
|
|
89
105
|
return
|
|
90
106
|
}
|
|
91
107
|
|
|
@@ -129,16 +145,31 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
129
145
|
)
|
|
130
146
|
}
|
|
131
147
|
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
148
|
+
// If fully covered, draw soldermask overlay
|
|
149
|
+
if (isCoveredWithSoldermask) {
|
|
150
|
+
drawOval({
|
|
151
|
+
ctx,
|
|
152
|
+
center: { x: hole.x, y: hole.y },
|
|
153
|
+
radius_x: hole.outer_width / 2,
|
|
154
|
+
radius_y: hole.outer_height / 2,
|
|
155
|
+
fill: soldermaskRingColor,
|
|
156
|
+
realToCanvasMat,
|
|
157
|
+
rotation: hole.ccw_rotation,
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Draw inner drill hole (only if not fully covered with soldermask)
|
|
162
|
+
if (!isCoveredWithSoldermask) {
|
|
163
|
+
drawOval({
|
|
164
|
+
ctx,
|
|
165
|
+
center: { x: hole.x, y: hole.y },
|
|
166
|
+
radius_x: hole.hole_width / 2,
|
|
167
|
+
radius_y: hole.hole_height / 2,
|
|
168
|
+
fill: colorMap.drill,
|
|
169
|
+
realToCanvasMat,
|
|
170
|
+
rotation: hole.ccw_rotation,
|
|
171
|
+
})
|
|
172
|
+
}
|
|
142
173
|
return
|
|
143
174
|
}
|
|
144
175
|
|
|
@@ -182,16 +213,31 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
182
213
|
)
|
|
183
214
|
}
|
|
184
215
|
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
216
|
+
// If fully covered, draw soldermask overlay
|
|
217
|
+
if (isCoveredWithSoldermask) {
|
|
218
|
+
drawPill({
|
|
219
|
+
ctx,
|
|
220
|
+
center: { x: hole.x, y: hole.y },
|
|
221
|
+
width: hole.outer_width,
|
|
222
|
+
height: hole.outer_height,
|
|
223
|
+
fill: soldermaskRingColor,
|
|
224
|
+
realToCanvasMat,
|
|
225
|
+
rotation: hole.ccw_rotation,
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Draw inner drill hole (only if not fully covered with soldermask)
|
|
230
|
+
if (!isCoveredWithSoldermask) {
|
|
231
|
+
drawPill({
|
|
232
|
+
ctx,
|
|
233
|
+
center: { x: hole.x, y: hole.y },
|
|
234
|
+
width: hole.hole_width,
|
|
235
|
+
height: hole.hole_height,
|
|
236
|
+
fill: colorMap.drill,
|
|
237
|
+
realToCanvasMat,
|
|
238
|
+
rotation: hole.ccw_rotation,
|
|
239
|
+
})
|
|
240
|
+
}
|
|
195
241
|
return
|
|
196
242
|
}
|
|
197
243
|
|
|
@@ -205,7 +251,7 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
205
251
|
height: hole.rect_pad_height + margin * 2,
|
|
206
252
|
fill: positiveMarginColor,
|
|
207
253
|
realToCanvasMat,
|
|
208
|
-
borderRadius:
|
|
254
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
209
255
|
})
|
|
210
256
|
}
|
|
211
257
|
|
|
@@ -236,16 +282,31 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
236
282
|
)
|
|
237
283
|
}
|
|
238
284
|
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
285
|
+
// If fully covered, draw soldermask overlay
|
|
286
|
+
if (isCoveredWithSoldermask) {
|
|
287
|
+
drawRect({
|
|
288
|
+
ctx,
|
|
289
|
+
center: { x: hole.x, y: hole.y },
|
|
290
|
+
width: hole.rect_pad_width,
|
|
291
|
+
height: hole.rect_pad_height,
|
|
292
|
+
fill: soldermaskRingColor,
|
|
293
|
+
realToCanvasMat,
|
|
294
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Draw circular drill hole (with offset, only if not fully covered with soldermask)
|
|
299
|
+
if (!isCoveredWithSoldermask) {
|
|
300
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
301
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
302
|
+
drawCircle({
|
|
303
|
+
ctx,
|
|
304
|
+
center: { x: holeX, y: holeY },
|
|
305
|
+
radius: hole.hole_diameter / 2,
|
|
306
|
+
fill: colorMap.drill,
|
|
307
|
+
realToCanvasMat,
|
|
308
|
+
})
|
|
309
|
+
}
|
|
249
310
|
return
|
|
250
311
|
}
|
|
251
312
|
|
|
@@ -259,7 +320,7 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
259
320
|
height: hole.rect_pad_height + margin * 2,
|
|
260
321
|
fill: positiveMarginColor,
|
|
261
322
|
realToCanvasMat,
|
|
262
|
-
borderRadius:
|
|
323
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
263
324
|
})
|
|
264
325
|
}
|
|
265
326
|
|
|
@@ -290,17 +351,32 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
290
351
|
)
|
|
291
352
|
}
|
|
292
353
|
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
354
|
+
// If fully covered, draw soldermask overlay
|
|
355
|
+
if (isCoveredWithSoldermask) {
|
|
356
|
+
drawRect({
|
|
357
|
+
ctx,
|
|
358
|
+
center: { x: hole.x, y: hole.y },
|
|
359
|
+
width: hole.rect_pad_width,
|
|
360
|
+
height: hole.rect_pad_height,
|
|
361
|
+
fill: soldermaskRingColor,
|
|
362
|
+
realToCanvasMat,
|
|
363
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
364
|
+
})
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Draw pill drill hole (with offset, only if not fully covered with soldermask)
|
|
368
|
+
if (!isCoveredWithSoldermask) {
|
|
369
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
370
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
371
|
+
drawPill({
|
|
372
|
+
ctx,
|
|
373
|
+
center: { x: holeX, y: holeY },
|
|
374
|
+
width: hole.hole_width,
|
|
375
|
+
height: hole.hole_height,
|
|
376
|
+
fill: colorMap.drill,
|
|
377
|
+
realToCanvasMat,
|
|
378
|
+
})
|
|
379
|
+
}
|
|
304
380
|
return
|
|
305
381
|
}
|
|
306
382
|
|
|
@@ -314,7 +390,7 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
314
390
|
height: hole.rect_pad_height + margin * 2,
|
|
315
391
|
fill: positiveMarginColor,
|
|
316
392
|
realToCanvasMat,
|
|
317
|
-
borderRadius:
|
|
393
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
318
394
|
rotation: hole.rect_ccw_rotation,
|
|
319
395
|
})
|
|
320
396
|
}
|
|
@@ -347,24 +423,38 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
347
423
|
)
|
|
348
424
|
}
|
|
349
425
|
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
426
|
+
// If fully covered, draw soldermask overlay
|
|
427
|
+
if (isCoveredWithSoldermask) {
|
|
428
|
+
drawRect({
|
|
429
|
+
ctx,
|
|
430
|
+
center: { x: hole.x, y: hole.y },
|
|
431
|
+
width: hole.rect_pad_width,
|
|
432
|
+
height: hole.rect_pad_height,
|
|
433
|
+
fill: soldermaskRingColor,
|
|
434
|
+
realToCanvasMat,
|
|
435
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
436
|
+
rotation: hole.rect_ccw_rotation,
|
|
437
|
+
})
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Draw rotated pill drill hole (with offset, only if not fully covered with soldermask)
|
|
441
|
+
if (!isCoveredWithSoldermask) {
|
|
442
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
443
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
444
|
+
drawPill({
|
|
445
|
+
ctx,
|
|
446
|
+
center: { x: holeX, y: holeY },
|
|
447
|
+
width: hole.hole_width,
|
|
448
|
+
height: hole.hole_height,
|
|
449
|
+
fill: colorMap.drill,
|
|
450
|
+
realToCanvasMat,
|
|
451
|
+
rotation: hole.hole_ccw_rotation,
|
|
452
|
+
})
|
|
453
|
+
}
|
|
362
454
|
return
|
|
363
455
|
}
|
|
364
456
|
|
|
365
457
|
if (hole.shape === "hole_with_polygon_pad") {
|
|
366
|
-
// Note: Polygon pads don't support soldermask margins (similar to SMT polygon pads)
|
|
367
|
-
// Draw polygon pad
|
|
368
458
|
const padOutline = hole.pad_outline
|
|
369
459
|
if (padOutline && padOutline.length >= 3) {
|
|
370
460
|
// Transform pad_outline points to be relative to hole.x, hole.y
|
|
@@ -372,54 +462,91 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
372
462
|
x: hole.x + point.x,
|
|
373
463
|
y: hole.y + point.y,
|
|
374
464
|
}))
|
|
465
|
+
|
|
466
|
+
// For positive margins, draw extended mask area first
|
|
467
|
+
if (hasSoldermask && margin > 0) {
|
|
468
|
+
const expandedPoints = offsetPolygonPoints(padPoints, margin)
|
|
469
|
+
drawPolygon({
|
|
470
|
+
ctx,
|
|
471
|
+
points: expandedPoints,
|
|
472
|
+
fill: positiveMarginColor,
|
|
473
|
+
realToCanvasMat,
|
|
474
|
+
})
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Draw polygon pad
|
|
375
478
|
drawPolygon({
|
|
376
479
|
ctx,
|
|
377
480
|
points: padPoints,
|
|
378
481
|
fill: copperColor,
|
|
379
482
|
realToCanvasMat,
|
|
380
483
|
})
|
|
484
|
+
|
|
485
|
+
// For negative margins, draw soldermask ring on top of the pad
|
|
486
|
+
if (hasSoldermask && margin < 0) {
|
|
487
|
+
drawSoldermaskRingForPolygon(
|
|
488
|
+
ctx,
|
|
489
|
+
padPoints,
|
|
490
|
+
margin,
|
|
491
|
+
realToCanvasMat,
|
|
492
|
+
soldermaskRingColor,
|
|
493
|
+
copperColor,
|
|
494
|
+
)
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// If fully covered, draw soldermask overlay
|
|
498
|
+
if (isCoveredWithSoldermask) {
|
|
499
|
+
drawPolygon({
|
|
500
|
+
ctx,
|
|
501
|
+
points: padPoints,
|
|
502
|
+
fill: soldermaskRingColor,
|
|
503
|
+
realToCanvasMat,
|
|
504
|
+
})
|
|
505
|
+
}
|
|
381
506
|
}
|
|
382
507
|
|
|
383
|
-
// Draw drill hole (with offset)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
508
|
+
// Draw drill hole (with offset, only if not fully covered with soldermask)
|
|
509
|
+
if (!isCoveredWithSoldermask) {
|
|
510
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
511
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
512
|
+
const holeShape = hole.hole_shape
|
|
387
513
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
514
|
+
if (holeShape === "circle") {
|
|
515
|
+
drawCircle({
|
|
516
|
+
ctx,
|
|
517
|
+
center: { x: holeX, y: holeY },
|
|
518
|
+
radius: (hole.hole_diameter ?? 0) / 2,
|
|
519
|
+
fill: colorMap.drill,
|
|
520
|
+
realToCanvasMat,
|
|
521
|
+
})
|
|
522
|
+
} else if (holeShape === "oval") {
|
|
523
|
+
drawOval({
|
|
524
|
+
ctx,
|
|
525
|
+
center: { x: holeX, y: holeY },
|
|
526
|
+
radius_x: (hole.hole_width ?? 0) / 2,
|
|
527
|
+
radius_y: (hole.hole_height ?? 0) / 2,
|
|
528
|
+
fill: colorMap.drill,
|
|
529
|
+
realToCanvasMat,
|
|
530
|
+
})
|
|
531
|
+
} else if (holeShape === "pill") {
|
|
532
|
+
drawPill({
|
|
533
|
+
ctx,
|
|
534
|
+
center: { x: holeX, y: holeY },
|
|
535
|
+
width: hole.hole_width ?? 0,
|
|
536
|
+
height: hole.hole_height ?? 0,
|
|
537
|
+
fill: colorMap.drill,
|
|
538
|
+
realToCanvasMat,
|
|
539
|
+
})
|
|
540
|
+
} else if (holeShape === "rotated_pill") {
|
|
541
|
+
drawPill({
|
|
542
|
+
ctx,
|
|
543
|
+
center: { x: holeX, y: holeY },
|
|
544
|
+
width: hole.hole_width ?? 0,
|
|
545
|
+
height: hole.hole_height ?? 0,
|
|
546
|
+
fill: colorMap.drill,
|
|
547
|
+
realToCanvasMat,
|
|
548
|
+
})
|
|
549
|
+
}
|
|
423
550
|
}
|
|
424
551
|
return
|
|
425
552
|
}
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
drawSoldermaskRingForRect,
|
|
10
10
|
drawSoldermaskRingForCircle,
|
|
11
11
|
drawSoldermaskRingForPill,
|
|
12
|
+
drawSoldermaskRingForPolygon,
|
|
13
|
+
offsetPolygonPoints,
|
|
12
14
|
} from "./soldermask-margin"
|
|
13
15
|
|
|
14
16
|
export interface DrawPcbSmtPadParams {
|
|
@@ -33,7 +35,7 @@ function getSoldermaskColor(layer: string, colorMap: PcbColorMap): string {
|
|
|
33
35
|
)
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
function getBorderRadius(pad: PcbSmtPad, margin
|
|
38
|
+
function getBorderRadius(pad: PcbSmtPad, margin = 0): number {
|
|
37
39
|
return (
|
|
38
40
|
((pad as { corner_radius?: number }).corner_radius ??
|
|
39
41
|
(pad as { rect_border_radius?: number }).rect_border_radius ??
|
|
@@ -46,13 +48,10 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
46
48
|
|
|
47
49
|
const color = layerToColor(pad.layer, colorMap)
|
|
48
50
|
const isCoveredWithSoldermask = pad.is_covered_with_solder_mask === true
|
|
49
|
-
//
|
|
50
|
-
const margin =
|
|
51
|
-
isCoveredWithSoldermask && pad.soldermask_margin !== undefined
|
|
52
|
-
? pad.soldermask_margin
|
|
53
|
-
: 0
|
|
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)
|
|
54
53
|
const hasSoldermask =
|
|
55
|
-
isCoveredWithSoldermask &&
|
|
54
|
+
!isCoveredWithSoldermask &&
|
|
56
55
|
pad.soldermask_margin !== undefined &&
|
|
57
56
|
pad.soldermask_margin !== 0
|
|
58
57
|
const soldermaskRingColor = getSoldermaskColor(pad.layer, colorMap)
|
|
@@ -61,8 +60,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
61
60
|
|
|
62
61
|
// Draw the copper pad
|
|
63
62
|
if (pad.shape === "rect") {
|
|
64
|
-
// For positive margins
|
|
65
|
-
if (
|
|
63
|
+
// For positive margins, draw extended mask area first
|
|
64
|
+
if (hasSoldermask && margin > 0) {
|
|
66
65
|
drawRect({
|
|
67
66
|
ctx,
|
|
68
67
|
center: { x: pad.x, y: pad.y },
|
|
@@ -70,7 +69,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
70
69
|
height: pad.height + margin * 2,
|
|
71
70
|
fill: positiveMarginColor,
|
|
72
71
|
realToCanvasMat,
|
|
73
|
-
borderRadius: getBorderRadius(pad
|
|
72
|
+
borderRadius: getBorderRadius(pad),
|
|
74
73
|
})
|
|
75
74
|
}
|
|
76
75
|
|
|
@@ -117,8 +116,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
if (pad.shape === "rotated_rect") {
|
|
120
|
-
// For positive margins
|
|
121
|
-
if (
|
|
119
|
+
// For positive margins, draw extended mask area first
|
|
120
|
+
if (hasSoldermask && margin > 0) {
|
|
122
121
|
drawRect({
|
|
123
122
|
ctx,
|
|
124
123
|
center: { x: pad.x, y: pad.y },
|
|
@@ -126,7 +125,7 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
126
125
|
height: pad.height + margin * 2,
|
|
127
126
|
fill: positiveMarginColor,
|
|
128
127
|
realToCanvasMat,
|
|
129
|
-
borderRadius: getBorderRadius(pad
|
|
128
|
+
borderRadius: getBorderRadius(pad),
|
|
130
129
|
rotation: pad.ccw_rotation ?? 0,
|
|
131
130
|
})
|
|
132
131
|
}
|
|
@@ -176,8 +175,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
176
175
|
}
|
|
177
176
|
|
|
178
177
|
if (pad.shape === "circle") {
|
|
179
|
-
// For positive margins
|
|
180
|
-
if (
|
|
178
|
+
// For positive margins, draw extended mask area first
|
|
179
|
+
if (hasSoldermask && margin > 0) {
|
|
181
180
|
drawCircle({
|
|
182
181
|
ctx,
|
|
183
182
|
center: { x: pad.x, y: pad.y },
|
|
@@ -223,8 +222,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
223
222
|
}
|
|
224
223
|
|
|
225
224
|
if (pad.shape === "pill") {
|
|
226
|
-
// For positive margins
|
|
227
|
-
if (
|
|
225
|
+
// For positive margins, draw extended mask area first
|
|
226
|
+
if (hasSoldermask && margin > 0) {
|
|
228
227
|
drawPill({
|
|
229
228
|
ctx,
|
|
230
229
|
center: { x: pad.x, y: pad.y },
|
|
@@ -275,8 +274,8 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
275
274
|
}
|
|
276
275
|
|
|
277
276
|
if (pad.shape === "rotated_pill") {
|
|
278
|
-
// For positive margins
|
|
279
|
-
if (
|
|
277
|
+
// For positive margins, draw extended mask area first
|
|
278
|
+
if (hasSoldermask && margin > 0) {
|
|
280
279
|
drawPill({
|
|
281
280
|
ctx,
|
|
282
281
|
center: { x: pad.x, y: pad.y },
|
|
@@ -331,6 +330,17 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
331
330
|
|
|
332
331
|
if (pad.shape === "polygon") {
|
|
333
332
|
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
|
+
|
|
334
344
|
// Draw the copper pad
|
|
335
345
|
drawPolygon({
|
|
336
346
|
ctx,
|
|
@@ -339,8 +349,20 @@ export function drawPcbSmtPad(params: DrawPcbSmtPadParams): void {
|
|
|
339
349
|
realToCanvasMat,
|
|
340
350
|
})
|
|
341
351
|
|
|
342
|
-
//
|
|
343
|
-
if (
|
|
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) {
|
|
344
366
|
drawPolygon({
|
|
345
367
|
ctx,
|
|
346
368
|
points: pad.points,
|