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
package/dist/index.js
CHANGED
|
@@ -456,6 +456,90 @@ function drawSoldermaskRingForOval(ctx, center, radius_x, radius_y, margin, rota
|
|
|
456
456
|
}
|
|
457
457
|
ctx.restore();
|
|
458
458
|
}
|
|
459
|
+
function offsetPolygonPoints(points, offset) {
|
|
460
|
+
if (points.length < 3 || offset === 0) return points;
|
|
461
|
+
let centerX = 0;
|
|
462
|
+
let centerY = 0;
|
|
463
|
+
for (const point of points) {
|
|
464
|
+
centerX += point.x;
|
|
465
|
+
centerY += point.y;
|
|
466
|
+
}
|
|
467
|
+
centerX /= points.length;
|
|
468
|
+
centerY /= points.length;
|
|
469
|
+
const result = [];
|
|
470
|
+
for (const point of points) {
|
|
471
|
+
const vectorX = point.x - centerX;
|
|
472
|
+
const vectorY = point.y - centerY;
|
|
473
|
+
const distance = Math.sqrt(vectorX * vectorX + vectorY * vectorY);
|
|
474
|
+
if (distance > 0) {
|
|
475
|
+
const normalizedX = vectorX / distance;
|
|
476
|
+
const normalizedY = vectorY / distance;
|
|
477
|
+
result.push({
|
|
478
|
+
x: point.x + normalizedX * offset,
|
|
479
|
+
y: point.y + normalizedY * offset
|
|
480
|
+
});
|
|
481
|
+
} else {
|
|
482
|
+
result.push({
|
|
483
|
+
x: point.x + offset,
|
|
484
|
+
y: point.y
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return result;
|
|
489
|
+
}
|
|
490
|
+
function drawSoldermaskRingForPolygon(ctx, points, margin, realToCanvasMat, soldermaskColor, padColor) {
|
|
491
|
+
if (points.length < 3 || margin >= 0) return;
|
|
492
|
+
const scaledMargin = Math.abs(margin) * Math.abs(realToCanvasMat.a);
|
|
493
|
+
const prevCompositeOp = ctx.globalCompositeOperation;
|
|
494
|
+
if (ctx.globalCompositeOperation !== void 0) {
|
|
495
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
496
|
+
}
|
|
497
|
+
ctx.beginPath();
|
|
498
|
+
const canvasPoints = points.map(
|
|
499
|
+
(p) => applyToPoint6(realToCanvasMat, [p.x, p.y])
|
|
500
|
+
);
|
|
501
|
+
const firstPoint = canvasPoints[0];
|
|
502
|
+
if (firstPoint) {
|
|
503
|
+
const [firstX, firstY] = firstPoint;
|
|
504
|
+
ctx.moveTo(firstX, firstY);
|
|
505
|
+
for (let i = 1; i < canvasPoints.length; i++) {
|
|
506
|
+
const point = canvasPoints[i];
|
|
507
|
+
if (point) {
|
|
508
|
+
const [x, y] = point;
|
|
509
|
+
ctx.lineTo(x, y);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
ctx.closePath();
|
|
513
|
+
ctx.fillStyle = soldermaskColor;
|
|
514
|
+
ctx.fill();
|
|
515
|
+
}
|
|
516
|
+
if (ctx.globalCompositeOperation !== void 0) {
|
|
517
|
+
ctx.globalCompositeOperation = prevCompositeOp || "source-over";
|
|
518
|
+
}
|
|
519
|
+
const innerPoints = offsetPolygonPoints(points, margin);
|
|
520
|
+
if (innerPoints.length >= 3) {
|
|
521
|
+
ctx.beginPath();
|
|
522
|
+
const innerCanvasPoints = innerPoints.map(
|
|
523
|
+
(p) => applyToPoint6(realToCanvasMat, [p.x, p.y])
|
|
524
|
+
);
|
|
525
|
+
const firstInnerPoint = innerCanvasPoints[0];
|
|
526
|
+
if (firstInnerPoint) {
|
|
527
|
+
const [firstX, firstY] = firstInnerPoint;
|
|
528
|
+
ctx.moveTo(firstX, firstY);
|
|
529
|
+
for (let i = 1; i < innerCanvasPoints.length; i++) {
|
|
530
|
+
const point = innerCanvasPoints[i];
|
|
531
|
+
if (point) {
|
|
532
|
+
const [x, y] = point;
|
|
533
|
+
ctx.lineTo(x, y);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
ctx.closePath();
|
|
537
|
+
ctx.fillStyle = padColor;
|
|
538
|
+
ctx.fill();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
ctx.restore();
|
|
542
|
+
}
|
|
459
543
|
|
|
460
544
|
// lib/drawer/elements/pcb-plated-hole.ts
|
|
461
545
|
function getSoldermaskColor(layers, colorMap) {
|
|
@@ -464,8 +548,9 @@ function getSoldermaskColor(layers, colorMap) {
|
|
|
464
548
|
}
|
|
465
549
|
function drawPcbPlatedHole(params) {
|
|
466
550
|
const { ctx, hole, realToCanvasMat, colorMap } = params;
|
|
467
|
-
const
|
|
468
|
-
const margin =
|
|
551
|
+
const isCoveredWithSoldermask = hole.is_covered_with_solder_mask === true;
|
|
552
|
+
const margin = isCoveredWithSoldermask ? 0 : hole.soldermask_margin ?? 0;
|
|
553
|
+
const hasSoldermask = !isCoveredWithSoldermask && hole.soldermask_margin !== void 0 && hole.soldermask_margin !== 0;
|
|
469
554
|
const soldermaskRingColor = getSoldermaskColor(hole.layers, colorMap);
|
|
470
555
|
const positiveMarginColor = colorMap.substrate;
|
|
471
556
|
const copperColor = colorMap.copper.top;
|
|
@@ -497,13 +582,24 @@ function drawPcbPlatedHole(params) {
|
|
|
497
582
|
copperColor
|
|
498
583
|
);
|
|
499
584
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
585
|
+
if (isCoveredWithSoldermask) {
|
|
586
|
+
drawCircle({
|
|
587
|
+
ctx,
|
|
588
|
+
center: { x: hole.x, y: hole.y },
|
|
589
|
+
radius: hole.outer_diameter / 2,
|
|
590
|
+
fill: soldermaskRingColor,
|
|
591
|
+
realToCanvasMat
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
if (!isCoveredWithSoldermask) {
|
|
595
|
+
drawCircle({
|
|
596
|
+
ctx,
|
|
597
|
+
center: { x: hole.x, y: hole.y },
|
|
598
|
+
radius: hole.hole_diameter / 2,
|
|
599
|
+
fill: colorMap.drill,
|
|
600
|
+
realToCanvasMat
|
|
601
|
+
});
|
|
602
|
+
}
|
|
507
603
|
return;
|
|
508
604
|
}
|
|
509
605
|
if (hole.shape === "oval") {
|
|
@@ -540,15 +636,28 @@ function drawPcbPlatedHole(params) {
|
|
|
540
636
|
copperColor
|
|
541
637
|
);
|
|
542
638
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
639
|
+
if (isCoveredWithSoldermask) {
|
|
640
|
+
drawOval({
|
|
641
|
+
ctx,
|
|
642
|
+
center: { x: hole.x, y: hole.y },
|
|
643
|
+
radius_x: hole.outer_width / 2,
|
|
644
|
+
radius_y: hole.outer_height / 2,
|
|
645
|
+
fill: soldermaskRingColor,
|
|
646
|
+
realToCanvasMat,
|
|
647
|
+
rotation: hole.ccw_rotation
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
if (!isCoveredWithSoldermask) {
|
|
651
|
+
drawOval({
|
|
652
|
+
ctx,
|
|
653
|
+
center: { x: hole.x, y: hole.y },
|
|
654
|
+
radius_x: hole.hole_width / 2,
|
|
655
|
+
radius_y: hole.hole_height / 2,
|
|
656
|
+
fill: colorMap.drill,
|
|
657
|
+
realToCanvasMat,
|
|
658
|
+
rotation: hole.ccw_rotation
|
|
659
|
+
});
|
|
660
|
+
}
|
|
552
661
|
return;
|
|
553
662
|
}
|
|
554
663
|
if (hole.shape === "pill") {
|
|
@@ -585,15 +694,28 @@ function drawPcbPlatedHole(params) {
|
|
|
585
694
|
copperColor
|
|
586
695
|
);
|
|
587
696
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
697
|
+
if (isCoveredWithSoldermask) {
|
|
698
|
+
drawPill({
|
|
699
|
+
ctx,
|
|
700
|
+
center: { x: hole.x, y: hole.y },
|
|
701
|
+
width: hole.outer_width,
|
|
702
|
+
height: hole.outer_height,
|
|
703
|
+
fill: soldermaskRingColor,
|
|
704
|
+
realToCanvasMat,
|
|
705
|
+
rotation: hole.ccw_rotation
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
if (!isCoveredWithSoldermask) {
|
|
709
|
+
drawPill({
|
|
710
|
+
ctx,
|
|
711
|
+
center: { x: hole.x, y: hole.y },
|
|
712
|
+
width: hole.hole_width,
|
|
713
|
+
height: hole.hole_height,
|
|
714
|
+
fill: colorMap.drill,
|
|
715
|
+
realToCanvasMat,
|
|
716
|
+
rotation: hole.ccw_rotation
|
|
717
|
+
});
|
|
718
|
+
}
|
|
597
719
|
return;
|
|
598
720
|
}
|
|
599
721
|
if (hole.shape === "circular_hole_with_rect_pad") {
|
|
@@ -605,7 +727,7 @@ function drawPcbPlatedHole(params) {
|
|
|
605
727
|
height: hole.rect_pad_height + margin * 2,
|
|
606
728
|
fill: positiveMarginColor,
|
|
607
729
|
realToCanvasMat,
|
|
608
|
-
borderRadius:
|
|
730
|
+
borderRadius: hole.rect_border_radius ?? 0
|
|
609
731
|
});
|
|
610
732
|
}
|
|
611
733
|
drawRect({
|
|
@@ -631,15 +753,28 @@ function drawPcbPlatedHole(params) {
|
|
|
631
753
|
copperColor
|
|
632
754
|
);
|
|
633
755
|
}
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
756
|
+
if (isCoveredWithSoldermask) {
|
|
757
|
+
drawRect({
|
|
758
|
+
ctx,
|
|
759
|
+
center: { x: hole.x, y: hole.y },
|
|
760
|
+
width: hole.rect_pad_width,
|
|
761
|
+
height: hole.rect_pad_height,
|
|
762
|
+
fill: soldermaskRingColor,
|
|
763
|
+
realToCanvasMat,
|
|
764
|
+
borderRadius: hole.rect_border_radius ?? 0
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
if (!isCoveredWithSoldermask) {
|
|
768
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0);
|
|
769
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0);
|
|
770
|
+
drawCircle({
|
|
771
|
+
ctx,
|
|
772
|
+
center: { x: holeX, y: holeY },
|
|
773
|
+
radius: hole.hole_diameter / 2,
|
|
774
|
+
fill: colorMap.drill,
|
|
775
|
+
realToCanvasMat
|
|
776
|
+
});
|
|
777
|
+
}
|
|
643
778
|
return;
|
|
644
779
|
}
|
|
645
780
|
if (hole.shape === "pill_hole_with_rect_pad") {
|
|
@@ -651,7 +786,7 @@ function drawPcbPlatedHole(params) {
|
|
|
651
786
|
height: hole.rect_pad_height + margin * 2,
|
|
652
787
|
fill: positiveMarginColor,
|
|
653
788
|
realToCanvasMat,
|
|
654
|
-
borderRadius:
|
|
789
|
+
borderRadius: hole.rect_border_radius ?? 0
|
|
655
790
|
});
|
|
656
791
|
}
|
|
657
792
|
drawRect({
|
|
@@ -677,16 +812,29 @@ function drawPcbPlatedHole(params) {
|
|
|
677
812
|
copperColor
|
|
678
813
|
);
|
|
679
814
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
815
|
+
if (isCoveredWithSoldermask) {
|
|
816
|
+
drawRect({
|
|
817
|
+
ctx,
|
|
818
|
+
center: { x: hole.x, y: hole.y },
|
|
819
|
+
width: hole.rect_pad_width,
|
|
820
|
+
height: hole.rect_pad_height,
|
|
821
|
+
fill: soldermaskRingColor,
|
|
822
|
+
realToCanvasMat,
|
|
823
|
+
borderRadius: hole.rect_border_radius ?? 0
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
if (!isCoveredWithSoldermask) {
|
|
827
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0);
|
|
828
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0);
|
|
829
|
+
drawPill({
|
|
830
|
+
ctx,
|
|
831
|
+
center: { x: holeX, y: holeY },
|
|
832
|
+
width: hole.hole_width,
|
|
833
|
+
height: hole.hole_height,
|
|
834
|
+
fill: colorMap.drill,
|
|
835
|
+
realToCanvasMat
|
|
836
|
+
});
|
|
837
|
+
}
|
|
690
838
|
return;
|
|
691
839
|
}
|
|
692
840
|
if (hole.shape === "rotated_pill_hole_with_rect_pad") {
|
|
@@ -698,7 +846,7 @@ function drawPcbPlatedHole(params) {
|
|
|
698
846
|
height: hole.rect_pad_height + margin * 2,
|
|
699
847
|
fill: positiveMarginColor,
|
|
700
848
|
realToCanvasMat,
|
|
701
|
-
borderRadius:
|
|
849
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
702
850
|
rotation: hole.rect_ccw_rotation
|
|
703
851
|
});
|
|
704
852
|
}
|
|
@@ -726,17 +874,31 @@ function drawPcbPlatedHole(params) {
|
|
|
726
874
|
copperColor
|
|
727
875
|
);
|
|
728
876
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
877
|
+
if (isCoveredWithSoldermask) {
|
|
878
|
+
drawRect({
|
|
879
|
+
ctx,
|
|
880
|
+
center: { x: hole.x, y: hole.y },
|
|
881
|
+
width: hole.rect_pad_width,
|
|
882
|
+
height: hole.rect_pad_height,
|
|
883
|
+
fill: soldermaskRingColor,
|
|
884
|
+
realToCanvasMat,
|
|
885
|
+
borderRadius: hole.rect_border_radius ?? 0,
|
|
886
|
+
rotation: hole.rect_ccw_rotation
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
if (!isCoveredWithSoldermask) {
|
|
890
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0);
|
|
891
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0);
|
|
892
|
+
drawPill({
|
|
893
|
+
ctx,
|
|
894
|
+
center: { x: holeX, y: holeY },
|
|
895
|
+
width: hole.hole_width,
|
|
896
|
+
height: hole.hole_height,
|
|
897
|
+
fill: colorMap.drill,
|
|
898
|
+
realToCanvasMat,
|
|
899
|
+
rotation: hole.hole_ccw_rotation
|
|
900
|
+
});
|
|
901
|
+
}
|
|
740
902
|
return;
|
|
741
903
|
}
|
|
742
904
|
if (hole.shape === "hole_with_polygon_pad") {
|
|
@@ -746,51 +908,80 @@ function drawPcbPlatedHole(params) {
|
|
|
746
908
|
x: hole.x + point.x,
|
|
747
909
|
y: hole.y + point.y
|
|
748
910
|
}));
|
|
911
|
+
if (hasSoldermask && margin > 0) {
|
|
912
|
+
const expandedPoints = offsetPolygonPoints(padPoints, margin);
|
|
913
|
+
drawPolygon({
|
|
914
|
+
ctx,
|
|
915
|
+
points: expandedPoints,
|
|
916
|
+
fill: positiveMarginColor,
|
|
917
|
+
realToCanvasMat
|
|
918
|
+
});
|
|
919
|
+
}
|
|
749
920
|
drawPolygon({
|
|
750
921
|
ctx,
|
|
751
922
|
points: padPoints,
|
|
752
923
|
fill: copperColor,
|
|
753
924
|
realToCanvasMat
|
|
754
925
|
});
|
|
926
|
+
if (hasSoldermask && margin < 0) {
|
|
927
|
+
drawSoldermaskRingForPolygon(
|
|
928
|
+
ctx,
|
|
929
|
+
padPoints,
|
|
930
|
+
margin,
|
|
931
|
+
realToCanvasMat,
|
|
932
|
+
soldermaskRingColor,
|
|
933
|
+
copperColor
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
if (isCoveredWithSoldermask) {
|
|
937
|
+
drawPolygon({
|
|
938
|
+
ctx,
|
|
939
|
+
points: padPoints,
|
|
940
|
+
fill: soldermaskRingColor,
|
|
941
|
+
realToCanvasMat
|
|
942
|
+
});
|
|
943
|
+
}
|
|
755
944
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
945
|
+
if (!isCoveredWithSoldermask) {
|
|
946
|
+
const holeX = hole.x + (hole.hole_offset_x ?? 0);
|
|
947
|
+
const holeY = hole.y + (hole.hole_offset_y ?? 0);
|
|
948
|
+
const holeShape = hole.hole_shape;
|
|
949
|
+
if (holeShape === "circle") {
|
|
950
|
+
drawCircle({
|
|
951
|
+
ctx,
|
|
952
|
+
center: { x: holeX, y: holeY },
|
|
953
|
+
radius: (hole.hole_diameter ?? 0) / 2,
|
|
954
|
+
fill: colorMap.drill,
|
|
955
|
+
realToCanvasMat
|
|
956
|
+
});
|
|
957
|
+
} else if (holeShape === "oval") {
|
|
958
|
+
drawOval({
|
|
959
|
+
ctx,
|
|
960
|
+
center: { x: holeX, y: holeY },
|
|
961
|
+
radius_x: (hole.hole_width ?? 0) / 2,
|
|
962
|
+
radius_y: (hole.hole_height ?? 0) / 2,
|
|
963
|
+
fill: colorMap.drill,
|
|
964
|
+
realToCanvasMat
|
|
965
|
+
});
|
|
966
|
+
} else if (holeShape === "pill") {
|
|
967
|
+
drawPill({
|
|
968
|
+
ctx,
|
|
969
|
+
center: { x: holeX, y: holeY },
|
|
970
|
+
width: hole.hole_width ?? 0,
|
|
971
|
+
height: hole.hole_height ?? 0,
|
|
972
|
+
fill: colorMap.drill,
|
|
973
|
+
realToCanvasMat
|
|
974
|
+
});
|
|
975
|
+
} else if (holeShape === "rotated_pill") {
|
|
976
|
+
drawPill({
|
|
977
|
+
ctx,
|
|
978
|
+
center: { x: holeX, y: holeY },
|
|
979
|
+
width: hole.hole_width ?? 0,
|
|
980
|
+
height: hole.hole_height ?? 0,
|
|
981
|
+
fill: colorMap.drill,
|
|
982
|
+
realToCanvasMat
|
|
983
|
+
});
|
|
984
|
+
}
|
|
794
985
|
}
|
|
795
986
|
return;
|
|
796
987
|
}
|
|
@@ -824,9 +1015,12 @@ function getRotation(hole) {
|
|
|
824
1015
|
}
|
|
825
1016
|
function drawPcbHole(params) {
|
|
826
1017
|
const { ctx, hole, realToCanvasMat, colorMap } = params;
|
|
827
|
-
const
|
|
828
|
-
const margin =
|
|
1018
|
+
const isCoveredWithSoldermask = hole.is_covered_with_solder_mask === true;
|
|
1019
|
+
const margin = isCoveredWithSoldermask ? 0 : hole.soldermask_margin ?? 0;
|
|
1020
|
+
const hasSoldermask = !isCoveredWithSoldermask && hole.soldermask_margin !== void 0 && hole.soldermask_margin !== 0;
|
|
829
1021
|
const positiveMarginColor = colorMap.substrate;
|
|
1022
|
+
const soldermaskOverlayColor = colorMap.soldermask.top;
|
|
1023
|
+
const soldermaskRingColor = colorMap.soldermask.top;
|
|
830
1024
|
if (hole.hole_shape === "circle") {
|
|
831
1025
|
if (hasSoldermask && margin > 0) {
|
|
832
1026
|
drawCircle({
|
|
@@ -837,13 +1031,35 @@ function drawPcbHole(params) {
|
|
|
837
1031
|
realToCanvasMat
|
|
838
1032
|
});
|
|
839
1033
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1034
|
+
if (!isCoveredWithSoldermask) {
|
|
1035
|
+
drawCircle({
|
|
1036
|
+
ctx,
|
|
1037
|
+
center: { x: hole.x, y: hole.y },
|
|
1038
|
+
radius: hole.hole_diameter / 2,
|
|
1039
|
+
fill: colorMap.drill,
|
|
1040
|
+
realToCanvasMat
|
|
1041
|
+
});
|
|
1042
|
+
if (hasSoldermask && margin < 0) {
|
|
1043
|
+
drawSoldermaskRingForCircle(
|
|
1044
|
+
ctx,
|
|
1045
|
+
{ x: hole.x, y: hole.y },
|
|
1046
|
+
hole.hole_diameter / 2,
|
|
1047
|
+
margin,
|
|
1048
|
+
realToCanvasMat,
|
|
1049
|
+
soldermaskRingColor,
|
|
1050
|
+
colorMap.drill
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
if (isCoveredWithSoldermask) {
|
|
1055
|
+
drawCircle({
|
|
1056
|
+
ctx,
|
|
1057
|
+
center: { x: hole.x, y: hole.y },
|
|
1058
|
+
radius: hole.hole_diameter / 2,
|
|
1059
|
+
fill: soldermaskOverlayColor,
|
|
1060
|
+
realToCanvasMat
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
847
1063
|
return;
|
|
848
1064
|
}
|
|
849
1065
|
if (hole.hole_shape === "square") {
|
|
@@ -859,15 +1075,42 @@ function drawPcbHole(params) {
|
|
|
859
1075
|
rotation
|
|
860
1076
|
});
|
|
861
1077
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1078
|
+
if (!isCoveredWithSoldermask) {
|
|
1079
|
+
drawRect({
|
|
1080
|
+
ctx,
|
|
1081
|
+
center: { x: hole.x, y: hole.y },
|
|
1082
|
+
width: hole.hole_diameter,
|
|
1083
|
+
height: hole.hole_diameter,
|
|
1084
|
+
fill: colorMap.drill,
|
|
1085
|
+
realToCanvasMat,
|
|
1086
|
+
rotation
|
|
1087
|
+
});
|
|
1088
|
+
if (hasSoldermask && margin < 0) {
|
|
1089
|
+
drawSoldermaskRingForRect(
|
|
1090
|
+
ctx,
|
|
1091
|
+
{ x: hole.x, y: hole.y },
|
|
1092
|
+
hole.hole_diameter,
|
|
1093
|
+
hole.hole_diameter,
|
|
1094
|
+
margin,
|
|
1095
|
+
0,
|
|
1096
|
+
rotation,
|
|
1097
|
+
realToCanvasMat,
|
|
1098
|
+
soldermaskRingColor,
|
|
1099
|
+
colorMap.drill
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
if (isCoveredWithSoldermask) {
|
|
1104
|
+
drawRect({
|
|
1105
|
+
ctx,
|
|
1106
|
+
center: { x: hole.x, y: hole.y },
|
|
1107
|
+
width: hole.hole_diameter,
|
|
1108
|
+
height: hole.hole_diameter,
|
|
1109
|
+
fill: soldermaskOverlayColor,
|
|
1110
|
+
realToCanvasMat,
|
|
1111
|
+
rotation
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
871
1114
|
return;
|
|
872
1115
|
}
|
|
873
1116
|
if (hole.hole_shape === "oval") {
|
|
@@ -883,15 +1126,41 @@ function drawPcbHole(params) {
|
|
|
883
1126
|
rotation
|
|
884
1127
|
});
|
|
885
1128
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
1129
|
+
if (!isCoveredWithSoldermask) {
|
|
1130
|
+
drawOval({
|
|
1131
|
+
ctx,
|
|
1132
|
+
center: { x: hole.x, y: hole.y },
|
|
1133
|
+
radius_x: hole.hole_width / 2,
|
|
1134
|
+
radius_y: hole.hole_height / 2,
|
|
1135
|
+
fill: colorMap.drill,
|
|
1136
|
+
realToCanvasMat,
|
|
1137
|
+
rotation
|
|
1138
|
+
});
|
|
1139
|
+
if (hasSoldermask && margin < 0) {
|
|
1140
|
+
drawSoldermaskRingForOval(
|
|
1141
|
+
ctx,
|
|
1142
|
+
{ x: hole.x, y: hole.y },
|
|
1143
|
+
hole.hole_width / 2,
|
|
1144
|
+
hole.hole_height / 2,
|
|
1145
|
+
margin,
|
|
1146
|
+
rotation,
|
|
1147
|
+
realToCanvasMat,
|
|
1148
|
+
soldermaskRingColor,
|
|
1149
|
+
colorMap.drill
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
if (isCoveredWithSoldermask) {
|
|
1154
|
+
drawOval({
|
|
1155
|
+
ctx,
|
|
1156
|
+
center: { x: hole.x, y: hole.y },
|
|
1157
|
+
radius_x: hole.hole_width / 2,
|
|
1158
|
+
radius_y: hole.hole_height / 2,
|
|
1159
|
+
fill: soldermaskOverlayColor,
|
|
1160
|
+
realToCanvasMat,
|
|
1161
|
+
rotation
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
895
1164
|
return;
|
|
896
1165
|
}
|
|
897
1166
|
if (hole.hole_shape === "rect") {
|
|
@@ -907,15 +1176,42 @@ function drawPcbHole(params) {
|
|
|
907
1176
|
rotation
|
|
908
1177
|
});
|
|
909
1178
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1179
|
+
if (!isCoveredWithSoldermask) {
|
|
1180
|
+
drawRect({
|
|
1181
|
+
ctx,
|
|
1182
|
+
center: { x: hole.x, y: hole.y },
|
|
1183
|
+
width: hole.hole_width,
|
|
1184
|
+
height: hole.hole_height,
|
|
1185
|
+
fill: colorMap.drill,
|
|
1186
|
+
realToCanvasMat,
|
|
1187
|
+
rotation
|
|
1188
|
+
});
|
|
1189
|
+
if (hasSoldermask && margin < 0) {
|
|
1190
|
+
drawSoldermaskRingForRect(
|
|
1191
|
+
ctx,
|
|
1192
|
+
{ x: hole.x, y: hole.y },
|
|
1193
|
+
hole.hole_width,
|
|
1194
|
+
hole.hole_height,
|
|
1195
|
+
margin,
|
|
1196
|
+
0,
|
|
1197
|
+
rotation,
|
|
1198
|
+
realToCanvasMat,
|
|
1199
|
+
soldermaskRingColor,
|
|
1200
|
+
colorMap.drill
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
if (isCoveredWithSoldermask) {
|
|
1205
|
+
drawRect({
|
|
1206
|
+
ctx,
|
|
1207
|
+
center: { x: hole.x, y: hole.y },
|
|
1208
|
+
width: hole.hole_width,
|
|
1209
|
+
height: hole.hole_height,
|
|
1210
|
+
fill: soldermaskOverlayColor,
|
|
1211
|
+
realToCanvasMat,
|
|
1212
|
+
rotation
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
919
1215
|
return;
|
|
920
1216
|
}
|
|
921
1217
|
if (hole.hole_shape === "pill") {
|
|
@@ -931,15 +1227,41 @@ function drawPcbHole(params) {
|
|
|
931
1227
|
rotation
|
|
932
1228
|
});
|
|
933
1229
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1230
|
+
if (!isCoveredWithSoldermask) {
|
|
1231
|
+
drawPill({
|
|
1232
|
+
ctx,
|
|
1233
|
+
center: { x: hole.x, y: hole.y },
|
|
1234
|
+
width: hole.hole_width,
|
|
1235
|
+
height: hole.hole_height,
|
|
1236
|
+
fill: colorMap.drill,
|
|
1237
|
+
realToCanvasMat,
|
|
1238
|
+
rotation
|
|
1239
|
+
});
|
|
1240
|
+
if (hasSoldermask && margin < 0) {
|
|
1241
|
+
drawSoldermaskRingForPill(
|
|
1242
|
+
ctx,
|
|
1243
|
+
{ x: hole.x, y: hole.y },
|
|
1244
|
+
hole.hole_width,
|
|
1245
|
+
hole.hole_height,
|
|
1246
|
+
margin,
|
|
1247
|
+
rotation,
|
|
1248
|
+
realToCanvasMat,
|
|
1249
|
+
soldermaskRingColor,
|
|
1250
|
+
colorMap.drill
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
if (isCoveredWithSoldermask) {
|
|
1255
|
+
drawPill({
|
|
1256
|
+
ctx,
|
|
1257
|
+
center: { x: hole.x, y: hole.y },
|
|
1258
|
+
width: hole.hole_width,
|
|
1259
|
+
height: hole.hole_height,
|
|
1260
|
+
fill: soldermaskOverlayColor,
|
|
1261
|
+
realToCanvasMat,
|
|
1262
|
+
rotation
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
943
1265
|
return;
|
|
944
1266
|
}
|
|
945
1267
|
if (hole.hole_shape === "rotated_pill") {
|
|
@@ -955,15 +1277,41 @@ function drawPcbHole(params) {
|
|
|
955
1277
|
rotation
|
|
956
1278
|
});
|
|
957
1279
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1280
|
+
if (!isCoveredWithSoldermask) {
|
|
1281
|
+
drawPill({
|
|
1282
|
+
ctx,
|
|
1283
|
+
center: { x: hole.x, y: hole.y },
|
|
1284
|
+
width: hole.hole_width,
|
|
1285
|
+
height: hole.hole_height,
|
|
1286
|
+
fill: colorMap.drill,
|
|
1287
|
+
realToCanvasMat,
|
|
1288
|
+
rotation
|
|
1289
|
+
});
|
|
1290
|
+
if (hasSoldermask && margin < 0) {
|
|
1291
|
+
drawSoldermaskRingForPill(
|
|
1292
|
+
ctx,
|
|
1293
|
+
{ x: hole.x, y: hole.y },
|
|
1294
|
+
hole.hole_width,
|
|
1295
|
+
hole.hole_height,
|
|
1296
|
+
margin,
|
|
1297
|
+
rotation,
|
|
1298
|
+
realToCanvasMat,
|
|
1299
|
+
soldermaskRingColor,
|
|
1300
|
+
colorMap.drill
|
|
1301
|
+
);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
if (isCoveredWithSoldermask) {
|
|
1305
|
+
drawPill({
|
|
1306
|
+
ctx,
|
|
1307
|
+
center: { x: hole.x, y: hole.y },
|
|
1308
|
+
width: hole.hole_width,
|
|
1309
|
+
height: hole.hole_height,
|
|
1310
|
+
fill: soldermaskOverlayColor,
|
|
1311
|
+
realToCanvasMat,
|
|
1312
|
+
rotation
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
967
1315
|
return;
|
|
968
1316
|
}
|
|
969
1317
|
}
|
|
@@ -982,13 +1330,13 @@ function drawPcbSmtPad(params) {
|
|
|
982
1330
|
const { ctx, pad, realToCanvasMat, colorMap } = params;
|
|
983
1331
|
const color = layerToColor(pad.layer, colorMap);
|
|
984
1332
|
const isCoveredWithSoldermask = pad.is_covered_with_solder_mask === true;
|
|
985
|
-
const margin = isCoveredWithSoldermask
|
|
986
|
-
const hasSoldermask = isCoveredWithSoldermask && pad.soldermask_margin !== void 0 && pad.soldermask_margin !== 0;
|
|
1333
|
+
const margin = isCoveredWithSoldermask ? 0 : pad.soldermask_margin ?? 0;
|
|
1334
|
+
const hasSoldermask = !isCoveredWithSoldermask && pad.soldermask_margin !== void 0 && pad.soldermask_margin !== 0;
|
|
987
1335
|
const soldermaskRingColor = getSoldermaskColor2(pad.layer, colorMap);
|
|
988
1336
|
const positiveMarginColor = colorMap.substrate;
|
|
989
1337
|
const soldermaskOverlayColor = getSoldermaskColor2(pad.layer, colorMap);
|
|
990
1338
|
if (pad.shape === "rect") {
|
|
991
|
-
if (
|
|
1339
|
+
if (hasSoldermask && margin > 0) {
|
|
992
1340
|
drawRect({
|
|
993
1341
|
ctx,
|
|
994
1342
|
center: { x: pad.x, y: pad.y },
|
|
@@ -996,7 +1344,7 @@ function drawPcbSmtPad(params) {
|
|
|
996
1344
|
height: pad.height + margin * 2,
|
|
997
1345
|
fill: positiveMarginColor,
|
|
998
1346
|
realToCanvasMat,
|
|
999
|
-
borderRadius: getBorderRadius(pad
|
|
1347
|
+
borderRadius: getBorderRadius(pad)
|
|
1000
1348
|
});
|
|
1001
1349
|
}
|
|
1002
1350
|
drawRect({
|
|
@@ -1036,7 +1384,7 @@ function drawPcbSmtPad(params) {
|
|
|
1036
1384
|
return;
|
|
1037
1385
|
}
|
|
1038
1386
|
if (pad.shape === "rotated_rect") {
|
|
1039
|
-
if (
|
|
1387
|
+
if (hasSoldermask && margin > 0) {
|
|
1040
1388
|
drawRect({
|
|
1041
1389
|
ctx,
|
|
1042
1390
|
center: { x: pad.x, y: pad.y },
|
|
@@ -1044,7 +1392,7 @@ function drawPcbSmtPad(params) {
|
|
|
1044
1392
|
height: pad.height + margin * 2,
|
|
1045
1393
|
fill: positiveMarginColor,
|
|
1046
1394
|
realToCanvasMat,
|
|
1047
|
-
borderRadius: getBorderRadius(pad
|
|
1395
|
+
borderRadius: getBorderRadius(pad),
|
|
1048
1396
|
rotation: pad.ccw_rotation ?? 0
|
|
1049
1397
|
});
|
|
1050
1398
|
}
|
|
@@ -1087,7 +1435,7 @@ function drawPcbSmtPad(params) {
|
|
|
1087
1435
|
return;
|
|
1088
1436
|
}
|
|
1089
1437
|
if (pad.shape === "circle") {
|
|
1090
|
-
if (
|
|
1438
|
+
if (hasSoldermask && margin > 0) {
|
|
1091
1439
|
drawCircle({
|
|
1092
1440
|
ctx,
|
|
1093
1441
|
center: { x: pad.x, y: pad.y },
|
|
@@ -1126,7 +1474,7 @@ function drawPcbSmtPad(params) {
|
|
|
1126
1474
|
return;
|
|
1127
1475
|
}
|
|
1128
1476
|
if (pad.shape === "pill") {
|
|
1129
|
-
if (
|
|
1477
|
+
if (hasSoldermask && margin > 0) {
|
|
1130
1478
|
drawPill({
|
|
1131
1479
|
ctx,
|
|
1132
1480
|
center: { x: pad.x, y: pad.y },
|
|
@@ -1170,7 +1518,7 @@ function drawPcbSmtPad(params) {
|
|
|
1170
1518
|
return;
|
|
1171
1519
|
}
|
|
1172
1520
|
if (pad.shape === "rotated_pill") {
|
|
1173
|
-
if (
|
|
1521
|
+
if (hasSoldermask && margin > 0) {
|
|
1174
1522
|
drawPill({
|
|
1175
1523
|
ctx,
|
|
1176
1524
|
center: { x: pad.x, y: pad.y },
|
|
@@ -1218,13 +1566,32 @@ function drawPcbSmtPad(params) {
|
|
|
1218
1566
|
}
|
|
1219
1567
|
if (pad.shape === "polygon") {
|
|
1220
1568
|
if (pad.points && pad.points.length >= 3) {
|
|
1569
|
+
if (hasSoldermask && margin > 0) {
|
|
1570
|
+
const expandedPoints = offsetPolygonPoints(pad.points, margin);
|
|
1571
|
+
drawPolygon({
|
|
1572
|
+
ctx,
|
|
1573
|
+
points: expandedPoints,
|
|
1574
|
+
fill: positiveMarginColor,
|
|
1575
|
+
realToCanvasMat
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1221
1578
|
drawPolygon({
|
|
1222
1579
|
ctx,
|
|
1223
1580
|
points: pad.points,
|
|
1224
1581
|
fill: color,
|
|
1225
1582
|
realToCanvasMat
|
|
1226
1583
|
});
|
|
1227
|
-
if (
|
|
1584
|
+
if (hasSoldermask && margin < 0) {
|
|
1585
|
+
drawSoldermaskRingForPolygon(
|
|
1586
|
+
ctx,
|
|
1587
|
+
pad.points,
|
|
1588
|
+
margin,
|
|
1589
|
+
realToCanvasMat,
|
|
1590
|
+
soldermaskRingColor,
|
|
1591
|
+
color
|
|
1592
|
+
);
|
|
1593
|
+
}
|
|
1594
|
+
if (isCoveredWithSoldermask && margin === 0) {
|
|
1228
1595
|
drawPolygon({
|
|
1229
1596
|
ctx,
|
|
1230
1597
|
points: pad.points,
|
|
@@ -2355,7 +2722,7 @@ var CircuitToCanvasDrawer = class {
|
|
|
2355
2722
|
(el) => el.type === "pcb_plated_hole" && el.is_covered_with_solder_mask === true
|
|
2356
2723
|
);
|
|
2357
2724
|
for (const element of elements) {
|
|
2358
|
-
if (element.type === "pcb_board"
|
|
2725
|
+
if (element.type === "pcb_board") {
|
|
2359
2726
|
this.drawBoardWithSoldermask(element);
|
|
2360
2727
|
} else {
|
|
2361
2728
|
this.drawElement(element, options);
|