@tscircuit/3d-viewer 0.0.494 → 0.0.496
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 +397 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30825,7 +30825,7 @@ import * as THREE16 from "three";
|
|
|
30825
30825
|
// package.json
|
|
30826
30826
|
var package_default = {
|
|
30827
30827
|
name: "@tscircuit/3d-viewer",
|
|
30828
|
-
version: "0.0.
|
|
30828
|
+
version: "0.0.495",
|
|
30829
30829
|
main: "./dist/index.js",
|
|
30830
30830
|
module: "./dist/index.js",
|
|
30831
30831
|
type: "module",
|
|
@@ -32663,6 +32663,149 @@ var platedHole = (plated_hole, ctx, options = {}) => {
|
|
|
32663
32663
|
clipGeom
|
|
32664
32664
|
);
|
|
32665
32665
|
return (0, import_colors2.colorize)(colors.copper, finalCopper);
|
|
32666
|
+
} else if (plated_hole.shape === "rotated_pill_hole_with_rect_pad") {
|
|
32667
|
+
if (plated_hole.hole_shape && plated_hole.hole_shape !== "rotated_pill" || plated_hole.pad_shape && plated_hole.pad_shape !== "rect") {
|
|
32668
|
+
throw new Error(
|
|
32669
|
+
`Invalid hole_shape or pad_shape for rotated_pill_hole_with_rect_pad`
|
|
32670
|
+
);
|
|
32671
|
+
}
|
|
32672
|
+
const holeOffsetX = plated_hole.hole_offset_x || 0;
|
|
32673
|
+
const holeOffsetY = plated_hole.hole_offset_y || 0;
|
|
32674
|
+
const holeWidth = plated_hole.hole_width;
|
|
32675
|
+
const holeHeight = plated_hole.hole_height;
|
|
32676
|
+
const isHorizontal = holeWidth >= holeHeight;
|
|
32677
|
+
const longDim = isHorizontal ? holeWidth : holeHeight;
|
|
32678
|
+
const shortDim = isHorizontal ? holeHeight : holeWidth;
|
|
32679
|
+
const holeRadius = shortDim / 2;
|
|
32680
|
+
const rectLength = Math.abs(longDim - shortDim);
|
|
32681
|
+
const padWidth = plated_hole.rect_pad_width || holeWidth + 0.2;
|
|
32682
|
+
const padHeight = plated_hole.rect_pad_height || holeHeight + 0.2;
|
|
32683
|
+
const rectBorderRadius = extractRectBorderRadius(plated_hole);
|
|
32684
|
+
const barrelMargin = 0.03;
|
|
32685
|
+
const holeRotationRadians = (plated_hole.hole_ccw_rotation || 0) * Math.PI / 180;
|
|
32686
|
+
const rectRotationRadians = (plated_hole.rect_ccw_rotation || 0) * Math.PI / 180;
|
|
32687
|
+
const rotateHole = (geom) => {
|
|
32688
|
+
const rotatedOffsetX = holeOffsetX * Math.cos(holeRotationRadians) - holeOffsetY * Math.sin(holeRotationRadians);
|
|
32689
|
+
const rotatedOffsetY = holeOffsetX * Math.sin(holeRotationRadians) + holeOffsetY * Math.cos(holeRotationRadians);
|
|
32690
|
+
const rotated = (0, import_transforms4.rotate)([0, 0, holeRotationRadians], geom);
|
|
32691
|
+
return (0, import_transforms4.translate)(
|
|
32692
|
+
[plated_hole.x + rotatedOffsetX, plated_hole.y + rotatedOffsetY, 0],
|
|
32693
|
+
rotated
|
|
32694
|
+
);
|
|
32695
|
+
};
|
|
32696
|
+
const rotateRectPad = (geom) => {
|
|
32697
|
+
if (!rectRotationRadians) return geom;
|
|
32698
|
+
const toOrigin = (0, import_transforms4.translate)([-plated_hole.x, -plated_hole.y, 0], geom);
|
|
32699
|
+
const rotated = (0, import_transforms4.rotate)([0, 0, rectRotationRadians], toOrigin);
|
|
32700
|
+
return (0, import_transforms4.translate)([plated_hole.x, plated_hole.y, 0], rotated);
|
|
32701
|
+
};
|
|
32702
|
+
const barrel = rotateHole(
|
|
32703
|
+
(0, import_booleans2.union)(
|
|
32704
|
+
(0, import_primitives4.cuboid)({
|
|
32705
|
+
center: [0, 0, 0],
|
|
32706
|
+
size: isHorizontal ? [
|
|
32707
|
+
rectLength + 2 * barrelMargin,
|
|
32708
|
+
shortDim + 2 * barrelMargin,
|
|
32709
|
+
copperSpan
|
|
32710
|
+
] : [
|
|
32711
|
+
shortDim + 2 * barrelMargin,
|
|
32712
|
+
rectLength + 2 * barrelMargin,
|
|
32713
|
+
copperSpan
|
|
32714
|
+
]
|
|
32715
|
+
}),
|
|
32716
|
+
(0, import_primitives4.cylinder)({
|
|
32717
|
+
center: isHorizontal ? [-rectLength / 2, 0, 0] : [0, -rectLength / 2, 0],
|
|
32718
|
+
radius: holeRadius + barrelMargin,
|
|
32719
|
+
height: copperSpan
|
|
32720
|
+
}),
|
|
32721
|
+
(0, import_primitives4.cylinder)({
|
|
32722
|
+
center: isHorizontal ? [rectLength / 2, 0, 0] : [0, rectLength / 2, 0],
|
|
32723
|
+
radius: holeRadius + barrelMargin,
|
|
32724
|
+
height: copperSpan
|
|
32725
|
+
})
|
|
32726
|
+
)
|
|
32727
|
+
);
|
|
32728
|
+
const holeCut = rotateHole(
|
|
32729
|
+
(0, import_booleans2.union)(
|
|
32730
|
+
(0, import_primitives4.cuboid)({
|
|
32731
|
+
center: [0, 0, 0],
|
|
32732
|
+
size: isHorizontal ? [rectLength, shortDim, throughDrillHeight * 1.1] : [shortDim, rectLength, throughDrillHeight * 1.1]
|
|
32733
|
+
}),
|
|
32734
|
+
(0, import_primitives4.cylinder)({
|
|
32735
|
+
center: isHorizontal ? [-rectLength / 2, 0, 0] : [0, -rectLength / 2, 0],
|
|
32736
|
+
radius: holeRadius,
|
|
32737
|
+
height: throughDrillHeight * 1.1
|
|
32738
|
+
}),
|
|
32739
|
+
(0, import_primitives4.cylinder)({
|
|
32740
|
+
center: isHorizontal ? [rectLength / 2, 0, 0] : [0, rectLength / 2, 0],
|
|
32741
|
+
radius: holeRadius,
|
|
32742
|
+
height: throughDrillHeight * 1.1
|
|
32743
|
+
})
|
|
32744
|
+
)
|
|
32745
|
+
);
|
|
32746
|
+
const copperTopPad = rotateRectPad(
|
|
32747
|
+
createRectPadGeom({
|
|
32748
|
+
width: padWidth,
|
|
32749
|
+
height: padHeight,
|
|
32750
|
+
thickness: platedHoleLipHeight,
|
|
32751
|
+
center: [plated_hole.x, plated_hole.y, topSurfaceZ],
|
|
32752
|
+
borderRadius: rectBorderRadius
|
|
32753
|
+
})
|
|
32754
|
+
);
|
|
32755
|
+
const copperBottomPad = rotateRectPad(
|
|
32756
|
+
createRectPadGeom({
|
|
32757
|
+
width: padWidth,
|
|
32758
|
+
height: padHeight,
|
|
32759
|
+
thickness: platedHoleLipHeight,
|
|
32760
|
+
center: [plated_hole.x, plated_hole.y, bottomSurfaceZ],
|
|
32761
|
+
borderRadius: rectBorderRadius
|
|
32762
|
+
})
|
|
32763
|
+
);
|
|
32764
|
+
const copperFill = rotateRectPad(
|
|
32765
|
+
(() => {
|
|
32766
|
+
const height10 = Math.max(copperSpan - platedHoleLipHeight * 2, M);
|
|
32767
|
+
const topPadBottom = topSurfaceZ;
|
|
32768
|
+
const bottomPadTop = bottomSurfaceZ;
|
|
32769
|
+
const centerZ = (topPadBottom + bottomPadTop) / 2;
|
|
32770
|
+
const rect2d = (0, import_primitives4.roundedRectangle)({
|
|
32771
|
+
size: [padWidth, padHeight],
|
|
32772
|
+
roundRadius: rectBorderRadius || 0,
|
|
32773
|
+
segments: RECT_PAD_SEGMENTS
|
|
32774
|
+
});
|
|
32775
|
+
const extruded = (0, import_extrusions3.extrudeLinear)({ height: height10 }, rect2d);
|
|
32776
|
+
return (0, import_transforms4.translate)(
|
|
32777
|
+
[plated_hole.x, plated_hole.y, centerZ - height10 / 2],
|
|
32778
|
+
extruded
|
|
32779
|
+
);
|
|
32780
|
+
})()
|
|
32781
|
+
);
|
|
32782
|
+
const copperTopPadCut = (0, import_booleans2.subtract)(copperTopPad, holeCut);
|
|
32783
|
+
const copperBottomPadCut = (0, import_booleans2.subtract)(copperBottomPad, holeCut);
|
|
32784
|
+
const copperFillCut = (0, import_booleans2.subtract)(copperFill, holeCut);
|
|
32785
|
+
const barrelHoleCut = rotateHole(
|
|
32786
|
+
(0, import_booleans2.union)(
|
|
32787
|
+
(0, import_primitives4.cuboid)({
|
|
32788
|
+
center: [0, 0, 0],
|
|
32789
|
+
size: isHorizontal ? [rectLength - 2 * M, shortDim - 2 * M, throughDrillHeight * 1.1] : [shortDim - 2 * M, rectLength - 2 * M, throughDrillHeight * 1.1]
|
|
32790
|
+
}),
|
|
32791
|
+
(0, import_primitives4.cylinder)({
|
|
32792
|
+
center: isHorizontal ? [-rectLength / 2, 0, 0] : [0, -rectLength / 2, 0],
|
|
32793
|
+
radius: holeRadius - M,
|
|
32794
|
+
height: throughDrillHeight * 1.1
|
|
32795
|
+
}),
|
|
32796
|
+
(0, import_primitives4.cylinder)({
|
|
32797
|
+
center: isHorizontal ? [rectLength / 2, 0, 0] : [0, rectLength / 2, 0],
|
|
32798
|
+
radius: holeRadius - M,
|
|
32799
|
+
height: throughDrillHeight * 1.1
|
|
32800
|
+
})
|
|
32801
|
+
)
|
|
32802
|
+
);
|
|
32803
|
+
const barrelWithHole = (0, import_booleans2.subtract)(barrel, barrelHoleCut);
|
|
32804
|
+
const finalCopper = maybeClip(
|
|
32805
|
+
(0, import_booleans2.union)(copperTopPadCut, copperBottomPadCut, copperFillCut, barrelWithHole),
|
|
32806
|
+
clipGeom
|
|
32807
|
+
);
|
|
32808
|
+
return (0, import_colors2.colorize)(colors.copper, finalCopper);
|
|
32666
32809
|
} else if (plated_hole.shape === "hole_with_polygon_pad") {
|
|
32667
32810
|
const padOutline = plated_hole.pad_outline;
|
|
32668
32811
|
if (!Array.isArray(padOutline) || padOutline.length < 3) {
|
|
@@ -33313,6 +33456,53 @@ var BoardGeomBuilder = class {
|
|
|
33313
33456
|
clipGeom: this.boardClipGeom
|
|
33314
33457
|
});
|
|
33315
33458
|
this.platedHoleGeoms.push(platedHoleGeom);
|
|
33459
|
+
} else if (ph.shape === "rotated_pill_hole_with_rect_pad") {
|
|
33460
|
+
if (ph.hole_shape && ph.hole_shape !== "rotated_pill" || ph.pad_shape && ph.pad_shape !== "rect") {
|
|
33461
|
+
return;
|
|
33462
|
+
}
|
|
33463
|
+
const rphHoleWidth = ph.hole_width;
|
|
33464
|
+
const rphHoleHeight = ph.hole_height;
|
|
33465
|
+
const rphIsHorizontal = rphHoleWidth >= rphHoleHeight;
|
|
33466
|
+
const rphLongDim = rphIsHorizontal ? rphHoleWidth : rphHoleHeight;
|
|
33467
|
+
const rphShortDim = rphIsHorizontal ? rphHoleHeight : rphHoleWidth;
|
|
33468
|
+
const rphHoleRadius = rphShortDim / 2;
|
|
33469
|
+
const rphRectLength = Math.abs(rphLongDim - rphShortDim);
|
|
33470
|
+
const rphHoleOffsetX = ph.hole_offset_x || 0;
|
|
33471
|
+
const rphHoleOffsetY = ph.hole_offset_y || 0;
|
|
33472
|
+
let rphPillHole = (0, import_booleans5.union)(
|
|
33473
|
+
(0, import_primitives7.cuboid)({
|
|
33474
|
+
center: [0, 0, 0],
|
|
33475
|
+
size: rphIsHorizontal ? [rphRectLength, rphShortDim, this.ctx.pcbThickness * 1.5] : [rphShortDim, rphRectLength, this.ctx.pcbThickness * 1.5]
|
|
33476
|
+
}),
|
|
33477
|
+
(0, import_primitives7.cylinder)({
|
|
33478
|
+
center: rphIsHorizontal ? [-rphRectLength / 2, 0, 0] : [0, -rphRectLength / 2, 0],
|
|
33479
|
+
radius: rphHoleRadius,
|
|
33480
|
+
height: this.ctx.pcbThickness * 1.5
|
|
33481
|
+
}),
|
|
33482
|
+
(0, import_primitives7.cylinder)({
|
|
33483
|
+
center: rphIsHorizontal ? [rphRectLength / 2, 0, 0] : [0, rphRectLength / 2, 0],
|
|
33484
|
+
radius: rphHoleRadius,
|
|
33485
|
+
height: this.ctx.pcbThickness * 1.5
|
|
33486
|
+
})
|
|
33487
|
+
);
|
|
33488
|
+
const rphHoleRotationRadians = (ph.hole_ccw_rotation || 0) * Math.PI / 180;
|
|
33489
|
+
const rphRotatedOffsetX = rphHoleOffsetX * Math.cos(rphHoleRotationRadians) - rphHoleOffsetY * Math.sin(rphHoleRotationRadians);
|
|
33490
|
+
const rphRotatedOffsetY = rphHoleOffsetX * Math.sin(rphHoleRotationRadians) + rphHoleOffsetY * Math.cos(rphHoleRotationRadians);
|
|
33491
|
+
rphPillHole = (0, import_transforms6.rotateZ)(rphHoleRotationRadians, rphPillHole);
|
|
33492
|
+
const pillHole = (0, import_transforms6.translate)(
|
|
33493
|
+
[ph.x + rphRotatedOffsetX, ph.y + rphRotatedOffsetY, 0],
|
|
33494
|
+
rphPillHole
|
|
33495
|
+
);
|
|
33496
|
+
if (!opts.dontCutBoard) {
|
|
33497
|
+
this.boardGeom = (0, import_booleans5.subtract)(this.boardGeom, pillHole);
|
|
33498
|
+
}
|
|
33499
|
+
this.padGeoms = this.padGeoms.map(
|
|
33500
|
+
(pg) => (0, import_colors3.colorize)(colors.copper, (0, import_booleans5.subtract)(pg, pillHole))
|
|
33501
|
+
);
|
|
33502
|
+
const platedHoleGeom = platedHole(ph, this.ctx, {
|
|
33503
|
+
clipGeom: this.boardClipGeom
|
|
33504
|
+
});
|
|
33505
|
+
this.platedHoleGeoms.push(platedHoleGeom);
|
|
33316
33506
|
} else if (ph.shape === "hole_with_polygon_pad") {
|
|
33317
33507
|
const padOutline = ph.pad_outline;
|
|
33318
33508
|
if (!Array.isArray(padOutline) || padOutline.length < 3) {
|
|
@@ -33869,8 +34059,8 @@ import * as THREE24 from "three";
|
|
|
33869
34059
|
import { su as su9 } from "@tscircuit/circuit-json-util";
|
|
33870
34060
|
|
|
33871
34061
|
// src/utils/soldermask-texture.ts
|
|
33872
|
-
import * as THREE19 from "three";
|
|
33873
34062
|
import { su as su5 } from "@tscircuit/circuit-json-util";
|
|
34063
|
+
import * as THREE19 from "three";
|
|
33874
34064
|
|
|
33875
34065
|
// node_modules/@tscircuit/math-utils/dist/chunk-5N7UJNVK.js
|
|
33876
34066
|
var getBoundsFromPoints = (points) => {
|
|
@@ -34191,6 +34381,22 @@ function createSoldermaskTextureForLayer({
|
|
|
34191
34381
|
ctx.arc(adjustedCanvasX, adjustedCanvasY, canvasRadius, 0, 2 * Math.PI);
|
|
34192
34382
|
ctx.fill();
|
|
34193
34383
|
}
|
|
34384
|
+
if (hole.pad_outline && hole.pad_outline.length >= 3) {
|
|
34385
|
+
ctx.beginPath();
|
|
34386
|
+
hole.pad_outline.forEach(
|
|
34387
|
+
(point2, index2) => {
|
|
34388
|
+
const px = canvasXFromPcb(hole.x + point2.x);
|
|
34389
|
+
const py = canvasYFromPcb(hole.y + point2.y);
|
|
34390
|
+
if (index2 === 0) {
|
|
34391
|
+
ctx.moveTo(px, py);
|
|
34392
|
+
} else {
|
|
34393
|
+
ctx.lineTo(px, py);
|
|
34394
|
+
}
|
|
34395
|
+
}
|
|
34396
|
+
);
|
|
34397
|
+
ctx.closePath();
|
|
34398
|
+
ctx.fill();
|
|
34399
|
+
}
|
|
34194
34400
|
} else if (hole.shape === "circular_hole_with_rect_pad") {
|
|
34195
34401
|
const padWidth = (hole.rect_pad_width ?? hole.hole_diameter ?? 0) * traceTextureResolution;
|
|
34196
34402
|
const padHeight = (hole.rect_pad_height ?? hole.hole_diameter ?? 0) * traceTextureResolution;
|
|
@@ -34254,6 +34460,42 @@ function createSoldermaskTextureForLayer({
|
|
|
34254
34460
|
);
|
|
34255
34461
|
ctx.fill();
|
|
34256
34462
|
}
|
|
34463
|
+
} else if (hole.shape === "rotated_pill_hole_with_rect_pad") {
|
|
34464
|
+
const padWidth = (hole.rect_pad_width ?? hole.hole_width ?? 0) * traceTextureResolution;
|
|
34465
|
+
const padHeight = (hole.rect_pad_height ?? hole.hole_height ?? 0) * traceTextureResolution;
|
|
34466
|
+
const rawRadius = extractRectBorderRadius(hole);
|
|
34467
|
+
const borderRadius = clampRectBorderRadius(
|
|
34468
|
+
hole.rect_pad_width ?? hole.hole_width ?? 0,
|
|
34469
|
+
hole.rect_pad_height ?? hole.hole_height ?? 0,
|
|
34470
|
+
rawRadius
|
|
34471
|
+
) * traceTextureResolution;
|
|
34472
|
+
const rectCcwRotationDeg = hole.rect_ccw_rotation || 0;
|
|
34473
|
+
const rectRotation = -rectCcwRotationDeg;
|
|
34474
|
+
if (rectRotation) {
|
|
34475
|
+
ctx.save();
|
|
34476
|
+
ctx.translate(canvasX, canvasY);
|
|
34477
|
+
ctx.rotate(rectRotation * Math.PI / 180);
|
|
34478
|
+
ctx.beginPath();
|
|
34479
|
+
ctx.roundRect(
|
|
34480
|
+
-padWidth / 2,
|
|
34481
|
+
-padHeight / 2,
|
|
34482
|
+
padWidth,
|
|
34483
|
+
padHeight,
|
|
34484
|
+
borderRadius
|
|
34485
|
+
);
|
|
34486
|
+
ctx.fill();
|
|
34487
|
+
ctx.restore();
|
|
34488
|
+
} else {
|
|
34489
|
+
ctx.beginPath();
|
|
34490
|
+
ctx.roundRect(
|
|
34491
|
+
canvasX - padWidth / 2,
|
|
34492
|
+
canvasY - padHeight / 2,
|
|
34493
|
+
padWidth,
|
|
34494
|
+
padHeight,
|
|
34495
|
+
borderRadius
|
|
34496
|
+
);
|
|
34497
|
+
ctx.fill();
|
|
34498
|
+
}
|
|
34257
34499
|
}
|
|
34258
34500
|
});
|
|
34259
34501
|
const pcbHoles = su5(circuitJson).pcb_hole.list();
|
|
@@ -35200,6 +35442,31 @@ function createTraceTextureForLayer({
|
|
|
35200
35442
|
ctx.beginPath();
|
|
35201
35443
|
ctx.arc(canvasX, canvasY, canvasRadius, 0, 2 * Math.PI, false);
|
|
35202
35444
|
ctx.fill();
|
|
35445
|
+
} else if (ph.layers.includes(layer) && ph.shape === "rotated_pill_hole_with_rect_pad") {
|
|
35446
|
+
const canvasX = (ph.x - boardOutlineBounds.minX) * traceTextureResolution;
|
|
35447
|
+
const canvasY = (boardOutlineBounds.maxY - ph.y) * traceTextureResolution;
|
|
35448
|
+
const padWidth = (ph.rect_pad_width ?? ph.hole_width ?? 0) * traceTextureResolution;
|
|
35449
|
+
const padHeight = (ph.rect_pad_height ?? ph.hole_height ?? 0) * traceTextureResolution;
|
|
35450
|
+
const rectCcwRotationDeg = ph.rect_ccw_rotation || 0;
|
|
35451
|
+
const rectRotation = -rectCcwRotationDeg;
|
|
35452
|
+
if (rectRotation) {
|
|
35453
|
+
ctx.save();
|
|
35454
|
+
ctx.translate(canvasX, canvasY);
|
|
35455
|
+
ctx.rotate(rectRotation * Math.PI / 180);
|
|
35456
|
+
ctx.beginPath();
|
|
35457
|
+
ctx.rect(-padWidth / 2, -padHeight / 2, padWidth, padHeight);
|
|
35458
|
+
ctx.fill();
|
|
35459
|
+
ctx.restore();
|
|
35460
|
+
} else {
|
|
35461
|
+
ctx.beginPath();
|
|
35462
|
+
ctx.rect(
|
|
35463
|
+
canvasX - padWidth / 2,
|
|
35464
|
+
canvasY - padHeight / 2,
|
|
35465
|
+
padWidth,
|
|
35466
|
+
padHeight
|
|
35467
|
+
);
|
|
35468
|
+
ctx.fill();
|
|
35469
|
+
}
|
|
35203
35470
|
}
|
|
35204
35471
|
});
|
|
35205
35472
|
ctx.globalCompositeOperation = "source-over";
|
|
@@ -36759,6 +37026,134 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
36759
37026
|
geometry: threeGeom,
|
|
36760
37027
|
color: COPPER_COLOR
|
|
36761
37028
|
});
|
|
37029
|
+
} else if (ph.shape === "rotated_pill_hole_with_rect_pad") {
|
|
37030
|
+
if (ph.hole_shape && ph.hole_shape !== "rotated_pill" || ph.pad_shape && ph.pad_shape !== "rect") {
|
|
37031
|
+
return;
|
|
37032
|
+
}
|
|
37033
|
+
const holeW = ph.hole_width;
|
|
37034
|
+
const holeH = ph.hole_height;
|
|
37035
|
+
const holeOffsetX = ph.hole_offset_x || 0;
|
|
37036
|
+
const holeOffsetY = ph.hole_offset_y || 0;
|
|
37037
|
+
const padWidth = ph.rect_pad_width;
|
|
37038
|
+
const padHeight = ph.rect_pad_height;
|
|
37039
|
+
const rectBorderRadius = extractRectBorderRadius(ph);
|
|
37040
|
+
const padThickness = DEFAULT_SMT_PAD_THICKNESS;
|
|
37041
|
+
const drillW = holeW + 2 * MANIFOLD_Z_OFFSET;
|
|
37042
|
+
const drillH = holeH + 2 * MANIFOLD_Z_OFFSET;
|
|
37043
|
+
const drillDepth = pcbThickness * 1.2;
|
|
37044
|
+
let boardPillDrillOp = createPillOp(drillW, drillH, drillDepth).translate(
|
|
37045
|
+
[holeOffsetX, holeOffsetY, 0]
|
|
37046
|
+
);
|
|
37047
|
+
if (ph.hole_ccw_rotation) {
|
|
37048
|
+
const rotatedDrill = boardPillDrillOp.rotate([
|
|
37049
|
+
0,
|
|
37050
|
+
0,
|
|
37051
|
+
ph.hole_ccw_rotation
|
|
37052
|
+
]);
|
|
37053
|
+
manifoldInstancesForCleanup.push(rotatedDrill);
|
|
37054
|
+
boardPillDrillOp = rotatedDrill;
|
|
37055
|
+
}
|
|
37056
|
+
const translatedBoardPillDrill = boardPillDrillOp.translate([
|
|
37057
|
+
ph.x,
|
|
37058
|
+
ph.y,
|
|
37059
|
+
0
|
|
37060
|
+
]);
|
|
37061
|
+
manifoldInstancesForCleanup.push(translatedBoardPillDrill);
|
|
37062
|
+
platedHoleBoardDrills.push(translatedBoardPillDrill);
|
|
37063
|
+
let mainFill = createRoundedRectPrism({
|
|
37064
|
+
Manifold,
|
|
37065
|
+
width: padWidth,
|
|
37066
|
+
height: padHeight,
|
|
37067
|
+
thickness: pcbThickness - 2 * padThickness - 2 * BOARD_SURFACE_OFFSET.copper + 0.1,
|
|
37068
|
+
// Fill between pads
|
|
37069
|
+
borderRadius: rectBorderRadius
|
|
37070
|
+
});
|
|
37071
|
+
manifoldInstancesForCleanup.push(mainFill);
|
|
37072
|
+
if (ph.rect_ccw_rotation) {
|
|
37073
|
+
const rotatedMainFill = mainFill.rotate([0, 0, ph.rect_ccw_rotation]);
|
|
37074
|
+
manifoldInstancesForCleanup.push(rotatedMainFill);
|
|
37075
|
+
mainFill = rotatedMainFill;
|
|
37076
|
+
}
|
|
37077
|
+
let topPad = createRoundedRectPrism({
|
|
37078
|
+
Manifold,
|
|
37079
|
+
width: padWidth,
|
|
37080
|
+
height: padHeight,
|
|
37081
|
+
thickness: padThickness,
|
|
37082
|
+
borderRadius: rectBorderRadius
|
|
37083
|
+
}).translate([0, 0, pcbThickness / 2 / 2 + BOARD_SURFACE_OFFSET.copper]);
|
|
37084
|
+
if (ph.rect_ccw_rotation) {
|
|
37085
|
+
const rotatedTopPad = topPad.rotate([0, 0, ph.rect_ccw_rotation]);
|
|
37086
|
+
manifoldInstancesForCleanup.push(rotatedTopPad);
|
|
37087
|
+
topPad = rotatedTopPad;
|
|
37088
|
+
}
|
|
37089
|
+
let bottomPad = createRoundedRectPrism({
|
|
37090
|
+
Manifold,
|
|
37091
|
+
width: padWidth,
|
|
37092
|
+
height: padHeight,
|
|
37093
|
+
thickness: padThickness,
|
|
37094
|
+
borderRadius: rectBorderRadius
|
|
37095
|
+
}).translate([0, 0, -pcbThickness / 2 / 2 - BOARD_SURFACE_OFFSET.copper]);
|
|
37096
|
+
if (ph.rect_ccw_rotation) {
|
|
37097
|
+
const rotatedBottomPad = bottomPad.rotate([0, 0, ph.rect_ccw_rotation]);
|
|
37098
|
+
manifoldInstancesForCleanup.push(rotatedBottomPad);
|
|
37099
|
+
bottomPad = rotatedBottomPad;
|
|
37100
|
+
}
|
|
37101
|
+
manifoldInstancesForCleanup.push(topPad, bottomPad);
|
|
37102
|
+
const barrelPill = createPillOp(
|
|
37103
|
+
holeW,
|
|
37104
|
+
holeH,
|
|
37105
|
+
pcbThickness * 1.02
|
|
37106
|
+
// Slightly taller than board
|
|
37107
|
+
).translate([holeOffsetX, holeOffsetY, 0]);
|
|
37108
|
+
if (ph.hole_ccw_rotation) {
|
|
37109
|
+
const rotatedDrill = boardPillDrillOp.rotate([
|
|
37110
|
+
0,
|
|
37111
|
+
0,
|
|
37112
|
+
ph.hole_ccw_rotation
|
|
37113
|
+
]);
|
|
37114
|
+
manifoldInstancesForCleanup.push(rotatedDrill);
|
|
37115
|
+
boardPillDrillOp = rotatedDrill;
|
|
37116
|
+
}
|
|
37117
|
+
manifoldInstancesForCleanup.push(barrelPill);
|
|
37118
|
+
const copperUnion = Manifold.union([
|
|
37119
|
+
mainFill,
|
|
37120
|
+
topPad,
|
|
37121
|
+
bottomPad,
|
|
37122
|
+
barrelPill
|
|
37123
|
+
]);
|
|
37124
|
+
manifoldInstancesForCleanup.push(copperUnion);
|
|
37125
|
+
let holeCutOp = createPillOp(
|
|
37126
|
+
Math.max(holeW - 2 * PLATED_HOLE_LIP_HEIGHT, 0.01),
|
|
37127
|
+
Math.max(holeH - 2 * PLATED_HOLE_LIP_HEIGHT, 0.01),
|
|
37128
|
+
pcbThickness * 1.2
|
|
37129
|
+
// Ensure it cuts through
|
|
37130
|
+
).translate([holeOffsetX, holeOffsetY, 0]);
|
|
37131
|
+
if (ph.hole_ccw_rotation) {
|
|
37132
|
+
const rotatedHoleCut = holeCutOp.rotate([0, 0, ph.hole_ccw_rotation]);
|
|
37133
|
+
manifoldInstancesForCleanup.push(rotatedHoleCut);
|
|
37134
|
+
holeCutOp = rotatedHoleCut;
|
|
37135
|
+
}
|
|
37136
|
+
manifoldInstancesForCleanup.push(holeCutOp);
|
|
37137
|
+
const finalCopper = copperUnion.subtract(holeCutOp);
|
|
37138
|
+
manifoldInstancesForCleanup.push(finalCopper);
|
|
37139
|
+
const translatedCopper = finalCopper.translate([ph.x, ph.y, 0]);
|
|
37140
|
+
manifoldInstancesForCleanup.push(translatedCopper);
|
|
37141
|
+
let finalCopperOp = translatedCopper;
|
|
37142
|
+
if (boardClipVolume) {
|
|
37143
|
+
const clipped = Manifold.intersection([
|
|
37144
|
+
translatedCopper,
|
|
37145
|
+
boardClipVolume
|
|
37146
|
+
]);
|
|
37147
|
+
manifoldInstancesForCleanup.push(clipped);
|
|
37148
|
+
finalCopperOp = clipped;
|
|
37149
|
+
}
|
|
37150
|
+
platedHoleCopperOpsForSubtract.push(finalCopperOp);
|
|
37151
|
+
const threeGeom = manifoldMeshToThreeGeometry(finalCopperOp.getMesh());
|
|
37152
|
+
platedHoleCopperGeoms.push({
|
|
37153
|
+
key: `ph-${ph.pcb_plated_hole_id || index2}`,
|
|
37154
|
+
geometry: threeGeom,
|
|
37155
|
+
color: COPPER_COLOR
|
|
37156
|
+
});
|
|
36762
37157
|
} else if (ph.shape === "hole_with_polygon_pad") {
|
|
36763
37158
|
const padOutline = ph.pad_outline;
|
|
36764
37159
|
if (!Array.isArray(padOutline) || padOutline.length < 3) {
|