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
|
@@ -6,451 +6,192 @@ import { drawRect } from "../shapes/rect"
|
|
|
6
6
|
import { drawOval } from "../shapes/oval"
|
|
7
7
|
import { drawPill } from "../shapes/pill"
|
|
8
8
|
import { drawPolygon } from "../shapes/polygon"
|
|
9
|
-
import {
|
|
10
|
-
drawSoldermaskRingForCircle,
|
|
11
|
-
drawSoldermaskRingForOval,
|
|
12
|
-
drawSoldermaskRingForPill,
|
|
13
|
-
drawSoldermaskRingForRect,
|
|
14
|
-
drawSoldermaskRingForPolygon,
|
|
15
|
-
offsetPolygonPoints,
|
|
16
|
-
} from "./soldermask-margin"
|
|
9
|
+
import { offsetPolygonPoints } from "./soldermask-margin"
|
|
17
10
|
|
|
18
11
|
export interface DrawPcbPlatedHoleParams {
|
|
19
12
|
ctx: CanvasContext
|
|
20
13
|
hole: PcbPlatedHole
|
|
21
14
|
realToCanvasMat: Matrix
|
|
22
15
|
colorMap: PcbColorMap
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
function getSoldermaskColor(
|
|
26
|
-
layers: string[] | undefined,
|
|
27
|
-
colorMap: PcbColorMap,
|
|
28
|
-
): string {
|
|
29
|
-
const layer = layers?.includes("top") ? "top" : "bottom"
|
|
30
|
-
return (
|
|
31
|
-
colorMap.soldermaskOverCopper[
|
|
32
|
-
layer as keyof typeof colorMap.soldermaskOverCopper
|
|
33
|
-
] ?? colorMap.soldermaskOverCopper.top
|
|
34
|
-
)
|
|
16
|
+
soldermaskMargin?: number
|
|
17
|
+
showSoldermask?: boolean
|
|
35
18
|
}
|
|
36
19
|
|
|
37
20
|
export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
38
|
-
const {
|
|
21
|
+
const {
|
|
22
|
+
ctx,
|
|
23
|
+
hole,
|
|
24
|
+
realToCanvasMat,
|
|
25
|
+
colorMap,
|
|
26
|
+
soldermaskMargin = 0,
|
|
27
|
+
showSoldermask,
|
|
28
|
+
} = params
|
|
29
|
+
|
|
30
|
+
// Skip holes that are fully covered with soldermask when soldermask is enabled,
|
|
31
|
+
// as they should have been handled by soldermask processing.
|
|
32
|
+
// When soldermask is disabled, fully covered holes should be drawn as normal copper.
|
|
33
|
+
if (hole.is_covered_with_solder_mask === true && showSoldermask) {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
39
36
|
|
|
40
|
-
const isCoveredWithSoldermask = hole.is_covered_with_solder_mask === true
|
|
41
|
-
const margin = isCoveredWithSoldermask ? 0 : (hole.soldermask_margin ?? 0)
|
|
42
|
-
const hasSoldermask =
|
|
43
|
-
!isCoveredWithSoldermask &&
|
|
44
|
-
hole.soldermask_margin !== undefined &&
|
|
45
|
-
hole.soldermask_margin !== 0
|
|
46
|
-
const soldermaskRingColor = getSoldermaskColor(hole.layers, colorMap)
|
|
47
|
-
const positiveMarginColor = colorMap.substrate
|
|
48
37
|
const copperColor = colorMap.copper.top
|
|
49
38
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (hasSoldermask && margin > 0) {
|
|
53
|
-
drawCircle({
|
|
54
|
-
ctx,
|
|
55
|
-
center: { x: hole.x, y: hole.y },
|
|
56
|
-
radius: hole.outer_diameter / 2 + margin,
|
|
57
|
-
fill: positiveMarginColor,
|
|
58
|
-
realToCanvasMat,
|
|
59
|
-
})
|
|
60
|
-
}
|
|
39
|
+
// For negative margins, draw smaller copper (inset by margin amount)
|
|
40
|
+
const copperInset = soldermaskMargin < 0 ? Math.abs(soldermaskMargin) : 0
|
|
61
41
|
|
|
62
|
-
|
|
42
|
+
if (hole.shape === "circle") {
|
|
43
|
+
// Draw outer copper ring (smaller if negative margin)
|
|
63
44
|
drawCircle({
|
|
64
45
|
ctx,
|
|
65
46
|
center: { x: hole.x, y: hole.y },
|
|
66
|
-
radius: hole.outer_diameter / 2,
|
|
47
|
+
radius: hole.outer_diameter / 2 - copperInset,
|
|
67
48
|
fill: copperColor,
|
|
68
49
|
realToCanvasMat,
|
|
69
50
|
})
|
|
70
51
|
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
soldermaskRingColor,
|
|
80
|
-
copperColor,
|
|
81
|
-
)
|
|
82
|
-
}
|
|
83
|
-
|
|
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
|
-
}
|
|
52
|
+
// Draw inner drill hole
|
|
53
|
+
drawCircle({
|
|
54
|
+
ctx,
|
|
55
|
+
center: { x: hole.x, y: hole.y },
|
|
56
|
+
radius: hole.hole_diameter / 2,
|
|
57
|
+
fill: colorMap.drill,
|
|
58
|
+
realToCanvasMat,
|
|
59
|
+
})
|
|
105
60
|
return
|
|
106
61
|
}
|
|
107
62
|
|
|
108
63
|
if (hole.shape === "oval") {
|
|
109
|
-
//
|
|
110
|
-
if (hasSoldermask && margin > 0) {
|
|
111
|
-
drawOval({
|
|
112
|
-
ctx,
|
|
113
|
-
center: { x: hole.x, y: hole.y },
|
|
114
|
-
radius_x: hole.outer_width / 2 + margin,
|
|
115
|
-
radius_y: hole.outer_height / 2 + margin,
|
|
116
|
-
fill: positiveMarginColor,
|
|
117
|
-
realToCanvasMat,
|
|
118
|
-
rotation: hole.ccw_rotation,
|
|
119
|
-
})
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Draw outer copper oval
|
|
64
|
+
// Draw outer copper oval (smaller if negative margin)
|
|
123
65
|
drawOval({
|
|
124
66
|
ctx,
|
|
125
67
|
center: { x: hole.x, y: hole.y },
|
|
126
|
-
radius_x: hole.outer_width / 2,
|
|
127
|
-
radius_y: hole.outer_height / 2,
|
|
68
|
+
radius_x: hole.outer_width / 2 - copperInset,
|
|
69
|
+
radius_y: hole.outer_height / 2 - copperInset,
|
|
128
70
|
fill: copperColor,
|
|
129
71
|
realToCanvasMat,
|
|
130
72
|
rotation: hole.ccw_rotation,
|
|
131
73
|
})
|
|
132
74
|
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
soldermaskRingColor,
|
|
144
|
-
copperColor,
|
|
145
|
-
)
|
|
146
|
-
}
|
|
147
|
-
|
|
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
|
-
}
|
|
75
|
+
// Draw inner drill hole
|
|
76
|
+
drawOval({
|
|
77
|
+
ctx,
|
|
78
|
+
center: { x: hole.x, y: hole.y },
|
|
79
|
+
radius_x: hole.hole_width / 2,
|
|
80
|
+
radius_y: hole.hole_height / 2,
|
|
81
|
+
fill: colorMap.drill,
|
|
82
|
+
realToCanvasMat,
|
|
83
|
+
rotation: hole.ccw_rotation,
|
|
84
|
+
})
|
|
173
85
|
return
|
|
174
86
|
}
|
|
175
87
|
|
|
176
88
|
if (hole.shape === "pill") {
|
|
177
|
-
//
|
|
178
|
-
if (hasSoldermask && margin > 0) {
|
|
179
|
-
drawPill({
|
|
180
|
-
ctx,
|
|
181
|
-
center: { x: hole.x, y: hole.y },
|
|
182
|
-
width: hole.outer_width + margin * 2,
|
|
183
|
-
height: hole.outer_height + margin * 2,
|
|
184
|
-
fill: positiveMarginColor,
|
|
185
|
-
realToCanvasMat,
|
|
186
|
-
rotation: hole.ccw_rotation,
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Draw outer copper pill
|
|
89
|
+
// Draw outer copper pill (smaller if negative margin)
|
|
191
90
|
drawPill({
|
|
192
91
|
ctx,
|
|
193
92
|
center: { x: hole.x, y: hole.y },
|
|
194
|
-
width: hole.outer_width,
|
|
195
|
-
height: hole.outer_height,
|
|
93
|
+
width: hole.outer_width - copperInset * 2,
|
|
94
|
+
height: hole.outer_height - copperInset * 2,
|
|
196
95
|
fill: copperColor,
|
|
197
96
|
realToCanvasMat,
|
|
198
97
|
rotation: hole.ccw_rotation,
|
|
199
98
|
})
|
|
200
99
|
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
soldermaskRingColor,
|
|
212
|
-
copperColor,
|
|
213
|
-
)
|
|
214
|
-
}
|
|
215
|
-
|
|
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
|
-
}
|
|
100
|
+
// Draw inner drill hole
|
|
101
|
+
drawPill({
|
|
102
|
+
ctx,
|
|
103
|
+
center: { x: hole.x, y: hole.y },
|
|
104
|
+
width: hole.hole_width,
|
|
105
|
+
height: hole.hole_height,
|
|
106
|
+
fill: colorMap.drill,
|
|
107
|
+
realToCanvasMat,
|
|
108
|
+
rotation: hole.ccw_rotation,
|
|
109
|
+
})
|
|
241
110
|
return
|
|
242
111
|
}
|
|
243
112
|
|
|
244
113
|
if (hole.shape === "circular_hole_with_rect_pad") {
|
|
245
|
-
//
|
|
246
|
-
if (hasSoldermask && margin > 0) {
|
|
247
|
-
drawRect({
|
|
248
|
-
ctx,
|
|
249
|
-
center: { x: hole.x, y: hole.y },
|
|
250
|
-
width: hole.rect_pad_width + margin * 2,
|
|
251
|
-
height: hole.rect_pad_height + margin * 2,
|
|
252
|
-
fill: positiveMarginColor,
|
|
253
|
-
realToCanvasMat,
|
|
254
|
-
borderRadius: hole.rect_border_radius ?? 0,
|
|
255
|
-
})
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Draw rectangular pad
|
|
114
|
+
// Draw rectangular pad (smaller if negative margin)
|
|
259
115
|
drawRect({
|
|
260
116
|
ctx,
|
|
261
117
|
center: { x: hole.x, y: hole.y },
|
|
262
|
-
width: hole.rect_pad_width,
|
|
263
|
-
height: hole.rect_pad_height,
|
|
118
|
+
width: hole.rect_pad_width - copperInset * 2,
|
|
119
|
+
height: hole.rect_pad_height - copperInset * 2,
|
|
264
120
|
fill: copperColor,
|
|
265
121
|
realToCanvasMat,
|
|
266
|
-
borderRadius: hole.rect_border_radius
|
|
122
|
+
borderRadius: hole.rect_border_radius
|
|
123
|
+
? Math.max(0, hole.rect_border_radius - copperInset)
|
|
124
|
+
: 0,
|
|
267
125
|
})
|
|
268
126
|
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
realToCanvasMat,
|
|
280
|
-
soldermaskRingColor,
|
|
281
|
-
copperColor,
|
|
282
|
-
)
|
|
283
|
-
}
|
|
284
|
-
|
|
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
|
-
}
|
|
127
|
+
// Draw circular drill hole (with offset)
|
|
128
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
129
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
130
|
+
drawCircle({
|
|
131
|
+
ctx,
|
|
132
|
+
center: { x: holeX, y: holeY },
|
|
133
|
+
radius: hole.hole_diameter / 2,
|
|
134
|
+
fill: colorMap.drill,
|
|
135
|
+
realToCanvasMat,
|
|
136
|
+
})
|
|
310
137
|
return
|
|
311
138
|
}
|
|
312
139
|
|
|
313
140
|
if (hole.shape === "pill_hole_with_rect_pad") {
|
|
314
|
-
//
|
|
315
|
-
if (hasSoldermask && margin > 0) {
|
|
316
|
-
drawRect({
|
|
317
|
-
ctx,
|
|
318
|
-
center: { x: hole.x, y: hole.y },
|
|
319
|
-
width: hole.rect_pad_width + margin * 2,
|
|
320
|
-
height: hole.rect_pad_height + margin * 2,
|
|
321
|
-
fill: positiveMarginColor,
|
|
322
|
-
realToCanvasMat,
|
|
323
|
-
borderRadius: hole.rect_border_radius ?? 0,
|
|
324
|
-
})
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Draw rectangular pad
|
|
141
|
+
// Draw rectangular pad (smaller if negative margin)
|
|
328
142
|
drawRect({
|
|
329
143
|
ctx,
|
|
330
144
|
center: { x: hole.x, y: hole.y },
|
|
331
|
-
width: hole.rect_pad_width,
|
|
332
|
-
height: hole.rect_pad_height,
|
|
145
|
+
width: hole.rect_pad_width - copperInset * 2,
|
|
146
|
+
height: hole.rect_pad_height - copperInset * 2,
|
|
333
147
|
fill: copperColor,
|
|
334
148
|
realToCanvasMat,
|
|
335
|
-
borderRadius: hole.rect_border_radius
|
|
149
|
+
borderRadius: hole.rect_border_radius
|
|
150
|
+
? Math.max(0, hole.rect_border_radius - copperInset)
|
|
151
|
+
: 0,
|
|
336
152
|
})
|
|
337
153
|
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
soldermaskRingColor,
|
|
350
|
-
copperColor,
|
|
351
|
-
)
|
|
352
|
-
}
|
|
353
|
-
|
|
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
|
-
}
|
|
154
|
+
// Draw pill drill hole (with offset)
|
|
155
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
156
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
157
|
+
drawPill({
|
|
158
|
+
ctx,
|
|
159
|
+
center: { x: holeX, y: holeY },
|
|
160
|
+
width: hole.hole_width,
|
|
161
|
+
height: hole.hole_height,
|
|
162
|
+
fill: colorMap.drill,
|
|
163
|
+
realToCanvasMat,
|
|
164
|
+
})
|
|
380
165
|
return
|
|
381
166
|
}
|
|
382
167
|
|
|
383
168
|
if (hole.shape === "rotated_pill_hole_with_rect_pad") {
|
|
384
|
-
//
|
|
385
|
-
if (hasSoldermask && margin > 0) {
|
|
386
|
-
drawRect({
|
|
387
|
-
ctx,
|
|
388
|
-
center: { x: hole.x, y: hole.y },
|
|
389
|
-
width: hole.rect_pad_width + margin * 2,
|
|
390
|
-
height: hole.rect_pad_height + margin * 2,
|
|
391
|
-
fill: positiveMarginColor,
|
|
392
|
-
realToCanvasMat,
|
|
393
|
-
borderRadius: hole.rect_border_radius ?? 0,
|
|
394
|
-
rotation: hole.rect_ccw_rotation,
|
|
395
|
-
})
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// Draw rotated rectangular pad
|
|
169
|
+
// Draw rotated rectangular pad (smaller if negative margin)
|
|
399
170
|
drawRect({
|
|
400
171
|
ctx,
|
|
401
172
|
center: { x: hole.x, y: hole.y },
|
|
402
|
-
width: hole.rect_pad_width,
|
|
403
|
-
height: hole.rect_pad_height,
|
|
173
|
+
width: hole.rect_pad_width - copperInset * 2,
|
|
174
|
+
height: hole.rect_pad_height - copperInset * 2,
|
|
404
175
|
fill: copperColor,
|
|
405
176
|
realToCanvasMat,
|
|
406
|
-
borderRadius: hole.rect_border_radius
|
|
177
|
+
borderRadius: hole.rect_border_radius
|
|
178
|
+
? Math.max(0, hole.rect_border_radius - copperInset)
|
|
179
|
+
: 0,
|
|
407
180
|
rotation: hole.rect_ccw_rotation,
|
|
408
181
|
})
|
|
409
182
|
|
|
410
|
-
//
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
copperColor,
|
|
423
|
-
)
|
|
424
|
-
}
|
|
425
|
-
|
|
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
|
-
}
|
|
183
|
+
// Draw rotated pill drill hole (with offset)
|
|
184
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
185
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
186
|
+
drawPill({
|
|
187
|
+
ctx,
|
|
188
|
+
center: { x: holeX, y: holeY },
|
|
189
|
+
width: hole.hole_width,
|
|
190
|
+
height: hole.hole_height,
|
|
191
|
+
fill: colorMap.drill,
|
|
192
|
+
realToCanvasMat,
|
|
193
|
+
rotation: hole.hole_ccw_rotation,
|
|
194
|
+
})
|
|
454
195
|
return
|
|
455
196
|
}
|
|
456
197
|
|
|
@@ -463,90 +204,61 @@ export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
|
|
|
463
204
|
y: hole.y + point.y,
|
|
464
205
|
}))
|
|
465
206
|
|
|
466
|
-
//
|
|
467
|
-
|
|
468
|
-
|
|
207
|
+
// Draw polygon pad (smaller if negative margin)
|
|
208
|
+
const copperPoints =
|
|
209
|
+
copperInset > 0
|
|
210
|
+
? offsetPolygonPoints(padPoints, -copperInset)
|
|
211
|
+
: padPoints
|
|
212
|
+
if (copperPoints.length >= 3) {
|
|
469
213
|
drawPolygon({
|
|
470
214
|
ctx,
|
|
471
|
-
points:
|
|
472
|
-
fill:
|
|
215
|
+
points: copperPoints,
|
|
216
|
+
fill: copperColor,
|
|
473
217
|
realToCanvasMat,
|
|
474
218
|
})
|
|
475
219
|
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Draw drill hole (with offset)
|
|
223
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0)
|
|
224
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0)
|
|
225
|
+
const holeShape = hole.hole_shape
|
|
476
226
|
|
|
477
|
-
|
|
478
|
-
|
|
227
|
+
if (holeShape === "circle") {
|
|
228
|
+
drawCircle({
|
|
479
229
|
ctx,
|
|
480
|
-
|
|
481
|
-
|
|
230
|
+
center: { x: holeX, y: holeY },
|
|
231
|
+
radius: (hole.hole_diameter ?? 0) / 2,
|
|
232
|
+
fill: colorMap.drill,
|
|
233
|
+
realToCanvasMat,
|
|
234
|
+
})
|
|
235
|
+
} else if (holeShape === "oval") {
|
|
236
|
+
drawOval({
|
|
237
|
+
ctx,
|
|
238
|
+
center: { x: holeX, y: holeY },
|
|
239
|
+
radius_x: (hole.hole_width ?? 0) / 2,
|
|
240
|
+
radius_y: (hole.hole_height ?? 0) / 2,
|
|
241
|
+
fill: colorMap.drill,
|
|
242
|
+
realToCanvasMat,
|
|
243
|
+
})
|
|
244
|
+
} else if (holeShape === "pill") {
|
|
245
|
+
drawPill({
|
|
246
|
+
ctx,
|
|
247
|
+
center: { x: holeX, y: holeY },
|
|
248
|
+
width: hole.hole_width ?? 0,
|
|
249
|
+
height: hole.hole_height ?? 0,
|
|
250
|
+
fill: colorMap.drill,
|
|
251
|
+
realToCanvasMat,
|
|
252
|
+
})
|
|
253
|
+
} else if (holeShape === "rotated_pill") {
|
|
254
|
+
drawPill({
|
|
255
|
+
ctx,
|
|
256
|
+
center: { x: holeX, y: holeY },
|
|
257
|
+
width: hole.hole_width ?? 0,
|
|
258
|
+
height: hole.hole_height ?? 0,
|
|
259
|
+
fill: colorMap.drill,
|
|
482
260
|
realToCanvasMat,
|
|
483
261
|
})
|
|
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
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
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
|
|
513
|
-
|
|
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
|
-
}
|
|
550
262
|
}
|
|
551
263
|
return
|
|
552
264
|
}
|