circuit-to-svg 0.0.283 → 0.0.284
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 +556 -539
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3508,180 +3508,503 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
|
3508
3508
|
}
|
|
3509
3509
|
|
|
3510
3510
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-board.ts
|
|
3511
|
+
import { applyToPoint as applyToPoint22 } from "transformation-matrix";
|
|
3512
|
+
|
|
3513
|
+
// lib/utils/create-pcb-component-anchor-offset-indicators.ts
|
|
3511
3514
|
import { applyToPoint as applyToPoint21 } from "transformation-matrix";
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
const
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
name: "path",
|
|
3549
|
-
type: "element",
|
|
3550
|
-
value: "",
|
|
3551
|
-
children: [],
|
|
3552
|
-
attributes: {
|
|
3553
|
-
class: "pcb-board-soldermask",
|
|
3554
|
-
d: path,
|
|
3555
|
-
fill: colorMap2.soldermask.top,
|
|
3556
|
-
"fill-opacity": "0.8",
|
|
3557
|
-
stroke: "none",
|
|
3558
|
-
"data-type": "pcb_soldermask",
|
|
3559
|
-
"data-pcb-layer": maskLayer
|
|
3560
|
-
}
|
|
3561
|
-
});
|
|
3562
|
-
}
|
|
3563
|
-
svgObjects.push({
|
|
3564
|
-
name: "path",
|
|
3515
|
+
var OFFSET_THRESHOLD_MM = 0.01;
|
|
3516
|
+
var TICK_SIZE_PX = 4;
|
|
3517
|
+
var LABEL_GAP_PX = 8;
|
|
3518
|
+
var LABEL_FONT_SIZE_PX = 11;
|
|
3519
|
+
var STROKE_WIDTH_PX = 1;
|
|
3520
|
+
var ANCHOR_MARKER_SIZE_PX = 5;
|
|
3521
|
+
var ANCHOR_MARKER_STROKE_WIDTH_PX = 1.5;
|
|
3522
|
+
var COMPONENT_GAP_PX = 15;
|
|
3523
|
+
var COMPONENT_SIDE_GAP_PX = 10;
|
|
3524
|
+
var DISTANCE_MULTIPLIER = 0.2;
|
|
3525
|
+
var MAX_OFFSET_PX = 50;
|
|
3526
|
+
function createAnchorOffsetIndicators(params) {
|
|
3527
|
+
const {
|
|
3528
|
+
groupAnchorPosition,
|
|
3529
|
+
componentPosition,
|
|
3530
|
+
transform,
|
|
3531
|
+
componentWidth = 0,
|
|
3532
|
+
componentHeight = 0
|
|
3533
|
+
} = params;
|
|
3534
|
+
const objects = [];
|
|
3535
|
+
const [screenGroupAnchorX, screenGroupAnchorY] = applyToPoint21(transform, [
|
|
3536
|
+
groupAnchorPosition.x,
|
|
3537
|
+
groupAnchorPosition.y
|
|
3538
|
+
]);
|
|
3539
|
+
const [screenComponentX, screenComponentY] = applyToPoint21(transform, [
|
|
3540
|
+
componentPosition.x,
|
|
3541
|
+
componentPosition.y
|
|
3542
|
+
]);
|
|
3543
|
+
const offsetX = componentPosition.x - groupAnchorPosition.x;
|
|
3544
|
+
const offsetY = componentPosition.y - groupAnchorPosition.y;
|
|
3545
|
+
const scale9 = Math.abs(transform.a);
|
|
3546
|
+
const screenComponentWidth = componentWidth * scale9;
|
|
3547
|
+
const screenComponentHeight = componentHeight * scale9;
|
|
3548
|
+
objects.push(createAnchorMarker(screenGroupAnchorX, screenGroupAnchorY));
|
|
3549
|
+
objects.push({
|
|
3550
|
+
name: "line",
|
|
3565
3551
|
type: "element",
|
|
3566
|
-
|
|
3552
|
+
attributes: {
|
|
3553
|
+
x1: screenGroupAnchorX.toString(),
|
|
3554
|
+
y1: screenGroupAnchorY.toString(),
|
|
3555
|
+
x2: screenComponentX.toString(),
|
|
3556
|
+
y2: screenComponentY.toString(),
|
|
3557
|
+
stroke: "#ffffff",
|
|
3558
|
+
"stroke-width": "0.5",
|
|
3559
|
+
"stroke-dasharray": "3,3",
|
|
3560
|
+
opacity: "0.5",
|
|
3561
|
+
class: "anchor-offset-connector"
|
|
3562
|
+
},
|
|
3567
3563
|
children: [],
|
|
3564
|
+
value: ""
|
|
3565
|
+
});
|
|
3566
|
+
objects.push({
|
|
3567
|
+
name: "circle",
|
|
3568
|
+
type: "element",
|
|
3568
3569
|
attributes: {
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3570
|
+
cx: screenComponentX.toString(),
|
|
3571
|
+
cy: screenComponentY.toString(),
|
|
3572
|
+
r: "2",
|
|
3573
|
+
fill: "#ffffff",
|
|
3574
|
+
opacity: "0.7",
|
|
3575
|
+
class: "anchor-offset-component-marker"
|
|
3576
|
+
},
|
|
3577
|
+
children: [],
|
|
3578
|
+
value: ""
|
|
3577
3579
|
});
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
const width = Number(pcbPanel.width);
|
|
3586
|
-
const height = Number(pcbPanel.height);
|
|
3587
|
-
const center = pcbPanel.center ?? { x: width / 2, y: height / 2 };
|
|
3588
|
-
const halfWidth = width / 2;
|
|
3589
|
-
const halfHeight = height / 2;
|
|
3590
|
-
const topLeft = applyToPoint22(transform, [
|
|
3591
|
-
center.x - halfWidth,
|
|
3592
|
-
center.y - halfHeight
|
|
3593
|
-
]);
|
|
3594
|
-
const topRight = applyToPoint22(transform, [
|
|
3595
|
-
center.x + halfWidth,
|
|
3596
|
-
center.y - halfHeight
|
|
3597
|
-
]);
|
|
3598
|
-
const bottomRight = applyToPoint22(transform, [
|
|
3599
|
-
center.x + halfWidth,
|
|
3600
|
-
center.y + halfHeight
|
|
3601
|
-
]);
|
|
3602
|
-
const bottomLeft = applyToPoint22(transform, [
|
|
3603
|
-
center.x - halfWidth,
|
|
3604
|
-
center.y + halfHeight
|
|
3605
|
-
]);
|
|
3606
|
-
const path = `M ${topLeft[0]} ${topLeft[1]} L ${topRight[0]} ${topRight[1]} L ${bottomRight[0]} ${bottomRight[1]} L ${bottomLeft[0]} ${bottomLeft[1]} Z`;
|
|
3607
|
-
const isCoveredWithSolderMask = pcbPanel.covered_with_solder_mask !== false;
|
|
3608
|
-
const shouldShowSolderMask = Boolean(
|
|
3609
|
-
showSolderMask && isCoveredWithSolderMask
|
|
3580
|
+
const yDistance = Math.abs(screenComponentY - screenGroupAnchorY);
|
|
3581
|
+
const xDistance = Math.abs(screenComponentX - screenGroupAnchorX);
|
|
3582
|
+
const totalDistance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
|
|
3583
|
+
const componentHeightOffset = screenComponentHeight / 2 + COMPONENT_GAP_PX;
|
|
3584
|
+
const dynamicOffset = Math.max(
|
|
3585
|
+
componentHeightOffset,
|
|
3586
|
+
Math.min(MAX_OFFSET_PX, totalDistance * DISTANCE_MULTIPLIER)
|
|
3610
3587
|
);
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3588
|
+
const horizontalLineY = offsetY > 0 ? screenComponentY - dynamicOffset : screenComponentY + dynamicOffset;
|
|
3589
|
+
const componentWidthOffset = screenComponentWidth / 2 + COMPONENT_SIDE_GAP_PX;
|
|
3590
|
+
const verticalLineX = offsetX > 0 ? screenComponentX + componentWidthOffset : screenComponentX - componentWidthOffset;
|
|
3591
|
+
if (Math.abs(offsetX) > OFFSET_THRESHOLD_MM) {
|
|
3592
|
+
objects.push(
|
|
3593
|
+
...createHorizontalDimension({
|
|
3594
|
+
startX: screenGroupAnchorX,
|
|
3595
|
+
endX: screenComponentX,
|
|
3596
|
+
y: horizontalLineY,
|
|
3597
|
+
offsetMm: offsetX,
|
|
3598
|
+
offsetY
|
|
3599
|
+
})
|
|
3600
|
+
);
|
|
3601
|
+
}
|
|
3602
|
+
if (Math.abs(offsetY) > OFFSET_THRESHOLD_MM) {
|
|
3603
|
+
objects.push(
|
|
3604
|
+
...createVerticalDimension({
|
|
3605
|
+
x: verticalLineX,
|
|
3606
|
+
startY: screenGroupAnchorY,
|
|
3607
|
+
endY: screenComponentY,
|
|
3608
|
+
offsetMm: offsetY,
|
|
3609
|
+
offsetX
|
|
3610
|
+
})
|
|
3611
|
+
);
|
|
3612
|
+
}
|
|
3613
|
+
return objects;
|
|
3628
3614
|
}
|
|
3629
|
-
|
|
3630
|
-
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-via.ts
|
|
3631
|
-
import { applyToPoint as applyToPoint23 } from "transformation-matrix";
|
|
3632
|
-
function createSvgObjectsFromPcbVia(hole, ctx) {
|
|
3633
|
-
const { transform, colorMap: colorMap2 } = ctx;
|
|
3634
|
-
const [x, y] = applyToPoint23(transform, [hole.x, hole.y]);
|
|
3635
|
-
const scaledOuterWidth = hole.outer_diameter * Math.abs(transform.a);
|
|
3636
|
-
const scaledOuterHeight = hole.outer_diameter * Math.abs(transform.a);
|
|
3637
|
-
const scaledHoleWidth = hole.hole_diameter * Math.abs(transform.a);
|
|
3638
|
-
const scaledHoleHeight = hole.hole_diameter * Math.abs(transform.a);
|
|
3639
|
-
const outerRadius = Math.min(scaledOuterWidth, scaledOuterHeight) / 2;
|
|
3640
|
-
const innerRadius = Math.min(scaledHoleWidth, scaledHoleHeight) / 2;
|
|
3615
|
+
function createAnchorMarker(x, y) {
|
|
3641
3616
|
return {
|
|
3642
3617
|
name: "g",
|
|
3643
3618
|
type: "element",
|
|
3644
3619
|
attributes: {
|
|
3645
|
-
|
|
3646
|
-
"data-
|
|
3620
|
+
class: "anchor-offset-marker",
|
|
3621
|
+
"data-type": "anchor_offset_marker"
|
|
3647
3622
|
},
|
|
3648
3623
|
children: [
|
|
3649
3624
|
{
|
|
3650
|
-
name: "
|
|
3625
|
+
name: "line",
|
|
3651
3626
|
type: "element",
|
|
3652
3627
|
attributes: {
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
"
|
|
3659
|
-
"
|
|
3660
|
-
}
|
|
3628
|
+
x1: x.toString(),
|
|
3629
|
+
y1: (y - ANCHOR_MARKER_SIZE_PX).toString(),
|
|
3630
|
+
x2: x.toString(),
|
|
3631
|
+
y2: (y + ANCHOR_MARKER_SIZE_PX).toString(),
|
|
3632
|
+
stroke: "#ffffff",
|
|
3633
|
+
"stroke-width": ANCHOR_MARKER_STROKE_WIDTH_PX.toString(),
|
|
3634
|
+
"stroke-linecap": "round"
|
|
3635
|
+
},
|
|
3636
|
+
children: [],
|
|
3637
|
+
value: ""
|
|
3661
3638
|
},
|
|
3662
3639
|
{
|
|
3663
|
-
name: "
|
|
3640
|
+
name: "line",
|
|
3664
3641
|
type: "element",
|
|
3665
3642
|
attributes: {
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
"
|
|
3672
|
-
"
|
|
3673
|
-
}
|
|
3643
|
+
x1: (x - ANCHOR_MARKER_SIZE_PX).toString(),
|
|
3644
|
+
y1: y.toString(),
|
|
3645
|
+
x2: (x + ANCHOR_MARKER_SIZE_PX).toString(),
|
|
3646
|
+
y2: y.toString(),
|
|
3647
|
+
stroke: "#ffffff",
|
|
3648
|
+
"stroke-width": ANCHOR_MARKER_STROKE_WIDTH_PX.toString(),
|
|
3649
|
+
"stroke-linecap": "round"
|
|
3650
|
+
},
|
|
3651
|
+
children: [],
|
|
3652
|
+
value: ""
|
|
3674
3653
|
}
|
|
3675
|
-
]
|
|
3654
|
+
],
|
|
3655
|
+
value: ""
|
|
3676
3656
|
};
|
|
3677
3657
|
}
|
|
3678
|
-
|
|
3679
|
-
|
|
3658
|
+
function createHorizontalDimension({
|
|
3659
|
+
startX,
|
|
3660
|
+
endX,
|
|
3661
|
+
y,
|
|
3662
|
+
offsetMm,
|
|
3663
|
+
offsetY
|
|
3664
|
+
}) {
|
|
3665
|
+
const objects = [];
|
|
3666
|
+
objects.push({
|
|
3667
|
+
name: "line",
|
|
3668
|
+
type: "element",
|
|
3669
|
+
attributes: {
|
|
3670
|
+
x1: startX.toString(),
|
|
3671
|
+
y1: y.toString(),
|
|
3672
|
+
x2: endX.toString(),
|
|
3673
|
+
y2: y.toString(),
|
|
3674
|
+
stroke: "#ffffff",
|
|
3675
|
+
"stroke-width": STROKE_WIDTH_PX.toString(),
|
|
3676
|
+
class: "anchor-offset-dimension-x"
|
|
3677
|
+
},
|
|
3678
|
+
children: [],
|
|
3679
|
+
value: ""
|
|
3680
|
+
});
|
|
3681
|
+
objects.push({
|
|
3682
|
+
name: "line",
|
|
3683
|
+
type: "element",
|
|
3684
|
+
attributes: {
|
|
3685
|
+
x1: startX.toString(),
|
|
3686
|
+
y1: (y - TICK_SIZE_PX).toString(),
|
|
3687
|
+
x2: startX.toString(),
|
|
3688
|
+
y2: (y + TICK_SIZE_PX).toString(),
|
|
3689
|
+
stroke: "#ffffff",
|
|
3690
|
+
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
3691
|
+
},
|
|
3692
|
+
children: [],
|
|
3693
|
+
value: ""
|
|
3694
|
+
});
|
|
3695
|
+
objects.push({
|
|
3696
|
+
name: "line",
|
|
3697
|
+
type: "element",
|
|
3698
|
+
attributes: {
|
|
3699
|
+
x1: endX.toString(),
|
|
3700
|
+
y1: (y - TICK_SIZE_PX).toString(),
|
|
3701
|
+
x2: endX.toString(),
|
|
3702
|
+
y2: (y + TICK_SIZE_PX).toString(),
|
|
3703
|
+
stroke: "#ffffff",
|
|
3704
|
+
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
3705
|
+
},
|
|
3706
|
+
children: [],
|
|
3707
|
+
value: ""
|
|
3708
|
+
});
|
|
3709
|
+
const midX = (startX + endX) / 2;
|
|
3710
|
+
const labelY = offsetY > 0 ? y - TICK_SIZE_PX - LABEL_GAP_PX : y + TICK_SIZE_PX + LABEL_GAP_PX;
|
|
3711
|
+
objects.push({
|
|
3712
|
+
name: "text",
|
|
3713
|
+
type: "element",
|
|
3714
|
+
attributes: {
|
|
3715
|
+
x: midX.toString(),
|
|
3716
|
+
y: labelY.toString(),
|
|
3717
|
+
fill: "#ffffff",
|
|
3718
|
+
"font-size": LABEL_FONT_SIZE_PX.toString(),
|
|
3719
|
+
"font-family": "Arial, sans-serif",
|
|
3720
|
+
"text-anchor": "middle",
|
|
3721
|
+
"dominant-baseline": offsetY > 0 ? "baseline" : "hanging",
|
|
3722
|
+
class: "anchor-offset-label"
|
|
3723
|
+
},
|
|
3724
|
+
children: [
|
|
3725
|
+
{
|
|
3726
|
+
type: "text",
|
|
3727
|
+
value: `X: ${offsetMm.toFixed(2)}mm`,
|
|
3728
|
+
name: "",
|
|
3729
|
+
attributes: {},
|
|
3730
|
+
children: []
|
|
3731
|
+
}
|
|
3732
|
+
],
|
|
3733
|
+
value: ""
|
|
3734
|
+
});
|
|
3735
|
+
return objects;
|
|
3736
|
+
}
|
|
3737
|
+
function createVerticalDimension({
|
|
3738
|
+
x,
|
|
3739
|
+
startY,
|
|
3740
|
+
endY,
|
|
3741
|
+
offsetMm,
|
|
3742
|
+
offsetX
|
|
3743
|
+
}) {
|
|
3744
|
+
const objects = [];
|
|
3745
|
+
objects.push({
|
|
3746
|
+
name: "line",
|
|
3747
|
+
type: "element",
|
|
3748
|
+
attributes: {
|
|
3749
|
+
x1: x.toString(),
|
|
3750
|
+
y1: startY.toString(),
|
|
3751
|
+
x2: x.toString(),
|
|
3752
|
+
y2: endY.toString(),
|
|
3753
|
+
stroke: "#ffffff",
|
|
3754
|
+
"stroke-width": STROKE_WIDTH_PX.toString(),
|
|
3755
|
+
class: "anchor-offset-dimension-y"
|
|
3756
|
+
},
|
|
3757
|
+
children: [],
|
|
3758
|
+
value: ""
|
|
3759
|
+
});
|
|
3760
|
+
objects.push({
|
|
3761
|
+
name: "line",
|
|
3762
|
+
type: "element",
|
|
3763
|
+
attributes: {
|
|
3764
|
+
x1: (x - TICK_SIZE_PX).toString(),
|
|
3765
|
+
y1: startY.toString(),
|
|
3766
|
+
x2: (x + TICK_SIZE_PX).toString(),
|
|
3767
|
+
y2: startY.toString(),
|
|
3768
|
+
stroke: "#ffffff",
|
|
3769
|
+
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
3770
|
+
},
|
|
3771
|
+
children: [],
|
|
3772
|
+
value: ""
|
|
3773
|
+
});
|
|
3774
|
+
objects.push({
|
|
3775
|
+
name: "line",
|
|
3776
|
+
type: "element",
|
|
3777
|
+
attributes: {
|
|
3778
|
+
x1: (x - TICK_SIZE_PX).toString(),
|
|
3779
|
+
y1: endY.toString(),
|
|
3780
|
+
x2: (x + TICK_SIZE_PX).toString(),
|
|
3781
|
+
y2: endY.toString(),
|
|
3782
|
+
stroke: "#ffffff",
|
|
3783
|
+
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
3784
|
+
},
|
|
3785
|
+
children: [],
|
|
3786
|
+
value: ""
|
|
3787
|
+
});
|
|
3788
|
+
const midY = (startY + endY) / 2;
|
|
3789
|
+
const labelX = offsetX < 0 ? x - TICK_SIZE_PX - 4 : x + TICK_SIZE_PX + 4;
|
|
3790
|
+
objects.push({
|
|
3791
|
+
name: "text",
|
|
3792
|
+
type: "element",
|
|
3793
|
+
attributes: {
|
|
3794
|
+
x: labelX.toString(),
|
|
3795
|
+
y: midY.toString(),
|
|
3796
|
+
fill: "#ffffff",
|
|
3797
|
+
"font-size": LABEL_FONT_SIZE_PX.toString(),
|
|
3798
|
+
"font-family": "Arial, sans-serif",
|
|
3799
|
+
"text-anchor": offsetX < 0 ? "end" : "start",
|
|
3800
|
+
"dominant-baseline": "middle",
|
|
3801
|
+
class: "anchor-offset-label"
|
|
3802
|
+
},
|
|
3803
|
+
children: [
|
|
3804
|
+
{
|
|
3805
|
+
type: "text",
|
|
3806
|
+
value: `Y: ${offsetMm.toFixed(2)}mm`,
|
|
3807
|
+
name: "",
|
|
3808
|
+
attributes: {},
|
|
3809
|
+
children: []
|
|
3810
|
+
}
|
|
3811
|
+
],
|
|
3812
|
+
value: ""
|
|
3813
|
+
});
|
|
3814
|
+
return objects;
|
|
3815
|
+
}
|
|
3816
|
+
|
|
3817
|
+
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-board.ts
|
|
3818
|
+
function createSvgObjectsFromPcbBoard(pcbBoard, ctx) {
|
|
3819
|
+
const { transform, colorMap: colorMap2, showSolderMask, circuitJson } = ctx;
|
|
3820
|
+
const { width, height, center, outline } = pcbBoard;
|
|
3821
|
+
let path;
|
|
3822
|
+
if (outline && Array.isArray(outline) && outline.length >= 3) {
|
|
3823
|
+
path = outline.map((point, index) => {
|
|
3824
|
+
const [x, y] = applyToPoint22(transform, [point.x, point.y]);
|
|
3825
|
+
return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
|
|
3826
|
+
}).join(" ");
|
|
3827
|
+
} else {
|
|
3828
|
+
const halfWidth = width / 2;
|
|
3829
|
+
const halfHeight = height / 2;
|
|
3830
|
+
const topLeft = applyToPoint22(transform, [
|
|
3831
|
+
center.x - halfWidth,
|
|
3832
|
+
center.y - halfHeight
|
|
3833
|
+
]);
|
|
3834
|
+
const topRight = applyToPoint22(transform, [
|
|
3835
|
+
center.x + halfWidth,
|
|
3836
|
+
center.y - halfHeight
|
|
3837
|
+
]);
|
|
3838
|
+
const bottomRight = applyToPoint22(transform, [
|
|
3839
|
+
center.x + halfWidth,
|
|
3840
|
+
center.y + halfHeight
|
|
3841
|
+
]);
|
|
3842
|
+
const bottomLeft = applyToPoint22(transform, [
|
|
3843
|
+
center.x - halfWidth,
|
|
3844
|
+
center.y + halfHeight
|
|
3845
|
+
]);
|
|
3846
|
+
path = `M ${topLeft[0]} ${topLeft[1]} L ${topRight[0]} ${topRight[1]} L ${bottomRight[0]} ${bottomRight[1]} L ${bottomLeft[0]} ${bottomLeft[1]}`;
|
|
3847
|
+
}
|
|
3848
|
+
path += " Z";
|
|
3849
|
+
const svgObjects = [];
|
|
3850
|
+
if (showSolderMask) {
|
|
3851
|
+
const layer = ctx.layer ?? "top";
|
|
3852
|
+
const maskLayer = layer === "bottom" ? "soldermask-bottom" : "soldermask-top";
|
|
3853
|
+
svgObjects.push({
|
|
3854
|
+
name: "path",
|
|
3855
|
+
type: "element",
|
|
3856
|
+
value: "",
|
|
3857
|
+
children: [],
|
|
3858
|
+
attributes: {
|
|
3859
|
+
class: "pcb-board-soldermask",
|
|
3860
|
+
d: path,
|
|
3861
|
+
fill: colorMap2.soldermask.top,
|
|
3862
|
+
"fill-opacity": "0.8",
|
|
3863
|
+
stroke: "none",
|
|
3864
|
+
"data-type": "pcb_soldermask",
|
|
3865
|
+
"data-pcb-layer": maskLayer
|
|
3866
|
+
}
|
|
3867
|
+
});
|
|
3868
|
+
}
|
|
3869
|
+
svgObjects.push({
|
|
3870
|
+
name: "path",
|
|
3871
|
+
type: "element",
|
|
3872
|
+
value: "",
|
|
3873
|
+
children: [],
|
|
3874
|
+
attributes: {
|
|
3875
|
+
class: "pcb-board",
|
|
3876
|
+
d: path,
|
|
3877
|
+
fill: "none",
|
|
3878
|
+
stroke: colorMap2.boardOutline,
|
|
3879
|
+
"stroke-width": (0.1 * Math.abs(transform.a)).toString(),
|
|
3880
|
+
"data-type": "pcb_board",
|
|
3881
|
+
"data-pcb-layer": "board"
|
|
3882
|
+
}
|
|
3883
|
+
});
|
|
3884
|
+
if (ctx.showAnchorOffsets && circuitJson) {
|
|
3885
|
+
const panel = circuitJson.find(
|
|
3886
|
+
(elm) => elm.type === "pcb_panel"
|
|
3887
|
+
);
|
|
3888
|
+
if (panel) {
|
|
3889
|
+
const panelCenter = panel.center ?? { x: 0, y: 0 };
|
|
3890
|
+
svgObjects.push(
|
|
3891
|
+
...createAnchorOffsetIndicators({
|
|
3892
|
+
groupAnchorPosition: panelCenter,
|
|
3893
|
+
componentPosition: center,
|
|
3894
|
+
transform,
|
|
3895
|
+
componentWidth: width,
|
|
3896
|
+
componentHeight: height
|
|
3897
|
+
})
|
|
3898
|
+
);
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3901
|
+
return svgObjects;
|
|
3902
|
+
}
|
|
3903
|
+
|
|
3904
|
+
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-panel.ts
|
|
3905
|
+
import { applyToPoint as applyToPoint23 } from "transformation-matrix";
|
|
3906
|
+
function createSvgObjectsFromPcbPanel(pcbPanel, ctx) {
|
|
3907
|
+
const { transform, colorMap: colorMap2, showSolderMask } = ctx;
|
|
3908
|
+
const width = Number(pcbPanel.width);
|
|
3909
|
+
const height = Number(pcbPanel.height);
|
|
3910
|
+
const center = pcbPanel.center ?? { x: width / 2, y: height / 2 };
|
|
3911
|
+
const halfWidth = width / 2;
|
|
3912
|
+
const halfHeight = height / 2;
|
|
3913
|
+
const topLeft = applyToPoint23(transform, [
|
|
3914
|
+
center.x - halfWidth,
|
|
3915
|
+
center.y - halfHeight
|
|
3916
|
+
]);
|
|
3917
|
+
const topRight = applyToPoint23(transform, [
|
|
3918
|
+
center.x + halfWidth,
|
|
3919
|
+
center.y - halfHeight
|
|
3920
|
+
]);
|
|
3921
|
+
const bottomRight = applyToPoint23(transform, [
|
|
3922
|
+
center.x + halfWidth,
|
|
3923
|
+
center.y + halfHeight
|
|
3924
|
+
]);
|
|
3925
|
+
const bottomLeft = applyToPoint23(transform, [
|
|
3926
|
+
center.x - halfWidth,
|
|
3927
|
+
center.y + halfHeight
|
|
3928
|
+
]);
|
|
3929
|
+
const path = `M ${topLeft[0]} ${topLeft[1]} L ${topRight[0]} ${topRight[1]} L ${bottomRight[0]} ${bottomRight[1]} L ${bottomLeft[0]} ${bottomLeft[1]} Z`;
|
|
3930
|
+
const isCoveredWithSolderMask = pcbPanel.covered_with_solder_mask !== false;
|
|
3931
|
+
const shouldShowSolderMask = Boolean(
|
|
3932
|
+
showSolderMask && isCoveredWithSolderMask
|
|
3933
|
+
);
|
|
3934
|
+
return [
|
|
3935
|
+
{
|
|
3936
|
+
name: "path",
|
|
3937
|
+
type: "element",
|
|
3938
|
+
value: "",
|
|
3939
|
+
children: [],
|
|
3940
|
+
attributes: {
|
|
3941
|
+
class: "pcb-panel",
|
|
3942
|
+
d: path,
|
|
3943
|
+
fill: "none",
|
|
3944
|
+
stroke: colorMap2.boardOutline,
|
|
3945
|
+
"stroke-width": (0.1 * Math.abs(transform.a)).toString(),
|
|
3946
|
+
"data-type": "pcb_panel",
|
|
3947
|
+
"data-pcb-layer": "board"
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
];
|
|
3951
|
+
}
|
|
3952
|
+
|
|
3953
|
+
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-via.ts
|
|
3680
3954
|
import { applyToPoint as applyToPoint24 } from "transformation-matrix";
|
|
3955
|
+
function createSvgObjectsFromPcbVia(hole, ctx) {
|
|
3956
|
+
const { transform, colorMap: colorMap2 } = ctx;
|
|
3957
|
+
const [x, y] = applyToPoint24(transform, [hole.x, hole.y]);
|
|
3958
|
+
const scaledOuterWidth = hole.outer_diameter * Math.abs(transform.a);
|
|
3959
|
+
const scaledOuterHeight = hole.outer_diameter * Math.abs(transform.a);
|
|
3960
|
+
const scaledHoleWidth = hole.hole_diameter * Math.abs(transform.a);
|
|
3961
|
+
const scaledHoleHeight = hole.hole_diameter * Math.abs(transform.a);
|
|
3962
|
+
const outerRadius = Math.min(scaledOuterWidth, scaledOuterHeight) / 2;
|
|
3963
|
+
const innerRadius = Math.min(scaledHoleWidth, scaledHoleHeight) / 2;
|
|
3964
|
+
return {
|
|
3965
|
+
name: "g",
|
|
3966
|
+
type: "element",
|
|
3967
|
+
attributes: {
|
|
3968
|
+
"data-type": "pcb_via",
|
|
3969
|
+
"data-pcb-layer": "through"
|
|
3970
|
+
},
|
|
3971
|
+
children: [
|
|
3972
|
+
{
|
|
3973
|
+
name: "circle",
|
|
3974
|
+
type: "element",
|
|
3975
|
+
attributes: {
|
|
3976
|
+
class: "pcb-hole-outer",
|
|
3977
|
+
fill: colorMap2.copper.top,
|
|
3978
|
+
cx: x.toString(),
|
|
3979
|
+
cy: y.toString(),
|
|
3980
|
+
r: outerRadius.toString(),
|
|
3981
|
+
"data-type": "pcb_via",
|
|
3982
|
+
"data-pcb-layer": "top"
|
|
3983
|
+
}
|
|
3984
|
+
},
|
|
3985
|
+
{
|
|
3986
|
+
name: "circle",
|
|
3987
|
+
type: "element",
|
|
3988
|
+
attributes: {
|
|
3989
|
+
class: "pcb-hole-inner",
|
|
3990
|
+
fill: colorMap2.drill,
|
|
3991
|
+
cx: x.toString(),
|
|
3992
|
+
cy: y.toString(),
|
|
3993
|
+
r: innerRadius.toString(),
|
|
3994
|
+
"data-type": "pcb_via",
|
|
3995
|
+
"data-pcb-layer": "drill"
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
]
|
|
3999
|
+
};
|
|
4000
|
+
}
|
|
4001
|
+
|
|
4002
|
+
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-hole.ts
|
|
4003
|
+
import { applyToPoint as applyToPoint25 } from "transformation-matrix";
|
|
3681
4004
|
function createSvgObjectsFromPcbHole(hole, ctx) {
|
|
3682
4005
|
const { transform, colorMap: colorMap2, showSolderMask } = ctx;
|
|
3683
4006
|
const layer = ctx.layer ?? "top";
|
|
3684
|
-
const [x, y] =
|
|
4007
|
+
const [x, y] = applyToPoint25(transform, [hole.x, hole.y]);
|
|
3685
4008
|
const isCoveredWithSolderMask = Boolean(hole.is_covered_with_solder_mask);
|
|
3686
4009
|
const soldermaskMargin = (hole.soldermask_margin ?? 0) * Math.abs(transform.a);
|
|
3687
4010
|
const shouldShowSolderMask = showSolderMask && isCoveredWithSolderMask && soldermaskMargin !== 0;
|
|
@@ -4178,7 +4501,7 @@ import {
|
|
|
4178
4501
|
getFullConnectivityMapFromCircuitJson
|
|
4179
4502
|
} from "circuit-json-to-connectivity-map";
|
|
4180
4503
|
import "svgson";
|
|
4181
|
-
import { applyToPoint as
|
|
4504
|
+
import { applyToPoint as applyToPoint26 } from "transformation-matrix";
|
|
4182
4505
|
|
|
4183
4506
|
// lib/pcb/create-svg-objects-from-pcb-rats-nest/get-element-position.ts
|
|
4184
4507
|
import { su } from "@tscircuit/circuit-json-util";
|
|
@@ -4258,11 +4581,11 @@ function createSvgObjectsForRatsNest(circuitJson, ctx) {
|
|
|
4258
4581
|
});
|
|
4259
4582
|
const svgObjects = [];
|
|
4260
4583
|
for (const line of ratsNestLines) {
|
|
4261
|
-
const transformedStart =
|
|
4584
|
+
const transformedStart = applyToPoint26(transform, [
|
|
4262
4585
|
line.startPoint.x,
|
|
4263
4586
|
line.startPoint.y
|
|
4264
4587
|
]);
|
|
4265
|
-
const transformedEnd =
|
|
4588
|
+
const transformedEnd = applyToPoint26(transform, [
|
|
4266
4589
|
line.endPoint.x,
|
|
4267
4590
|
line.endPoint.y
|
|
4268
4591
|
]);
|
|
@@ -4290,7 +4613,7 @@ function createSvgObjectsForRatsNest(circuitJson, ctx) {
|
|
|
4290
4613
|
|
|
4291
4614
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-cutout.ts
|
|
4292
4615
|
import {
|
|
4293
|
-
applyToPoint as
|
|
4616
|
+
applyToPoint as applyToPoint27,
|
|
4294
4617
|
compose as compose3,
|
|
4295
4618
|
rotate as rotate3,
|
|
4296
4619
|
translate as translate3,
|
|
@@ -4300,7 +4623,7 @@ function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
|
4300
4623
|
const { transform, colorMap: colorMap2 } = ctx;
|
|
4301
4624
|
if (cutout.shape === "rect") {
|
|
4302
4625
|
const rectCutout = cutout;
|
|
4303
|
-
const [cx, cy] =
|
|
4626
|
+
const [cx, cy] = applyToPoint27(transform, [
|
|
4304
4627
|
rectCutout.center.x,
|
|
4305
4628
|
rectCutout.center.y
|
|
4306
4629
|
]);
|
|
@@ -4342,7 +4665,7 @@ function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
|
4342
4665
|
}
|
|
4343
4666
|
if (cutout.shape === "circle") {
|
|
4344
4667
|
const circleCutout = cutout;
|
|
4345
|
-
const [cx, cy] =
|
|
4668
|
+
const [cx, cy] = applyToPoint27(transform, [
|
|
4346
4669
|
circleCutout.center.x,
|
|
4347
4670
|
circleCutout.center.y
|
|
4348
4671
|
]);
|
|
@@ -4369,7 +4692,7 @@ function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
|
4369
4692
|
const polygonCutout = cutout;
|
|
4370
4693
|
if (!polygonCutout.points || polygonCutout.points.length === 0) return [];
|
|
4371
4694
|
const transformedPoints = polygonCutout.points.map(
|
|
4372
|
-
(p) =>
|
|
4695
|
+
(p) => applyToPoint27(transform, [p.x, p.y])
|
|
4373
4696
|
);
|
|
4374
4697
|
const pointsString = transformedPoints.map((p) => `${p[0]},${p[1]}`).join(" ");
|
|
4375
4698
|
return [
|
|
@@ -4393,7 +4716,7 @@ function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
|
4393
4716
|
|
|
4394
4717
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-copper-pour.ts
|
|
4395
4718
|
import {
|
|
4396
|
-
applyToPoint as
|
|
4719
|
+
applyToPoint as applyToPoint29,
|
|
4397
4720
|
compose as compose4,
|
|
4398
4721
|
rotate as rotate4,
|
|
4399
4722
|
toString as matrixToString7,
|
|
@@ -4401,11 +4724,11 @@ import {
|
|
|
4401
4724
|
} from "transformation-matrix";
|
|
4402
4725
|
|
|
4403
4726
|
// lib/utils/ring-to-path-d.ts
|
|
4404
|
-
import { applyToPoint as
|
|
4727
|
+
import { applyToPoint as applyToPoint28 } from "transformation-matrix";
|
|
4405
4728
|
function ringToPathD(vertices, transform) {
|
|
4406
4729
|
if (vertices.length === 0) return "";
|
|
4407
4730
|
const transformedVertices = vertices.map((v) => {
|
|
4408
|
-
const [x, y] =
|
|
4731
|
+
const [x, y] = applyToPoint28(transform, [v.x, v.y]);
|
|
4409
4732
|
return { ...v, x, y };
|
|
4410
4733
|
});
|
|
4411
4734
|
let d = `M ${transformedVertices[0].x} ${transformedVertices[0].y}`;
|
|
@@ -4494,7 +4817,7 @@ function createSvgObjectsFromPcbCopperPour(pour, ctx) {
|
|
|
4494
4817
|
const maskOverlayColor = layer === "bottom" ? colorMap2.soldermaskOverCopper.bottom : colorMap2.soldermaskOverCopper.top;
|
|
4495
4818
|
const maskOverlayOpacity = "0.9";
|
|
4496
4819
|
if (pour.shape === "rect") {
|
|
4497
|
-
const [cx, cy] =
|
|
4820
|
+
const [cx, cy] = applyToPoint29(transform, [pour.center.x, pour.center.y]);
|
|
4498
4821
|
const scaledWidth = pour.width * Math.abs(transform.a);
|
|
4499
4822
|
const scaledHeight = pour.height * Math.abs(transform.d);
|
|
4500
4823
|
const svgRotation = -(pour.rotation ?? 0);
|
|
@@ -4546,7 +4869,7 @@ function createSvgObjectsFromPcbCopperPour(pour, ctx) {
|
|
|
4546
4869
|
if (pour.shape === "polygon") {
|
|
4547
4870
|
if (!pour.points || pour.points.length === 0) return [];
|
|
4548
4871
|
const transformedPoints = pour.points.map(
|
|
4549
|
-
(p) =>
|
|
4872
|
+
(p) => applyToPoint29(transform, [p.x, p.y])
|
|
4550
4873
|
);
|
|
4551
4874
|
const pointsString = transformedPoints.map((p) => `${p[0]},${p[1]}`).join(" ");
|
|
4552
4875
|
const copperPolygon = {
|
|
@@ -4684,398 +5007,92 @@ function createSvgObjectsForPcbGrid({
|
|
|
4684
5007
|
stroke: gridLineColor,
|
|
4685
5008
|
"stroke-width": "1",
|
|
4686
5009
|
"shape-rendering": "crispEdges"
|
|
4687
|
-
},
|
|
4688
|
-
children: []
|
|
4689
|
-
}
|
|
4690
|
-
];
|
|
4691
|
-
const defs = {
|
|
4692
|
-
name: "defs",
|
|
4693
|
-
type: "element",
|
|
4694
|
-
value: "",
|
|
4695
|
-
attributes: {},
|
|
4696
|
-
children: [
|
|
4697
|
-
{
|
|
4698
|
-
name: "pattern",
|
|
4699
|
-
type: "element",
|
|
4700
|
-
value: "",
|
|
4701
|
-
attributes: {
|
|
4702
|
-
id: GRID_PATTERN_ID,
|
|
4703
|
-
width: hasMajorGrid ? majorCellSize.toString() : gridCellSize.toString(),
|
|
4704
|
-
height: hasMajorGrid ? majorCellSize.toString() : gridCellSize.toString(),
|
|
4705
|
-
patternUnits: "userSpaceOnUse"
|
|
4706
|
-
},
|
|
4707
|
-
children: patternChildren
|
|
4708
|
-
}
|
|
4709
|
-
]
|
|
4710
|
-
};
|
|
4711
|
-
const rect = {
|
|
4712
|
-
name: "rect",
|
|
4713
|
-
type: "element",
|
|
4714
|
-
value: "",
|
|
4715
|
-
attributes: {
|
|
4716
|
-
x: "0",
|
|
4717
|
-
y: "0",
|
|
4718
|
-
width: svgWidth.toString(),
|
|
4719
|
-
height: svgHeight.toString(),
|
|
4720
|
-
fill: `url(#${GRID_PATTERN_ID})`,
|
|
4721
|
-
"pointer-events": "none",
|
|
4722
|
-
"data-type": "pcb_grid",
|
|
4723
|
-
"data-pcb-layer": "global"
|
|
4724
|
-
},
|
|
4725
|
-
children: []
|
|
4726
|
-
};
|
|
4727
|
-
return { defs, rect };
|
|
4728
|
-
}
|
|
4729
|
-
function createMajorGridPatternChildren(cellSize, majorCellSize, lineColor, majorLineColor) {
|
|
4730
|
-
const children = [];
|
|
4731
|
-
const steps = Math.round(majorCellSize / cellSize);
|
|
4732
|
-
for (let step = 0; step < steps; step += 1) {
|
|
4733
|
-
const offset = Number((step * cellSize).toFixed(6));
|
|
4734
|
-
const offsetString = offset.toString();
|
|
4735
|
-
const color = step === 0 ? majorLineColor : lineColor;
|
|
4736
|
-
const majorSizeString = majorCellSize.toString();
|
|
4737
|
-
children.push({
|
|
4738
|
-
name: "line",
|
|
4739
|
-
type: "element",
|
|
4740
|
-
value: "",
|
|
4741
|
-
attributes: {
|
|
4742
|
-
x1: offsetString,
|
|
4743
|
-
y1: "0",
|
|
4744
|
-
x2: offsetString,
|
|
4745
|
-
y2: majorSizeString,
|
|
4746
|
-
stroke: color,
|
|
4747
|
-
"stroke-width": "1",
|
|
4748
|
-
"shape-rendering": "crispEdges"
|
|
4749
|
-
},
|
|
4750
|
-
children: []
|
|
4751
|
-
});
|
|
4752
|
-
children.push({
|
|
4753
|
-
name: "line",
|
|
4754
|
-
type: "element",
|
|
4755
|
-
value: "",
|
|
4756
|
-
attributes: {
|
|
4757
|
-
x1: "0",
|
|
4758
|
-
y1: offsetString,
|
|
4759
|
-
x2: majorSizeString,
|
|
4760
|
-
y2: offsetString,
|
|
4761
|
-
stroke: color,
|
|
4762
|
-
"stroke-width": "1",
|
|
4763
|
-
"shape-rendering": "crispEdges"
|
|
4764
|
-
},
|
|
4765
|
-
children: []
|
|
4766
|
-
});
|
|
4767
|
-
}
|
|
4768
|
-
return children;
|
|
4769
|
-
}
|
|
4770
|
-
|
|
4771
|
-
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-component.ts
|
|
4772
|
-
import { applyToPoint as applyToPoint30 } from "transformation-matrix";
|
|
4773
|
-
|
|
4774
|
-
// lib/utils/create-pcb-component-anchor-offset-indicators.ts
|
|
4775
|
-
import { applyToPoint as applyToPoint29 } from "transformation-matrix";
|
|
4776
|
-
var OFFSET_THRESHOLD_MM = 0.01;
|
|
4777
|
-
var TICK_SIZE_PX = 4;
|
|
4778
|
-
var LABEL_GAP_PX = 8;
|
|
4779
|
-
var LABEL_FONT_SIZE_PX = 11;
|
|
4780
|
-
var STROKE_WIDTH_PX = 1;
|
|
4781
|
-
var ANCHOR_MARKER_SIZE_PX = 5;
|
|
4782
|
-
var ANCHOR_MARKER_STROKE_WIDTH_PX = 1.5;
|
|
4783
|
-
var COMPONENT_GAP_PX = 15;
|
|
4784
|
-
var COMPONENT_SIDE_GAP_PX = 10;
|
|
4785
|
-
var DISTANCE_MULTIPLIER = 0.2;
|
|
4786
|
-
var MAX_OFFSET_PX = 50;
|
|
4787
|
-
function createAnchorOffsetIndicators(params) {
|
|
4788
|
-
const {
|
|
4789
|
-
groupAnchorPosition,
|
|
4790
|
-
componentPosition,
|
|
4791
|
-
transform,
|
|
4792
|
-
componentWidth = 0,
|
|
4793
|
-
componentHeight = 0
|
|
4794
|
-
} = params;
|
|
4795
|
-
const objects = [];
|
|
4796
|
-
const [screenGroupAnchorX, screenGroupAnchorY] = applyToPoint29(transform, [
|
|
4797
|
-
groupAnchorPosition.x,
|
|
4798
|
-
groupAnchorPosition.y
|
|
4799
|
-
]);
|
|
4800
|
-
const [screenComponentX, screenComponentY] = applyToPoint29(transform, [
|
|
4801
|
-
componentPosition.x,
|
|
4802
|
-
componentPosition.y
|
|
4803
|
-
]);
|
|
4804
|
-
const offsetX = componentPosition.x - groupAnchorPosition.x;
|
|
4805
|
-
const offsetY = componentPosition.y - groupAnchorPosition.y;
|
|
4806
|
-
const scale9 = Math.abs(transform.a);
|
|
4807
|
-
const screenComponentWidth = componentWidth * scale9;
|
|
4808
|
-
const screenComponentHeight = componentHeight * scale9;
|
|
4809
|
-
objects.push(createAnchorMarker(screenGroupAnchorX, screenGroupAnchorY));
|
|
4810
|
-
objects.push({
|
|
4811
|
-
name: "line",
|
|
4812
|
-
type: "element",
|
|
4813
|
-
attributes: {
|
|
4814
|
-
x1: screenGroupAnchorX.toString(),
|
|
4815
|
-
y1: screenGroupAnchorY.toString(),
|
|
4816
|
-
x2: screenComponentX.toString(),
|
|
4817
|
-
y2: screenComponentY.toString(),
|
|
4818
|
-
stroke: "#ffffff",
|
|
4819
|
-
"stroke-width": "0.5",
|
|
4820
|
-
"stroke-dasharray": "3,3",
|
|
4821
|
-
opacity: "0.5",
|
|
4822
|
-
class: "anchor-offset-connector"
|
|
4823
|
-
},
|
|
4824
|
-
children: [],
|
|
4825
|
-
value: ""
|
|
4826
|
-
});
|
|
4827
|
-
objects.push({
|
|
4828
|
-
name: "circle",
|
|
4829
|
-
type: "element",
|
|
4830
|
-
attributes: {
|
|
4831
|
-
cx: screenComponentX.toString(),
|
|
4832
|
-
cy: screenComponentY.toString(),
|
|
4833
|
-
r: "2",
|
|
4834
|
-
fill: "#ffffff",
|
|
4835
|
-
opacity: "0.7",
|
|
4836
|
-
class: "anchor-offset-component-marker"
|
|
4837
|
-
},
|
|
4838
|
-
children: [],
|
|
4839
|
-
value: ""
|
|
4840
|
-
});
|
|
4841
|
-
const yDistance = Math.abs(screenComponentY - screenGroupAnchorY);
|
|
4842
|
-
const xDistance = Math.abs(screenComponentX - screenGroupAnchorX);
|
|
4843
|
-
const totalDistance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
|
|
4844
|
-
const componentHeightOffset = screenComponentHeight / 2 + COMPONENT_GAP_PX;
|
|
4845
|
-
const dynamicOffset = Math.max(
|
|
4846
|
-
componentHeightOffset,
|
|
4847
|
-
Math.min(MAX_OFFSET_PX, totalDistance * DISTANCE_MULTIPLIER)
|
|
4848
|
-
);
|
|
4849
|
-
const horizontalLineY = offsetY > 0 ? screenComponentY - dynamicOffset : screenComponentY + dynamicOffset;
|
|
4850
|
-
const componentWidthOffset = screenComponentWidth / 2 + COMPONENT_SIDE_GAP_PX;
|
|
4851
|
-
const verticalLineX = offsetX > 0 ? screenComponentX + componentWidthOffset : screenComponentX - componentWidthOffset;
|
|
4852
|
-
if (Math.abs(offsetX) > OFFSET_THRESHOLD_MM) {
|
|
4853
|
-
objects.push(
|
|
4854
|
-
...createHorizontalDimension({
|
|
4855
|
-
startX: screenGroupAnchorX,
|
|
4856
|
-
endX: screenComponentX,
|
|
4857
|
-
y: horizontalLineY,
|
|
4858
|
-
offsetMm: offsetX,
|
|
4859
|
-
offsetY
|
|
4860
|
-
})
|
|
4861
|
-
);
|
|
4862
|
-
}
|
|
4863
|
-
if (Math.abs(offsetY) > OFFSET_THRESHOLD_MM) {
|
|
4864
|
-
objects.push(
|
|
4865
|
-
...createVerticalDimension({
|
|
4866
|
-
x: verticalLineX,
|
|
4867
|
-
startY: screenGroupAnchorY,
|
|
4868
|
-
endY: screenComponentY,
|
|
4869
|
-
offsetMm: -offsetY,
|
|
4870
|
-
offsetX
|
|
4871
|
-
})
|
|
4872
|
-
);
|
|
4873
|
-
}
|
|
4874
|
-
return objects;
|
|
4875
|
-
}
|
|
4876
|
-
function createAnchorMarker(x, y) {
|
|
4877
|
-
return {
|
|
4878
|
-
name: "g",
|
|
5010
|
+
},
|
|
5011
|
+
children: []
|
|
5012
|
+
}
|
|
5013
|
+
];
|
|
5014
|
+
const defs = {
|
|
5015
|
+
name: "defs",
|
|
4879
5016
|
type: "element",
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
"data-type": "anchor_offset_marker"
|
|
4883
|
-
},
|
|
5017
|
+
value: "",
|
|
5018
|
+
attributes: {},
|
|
4884
5019
|
children: [
|
|
4885
5020
|
{
|
|
4886
|
-
name: "
|
|
4887
|
-
type: "element",
|
|
4888
|
-
attributes: {
|
|
4889
|
-
x1: x.toString(),
|
|
4890
|
-
y1: (y - ANCHOR_MARKER_SIZE_PX).toString(),
|
|
4891
|
-
x2: x.toString(),
|
|
4892
|
-
y2: (y + ANCHOR_MARKER_SIZE_PX).toString(),
|
|
4893
|
-
stroke: "#ffffff",
|
|
4894
|
-
"stroke-width": ANCHOR_MARKER_STROKE_WIDTH_PX.toString(),
|
|
4895
|
-
"stroke-linecap": "round"
|
|
4896
|
-
},
|
|
4897
|
-
children: [],
|
|
4898
|
-
value: ""
|
|
4899
|
-
},
|
|
4900
|
-
{
|
|
4901
|
-
name: "line",
|
|
5021
|
+
name: "pattern",
|
|
4902
5022
|
type: "element",
|
|
5023
|
+
value: "",
|
|
4903
5024
|
attributes: {
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
stroke: "#ffffff",
|
|
4909
|
-
"stroke-width": ANCHOR_MARKER_STROKE_WIDTH_PX.toString(),
|
|
4910
|
-
"stroke-linecap": "round"
|
|
5025
|
+
id: GRID_PATTERN_ID,
|
|
5026
|
+
width: hasMajorGrid ? majorCellSize.toString() : gridCellSize.toString(),
|
|
5027
|
+
height: hasMajorGrid ? majorCellSize.toString() : gridCellSize.toString(),
|
|
5028
|
+
patternUnits: "userSpaceOnUse"
|
|
4911
5029
|
},
|
|
4912
|
-
children:
|
|
4913
|
-
value: ""
|
|
5030
|
+
children: patternChildren
|
|
4914
5031
|
}
|
|
4915
|
-
]
|
|
4916
|
-
value: ""
|
|
5032
|
+
]
|
|
4917
5033
|
};
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
startX,
|
|
4921
|
-
endX,
|
|
4922
|
-
y,
|
|
4923
|
-
offsetMm,
|
|
4924
|
-
offsetY
|
|
4925
|
-
}) {
|
|
4926
|
-
const objects = [];
|
|
4927
|
-
objects.push({
|
|
4928
|
-
name: "line",
|
|
4929
|
-
type: "element",
|
|
4930
|
-
attributes: {
|
|
4931
|
-
x1: startX.toString(),
|
|
4932
|
-
y1: y.toString(),
|
|
4933
|
-
x2: endX.toString(),
|
|
4934
|
-
y2: y.toString(),
|
|
4935
|
-
stroke: "#ffffff",
|
|
4936
|
-
"stroke-width": STROKE_WIDTH_PX.toString(),
|
|
4937
|
-
class: "anchor-offset-dimension-x"
|
|
4938
|
-
},
|
|
4939
|
-
children: [],
|
|
4940
|
-
value: ""
|
|
4941
|
-
});
|
|
4942
|
-
objects.push({
|
|
4943
|
-
name: "line",
|
|
4944
|
-
type: "element",
|
|
4945
|
-
attributes: {
|
|
4946
|
-
x1: startX.toString(),
|
|
4947
|
-
y1: (y - TICK_SIZE_PX).toString(),
|
|
4948
|
-
x2: startX.toString(),
|
|
4949
|
-
y2: (y + TICK_SIZE_PX).toString(),
|
|
4950
|
-
stroke: "#ffffff",
|
|
4951
|
-
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
4952
|
-
},
|
|
4953
|
-
children: [],
|
|
4954
|
-
value: ""
|
|
4955
|
-
});
|
|
4956
|
-
objects.push({
|
|
4957
|
-
name: "line",
|
|
4958
|
-
type: "element",
|
|
4959
|
-
attributes: {
|
|
4960
|
-
x1: endX.toString(),
|
|
4961
|
-
y1: (y - TICK_SIZE_PX).toString(),
|
|
4962
|
-
x2: endX.toString(),
|
|
4963
|
-
y2: (y + TICK_SIZE_PX).toString(),
|
|
4964
|
-
stroke: "#ffffff",
|
|
4965
|
-
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
4966
|
-
},
|
|
4967
|
-
children: [],
|
|
4968
|
-
value: ""
|
|
4969
|
-
});
|
|
4970
|
-
const midX = (startX + endX) / 2;
|
|
4971
|
-
const labelY = offsetY > 0 ? y - TICK_SIZE_PX - LABEL_GAP_PX : y + TICK_SIZE_PX + LABEL_GAP_PX;
|
|
4972
|
-
objects.push({
|
|
4973
|
-
name: "text",
|
|
5034
|
+
const rect = {
|
|
5035
|
+
name: "rect",
|
|
4974
5036
|
type: "element",
|
|
5037
|
+
value: "",
|
|
4975
5038
|
attributes: {
|
|
4976
|
-
x:
|
|
4977
|
-
y:
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
"
|
|
4982
|
-
"
|
|
4983
|
-
|
|
5039
|
+
x: "0",
|
|
5040
|
+
y: "0",
|
|
5041
|
+
width: svgWidth.toString(),
|
|
5042
|
+
height: svgHeight.toString(),
|
|
5043
|
+
fill: `url(#${GRID_PATTERN_ID})`,
|
|
5044
|
+
"pointer-events": "none",
|
|
5045
|
+
"data-type": "pcb_grid",
|
|
5046
|
+
"data-pcb-layer": "global"
|
|
4984
5047
|
},
|
|
4985
|
-
children: [
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
value: `X: ${offsetMm.toFixed(2)}mm`,
|
|
4989
|
-
name: "",
|
|
4990
|
-
attributes: {},
|
|
4991
|
-
children: []
|
|
4992
|
-
}
|
|
4993
|
-
],
|
|
4994
|
-
value: ""
|
|
4995
|
-
});
|
|
4996
|
-
return objects;
|
|
5048
|
+
children: []
|
|
5049
|
+
};
|
|
5050
|
+
return { defs, rect };
|
|
4997
5051
|
}
|
|
4998
|
-
function
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
attributes: {
|
|
5039
|
-
x1: (x - TICK_SIZE_PX).toString(),
|
|
5040
|
-
y1: endY.toString(),
|
|
5041
|
-
x2: (x + TICK_SIZE_PX).toString(),
|
|
5042
|
-
y2: endY.toString(),
|
|
5043
|
-
stroke: "#ffffff",
|
|
5044
|
-
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
5045
|
-
},
|
|
5046
|
-
children: [],
|
|
5047
|
-
value: ""
|
|
5048
|
-
});
|
|
5049
|
-
const midY = (startY + endY) / 2;
|
|
5050
|
-
const labelX = offsetX < 0 ? x - TICK_SIZE_PX - 4 : x + TICK_SIZE_PX + 4;
|
|
5051
|
-
objects.push({
|
|
5052
|
-
name: "text",
|
|
5053
|
-
type: "element",
|
|
5054
|
-
attributes: {
|
|
5055
|
-
x: labelX.toString(),
|
|
5056
|
-
y: midY.toString(),
|
|
5057
|
-
fill: "#ffffff",
|
|
5058
|
-
"font-size": LABEL_FONT_SIZE_PX.toString(),
|
|
5059
|
-
"font-family": "Arial, sans-serif",
|
|
5060
|
-
"text-anchor": offsetX < 0 ? "end" : "start",
|
|
5061
|
-
"dominant-baseline": "middle",
|
|
5062
|
-
class: "anchor-offset-label"
|
|
5063
|
-
},
|
|
5064
|
-
children: [
|
|
5065
|
-
{
|
|
5066
|
-
type: "text",
|
|
5067
|
-
value: `Y: ${offsetMm.toFixed(2)}mm`,
|
|
5068
|
-
name: "",
|
|
5069
|
-
attributes: {},
|
|
5070
|
-
children: []
|
|
5071
|
-
}
|
|
5072
|
-
],
|
|
5073
|
-
value: ""
|
|
5074
|
-
});
|
|
5075
|
-
return objects;
|
|
5052
|
+
function createMajorGridPatternChildren(cellSize, majorCellSize, lineColor, majorLineColor) {
|
|
5053
|
+
const children = [];
|
|
5054
|
+
const steps = Math.round(majorCellSize / cellSize);
|
|
5055
|
+
for (let step = 0; step < steps; step += 1) {
|
|
5056
|
+
const offset = Number((step * cellSize).toFixed(6));
|
|
5057
|
+
const offsetString = offset.toString();
|
|
5058
|
+
const color = step === 0 ? majorLineColor : lineColor;
|
|
5059
|
+
const majorSizeString = majorCellSize.toString();
|
|
5060
|
+
children.push({
|
|
5061
|
+
name: "line",
|
|
5062
|
+
type: "element",
|
|
5063
|
+
value: "",
|
|
5064
|
+
attributes: {
|
|
5065
|
+
x1: offsetString,
|
|
5066
|
+
y1: "0",
|
|
5067
|
+
x2: offsetString,
|
|
5068
|
+
y2: majorSizeString,
|
|
5069
|
+
stroke: color,
|
|
5070
|
+
"stroke-width": "1",
|
|
5071
|
+
"shape-rendering": "crispEdges"
|
|
5072
|
+
},
|
|
5073
|
+
children: []
|
|
5074
|
+
});
|
|
5075
|
+
children.push({
|
|
5076
|
+
name: "line",
|
|
5077
|
+
type: "element",
|
|
5078
|
+
value: "",
|
|
5079
|
+
attributes: {
|
|
5080
|
+
x1: "0",
|
|
5081
|
+
y1: offsetString,
|
|
5082
|
+
x2: majorSizeString,
|
|
5083
|
+
y2: offsetString,
|
|
5084
|
+
stroke: color,
|
|
5085
|
+
"stroke-width": "1",
|
|
5086
|
+
"shape-rendering": "crispEdges"
|
|
5087
|
+
},
|
|
5088
|
+
children: []
|
|
5089
|
+
});
|
|
5090
|
+
}
|
|
5091
|
+
return children;
|
|
5076
5092
|
}
|
|
5077
5093
|
|
|
5078
5094
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-component.ts
|
|
5095
|
+
import { applyToPoint as applyToPoint30 } from "transformation-matrix";
|
|
5079
5096
|
function createSvgObjectsFromPcbComponent(component, ctx) {
|
|
5080
5097
|
const { transform, circuitJson } = ctx;
|
|
5081
5098
|
const { center, width, height, rotation = 0 } = component;
|
|
@@ -5223,7 +5240,7 @@ function getSoftwareUsedString(circuitJson) {
|
|
|
5223
5240
|
var package_default = {
|
|
5224
5241
|
name: "circuit-to-svg",
|
|
5225
5242
|
type: "module",
|
|
5226
|
-
version: "0.0.
|
|
5243
|
+
version: "0.0.283",
|
|
5227
5244
|
description: "Convert Circuit JSON to SVG",
|
|
5228
5245
|
main: "dist/index.js",
|
|
5229
5246
|
files: [
|
|
@@ -5247,12 +5264,12 @@ var package_default = {
|
|
|
5247
5264
|
"bun-match-svg": "^0.0.12",
|
|
5248
5265
|
esbuild: "^0.20.2",
|
|
5249
5266
|
"performance-now": "^2.1.0",
|
|
5250
|
-
"circuit-json": "^0.0.
|
|
5267
|
+
"circuit-json": "^0.0.327",
|
|
5251
5268
|
react: "19.1.0",
|
|
5252
5269
|
"react-cosmos": "7.0.0",
|
|
5253
5270
|
"react-cosmos-plugin-vite": "7.0.0",
|
|
5254
5271
|
"react-dom": "19.1.0",
|
|
5255
|
-
tscircuit: "^0.0.
|
|
5272
|
+
tscircuit: "^0.0.1018",
|
|
5256
5273
|
tsup: "^8.0.2",
|
|
5257
5274
|
typescript: "^5.4.5",
|
|
5258
5275
|
"vite-tsconfig-paths": "^5.0.1"
|