circuit-to-canvas 0.0.36 → 0.0.38

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.
@@ -0,0 +1,225 @@
1
+ import { expect, test } from "bun:test"
2
+ import { createCanvas } from "@napi-rs/canvas"
3
+ import type { PcbPlatedHole } from "circuit-json"
4
+ import { CircuitToCanvasDrawer } from "../../lib/drawer"
5
+
6
+ test("draw plated holes with positive and negative soldermask margins", async () => {
7
+ const canvas = createCanvas(800, 600)
8
+ const ctx = canvas.getContext("2d")
9
+ const drawer = new CircuitToCanvasDrawer(ctx)
10
+
11
+ ctx.fillStyle = "#1a1a1a"
12
+ ctx.fillRect(0, 0, 800, 600)
13
+
14
+ const circuit: any = [
15
+ {
16
+ type: "pcb_board",
17
+ pcb_board_id: "board0",
18
+ center: { x: 0, y: 0 },
19
+ width: 16,
20
+ height: 14,
21
+ },
22
+ // Circle with positive margin (mask extends beyond pad)
23
+ {
24
+ type: "pcb_plated_hole",
25
+ pcb_plated_hole_id: "hole_circle_positive",
26
+ shape: "circle",
27
+ x: -5,
28
+ y: 3.5,
29
+ outer_diameter: 2,
30
+ hole_diameter: 1,
31
+ layers: ["top", "bottom"],
32
+ is_covered_with_solder_mask: true,
33
+ soldermask_margin: 0.2,
34
+ },
35
+ // Circle with negative margin (spacing around copper, copper visible)
36
+ {
37
+ type: "pcb_plated_hole",
38
+ pcb_plated_hole_id: "hole_circle_negative",
39
+ shape: "circle",
40
+ x: -5,
41
+ y: -3.5,
42
+ outer_diameter: 2,
43
+ hole_diameter: 1,
44
+ layers: ["top", "bottom"],
45
+ is_covered_with_solder_mask: true,
46
+ soldermask_margin: -0.15,
47
+ },
48
+ // Oval with positive margin
49
+ {
50
+ type: "pcb_plated_hole",
51
+ pcb_plated_hole_id: "hole_oval_positive",
52
+ shape: "oval",
53
+ x: 0,
54
+ y: 3.5,
55
+ outer_width: 2.4,
56
+ outer_height: 1.6,
57
+ hole_width: 1.6,
58
+ hole_height: 0.8,
59
+ layers: ["top", "bottom"],
60
+ ccw_rotation: 0,
61
+ is_covered_with_solder_mask: true,
62
+ soldermask_margin: 0.15,
63
+ },
64
+ // Oval with negative margin
65
+ {
66
+ type: "pcb_plated_hole",
67
+ pcb_plated_hole_id: "hole_oval_negative",
68
+ shape: "oval",
69
+ x: 0,
70
+ y: -3.5,
71
+ outer_width: 2.4,
72
+ outer_height: 1.6,
73
+ hole_width: 1.6,
74
+ hole_height: 0.8,
75
+ layers: ["top", "bottom"],
76
+ ccw_rotation: 0,
77
+ is_covered_with_solder_mask: true,
78
+ soldermask_margin: -0.2,
79
+ },
80
+ // Pill with positive margin
81
+ {
82
+ type: "pcb_plated_hole",
83
+ pcb_plated_hole_id: "hole_pill_positive",
84
+ shape: "pill",
85
+ x: 5,
86
+ y: 3.5,
87
+ outer_width: 3,
88
+ outer_height: 1.5,
89
+ hole_width: 2,
90
+ hole_height: 1,
91
+ layers: ["top", "bottom"],
92
+ ccw_rotation: 0,
93
+ is_covered_with_solder_mask: true,
94
+ soldermask_margin: 0.1,
95
+ },
96
+ // Pill with negative margin
97
+ {
98
+ type: "pcb_plated_hole",
99
+ pcb_plated_hole_id: "hole_pill_negative",
100
+ shape: "pill",
101
+ x: 5,
102
+ y: -3.5,
103
+ outer_width: 3,
104
+ outer_height: 1.5,
105
+ hole_width: 2,
106
+ hole_height: 1,
107
+ layers: ["top", "bottom"],
108
+ ccw_rotation: 0,
109
+ is_covered_with_solder_mask: true,
110
+ soldermask_margin: -0.12,
111
+ },
112
+ // Rectangular pad with circular hole - positive margin
113
+ {
114
+ type: "pcb_plated_hole",
115
+ pcb_plated_hole_id: "hole_rect_circle_positive",
116
+ shape: "circular_hole_with_rect_pad",
117
+ x: -2.5,
118
+ y: 0,
119
+ rect_pad_width: 2.4,
120
+ rect_pad_height: 1.6,
121
+ rect_border_radius: 0.2,
122
+ hole_diameter: 1,
123
+ layers: ["top", "bottom"],
124
+ is_covered_with_solder_mask: true,
125
+ soldermask_margin: 0.15,
126
+ },
127
+ // Rectangular pad with circular hole - negative margin
128
+ {
129
+ type: "pcb_plated_hole",
130
+ pcb_plated_hole_id: "hole_rect_circle_negative",
131
+ shape: "circular_hole_with_rect_pad",
132
+ x: 2.5,
133
+ y: 0,
134
+ rect_pad_width: 2.4,
135
+ rect_pad_height: 1.6,
136
+ rect_border_radius: 0.2,
137
+ hole_diameter: 1,
138
+ layers: ["top", "bottom"],
139
+ is_covered_with_solder_mask: true,
140
+ soldermask_margin: -0.1,
141
+ },
142
+ // Silkscreen labels for positive margin holes (top row)
143
+ {
144
+ type: "pcb_silkscreen_text",
145
+ pcb_silkscreen_text_id: "text_circle_pos",
146
+ layer: "top",
147
+ anchor_position: { x: -5, y: 5.2 },
148
+ anchor_alignment: "center",
149
+ text: "+0.2mm",
150
+ font_size: 0.4,
151
+ },
152
+ {
153
+ type: "pcb_silkscreen_text",
154
+ pcb_silkscreen_text_id: "text_oval_pos",
155
+ layer: "top",
156
+ anchor_position: { x: 0, y: 5.2 },
157
+ anchor_alignment: "center",
158
+ text: "+0.15mm",
159
+ font_size: 0.4,
160
+ },
161
+ {
162
+ type: "pcb_silkscreen_text",
163
+ pcb_silkscreen_text_id: "text_pill_pos",
164
+ layer: "top",
165
+ anchor_position: { x: 5, y: 5.2 },
166
+ anchor_alignment: "center",
167
+ text: "+0.1mm",
168
+ font_size: 0.4,
169
+ },
170
+ // Silkscreen labels for middle row (rectangular pads)
171
+ {
172
+ type: "pcb_silkscreen_text",
173
+ pcb_silkscreen_text_id: "text_rect_pos",
174
+ layer: "top",
175
+ anchor_position: { x: -2.5, y: 1.8 },
176
+ anchor_alignment: "center",
177
+ text: "+0.15mm",
178
+ font_size: 0.4,
179
+ },
180
+ {
181
+ type: "pcb_silkscreen_text",
182
+ pcb_silkscreen_text_id: "text_rect_neg",
183
+ layer: "top",
184
+ anchor_position: { x: 2.5, y: -1.8 },
185
+ anchor_alignment: "center",
186
+ text: "-0.1mm",
187
+ font_size: 0.4,
188
+ },
189
+ // Silkscreen labels for negative margin holes (bottom row)
190
+ {
191
+ type: "pcb_silkscreen_text",
192
+ pcb_silkscreen_text_id: "text_circle_neg",
193
+ layer: "top",
194
+ anchor_position: { x: -5, y: -5.2 },
195
+ anchor_alignment: "center",
196
+ text: "-0.15mm",
197
+ font_size: 0.4,
198
+ },
199
+ {
200
+ type: "pcb_silkscreen_text",
201
+ pcb_silkscreen_text_id: "text_oval_neg",
202
+ layer: "top",
203
+ anchor_position: { x: 0, y: -5.2 },
204
+ anchor_alignment: "center",
205
+ text: "-0.2mm",
206
+ font_size: 0.4,
207
+ },
208
+ {
209
+ type: "pcb_silkscreen_text",
210
+ pcb_silkscreen_text_id: "text_pill_neg",
211
+ layer: "top",
212
+ anchor_position: { x: 5, y: -5.2 },
213
+ anchor_alignment: "center",
214
+ text: "-0.12mm",
215
+ font_size: 0.4,
216
+ },
217
+ ]
218
+
219
+ drawer.setCameraBounds({ minX: -8, maxX: 8, minY: -6.5, maxY: 6.5 })
220
+ drawer.drawElements(circuit)
221
+
222
+ await expect(canvas.toBuffer("image/png")).toMatchPngSnapshot(
223
+ import.meta.path,
224
+ )
225
+ })