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.
Files changed (53) hide show
  1. package/dist/index.d.ts +10 -4
  2. package/dist/index.js +2911 -2719
  3. package/lib/drawer/CircuitToCanvasDrawer.ts +317 -366
  4. package/lib/drawer/elements/helper-functions/draw-pill.ts +39 -0
  5. package/lib/drawer/elements/helper-functions/draw-polygon.ts +25 -0
  6. package/lib/drawer/elements/helper-functions/draw-rounded-rect.ts +34 -0
  7. package/lib/drawer/elements/helper-functions/index.ts +3 -0
  8. package/lib/drawer/elements/pcb-board.ts +28 -13
  9. package/lib/drawer/elements/pcb-hole.ts +56 -338
  10. package/lib/drawer/elements/pcb-plated-hole.ts +154 -442
  11. package/lib/drawer/elements/pcb-smtpad.ts +3 -292
  12. package/lib/drawer/elements/pcb-soldermask/board.ts +44 -0
  13. package/lib/drawer/elements/pcb-soldermask/cutout.ts +74 -0
  14. package/lib/drawer/elements/pcb-soldermask/hole.ts +288 -0
  15. package/lib/drawer/elements/pcb-soldermask/index.ts +140 -0
  16. package/lib/drawer/elements/pcb-soldermask/plated-hole.ts +365 -0
  17. package/lib/drawer/elements/pcb-soldermask/smt-pad.ts +354 -0
  18. package/lib/drawer/elements/pcb-soldermask/via.ts +27 -0
  19. package/package.json +1 -1
  20. package/tests/board-snapshot/__snapshots__/usb-c-flashlight-board.snap.png +0 -0
  21. package/tests/board-snapshot/usb-c-flashlight-board.test.ts +1 -0
  22. package/tests/elements/__snapshots__/board-with-elements.snap.png +0 -0
  23. package/tests/elements/__snapshots__/brep-copper-pours.snap.png +0 -0
  24. package/tests/elements/__snapshots__/custom-outline-board.snap.png +0 -0
  25. package/tests/elements/__snapshots__/oval-plated-hole.snap.png +0 -0
  26. package/tests/elements/__snapshots__/pcb-board.snap.png +0 -0
  27. package/tests/elements/__snapshots__/pcb-comprehensive-soldermask-margin.snap.png +0 -0
  28. package/tests/elements/__snapshots__/pcb-fabrication-note-dimension.snap.png +0 -0
  29. package/tests/elements/__snapshots__/pcb-hole-soldermask-margin.snap.png +0 -0
  30. package/tests/elements/__snapshots__/pcb-keepout-layer-filter.snap.png +0 -0
  31. package/tests/elements/__snapshots__/pcb-keepout-multiple-layers.snap.png +0 -0
  32. package/tests/elements/__snapshots__/pcb-keepout-rect-and-circle.snap.png +0 -0
  33. package/tests/elements/__snapshots__/pcb-keepout-with-group-id.snap.png +0 -0
  34. package/tests/elements/__snapshots__/pcb-no-soldermask.snap.png +0 -0
  35. package/tests/elements/__snapshots__/pcb-plated-hole-soldermask-margin.snap.png +0 -0
  36. package/tests/elements/__snapshots__/pcb-plated-hole.snap.png +0 -0
  37. package/tests/elements/__snapshots__/pcb-silkscreen-on-component.snap.png +0 -0
  38. package/tests/elements/__snapshots__/pcb-silkscreen-oval.snap.png +0 -0
  39. package/tests/elements/__snapshots__/pcb-smtpad-asymmetric-soldermask-margin.snap.png +0 -0
  40. package/tests/elements/__snapshots__/pcb-smtpad-soldermask-coverage.snap.png +0 -0
  41. package/tests/elements/__snapshots__/pcb-smtpad-soldermask-margin.snap.png +0 -0
  42. package/tests/elements/__snapshots__/pill-plated-hole.snap.png +0 -0
  43. package/tests/elements/pcb-board.test.ts +2 -2
  44. package/tests/elements/pcb-comprehensive-soldermask-margin.test.ts +2 -2
  45. package/tests/elements/pcb-hole-soldermask-margin.test.ts +155 -2
  46. package/tests/elements/pcb-keepout-with-group-id.test.ts +1 -1
  47. package/tests/elements/pcb-no-soldermask.test.ts +1281 -0
  48. package/tests/elements/pcb-plated-hole-soldermask-margin.test.ts +1 -1
  49. package/tests/elements/pcb-plated-hole.test.ts +40 -4
  50. package/tests/elements/pcb-smtpad-asymmetric-soldermask-margin.test.ts +1 -1
  51. package/tests/elements/pcb-smtpad-soldermask-coverage.test.ts +1 -1
  52. package/tests/elements/pcb-smtpad-soldermask-margin.test.ts +1 -1
  53. 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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "circuit-to-canvas",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.50",
4
+ "version": "0.0.52",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsup-node ./lib/index.ts --format esm --dts",
@@ -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)
@@ -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,