circuit-to-svg 0.0.282 → 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 +573 -553
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3202,6 +3202,9 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
|
3202
3202
|
const height = pad.height * Math.abs(transform.d);
|
|
3203
3203
|
const radius = pad.radius * Math.abs(transform.a);
|
|
3204
3204
|
const [x, y] = applyToPoint20(transform, [pad.x, pad.y]);
|
|
3205
|
+
const rotationTransformAttributes = isRotated ? {
|
|
3206
|
+
transform: `translate(${x} ${y}) rotate(${-(pad.ccw_rotation ?? 0)})`
|
|
3207
|
+
} : void 0;
|
|
3205
3208
|
const baseAttributes = {
|
|
3206
3209
|
class: "pcb-pad",
|
|
3207
3210
|
fill: layerNameToColor(pad.layer, colorMap2),
|
|
@@ -3213,9 +3216,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
|
3213
3216
|
ry: radius.toString(),
|
|
3214
3217
|
"data-type": "pcb_smtpad",
|
|
3215
3218
|
"data-pcb-layer": pad.layer,
|
|
3216
|
-
...
|
|
3217
|
-
transform: `translate(${x} ${y}) rotate(${-(pad.ccw_rotation ?? 0)})`
|
|
3218
|
-
} : {}
|
|
3219
|
+
...rotationTransformAttributes ?? {}
|
|
3219
3220
|
};
|
|
3220
3221
|
const padElement = {
|
|
3221
3222
|
name: "rect",
|
|
@@ -3239,14 +3240,15 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
|
3239
3240
|
attributes: {
|
|
3240
3241
|
class: "pcb-pad-covered",
|
|
3241
3242
|
fill: soldermaskWithCopperUnderneathColor,
|
|
3242
|
-
x: (x - width / 2).toString(),
|
|
3243
|
-
y: (y - height / 2).toString(),
|
|
3243
|
+
x: isRotated ? (-width / 2).toString() : (x - width / 2).toString(),
|
|
3244
|
+
y: isRotated ? (-height / 2).toString() : (y - height / 2).toString(),
|
|
3244
3245
|
width: width.toString(),
|
|
3245
3246
|
height: height.toString(),
|
|
3246
3247
|
rx: radius.toString(),
|
|
3247
3248
|
ry: radius.toString(),
|
|
3248
3249
|
"data-type": "pcb_smtpad",
|
|
3249
|
-
"data-pcb-layer": pad.layer
|
|
3250
|
+
"data-pcb-layer": pad.layer,
|
|
3251
|
+
...rotationTransformAttributes ?? {}
|
|
3250
3252
|
}
|
|
3251
3253
|
};
|
|
3252
3254
|
const exposedAttributes = {
|
|
@@ -3260,7 +3262,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
|
3260
3262
|
ry: maskRadius.toString(),
|
|
3261
3263
|
"data-type": "pcb_soldermask",
|
|
3262
3264
|
"data-pcb-layer": pad.layer,
|
|
3263
|
-
...
|
|
3265
|
+
...rotationTransformAttributes ?? {}
|
|
3264
3266
|
};
|
|
3265
3267
|
const exposedOpeningElement = {
|
|
3266
3268
|
name: "rect",
|
|
@@ -3280,14 +3282,15 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
|
3280
3282
|
attributes: {
|
|
3281
3283
|
class: "pcb-pad-covered",
|
|
3282
3284
|
fill: soldermaskWithCopperUnderneathColor,
|
|
3283
|
-
x: (x - width / 2).toString(),
|
|
3284
|
-
y: (y - height / 2).toString(),
|
|
3285
|
+
x: isRotated ? (-width / 2).toString() : (x - width / 2).toString(),
|
|
3286
|
+
y: isRotated ? (-height / 2).toString() : (y - height / 2).toString(),
|
|
3285
3287
|
width: width.toString(),
|
|
3286
3288
|
height: height.toString(),
|
|
3287
3289
|
rx: radius.toString(),
|
|
3288
3290
|
ry: radius.toString(),
|
|
3289
3291
|
"data-type": "pcb_smtpad",
|
|
3290
|
-
"data-pcb-layer": pad.layer
|
|
3292
|
+
"data-pcb-layer": pad.layer,
|
|
3293
|
+
...rotationTransformAttributes ?? {}
|
|
3291
3294
|
}
|
|
3292
3295
|
};
|
|
3293
3296
|
return [coveredPadElement];
|
|
@@ -3303,7 +3306,7 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
|
3303
3306
|
ry: maskRadius.toString(),
|
|
3304
3307
|
"data-type": "pcb_soldermask_opening",
|
|
3305
3308
|
"data-pcb-layer": pad.layer,
|
|
3306
|
-
...
|
|
3309
|
+
...rotationTransformAttributes ?? {}
|
|
3307
3310
|
};
|
|
3308
3311
|
const substrateElement = {
|
|
3309
3312
|
name: "rect",
|
|
@@ -3505,180 +3508,503 @@ function createSvgObjectsFromSmtPad(pad, ctx) {
|
|
|
3505
3508
|
}
|
|
3506
3509
|
|
|
3507
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
|
|
3508
3514
|
import { applyToPoint as applyToPoint21 } from "transformation-matrix";
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
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
|
-
const
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
name: "path",
|
|
3546
|
-
type: "element",
|
|
3547
|
-
value: "",
|
|
3548
|
-
children: [],
|
|
3549
|
-
attributes: {
|
|
3550
|
-
class: "pcb-board-soldermask",
|
|
3551
|
-
d: path,
|
|
3552
|
-
fill: colorMap2.soldermask.top,
|
|
3553
|
-
"fill-opacity": "0.8",
|
|
3554
|
-
stroke: "none",
|
|
3555
|
-
"data-type": "pcb_soldermask",
|
|
3556
|
-
"data-pcb-layer": maskLayer
|
|
3557
|
-
}
|
|
3558
|
-
});
|
|
3559
|
-
}
|
|
3560
|
-
svgObjects.push({
|
|
3561
|
-
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",
|
|
3562
3551
|
type: "element",
|
|
3563
|
-
|
|
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
|
+
},
|
|
3564
3563
|
children: [],
|
|
3564
|
+
value: ""
|
|
3565
|
+
});
|
|
3566
|
+
objects.push({
|
|
3567
|
+
name: "circle",
|
|
3568
|
+
type: "element",
|
|
3565
3569
|
attributes: {
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
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: ""
|
|
3574
3579
|
});
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
const width = Number(pcbPanel.width);
|
|
3583
|
-
const height = Number(pcbPanel.height);
|
|
3584
|
-
const center = pcbPanel.center ?? { x: width / 2, y: height / 2 };
|
|
3585
|
-
const halfWidth = width / 2;
|
|
3586
|
-
const halfHeight = height / 2;
|
|
3587
|
-
const topLeft = applyToPoint22(transform, [
|
|
3588
|
-
center.x - halfWidth,
|
|
3589
|
-
center.y - halfHeight
|
|
3590
|
-
]);
|
|
3591
|
-
const topRight = applyToPoint22(transform, [
|
|
3592
|
-
center.x + halfWidth,
|
|
3593
|
-
center.y - halfHeight
|
|
3594
|
-
]);
|
|
3595
|
-
const bottomRight = applyToPoint22(transform, [
|
|
3596
|
-
center.x + halfWidth,
|
|
3597
|
-
center.y + halfHeight
|
|
3598
|
-
]);
|
|
3599
|
-
const bottomLeft = applyToPoint22(transform, [
|
|
3600
|
-
center.x - halfWidth,
|
|
3601
|
-
center.y + halfHeight
|
|
3602
|
-
]);
|
|
3603
|
-
const path = `M ${topLeft[0]} ${topLeft[1]} L ${topRight[0]} ${topRight[1]} L ${bottomRight[0]} ${bottomRight[1]} L ${bottomLeft[0]} ${bottomLeft[1]} Z`;
|
|
3604
|
-
const isCoveredWithSolderMask = pcbPanel.covered_with_solder_mask !== false;
|
|
3605
|
-
const shouldShowSolderMask = Boolean(
|
|
3606
|
-
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)
|
|
3607
3587
|
);
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
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;
|
|
3625
3614
|
}
|
|
3626
|
-
|
|
3627
|
-
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-via.ts
|
|
3628
|
-
import { applyToPoint as applyToPoint23 } from "transformation-matrix";
|
|
3629
|
-
function createSvgObjectsFromPcbVia(hole, ctx) {
|
|
3630
|
-
const { transform, colorMap: colorMap2 } = ctx;
|
|
3631
|
-
const [x, y] = applyToPoint23(transform, [hole.x, hole.y]);
|
|
3632
|
-
const scaledOuterWidth = hole.outer_diameter * Math.abs(transform.a);
|
|
3633
|
-
const scaledOuterHeight = hole.outer_diameter * Math.abs(transform.a);
|
|
3634
|
-
const scaledHoleWidth = hole.hole_diameter * Math.abs(transform.a);
|
|
3635
|
-
const scaledHoleHeight = hole.hole_diameter * Math.abs(transform.a);
|
|
3636
|
-
const outerRadius = Math.min(scaledOuterWidth, scaledOuterHeight) / 2;
|
|
3637
|
-
const innerRadius = Math.min(scaledHoleWidth, scaledHoleHeight) / 2;
|
|
3615
|
+
function createAnchorMarker(x, y) {
|
|
3638
3616
|
return {
|
|
3639
3617
|
name: "g",
|
|
3640
3618
|
type: "element",
|
|
3641
3619
|
attributes: {
|
|
3642
|
-
|
|
3643
|
-
"data-
|
|
3620
|
+
class: "anchor-offset-marker",
|
|
3621
|
+
"data-type": "anchor_offset_marker"
|
|
3644
3622
|
},
|
|
3645
3623
|
children: [
|
|
3646
3624
|
{
|
|
3647
|
-
name: "
|
|
3625
|
+
name: "line",
|
|
3648
3626
|
type: "element",
|
|
3649
3627
|
attributes: {
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
"
|
|
3656
|
-
"
|
|
3657
|
-
}
|
|
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: ""
|
|
3658
3638
|
},
|
|
3659
3639
|
{
|
|
3660
|
-
name: "
|
|
3640
|
+
name: "line",
|
|
3661
3641
|
type: "element",
|
|
3662
3642
|
attributes: {
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
"
|
|
3669
|
-
"
|
|
3670
|
-
}
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
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: ""
|
|
3653
|
+
}
|
|
3654
|
+
],
|
|
3655
|
+
value: ""
|
|
3656
|
+
};
|
|
3657
|
+
}
|
|
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
|
|
3677
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";
|
|
3678
4004
|
function createSvgObjectsFromPcbHole(hole, ctx) {
|
|
3679
4005
|
const { transform, colorMap: colorMap2, showSolderMask } = ctx;
|
|
3680
4006
|
const layer = ctx.layer ?? "top";
|
|
3681
|
-
const [x, y] =
|
|
4007
|
+
const [x, y] = applyToPoint25(transform, [hole.x, hole.y]);
|
|
3682
4008
|
const isCoveredWithSolderMask = Boolean(hole.is_covered_with_solder_mask);
|
|
3683
4009
|
const soldermaskMargin = (hole.soldermask_margin ?? 0) * Math.abs(transform.a);
|
|
3684
4010
|
const shouldShowSolderMask = showSolderMask && isCoveredWithSolderMask && soldermaskMargin !== 0;
|
|
@@ -4175,7 +4501,7 @@ import {
|
|
|
4175
4501
|
getFullConnectivityMapFromCircuitJson
|
|
4176
4502
|
} from "circuit-json-to-connectivity-map";
|
|
4177
4503
|
import "svgson";
|
|
4178
|
-
import { applyToPoint as
|
|
4504
|
+
import { applyToPoint as applyToPoint26 } from "transformation-matrix";
|
|
4179
4505
|
|
|
4180
4506
|
// lib/pcb/create-svg-objects-from-pcb-rats-nest/get-element-position.ts
|
|
4181
4507
|
import { su } from "@tscircuit/circuit-json-util";
|
|
@@ -4255,11 +4581,11 @@ function createSvgObjectsForRatsNest(circuitJson, ctx) {
|
|
|
4255
4581
|
});
|
|
4256
4582
|
const svgObjects = [];
|
|
4257
4583
|
for (const line of ratsNestLines) {
|
|
4258
|
-
const transformedStart =
|
|
4584
|
+
const transformedStart = applyToPoint26(transform, [
|
|
4259
4585
|
line.startPoint.x,
|
|
4260
4586
|
line.startPoint.y
|
|
4261
4587
|
]);
|
|
4262
|
-
const transformedEnd =
|
|
4588
|
+
const transformedEnd = applyToPoint26(transform, [
|
|
4263
4589
|
line.endPoint.x,
|
|
4264
4590
|
line.endPoint.y
|
|
4265
4591
|
]);
|
|
@@ -4287,7 +4613,7 @@ function createSvgObjectsForRatsNest(circuitJson, ctx) {
|
|
|
4287
4613
|
|
|
4288
4614
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-cutout.ts
|
|
4289
4615
|
import {
|
|
4290
|
-
applyToPoint as
|
|
4616
|
+
applyToPoint as applyToPoint27,
|
|
4291
4617
|
compose as compose3,
|
|
4292
4618
|
rotate as rotate3,
|
|
4293
4619
|
translate as translate3,
|
|
@@ -4297,7 +4623,7 @@ function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
|
4297
4623
|
const { transform, colorMap: colorMap2 } = ctx;
|
|
4298
4624
|
if (cutout.shape === "rect") {
|
|
4299
4625
|
const rectCutout = cutout;
|
|
4300
|
-
const [cx, cy] =
|
|
4626
|
+
const [cx, cy] = applyToPoint27(transform, [
|
|
4301
4627
|
rectCutout.center.x,
|
|
4302
4628
|
rectCutout.center.y
|
|
4303
4629
|
]);
|
|
@@ -4339,7 +4665,7 @@ function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
|
4339
4665
|
}
|
|
4340
4666
|
if (cutout.shape === "circle") {
|
|
4341
4667
|
const circleCutout = cutout;
|
|
4342
|
-
const [cx, cy] =
|
|
4668
|
+
const [cx, cy] = applyToPoint27(transform, [
|
|
4343
4669
|
circleCutout.center.x,
|
|
4344
4670
|
circleCutout.center.y
|
|
4345
4671
|
]);
|
|
@@ -4366,7 +4692,7 @@ function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
|
4366
4692
|
const polygonCutout = cutout;
|
|
4367
4693
|
if (!polygonCutout.points || polygonCutout.points.length === 0) return [];
|
|
4368
4694
|
const transformedPoints = polygonCutout.points.map(
|
|
4369
|
-
(p) =>
|
|
4695
|
+
(p) => applyToPoint27(transform, [p.x, p.y])
|
|
4370
4696
|
);
|
|
4371
4697
|
const pointsString = transformedPoints.map((p) => `${p[0]},${p[1]}`).join(" ");
|
|
4372
4698
|
return [
|
|
@@ -4390,7 +4716,7 @@ function createSvgObjectsFromPcbCutout(cutout, ctx) {
|
|
|
4390
4716
|
|
|
4391
4717
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-copper-pour.ts
|
|
4392
4718
|
import {
|
|
4393
|
-
applyToPoint as
|
|
4719
|
+
applyToPoint as applyToPoint29,
|
|
4394
4720
|
compose as compose4,
|
|
4395
4721
|
rotate as rotate4,
|
|
4396
4722
|
toString as matrixToString7,
|
|
@@ -4398,11 +4724,11 @@ import {
|
|
|
4398
4724
|
} from "transformation-matrix";
|
|
4399
4725
|
|
|
4400
4726
|
// lib/utils/ring-to-path-d.ts
|
|
4401
|
-
import { applyToPoint as
|
|
4727
|
+
import { applyToPoint as applyToPoint28 } from "transformation-matrix";
|
|
4402
4728
|
function ringToPathD(vertices, transform) {
|
|
4403
4729
|
if (vertices.length === 0) return "";
|
|
4404
4730
|
const transformedVertices = vertices.map((v) => {
|
|
4405
|
-
const [x, y] =
|
|
4731
|
+
const [x, y] = applyToPoint28(transform, [v.x, v.y]);
|
|
4406
4732
|
return { ...v, x, y };
|
|
4407
4733
|
});
|
|
4408
4734
|
let d = `M ${transformedVertices[0].x} ${transformedVertices[0].y}`;
|
|
@@ -4491,7 +4817,7 @@ function createSvgObjectsFromPcbCopperPour(pour, ctx) {
|
|
|
4491
4817
|
const maskOverlayColor = layer === "bottom" ? colorMap2.soldermaskOverCopper.bottom : colorMap2.soldermaskOverCopper.top;
|
|
4492
4818
|
const maskOverlayOpacity = "0.9";
|
|
4493
4819
|
if (pour.shape === "rect") {
|
|
4494
|
-
const [cx, cy] =
|
|
4820
|
+
const [cx, cy] = applyToPoint29(transform, [pour.center.x, pour.center.y]);
|
|
4495
4821
|
const scaledWidth = pour.width * Math.abs(transform.a);
|
|
4496
4822
|
const scaledHeight = pour.height * Math.abs(transform.d);
|
|
4497
4823
|
const svgRotation = -(pour.rotation ?? 0);
|
|
@@ -4543,7 +4869,7 @@ function createSvgObjectsFromPcbCopperPour(pour, ctx) {
|
|
|
4543
4869
|
if (pour.shape === "polygon") {
|
|
4544
4870
|
if (!pour.points || pour.points.length === 0) return [];
|
|
4545
4871
|
const transformedPoints = pour.points.map(
|
|
4546
|
-
(p) =>
|
|
4872
|
+
(p) => applyToPoint29(transform, [p.x, p.y])
|
|
4547
4873
|
);
|
|
4548
4874
|
const pointsString = transformedPoints.map((p) => `${p[0]},${p[1]}`).join(" ");
|
|
4549
4875
|
const copperPolygon = {
|
|
@@ -4681,398 +5007,92 @@ function createSvgObjectsForPcbGrid({
|
|
|
4681
5007
|
stroke: gridLineColor,
|
|
4682
5008
|
"stroke-width": "1",
|
|
4683
5009
|
"shape-rendering": "crispEdges"
|
|
4684
|
-
},
|
|
4685
|
-
children: []
|
|
4686
|
-
}
|
|
4687
|
-
];
|
|
4688
|
-
const defs = {
|
|
4689
|
-
name: "defs",
|
|
4690
|
-
type: "element",
|
|
4691
|
-
value: "",
|
|
4692
|
-
attributes: {},
|
|
4693
|
-
children: [
|
|
4694
|
-
{
|
|
4695
|
-
name: "pattern",
|
|
4696
|
-
type: "element",
|
|
4697
|
-
value: "",
|
|
4698
|
-
attributes: {
|
|
4699
|
-
id: GRID_PATTERN_ID,
|
|
4700
|
-
width: hasMajorGrid ? majorCellSize.toString() : gridCellSize.toString(),
|
|
4701
|
-
height: hasMajorGrid ? majorCellSize.toString() : gridCellSize.toString(),
|
|
4702
|
-
patternUnits: "userSpaceOnUse"
|
|
4703
|
-
},
|
|
4704
|
-
children: patternChildren
|
|
4705
|
-
}
|
|
4706
|
-
]
|
|
4707
|
-
};
|
|
4708
|
-
const rect = {
|
|
4709
|
-
name: "rect",
|
|
4710
|
-
type: "element",
|
|
4711
|
-
value: "",
|
|
4712
|
-
attributes: {
|
|
4713
|
-
x: "0",
|
|
4714
|
-
y: "0",
|
|
4715
|
-
width: svgWidth.toString(),
|
|
4716
|
-
height: svgHeight.toString(),
|
|
4717
|
-
fill: `url(#${GRID_PATTERN_ID})`,
|
|
4718
|
-
"pointer-events": "none",
|
|
4719
|
-
"data-type": "pcb_grid",
|
|
4720
|
-
"data-pcb-layer": "global"
|
|
4721
|
-
},
|
|
4722
|
-
children: []
|
|
4723
|
-
};
|
|
4724
|
-
return { defs, rect };
|
|
4725
|
-
}
|
|
4726
|
-
function createMajorGridPatternChildren(cellSize, majorCellSize, lineColor, majorLineColor) {
|
|
4727
|
-
const children = [];
|
|
4728
|
-
const steps = Math.round(majorCellSize / cellSize);
|
|
4729
|
-
for (let step = 0; step < steps; step += 1) {
|
|
4730
|
-
const offset = Number((step * cellSize).toFixed(6));
|
|
4731
|
-
const offsetString = offset.toString();
|
|
4732
|
-
const color = step === 0 ? majorLineColor : lineColor;
|
|
4733
|
-
const majorSizeString = majorCellSize.toString();
|
|
4734
|
-
children.push({
|
|
4735
|
-
name: "line",
|
|
4736
|
-
type: "element",
|
|
4737
|
-
value: "",
|
|
4738
|
-
attributes: {
|
|
4739
|
-
x1: offsetString,
|
|
4740
|
-
y1: "0",
|
|
4741
|
-
x2: offsetString,
|
|
4742
|
-
y2: majorSizeString,
|
|
4743
|
-
stroke: color,
|
|
4744
|
-
"stroke-width": "1",
|
|
4745
|
-
"shape-rendering": "crispEdges"
|
|
4746
|
-
},
|
|
4747
|
-
children: []
|
|
4748
|
-
});
|
|
4749
|
-
children.push({
|
|
4750
|
-
name: "line",
|
|
4751
|
-
type: "element",
|
|
4752
|
-
value: "",
|
|
4753
|
-
attributes: {
|
|
4754
|
-
x1: "0",
|
|
4755
|
-
y1: offsetString,
|
|
4756
|
-
x2: majorSizeString,
|
|
4757
|
-
y2: offsetString,
|
|
4758
|
-
stroke: color,
|
|
4759
|
-
"stroke-width": "1",
|
|
4760
|
-
"shape-rendering": "crispEdges"
|
|
4761
|
-
},
|
|
4762
|
-
children: []
|
|
4763
|
-
});
|
|
4764
|
-
}
|
|
4765
|
-
return children;
|
|
4766
|
-
}
|
|
4767
|
-
|
|
4768
|
-
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-component.ts
|
|
4769
|
-
import { applyToPoint as applyToPoint30 } from "transformation-matrix";
|
|
4770
|
-
|
|
4771
|
-
// lib/utils/create-pcb-component-anchor-offset-indicators.ts
|
|
4772
|
-
import { applyToPoint as applyToPoint29 } from "transformation-matrix";
|
|
4773
|
-
var OFFSET_THRESHOLD_MM = 0.01;
|
|
4774
|
-
var TICK_SIZE_PX = 4;
|
|
4775
|
-
var LABEL_GAP_PX = 8;
|
|
4776
|
-
var LABEL_FONT_SIZE_PX = 11;
|
|
4777
|
-
var STROKE_WIDTH_PX = 1;
|
|
4778
|
-
var ANCHOR_MARKER_SIZE_PX = 5;
|
|
4779
|
-
var ANCHOR_MARKER_STROKE_WIDTH_PX = 1.5;
|
|
4780
|
-
var COMPONENT_GAP_PX = 15;
|
|
4781
|
-
var COMPONENT_SIDE_GAP_PX = 10;
|
|
4782
|
-
var DISTANCE_MULTIPLIER = 0.2;
|
|
4783
|
-
var MAX_OFFSET_PX = 50;
|
|
4784
|
-
function createAnchorOffsetIndicators(params) {
|
|
4785
|
-
const {
|
|
4786
|
-
groupAnchorPosition,
|
|
4787
|
-
componentPosition,
|
|
4788
|
-
transform,
|
|
4789
|
-
componentWidth = 0,
|
|
4790
|
-
componentHeight = 0
|
|
4791
|
-
} = params;
|
|
4792
|
-
const objects = [];
|
|
4793
|
-
const [screenGroupAnchorX, screenGroupAnchorY] = applyToPoint29(transform, [
|
|
4794
|
-
groupAnchorPosition.x,
|
|
4795
|
-
groupAnchorPosition.y
|
|
4796
|
-
]);
|
|
4797
|
-
const [screenComponentX, screenComponentY] = applyToPoint29(transform, [
|
|
4798
|
-
componentPosition.x,
|
|
4799
|
-
componentPosition.y
|
|
4800
|
-
]);
|
|
4801
|
-
const offsetX = componentPosition.x - groupAnchorPosition.x;
|
|
4802
|
-
const offsetY = componentPosition.y - groupAnchorPosition.y;
|
|
4803
|
-
const scale9 = Math.abs(transform.a);
|
|
4804
|
-
const screenComponentWidth = componentWidth * scale9;
|
|
4805
|
-
const screenComponentHeight = componentHeight * scale9;
|
|
4806
|
-
objects.push(createAnchorMarker(screenGroupAnchorX, screenGroupAnchorY));
|
|
4807
|
-
objects.push({
|
|
4808
|
-
name: "line",
|
|
4809
|
-
type: "element",
|
|
4810
|
-
attributes: {
|
|
4811
|
-
x1: screenGroupAnchorX.toString(),
|
|
4812
|
-
y1: screenGroupAnchorY.toString(),
|
|
4813
|
-
x2: screenComponentX.toString(),
|
|
4814
|
-
y2: screenComponentY.toString(),
|
|
4815
|
-
stroke: "#ffffff",
|
|
4816
|
-
"stroke-width": "0.5",
|
|
4817
|
-
"stroke-dasharray": "3,3",
|
|
4818
|
-
opacity: "0.5",
|
|
4819
|
-
class: "anchor-offset-connector"
|
|
4820
|
-
},
|
|
4821
|
-
children: [],
|
|
4822
|
-
value: ""
|
|
4823
|
-
});
|
|
4824
|
-
objects.push({
|
|
4825
|
-
name: "circle",
|
|
4826
|
-
type: "element",
|
|
4827
|
-
attributes: {
|
|
4828
|
-
cx: screenComponentX.toString(),
|
|
4829
|
-
cy: screenComponentY.toString(),
|
|
4830
|
-
r: "2",
|
|
4831
|
-
fill: "#ffffff",
|
|
4832
|
-
opacity: "0.7",
|
|
4833
|
-
class: "anchor-offset-component-marker"
|
|
4834
|
-
},
|
|
4835
|
-
children: [],
|
|
4836
|
-
value: ""
|
|
4837
|
-
});
|
|
4838
|
-
const yDistance = Math.abs(screenComponentY - screenGroupAnchorY);
|
|
4839
|
-
const xDistance = Math.abs(screenComponentX - screenGroupAnchorX);
|
|
4840
|
-
const totalDistance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
|
|
4841
|
-
const componentHeightOffset = screenComponentHeight / 2 + COMPONENT_GAP_PX;
|
|
4842
|
-
const dynamicOffset = Math.max(
|
|
4843
|
-
componentHeightOffset,
|
|
4844
|
-
Math.min(MAX_OFFSET_PX, totalDistance * DISTANCE_MULTIPLIER)
|
|
4845
|
-
);
|
|
4846
|
-
const horizontalLineY = offsetY > 0 ? screenComponentY - dynamicOffset : screenComponentY + dynamicOffset;
|
|
4847
|
-
const componentWidthOffset = screenComponentWidth / 2 + COMPONENT_SIDE_GAP_PX;
|
|
4848
|
-
const verticalLineX = offsetX > 0 ? screenComponentX + componentWidthOffset : screenComponentX - componentWidthOffset;
|
|
4849
|
-
if (Math.abs(offsetX) > OFFSET_THRESHOLD_MM) {
|
|
4850
|
-
objects.push(
|
|
4851
|
-
...createHorizontalDimension({
|
|
4852
|
-
startX: screenGroupAnchorX,
|
|
4853
|
-
endX: screenComponentX,
|
|
4854
|
-
y: horizontalLineY,
|
|
4855
|
-
offsetMm: offsetX,
|
|
4856
|
-
offsetY
|
|
4857
|
-
})
|
|
4858
|
-
);
|
|
4859
|
-
}
|
|
4860
|
-
if (Math.abs(offsetY) > OFFSET_THRESHOLD_MM) {
|
|
4861
|
-
objects.push(
|
|
4862
|
-
...createVerticalDimension({
|
|
4863
|
-
x: verticalLineX,
|
|
4864
|
-
startY: screenGroupAnchorY,
|
|
4865
|
-
endY: screenComponentY,
|
|
4866
|
-
offsetMm: -offsetY,
|
|
4867
|
-
offsetX
|
|
4868
|
-
})
|
|
4869
|
-
);
|
|
4870
|
-
}
|
|
4871
|
-
return objects;
|
|
4872
|
-
}
|
|
4873
|
-
function createAnchorMarker(x, y) {
|
|
4874
|
-
return {
|
|
4875
|
-
name: "g",
|
|
5010
|
+
},
|
|
5011
|
+
children: []
|
|
5012
|
+
}
|
|
5013
|
+
];
|
|
5014
|
+
const defs = {
|
|
5015
|
+
name: "defs",
|
|
4876
5016
|
type: "element",
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
"data-type": "anchor_offset_marker"
|
|
4880
|
-
},
|
|
5017
|
+
value: "",
|
|
5018
|
+
attributes: {},
|
|
4881
5019
|
children: [
|
|
4882
5020
|
{
|
|
4883
|
-
name: "
|
|
4884
|
-
type: "element",
|
|
4885
|
-
attributes: {
|
|
4886
|
-
x1: x.toString(),
|
|
4887
|
-
y1: (y - ANCHOR_MARKER_SIZE_PX).toString(),
|
|
4888
|
-
x2: x.toString(),
|
|
4889
|
-
y2: (y + ANCHOR_MARKER_SIZE_PX).toString(),
|
|
4890
|
-
stroke: "#ffffff",
|
|
4891
|
-
"stroke-width": ANCHOR_MARKER_STROKE_WIDTH_PX.toString(),
|
|
4892
|
-
"stroke-linecap": "round"
|
|
4893
|
-
},
|
|
4894
|
-
children: [],
|
|
4895
|
-
value: ""
|
|
4896
|
-
},
|
|
4897
|
-
{
|
|
4898
|
-
name: "line",
|
|
5021
|
+
name: "pattern",
|
|
4899
5022
|
type: "element",
|
|
5023
|
+
value: "",
|
|
4900
5024
|
attributes: {
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
stroke: "#ffffff",
|
|
4906
|
-
"stroke-width": ANCHOR_MARKER_STROKE_WIDTH_PX.toString(),
|
|
4907
|
-
"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"
|
|
4908
5029
|
},
|
|
4909
|
-
children:
|
|
4910
|
-
value: ""
|
|
5030
|
+
children: patternChildren
|
|
4911
5031
|
}
|
|
4912
|
-
]
|
|
4913
|
-
value: ""
|
|
5032
|
+
]
|
|
4914
5033
|
};
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
startX,
|
|
4918
|
-
endX,
|
|
4919
|
-
y,
|
|
4920
|
-
offsetMm,
|
|
4921
|
-
offsetY
|
|
4922
|
-
}) {
|
|
4923
|
-
const objects = [];
|
|
4924
|
-
objects.push({
|
|
4925
|
-
name: "line",
|
|
4926
|
-
type: "element",
|
|
4927
|
-
attributes: {
|
|
4928
|
-
x1: startX.toString(),
|
|
4929
|
-
y1: y.toString(),
|
|
4930
|
-
x2: endX.toString(),
|
|
4931
|
-
y2: y.toString(),
|
|
4932
|
-
stroke: "#ffffff",
|
|
4933
|
-
"stroke-width": STROKE_WIDTH_PX.toString(),
|
|
4934
|
-
class: "anchor-offset-dimension-x"
|
|
4935
|
-
},
|
|
4936
|
-
children: [],
|
|
4937
|
-
value: ""
|
|
4938
|
-
});
|
|
4939
|
-
objects.push({
|
|
4940
|
-
name: "line",
|
|
4941
|
-
type: "element",
|
|
4942
|
-
attributes: {
|
|
4943
|
-
x1: startX.toString(),
|
|
4944
|
-
y1: (y - TICK_SIZE_PX).toString(),
|
|
4945
|
-
x2: startX.toString(),
|
|
4946
|
-
y2: (y + TICK_SIZE_PX).toString(),
|
|
4947
|
-
stroke: "#ffffff",
|
|
4948
|
-
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
4949
|
-
},
|
|
4950
|
-
children: [],
|
|
4951
|
-
value: ""
|
|
4952
|
-
});
|
|
4953
|
-
objects.push({
|
|
4954
|
-
name: "line",
|
|
4955
|
-
type: "element",
|
|
4956
|
-
attributes: {
|
|
4957
|
-
x1: endX.toString(),
|
|
4958
|
-
y1: (y - TICK_SIZE_PX).toString(),
|
|
4959
|
-
x2: endX.toString(),
|
|
4960
|
-
y2: (y + TICK_SIZE_PX).toString(),
|
|
4961
|
-
stroke: "#ffffff",
|
|
4962
|
-
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
4963
|
-
},
|
|
4964
|
-
children: [],
|
|
4965
|
-
value: ""
|
|
4966
|
-
});
|
|
4967
|
-
const midX = (startX + endX) / 2;
|
|
4968
|
-
const labelY = offsetY > 0 ? y - TICK_SIZE_PX - LABEL_GAP_PX : y + TICK_SIZE_PX + LABEL_GAP_PX;
|
|
4969
|
-
objects.push({
|
|
4970
|
-
name: "text",
|
|
5034
|
+
const rect = {
|
|
5035
|
+
name: "rect",
|
|
4971
5036
|
type: "element",
|
|
5037
|
+
value: "",
|
|
4972
5038
|
attributes: {
|
|
4973
|
-
x:
|
|
4974
|
-
y:
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
"
|
|
4979
|
-
"
|
|
4980
|
-
|
|
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"
|
|
4981
5047
|
},
|
|
4982
|
-
children: [
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
value: `X: ${offsetMm.toFixed(2)}mm`,
|
|
4986
|
-
name: "",
|
|
4987
|
-
attributes: {},
|
|
4988
|
-
children: []
|
|
4989
|
-
}
|
|
4990
|
-
],
|
|
4991
|
-
value: ""
|
|
4992
|
-
});
|
|
4993
|
-
return objects;
|
|
5048
|
+
children: []
|
|
5049
|
+
};
|
|
5050
|
+
return { defs, rect };
|
|
4994
5051
|
}
|
|
4995
|
-
function
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
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
|
-
attributes: {
|
|
5036
|
-
x1: (x - TICK_SIZE_PX).toString(),
|
|
5037
|
-
y1: endY.toString(),
|
|
5038
|
-
x2: (x + TICK_SIZE_PX).toString(),
|
|
5039
|
-
y2: endY.toString(),
|
|
5040
|
-
stroke: "#ffffff",
|
|
5041
|
-
"stroke-width": STROKE_WIDTH_PX.toString()
|
|
5042
|
-
},
|
|
5043
|
-
children: [],
|
|
5044
|
-
value: ""
|
|
5045
|
-
});
|
|
5046
|
-
const midY = (startY + endY) / 2;
|
|
5047
|
-
const labelX = offsetX < 0 ? x - TICK_SIZE_PX - 4 : x + TICK_SIZE_PX + 4;
|
|
5048
|
-
objects.push({
|
|
5049
|
-
name: "text",
|
|
5050
|
-
type: "element",
|
|
5051
|
-
attributes: {
|
|
5052
|
-
x: labelX.toString(),
|
|
5053
|
-
y: midY.toString(),
|
|
5054
|
-
fill: "#ffffff",
|
|
5055
|
-
"font-size": LABEL_FONT_SIZE_PX.toString(),
|
|
5056
|
-
"font-family": "Arial, sans-serif",
|
|
5057
|
-
"text-anchor": offsetX < 0 ? "end" : "start",
|
|
5058
|
-
"dominant-baseline": "middle",
|
|
5059
|
-
class: "anchor-offset-label"
|
|
5060
|
-
},
|
|
5061
|
-
children: [
|
|
5062
|
-
{
|
|
5063
|
-
type: "text",
|
|
5064
|
-
value: `Y: ${offsetMm.toFixed(2)}mm`,
|
|
5065
|
-
name: "",
|
|
5066
|
-
attributes: {},
|
|
5067
|
-
children: []
|
|
5068
|
-
}
|
|
5069
|
-
],
|
|
5070
|
-
value: ""
|
|
5071
|
-
});
|
|
5072
|
-
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;
|
|
5073
5092
|
}
|
|
5074
5093
|
|
|
5075
5094
|
// lib/pcb/svg-object-fns/create-svg-objects-from-pcb-component.ts
|
|
5095
|
+
import { applyToPoint as applyToPoint30 } from "transformation-matrix";
|
|
5076
5096
|
function createSvgObjectsFromPcbComponent(component, ctx) {
|
|
5077
5097
|
const { transform, circuitJson } = ctx;
|
|
5078
5098
|
const { center, width, height, rotation = 0 } = component;
|
|
@@ -5220,7 +5240,7 @@ function getSoftwareUsedString(circuitJson) {
|
|
|
5220
5240
|
var package_default = {
|
|
5221
5241
|
name: "circuit-to-svg",
|
|
5222
5242
|
type: "module",
|
|
5223
|
-
version: "0.0.
|
|
5243
|
+
version: "0.0.283",
|
|
5224
5244
|
description: "Convert Circuit JSON to SVG",
|
|
5225
5245
|
main: "dist/index.js",
|
|
5226
5246
|
files: [
|
|
@@ -5244,12 +5264,12 @@ var package_default = {
|
|
|
5244
5264
|
"bun-match-svg": "^0.0.12",
|
|
5245
5265
|
esbuild: "^0.20.2",
|
|
5246
5266
|
"performance-now": "^2.1.0",
|
|
5247
|
-
"circuit-json": "^0.0.
|
|
5267
|
+
"circuit-json": "^0.0.327",
|
|
5248
5268
|
react: "19.1.0",
|
|
5249
5269
|
"react-cosmos": "7.0.0",
|
|
5250
5270
|
"react-cosmos-plugin-vite": "7.0.0",
|
|
5251
5271
|
"react-dom": "19.1.0",
|
|
5252
|
-
tscircuit: "^0.0.
|
|
5272
|
+
tscircuit: "^0.0.1018",
|
|
5253
5273
|
tsup: "^8.0.2",
|
|
5254
5274
|
typescript: "^5.4.5",
|
|
5255
5275
|
"vite-tsconfig-paths": "^5.0.1"
|