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.
Files changed (27) hide show
  1. package/dist/index.js +530 -163
  2. package/lib/drawer/CircuitToCanvasDrawer.ts +1 -5
  3. package/lib/drawer/elements/pcb-hole.ts +248 -61
  4. package/lib/drawer/elements/pcb-plated-hole.ts +234 -107
  5. package/lib/drawer/elements/pcb-smtpad.ts +43 -21
  6. package/lib/drawer/elements/soldermask-margin.ts +130 -0
  7. package/package.json +1 -1
  8. package/tests/board-snapshot/__snapshots__/usb-c-flashlight-board.snap.png +0 -0
  9. package/tests/elements/__snapshots__/board-with-elements.snap.png +0 -0
  10. package/tests/elements/__snapshots__/custom-outline-board.snap.png +0 -0
  11. package/tests/elements/__snapshots__/pcb-board.snap.png +0 -0
  12. package/tests/elements/__snapshots__/pcb-comprehensive-soldermask-margin.snap.png +0 -0
  13. package/tests/elements/__snapshots__/pcb-fabrication-note-dimension.snap.png +0 -0
  14. package/tests/elements/__snapshots__/pcb-hole-soldermask-margin.snap.png +0 -0
  15. package/tests/elements/__snapshots__/pcb-keepout-layer-filter.snap.png +0 -0
  16. package/tests/elements/__snapshots__/pcb-keepout-multiple-layers.snap.png +0 -0
  17. package/tests/elements/__snapshots__/pcb-keepout-rect-and-circle.snap.png +0 -0
  18. package/tests/elements/__snapshots__/pcb-keepout-with-group-id.snap.png +0 -0
  19. package/tests/elements/__snapshots__/pcb-note-dimension-with-offset.snap.png +0 -0
  20. package/tests/elements/__snapshots__/pcb-plated-hole-soldermask-margin.snap.png +0 -0
  21. package/tests/elements/__snapshots__/pcb-silkscreen-oval.snap.png +0 -0
  22. package/tests/elements/__snapshots__/pcb-smtpad-soldermask-margin.snap.png +0 -0
  23. package/tests/elements/pcb-comprehensive-soldermask-margin.test.ts +1281 -0
  24. package/tests/elements/pcb-hole-soldermask-margin.test.ts +5 -5
  25. package/tests/elements/pcb-plated-hole-soldermask-margin.test.ts +8 -8
  26. package/tests/elements/pcb-smtpad-soldermask-margin.test.ts +0 -6
  27. package/tests/shapes/__snapshots__/dimension-line.snap.png +0 -0
@@ -324,3 +324,133 @@ export function drawSoldermaskRingForOval(
324
324
 
325
325
  ctx.restore()
326
326
  }
327
+
328
+ /**
329
+ * Offsets polygon points by a given distance (positive = outward, negative = inward)
330
+ */
331
+ export function offsetPolygonPoints(
332
+ points: Array<{ x: number; y: number }>,
333
+ offset: number,
334
+ ): Array<{ x: number; y: number }> {
335
+ if (points.length < 3 || offset === 0) return points
336
+
337
+ // Calculate polygon centroid
338
+ let centerX = 0
339
+ let centerY = 0
340
+ for (const point of points) {
341
+ centerX += point.x
342
+ centerY += point.y
343
+ }
344
+ centerX /= points.length
345
+ centerY /= points.length
346
+
347
+ const result: Array<{ x: number; y: number }> = []
348
+
349
+ for (const point of points) {
350
+ // Calculate vector from center to point
351
+ const vectorX = point.x - centerX
352
+ const vectorY = point.y - centerY
353
+
354
+ // Calculate distance from center
355
+ const distance = Math.sqrt(vectorX * vectorX + vectorY * vectorY)
356
+
357
+ if (distance > 0) {
358
+ // Normalize vector and offset
359
+ const normalizedX = vectorX / distance
360
+ const normalizedY = vectorY / distance
361
+
362
+ result.push({
363
+ x: point.x + normalizedX * offset,
364
+ y: point.y + normalizedY * offset,
365
+ })
366
+ } else {
367
+ // Point is at center, offset in arbitrary direction
368
+ result.push({
369
+ x: point.x + offset,
370
+ y: point.y,
371
+ })
372
+ }
373
+ }
374
+
375
+ return result
376
+ }
377
+
378
+ /**
379
+ * Draws a soldermask ring for polygon shapes with negative margin
380
+ * (soldermask appears inside the pad boundary)
381
+ */
382
+ export function drawSoldermaskRingForPolygon(
383
+ ctx: CanvasContext,
384
+ points: Array<{ x: number; y: number }>,
385
+ margin: number,
386
+ realToCanvasMat: Matrix,
387
+ soldermaskColor: string,
388
+ padColor: string,
389
+ ): void {
390
+ if (points.length < 3 || margin >= 0) return
391
+
392
+ const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a)
393
+
394
+ // For negative margins, outer is pad boundary, inner is contracted by margin
395
+ // Use source-atop so the ring only appears on the pad
396
+ const prevCompositeOp = ctx.globalCompositeOperation
397
+ if (ctx.globalCompositeOperation !== undefined) {
398
+ ctx.globalCompositeOperation = "source-atop"
399
+ }
400
+
401
+ // Draw outer polygon filled (at pad boundary)
402
+ ctx.beginPath()
403
+ const canvasPoints = points.map((p) =>
404
+ applyToPoint(realToCanvasMat, [p.x, p.y]),
405
+ )
406
+
407
+ const firstPoint = canvasPoints[0]
408
+ if (firstPoint) {
409
+ const [firstX, firstY] = firstPoint
410
+ ctx.moveTo(firstX, firstY)
411
+
412
+ for (let i = 1; i < canvasPoints.length; i++) {
413
+ const point = canvasPoints[i]
414
+ if (point) {
415
+ const [x, y] = point
416
+ ctx.lineTo(x, y)
417
+ }
418
+ }
419
+ ctx.closePath()
420
+ ctx.fillStyle = soldermaskColor
421
+ ctx.fill()
422
+ }
423
+
424
+ // Reset composite operation and restore pad color in inner area
425
+ if (ctx.globalCompositeOperation !== undefined) {
426
+ ctx.globalCompositeOperation = prevCompositeOp || "source-over"
427
+ }
428
+
429
+ // Restore pad color in inner polygon (contracted by margin)
430
+ const innerPoints = offsetPolygonPoints(points, margin)
431
+ if (innerPoints.length >= 3) {
432
+ ctx.beginPath()
433
+ const innerCanvasPoints = innerPoints.map((p) =>
434
+ applyToPoint(realToCanvasMat, [p.x, p.y]),
435
+ )
436
+
437
+ const firstInnerPoint = innerCanvasPoints[0]
438
+ if (firstInnerPoint) {
439
+ const [firstX, firstY] = firstInnerPoint
440
+ ctx.moveTo(firstX, firstY)
441
+
442
+ for (let i = 1; i < innerCanvasPoints.length; i++) {
443
+ const point = innerCanvasPoints[i]
444
+ if (point) {
445
+ const [x, y] = point
446
+ ctx.lineTo(x, y)
447
+ }
448
+ }
449
+ ctx.closePath()
450
+ ctx.fillStyle = padColor
451
+ ctx.fill()
452
+ }
453
+ }
454
+
455
+ ctx.restore()
456
+ }
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.45",
4
+ "version": "0.0.47",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsup-node ./lib/index.ts --format esm --dts",