@tscircuit/3d-viewer 0.0.477 → 0.0.479
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.d.ts +19 -21
- package/dist/index.js +610 -545
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -14226,7 +14226,7 @@ var require_browser = __commonJS({
|
|
|
14226
14226
|
|
|
14227
14227
|
// src/CadViewer.tsx
|
|
14228
14228
|
import { useState as useState35, useCallback as useCallback21, useRef as useRef26, useEffect as useEffect43 } from "react";
|
|
14229
|
-
import * as
|
|
14229
|
+
import * as THREE34 from "three";
|
|
14230
14230
|
|
|
14231
14231
|
// src/CadViewerJscad.tsx
|
|
14232
14232
|
import { su as su12 } from "@tscircuit/circuit-json-util";
|
|
@@ -29487,12 +29487,12 @@ var AnyCadComponent = ({
|
|
|
29487
29487
|
|
|
29488
29488
|
// src/CadViewerContainer.tsx
|
|
29489
29489
|
import { forwardRef as forwardRef2, useEffect as useEffect16, useMemo as useMemo13, useState as useState9 } from "react";
|
|
29490
|
-
import * as
|
|
29490
|
+
import * as THREE16 from "three";
|
|
29491
29491
|
|
|
29492
29492
|
// package.json
|
|
29493
29493
|
var package_default = {
|
|
29494
29494
|
name: "@tscircuit/3d-viewer",
|
|
29495
|
-
version: "0.0.
|
|
29495
|
+
version: "0.0.478",
|
|
29496
29496
|
main: "./dist/index.js",
|
|
29497
29497
|
module: "./dist/index.js",
|
|
29498
29498
|
type: "module",
|
|
@@ -29521,6 +29521,7 @@ var package_default = {
|
|
|
29521
29521
|
dependencies: {
|
|
29522
29522
|
"@jscad/regl-renderer": "^2.6.12",
|
|
29523
29523
|
"@jscad/stl-serializer": "^2.1.20",
|
|
29524
|
+
"circuit-to-canvas": "^0.0.26",
|
|
29524
29525
|
"react-hot-toast": "^2.6.0",
|
|
29525
29526
|
three: "^0.165.0",
|
|
29526
29527
|
"three-stdlib": "^2.36.0",
|
|
@@ -29936,6 +29937,7 @@ var Canvas = forwardRef(
|
|
|
29936
29937
|
|
|
29937
29938
|
// src/react-three/OrbitControls.tsx
|
|
29938
29939
|
import { useEffect as useEffect11, useMemo as useMemo10 } from "react";
|
|
29940
|
+
import * as THREE11 from "three";
|
|
29939
29941
|
import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
29940
29942
|
var OrbitControls = ({
|
|
29941
29943
|
autoRotate,
|
|
@@ -29978,6 +29980,14 @@ var OrbitControls = ({
|
|
|
29978
29980
|
if (enableDamping !== void 0) controls.enableDamping = enableDamping;
|
|
29979
29981
|
if (dampingFactor !== void 0) controls.dampingFactor = dampingFactor;
|
|
29980
29982
|
controls.zoomToCursor = true;
|
|
29983
|
+
controls.mouseButtons = {
|
|
29984
|
+
LEFT: THREE11.MOUSE.ROTATE,
|
|
29985
|
+
// Left click to rotate
|
|
29986
|
+
MIDDLE: THREE11.MOUSE.PAN,
|
|
29987
|
+
// Middle click to pan
|
|
29988
|
+
RIGHT: null
|
|
29989
|
+
// Right-click always disabled - only context menu
|
|
29990
|
+
};
|
|
29981
29991
|
if (target) {
|
|
29982
29992
|
controls.target.set(target[0], target[1], target[2]);
|
|
29983
29993
|
controls.update();
|
|
@@ -30014,7 +30024,7 @@ var OrbitControls = ({
|
|
|
30014
30024
|
|
|
30015
30025
|
// src/react-three/Grid.tsx
|
|
30016
30026
|
import { useEffect as useEffect12, useMemo as useMemo11 } from "react";
|
|
30017
|
-
import * as
|
|
30027
|
+
import * as THREE12 from "three";
|
|
30018
30028
|
var vertexShader = `
|
|
30019
30029
|
varying vec3 worldPosition;
|
|
30020
30030
|
void main() {
|
|
@@ -30060,24 +30070,24 @@ var Grid = ({
|
|
|
30060
30070
|
const { scene, camera } = useThree();
|
|
30061
30071
|
const size5 = 1e3;
|
|
30062
30072
|
const gridMesh = useMemo11(() => {
|
|
30063
|
-
const geometry = new
|
|
30073
|
+
const geometry = new THREE12.PlaneGeometry(size5, size5);
|
|
30064
30074
|
geometry.rotateX(-Math.PI / 2);
|
|
30065
|
-
const material = new
|
|
30075
|
+
const material = new THREE12.ShaderMaterial({
|
|
30066
30076
|
vertexShader,
|
|
30067
30077
|
fragmentShader,
|
|
30068
30078
|
uniforms: {
|
|
30069
30079
|
cellSize: { value: cellSize },
|
|
30070
30080
|
sectionSize: { value: sectionSize },
|
|
30071
|
-
gridColor: { value: new
|
|
30072
|
-
sectionColor: { value: new
|
|
30081
|
+
gridColor: { value: new THREE12.Color(15658734) },
|
|
30082
|
+
sectionColor: { value: new THREE12.Color(13421823) },
|
|
30073
30083
|
fadeDistance: { value: 100 },
|
|
30074
30084
|
// Fade out based on sectionSize
|
|
30075
30085
|
fadeStrength: { value: 1.5 }
|
|
30076
30086
|
},
|
|
30077
30087
|
transparent: true,
|
|
30078
|
-
side:
|
|
30088
|
+
side: THREE12.DoubleSide
|
|
30079
30089
|
});
|
|
30080
|
-
const mesh = new
|
|
30090
|
+
const mesh = new THREE12.Mesh(geometry, material);
|
|
30081
30091
|
if (rotation2) {
|
|
30082
30092
|
mesh.rotation.fromArray(rotation2);
|
|
30083
30093
|
}
|
|
@@ -30106,15 +30116,15 @@ var Grid = ({
|
|
|
30106
30116
|
|
|
30107
30117
|
// src/react-three/Lights.tsx
|
|
30108
30118
|
import { useEffect as useEffect13, useMemo as useMemo12 } from "react";
|
|
30109
|
-
import * as
|
|
30119
|
+
import * as THREE13 from "three";
|
|
30110
30120
|
var Lights = () => {
|
|
30111
30121
|
const { scene } = useThree();
|
|
30112
30122
|
const ambientLight = useMemo12(
|
|
30113
|
-
() => new
|
|
30123
|
+
() => new THREE13.AmbientLight(16777215, Math.PI / 2),
|
|
30114
30124
|
[]
|
|
30115
30125
|
);
|
|
30116
30126
|
const pointLight = useMemo12(() => {
|
|
30117
|
-
const light = new
|
|
30127
|
+
const light = new THREE13.PointLight(16777215, Math.PI / 4);
|
|
30118
30128
|
light.position.set(-10, -10, 10);
|
|
30119
30129
|
light.decay = 0;
|
|
30120
30130
|
return light;
|
|
@@ -30133,7 +30143,7 @@ var Lights = () => {
|
|
|
30133
30143
|
|
|
30134
30144
|
// src/hooks/cameraAnimation.ts
|
|
30135
30145
|
import { useCallback as useCallback6, useEffect as useEffect14, useRef as useRef5 } from "react";
|
|
30136
|
-
import * as
|
|
30146
|
+
import * as THREE14 from "three";
|
|
30137
30147
|
var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
30138
30148
|
var CameraAnimatorWithContext = () => {
|
|
30139
30149
|
const {
|
|
@@ -30144,24 +30154,24 @@ var CameraAnimatorWithContext = () => {
|
|
|
30144
30154
|
getPresetConfig
|
|
30145
30155
|
} = useCameraController();
|
|
30146
30156
|
const animationRef = useRef5(null);
|
|
30147
|
-
const tempQuaternion = useRef5(new
|
|
30148
|
-
const tempTarget = useRef5(new
|
|
30149
|
-
const tempUp = useRef5(new
|
|
30150
|
-
const tempRoll = useRef5(new
|
|
30151
|
-
const tempRollTarget = useRef5(new
|
|
30152
|
-
const baseOrientationHelper = useRef5(new
|
|
30153
|
-
const orientationHelper = useRef5(new
|
|
30157
|
+
const tempQuaternion = useRef5(new THREE14.Quaternion());
|
|
30158
|
+
const tempTarget = useRef5(new THREE14.Vector3());
|
|
30159
|
+
const tempUp = useRef5(new THREE14.Vector3());
|
|
30160
|
+
const tempRoll = useRef5(new THREE14.Quaternion());
|
|
30161
|
+
const tempRollTarget = useRef5(new THREE14.Quaternion());
|
|
30162
|
+
const baseOrientationHelper = useRef5(new THREE14.Object3D());
|
|
30163
|
+
const orientationHelper = useRef5(new THREE14.Object3D());
|
|
30154
30164
|
const animateTo = useCallback6(
|
|
30155
30165
|
({ position, target, up, durationMs = 600 }) => {
|
|
30156
30166
|
if (!mainCameraRef.current) return;
|
|
30157
30167
|
const currentTarget = controlsRef.current?.target ?? defaultTarget;
|
|
30158
|
-
const toPosition = new
|
|
30168
|
+
const toPosition = new THREE14.Vector3(
|
|
30159
30169
|
position[0],
|
|
30160
30170
|
position[1],
|
|
30161
30171
|
position[2]
|
|
30162
30172
|
);
|
|
30163
|
-
const resolvedTarget = target ? new
|
|
30164
|
-
const resolvedUp = new
|
|
30173
|
+
const resolvedTarget = target ? new THREE14.Vector3(target[0], target[1], target[2]) : defaultTarget.clone();
|
|
30174
|
+
const resolvedUp = new THREE14.Vector3(...up ?? [0, 0, 1]).normalize();
|
|
30165
30175
|
const toOrientationHelper = orientationHelper.current;
|
|
30166
30176
|
toOrientationHelper.position.copy(toPosition);
|
|
30167
30177
|
toOrientationHelper.up.copy(resolvedUp);
|
|
@@ -30318,14 +30328,14 @@ var useCameraSession = () => {
|
|
|
30318
30328
|
|
|
30319
30329
|
// src/three-components/OrientationCubeCanvas.tsx
|
|
30320
30330
|
import { useEffect as useEffect15, useRef as useRef7 } from "react";
|
|
30321
|
-
import * as
|
|
30331
|
+
import * as THREE15 from "three";
|
|
30322
30332
|
import { Text as TroikaText } from "troika-three-text";
|
|
30323
30333
|
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
30324
30334
|
function computePointInFront(rotationVector, distance3) {
|
|
30325
|
-
const quaternion = new
|
|
30326
|
-
new
|
|
30335
|
+
const quaternion = new THREE15.Quaternion().setFromEuler(
|
|
30336
|
+
new THREE15.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
|
|
30327
30337
|
);
|
|
30328
|
-
const forwardVector = new
|
|
30338
|
+
const forwardVector = new THREE15.Vector3(0, 0, 1);
|
|
30329
30339
|
forwardVector.applyQuaternion(quaternion);
|
|
30330
30340
|
const result = forwardVector.multiplyScalar(distance3);
|
|
30331
30341
|
return result;
|
|
@@ -30343,7 +30353,7 @@ var OrientationCubeCanvas = () => {
|
|
|
30343
30353
|
const canvas = document.createElement("canvas");
|
|
30344
30354
|
canvasRef.current = canvas;
|
|
30345
30355
|
containerRef.current.appendChild(canvas);
|
|
30346
|
-
const renderer = new
|
|
30356
|
+
const renderer = new THREE15.WebGLRenderer({
|
|
30347
30357
|
canvas,
|
|
30348
30358
|
antialias: true,
|
|
30349
30359
|
alpha: true
|
|
@@ -30351,26 +30361,26 @@ var OrientationCubeCanvas = () => {
|
|
|
30351
30361
|
renderer.setSize(120, 120);
|
|
30352
30362
|
renderer.setPixelRatio(window.devicePixelRatio);
|
|
30353
30363
|
rendererRef.current = renderer;
|
|
30354
|
-
const scene = new
|
|
30364
|
+
const scene = new THREE15.Scene();
|
|
30355
30365
|
sceneRef.current = scene;
|
|
30356
|
-
const camera = new
|
|
30366
|
+
const camera = new THREE15.PerspectiveCamera(75, 1, 0.1, 1e3);
|
|
30357
30367
|
camera.up.set(0, 0, 1);
|
|
30358
30368
|
cameraRef.current = camera;
|
|
30359
|
-
const ambientLight = new
|
|
30369
|
+
const ambientLight = new THREE15.AmbientLight(16777215, Math.PI / 2);
|
|
30360
30370
|
scene.add(ambientLight);
|
|
30361
|
-
const group = new
|
|
30371
|
+
const group = new THREE15.Group();
|
|
30362
30372
|
group.rotation.fromArray([Math.PI / 2, 0, 0]);
|
|
30363
30373
|
const cubeSize = 1;
|
|
30364
|
-
const box = new
|
|
30365
|
-
new
|
|
30366
|
-
new
|
|
30374
|
+
const box = new THREE15.Mesh(
|
|
30375
|
+
new THREE15.BoxGeometry(cubeSize, cubeSize, cubeSize),
|
|
30376
|
+
new THREE15.MeshStandardMaterial({ color: "white" })
|
|
30367
30377
|
);
|
|
30368
30378
|
group.add(box);
|
|
30369
|
-
const edges = new
|
|
30370
|
-
new
|
|
30371
|
-
new
|
|
30379
|
+
const edges = new THREE15.LineSegments(
|
|
30380
|
+
new THREE15.EdgesGeometry(
|
|
30381
|
+
new THREE15.BoxGeometry(cubeSize, cubeSize, cubeSize)
|
|
30372
30382
|
),
|
|
30373
|
-
new
|
|
30383
|
+
new THREE15.LineBasicMaterial({ color: 0, linewidth: 2 })
|
|
30374
30384
|
);
|
|
30375
30385
|
group.add(edges);
|
|
30376
30386
|
scene.add(group);
|
|
@@ -30424,7 +30434,7 @@ var OrientationCubeCanvas = () => {
|
|
|
30424
30434
|
const animate = () => {
|
|
30425
30435
|
if (mainCameraRef.current) {
|
|
30426
30436
|
const cameraPosition = computePointInFront(
|
|
30427
|
-
mainCameraRef.current.rotation ?? new
|
|
30437
|
+
mainCameraRef.current.rotation ?? new THREE15.Euler(0, 0, 0),
|
|
30428
30438
|
2
|
|
30429
30439
|
);
|
|
30430
30440
|
if (!cameraPosition.equals(camera.position)) {
|
|
@@ -30527,7 +30537,7 @@ var CadViewerContainer = forwardRef2(
|
|
|
30527
30537
|
Canvas,
|
|
30528
30538
|
{
|
|
30529
30539
|
ref,
|
|
30530
|
-
scene: { up: new
|
|
30540
|
+
scene: { up: new THREE16.Vector3(0, 0, 1) },
|
|
30531
30541
|
camera: { up: [0, 0, 1], position: initialCameraPosition },
|
|
30532
30542
|
onCreated: ({ camera }) => {
|
|
30533
30543
|
mainCameraRef.current = camera;
|
|
@@ -32382,7 +32392,7 @@ var Text = ({
|
|
|
32382
32392
|
};
|
|
32383
32393
|
|
|
32384
32394
|
// src/three-components/Error3d.tsx
|
|
32385
|
-
import * as
|
|
32395
|
+
import * as THREE17 from "three";
|
|
32386
32396
|
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
32387
32397
|
var Error3d = ({
|
|
32388
32398
|
error,
|
|
@@ -32416,7 +32426,7 @@ var Error3d = ({
|
|
|
32416
32426
|
return [0, 0, 0];
|
|
32417
32427
|
}, [cad_component2]);
|
|
32418
32428
|
const group = useMemo17(() => {
|
|
32419
|
-
const g = new
|
|
32429
|
+
const g = new THREE17.Group();
|
|
32420
32430
|
g.position.fromArray(position);
|
|
32421
32431
|
return g;
|
|
32422
32432
|
}, [position]);
|
|
@@ -32476,9 +32486,9 @@ var Error3d = ({
|
|
|
32476
32486
|
};
|
|
32477
32487
|
var ErrorBox = ({ parent }) => {
|
|
32478
32488
|
const mesh = useMemo17(() => {
|
|
32479
|
-
const m = new
|
|
32480
|
-
new
|
|
32481
|
-
new
|
|
32489
|
+
const m = new THREE17.Mesh(
|
|
32490
|
+
new THREE17.BoxGeometry(0.5, 0.5, 0.5),
|
|
32491
|
+
new THREE17.MeshStandardMaterial({
|
|
32482
32492
|
depthTest: false,
|
|
32483
32493
|
transparent: true,
|
|
32484
32494
|
color: "red",
|
|
@@ -32500,7 +32510,7 @@ var ErrorBox = ({ parent }) => {
|
|
|
32500
32510
|
|
|
32501
32511
|
// src/three-components/STLModel.tsx
|
|
32502
32512
|
import { useState as useState13, useEffect as useEffect21, useMemo as useMemo18 } from "react";
|
|
32503
|
-
import * as
|
|
32513
|
+
import * as THREE18 from "three";
|
|
32504
32514
|
import { STLLoader } from "three-stdlib";
|
|
32505
32515
|
function STLModel({
|
|
32506
32516
|
stlUrl,
|
|
@@ -32531,12 +32541,12 @@ function STLModel({
|
|
|
32531
32541
|
}, [stlUrl, stlData]);
|
|
32532
32542
|
const mesh = useMemo18(() => {
|
|
32533
32543
|
if (!geom) return null;
|
|
32534
|
-
const material = new
|
|
32535
|
-
color: Array.isArray(color) ? new
|
|
32544
|
+
const material = new THREE18.MeshStandardMaterial({
|
|
32545
|
+
color: Array.isArray(color) ? new THREE18.Color(color[0], color[1], color[2]) : color,
|
|
32536
32546
|
transparent: opacity !== 1,
|
|
32537
32547
|
opacity
|
|
32538
32548
|
});
|
|
32539
|
-
return new
|
|
32549
|
+
return new THREE18.Mesh(geom, material);
|
|
32540
32550
|
}, [geom, color, opacity]);
|
|
32541
32551
|
useEffect21(() => {
|
|
32542
32552
|
if (!rootObject || !mesh) return;
|
|
@@ -32601,11 +32611,11 @@ var ThreeErrorBoundary = class extends React11.Component {
|
|
|
32601
32611
|
|
|
32602
32612
|
// src/three-components/JscadBoardTextures.tsx
|
|
32603
32613
|
import { useEffect as useEffect22, useMemo as useMemo19 } from "react";
|
|
32604
|
-
import * as
|
|
32614
|
+
import * as THREE24 from "three";
|
|
32605
32615
|
import { su as su9 } from "@tscircuit/circuit-json-util";
|
|
32606
32616
|
|
|
32607
32617
|
// src/utils/soldermask-texture.ts
|
|
32608
|
-
import * as
|
|
32618
|
+
import * as THREE19 from "three";
|
|
32609
32619
|
import { su as su5 } from "@tscircuit/circuit-json-util";
|
|
32610
32620
|
|
|
32611
32621
|
// node_modules/@tscircuit/math-utils/dist/chunk-5N7UJNVK.js
|
|
@@ -33150,10 +33160,10 @@ function createSoldermaskTextureForLayer({
|
|
|
33150
33160
|
}
|
|
33151
33161
|
});
|
|
33152
33162
|
ctx.globalCompositeOperation = "source-over";
|
|
33153
|
-
const texture = new
|
|
33163
|
+
const texture = new THREE19.CanvasTexture(canvas);
|
|
33154
33164
|
texture.generateMipmaps = true;
|
|
33155
|
-
texture.minFilter =
|
|
33156
|
-
texture.magFilter =
|
|
33165
|
+
texture.minFilter = THREE19.LinearMipmapLinearFilter;
|
|
33166
|
+
texture.magFilter = THREE19.LinearFilter;
|
|
33157
33167
|
texture.anisotropy = 16;
|
|
33158
33168
|
texture.needsUpdate = true;
|
|
33159
33169
|
return texture;
|
|
@@ -33161,7 +33171,7 @@ function createSoldermaskTextureForLayer({
|
|
|
33161
33171
|
|
|
33162
33172
|
// src/utils/silkscreen-texture.ts
|
|
33163
33173
|
var import_text = __toESM(require_text(), 1);
|
|
33164
|
-
import * as
|
|
33174
|
+
import * as THREE20 from "three";
|
|
33165
33175
|
|
|
33166
33176
|
// node_modules/transformation-matrix/src/applyToPoint.js
|
|
33167
33177
|
function applyToPoint(matrix, point2) {
|
|
@@ -33820,17 +33830,17 @@ function createSilkscreenTextureForLayer({
|
|
|
33820
33830
|
ctx.stroke();
|
|
33821
33831
|
});
|
|
33822
33832
|
});
|
|
33823
|
-
const texture = new
|
|
33833
|
+
const texture = new THREE20.CanvasTexture(canvas);
|
|
33824
33834
|
texture.generateMipmaps = true;
|
|
33825
|
-
texture.minFilter =
|
|
33826
|
-
texture.magFilter =
|
|
33835
|
+
texture.minFilter = THREE20.LinearMipmapLinearFilter;
|
|
33836
|
+
texture.magFilter = THREE20.LinearFilter;
|
|
33827
33837
|
texture.anisotropy = 16;
|
|
33828
33838
|
texture.needsUpdate = true;
|
|
33829
33839
|
return texture;
|
|
33830
33840
|
}
|
|
33831
33841
|
|
|
33832
33842
|
// src/utils/trace-texture.ts
|
|
33833
|
-
import * as
|
|
33843
|
+
import * as THREE21 from "three";
|
|
33834
33844
|
import { su as su7 } from "@tscircuit/circuit-json-util";
|
|
33835
33845
|
function isWireRoutePoint(point2) {
|
|
33836
33846
|
return point2 && point2.route_type === "wire" && typeof point2.layer === "string" && typeof point2.width === "number";
|
|
@@ -33918,10 +33928,10 @@ function createTraceTextureForLayer({
|
|
|
33918
33928
|
}
|
|
33919
33929
|
});
|
|
33920
33930
|
ctx.globalCompositeOperation = "source-over";
|
|
33921
|
-
const texture = new
|
|
33931
|
+
const texture = new THREE21.CanvasTexture(canvas);
|
|
33922
33932
|
texture.generateMipmaps = true;
|
|
33923
|
-
texture.minFilter =
|
|
33924
|
-
texture.magFilter =
|
|
33933
|
+
texture.minFilter = THREE21.LinearMipmapLinearFilter;
|
|
33934
|
+
texture.magFilter = THREE21.LinearFilter;
|
|
33925
33935
|
texture.anisotropy = 16;
|
|
33926
33936
|
texture.needsUpdate = true;
|
|
33927
33937
|
return texture;
|
|
@@ -33929,7 +33939,7 @@ function createTraceTextureForLayer({
|
|
|
33929
33939
|
|
|
33930
33940
|
// src/utils/copper-text-texture.ts
|
|
33931
33941
|
var import_text2 = __toESM(require_text(), 1);
|
|
33932
|
-
import * as
|
|
33942
|
+
import * as THREE22 from "three";
|
|
33933
33943
|
function parseDimension2(value, defaultValue) {
|
|
33934
33944
|
if (value === void 0) return defaultValue;
|
|
33935
33945
|
if (typeof value === "number") return value;
|
|
@@ -34168,17 +34178,17 @@ function createCopperTextTextureForLayer({
|
|
|
34168
34178
|
);
|
|
34169
34179
|
}
|
|
34170
34180
|
});
|
|
34171
|
-
const texture = new
|
|
34181
|
+
const texture = new THREE22.CanvasTexture(canvas);
|
|
34172
34182
|
texture.generateMipmaps = true;
|
|
34173
|
-
texture.minFilter =
|
|
34174
|
-
texture.magFilter =
|
|
34183
|
+
texture.minFilter = THREE22.LinearMipmapLinearFilter;
|
|
34184
|
+
texture.magFilter = THREE22.LinearFilter;
|
|
34175
34185
|
texture.anisotropy = 16;
|
|
34176
34186
|
texture.needsUpdate = true;
|
|
34177
34187
|
return texture;
|
|
34178
34188
|
}
|
|
34179
34189
|
|
|
34180
34190
|
// src/utils/panel-outline-texture.ts
|
|
34181
|
-
import * as
|
|
34191
|
+
import * as THREE23 from "three";
|
|
34182
34192
|
import { su as su8 } from "@tscircuit/circuit-json-util";
|
|
34183
34193
|
function createPanelOutlineTextureForLayer({
|
|
34184
34194
|
layer,
|
|
@@ -34234,10 +34244,10 @@ function createPanelOutlineTextureForLayer({
|
|
|
34234
34244
|
);
|
|
34235
34245
|
}
|
|
34236
34246
|
});
|
|
34237
|
-
const texture = new
|
|
34247
|
+
const texture = new THREE23.CanvasTexture(canvas);
|
|
34238
34248
|
texture.generateMipmaps = true;
|
|
34239
|
-
texture.minFilter =
|
|
34240
|
-
texture.magFilter =
|
|
34249
|
+
texture.minFilter = THREE23.LinearMipmapLinearFilter;
|
|
34250
|
+
texture.magFilter = THREE23.LinearFilter;
|
|
34241
34251
|
texture.anisotropy = 16;
|
|
34242
34252
|
texture.needsUpdate = true;
|
|
34243
34253
|
return texture;
|
|
@@ -34357,23 +34367,23 @@ function JscadBoardTextures({
|
|
|
34357
34367
|
useEffect22(() => {
|
|
34358
34368
|
if (!rootObject || !boardData || !textures) return;
|
|
34359
34369
|
const meshes = [];
|
|
34360
|
-
const
|
|
34370
|
+
const createTexturePlane2 = (texture, zOffset, isBottomLayer, name, usePolygonOffset = false, depthWrite = false) => {
|
|
34361
34371
|
if (!texture) return null;
|
|
34362
34372
|
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
34363
|
-
const planeGeom = new
|
|
34373
|
+
const planeGeom = new THREE24.PlaneGeometry(
|
|
34364
34374
|
boardOutlineBounds.width,
|
|
34365
34375
|
boardOutlineBounds.height
|
|
34366
34376
|
);
|
|
34367
|
-
const material = new
|
|
34377
|
+
const material = new THREE24.MeshBasicMaterial({
|
|
34368
34378
|
map: texture,
|
|
34369
34379
|
transparent: true,
|
|
34370
|
-
side:
|
|
34380
|
+
side: THREE24.DoubleSide,
|
|
34371
34381
|
depthWrite,
|
|
34372
34382
|
polygonOffset: usePolygonOffset,
|
|
34373
34383
|
polygonOffsetFactor: usePolygonOffset ? -1 : 0,
|
|
34374
34384
|
polygonOffsetUnits: usePolygonOffset ? -1 : 0
|
|
34375
34385
|
});
|
|
34376
|
-
const mesh = new
|
|
34386
|
+
const mesh = new THREE24.Mesh(planeGeom, material);
|
|
34377
34387
|
mesh.position.set(
|
|
34378
34388
|
boardOutlineBounds.centerX,
|
|
34379
34389
|
boardOutlineBounds.centerY,
|
|
@@ -34387,7 +34397,7 @@ function JscadBoardTextures({
|
|
|
34387
34397
|
};
|
|
34388
34398
|
const SURFACE_OFFSET = 1e-3;
|
|
34389
34399
|
if (visibility.topMask) {
|
|
34390
|
-
const topSoldermaskMesh =
|
|
34400
|
+
const topSoldermaskMesh = createTexturePlane2(
|
|
34391
34401
|
textures.topSoldermask,
|
|
34392
34402
|
pcbThickness / 2 + SURFACE_OFFSET,
|
|
34393
34403
|
false,
|
|
@@ -34400,7 +34410,7 @@ function JscadBoardTextures({
|
|
|
34400
34410
|
}
|
|
34401
34411
|
}
|
|
34402
34412
|
if (visibility.bottomMask) {
|
|
34403
|
-
const bottomSoldermaskMesh =
|
|
34413
|
+
const bottomSoldermaskMesh = createTexturePlane2(
|
|
34404
34414
|
textures.bottomSoldermask,
|
|
34405
34415
|
-pcbThickness / 2 - SURFACE_OFFSET,
|
|
34406
34416
|
true,
|
|
@@ -34413,7 +34423,7 @@ function JscadBoardTextures({
|
|
|
34413
34423
|
}
|
|
34414
34424
|
}
|
|
34415
34425
|
if (visibility.topCopper && visibility.topMask) {
|
|
34416
|
-
const topTraceWithMaskMesh =
|
|
34426
|
+
const topTraceWithMaskMesh = createTexturePlane2(
|
|
34417
34427
|
textures.topTraceWithMask,
|
|
34418
34428
|
pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces + 4e-3,
|
|
34419
34429
|
false,
|
|
@@ -34425,7 +34435,7 @@ function JscadBoardTextures({
|
|
|
34425
34435
|
}
|
|
34426
34436
|
}
|
|
34427
34437
|
if (visibility.bottomCopper && visibility.bottomMask) {
|
|
34428
|
-
const bottomTraceWithMaskMesh =
|
|
34438
|
+
const bottomTraceWithMaskMesh = createTexturePlane2(
|
|
34429
34439
|
textures.bottomTraceWithMask,
|
|
34430
34440
|
-pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces - 5e-3,
|
|
34431
34441
|
true,
|
|
@@ -34437,7 +34447,7 @@ function JscadBoardTextures({
|
|
|
34437
34447
|
}
|
|
34438
34448
|
}
|
|
34439
34449
|
if (visibility.topSilkscreen) {
|
|
34440
|
-
const topSilkscreenMesh =
|
|
34450
|
+
const topSilkscreenMesh = createTexturePlane2(
|
|
34441
34451
|
textures.topSilkscreen,
|
|
34442
34452
|
pcbThickness / 2 + SURFACE_OFFSET + 2e-3,
|
|
34443
34453
|
false,
|
|
@@ -34449,7 +34459,7 @@ function JscadBoardTextures({
|
|
|
34449
34459
|
}
|
|
34450
34460
|
}
|
|
34451
34461
|
if (visibility.bottomSilkscreen) {
|
|
34452
|
-
const bottomSilkscreenMesh =
|
|
34462
|
+
const bottomSilkscreenMesh = createTexturePlane2(
|
|
34453
34463
|
textures.bottomSilkscreen,
|
|
34454
34464
|
-pcbThickness / 2 - SURFACE_OFFSET - 2e-3,
|
|
34455
34465
|
true,
|
|
@@ -34461,7 +34471,7 @@ function JscadBoardTextures({
|
|
|
34461
34471
|
}
|
|
34462
34472
|
}
|
|
34463
34473
|
if (visibility.topCopper) {
|
|
34464
|
-
const topCopperTextMesh =
|
|
34474
|
+
const topCopperTextMesh = createTexturePlane2(
|
|
34465
34475
|
textures.topCopperText,
|
|
34466
34476
|
pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
|
|
34467
34477
|
false,
|
|
@@ -34473,7 +34483,7 @@ function JscadBoardTextures({
|
|
|
34473
34483
|
}
|
|
34474
34484
|
}
|
|
34475
34485
|
if (visibility.bottomCopper) {
|
|
34476
|
-
const bottomCopperTextMesh =
|
|
34486
|
+
const bottomCopperTextMesh = createTexturePlane2(
|
|
34477
34487
|
textures.bottomCopperText,
|
|
34478
34488
|
-pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
|
|
34479
34489
|
true,
|
|
@@ -34485,7 +34495,7 @@ function JscadBoardTextures({
|
|
|
34485
34495
|
}
|
|
34486
34496
|
}
|
|
34487
34497
|
if (visibility.boardBody) {
|
|
34488
|
-
const topPanelOutlinesMesh =
|
|
34498
|
+
const topPanelOutlinesMesh = createTexturePlane2(
|
|
34489
34499
|
textures.topPanelOutlines,
|
|
34490
34500
|
pcbThickness / 2 + SURFACE_OFFSET + 3e-3,
|
|
34491
34501
|
// Above silkscreen
|
|
@@ -34498,7 +34508,7 @@ function JscadBoardTextures({
|
|
|
34498
34508
|
meshes.push(topPanelOutlinesMesh);
|
|
34499
34509
|
rootObject.add(topPanelOutlinesMesh);
|
|
34500
34510
|
}
|
|
34501
|
-
const bottomPanelOutlinesMesh =
|
|
34511
|
+
const bottomPanelOutlinesMesh = createTexturePlane2(
|
|
34502
34512
|
textures.bottomPanelOutlines,
|
|
34503
34513
|
-pcbThickness / 2 - SURFACE_OFFSET - 3e-3,
|
|
34504
34514
|
// Below bottom silkscreen
|
|
@@ -34518,7 +34528,7 @@ function JscadBoardTextures({
|
|
|
34518
34528
|
rootObject.remove(mesh);
|
|
34519
34529
|
}
|
|
34520
34530
|
mesh.geometry.dispose();
|
|
34521
|
-
if (mesh.material instanceof
|
|
34531
|
+
if (mesh.material instanceof THREE24.Material) {
|
|
34522
34532
|
mesh.material.dispose();
|
|
34523
34533
|
}
|
|
34524
34534
|
});
|
|
@@ -34750,7 +34760,7 @@ import { useEffect as useEffect24, useMemo as useMemo22, useState as useState15
|
|
|
34750
34760
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
34751
34761
|
import { useState as useState14, useEffect as useEffect23, useMemo as useMemo21, useRef as useRef9 } from "react";
|
|
34752
34762
|
import { su as su18 } from "@tscircuit/circuit-json-util";
|
|
34753
|
-
import * as
|
|
34763
|
+
import * as THREE31 from "three";
|
|
34754
34764
|
|
|
34755
34765
|
// src/utils/manifold/create-manifold-board.ts
|
|
34756
34766
|
var arePointsClockwise3 = (points) => {
|
|
@@ -34810,202 +34820,6 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
|
|
|
34810
34820
|
return { boardOp, outlineCrossSection };
|
|
34811
34821
|
}
|
|
34812
34822
|
|
|
34813
|
-
// src/utils/manifold/process-copper-pours.ts
|
|
34814
|
-
import * as THREE25 from "three";
|
|
34815
|
-
|
|
34816
|
-
// src/utils/manifold-mesh-to-three-geometry.ts
|
|
34817
|
-
import * as THREE24 from "three";
|
|
34818
|
-
function manifoldMeshToThreeGeometry(manifoldMesh) {
|
|
34819
|
-
const geometry = new THREE24.BufferGeometry();
|
|
34820
|
-
geometry.setAttribute(
|
|
34821
|
-
"position",
|
|
34822
|
-
new THREE24.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
|
|
34823
|
-
);
|
|
34824
|
-
geometry.setIndex(new THREE24.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
|
|
34825
|
-
if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
|
|
34826
|
-
for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
|
|
34827
|
-
const start = manifoldMesh.runIndex[i];
|
|
34828
|
-
const count3 = manifoldMesh.runIndex[i + 1] - start;
|
|
34829
|
-
geometry.addGroup(start, count3, 0);
|
|
34830
|
-
}
|
|
34831
|
-
} else {
|
|
34832
|
-
geometry.addGroup(0, manifoldMesh.triVerts.length, 0);
|
|
34833
|
-
}
|
|
34834
|
-
return geometry;
|
|
34835
|
-
}
|
|
34836
|
-
|
|
34837
|
-
// src/utils/manifold/process-copper-pours.ts
|
|
34838
|
-
var arePointsClockwise4 = (points) => {
|
|
34839
|
-
let area = 0;
|
|
34840
|
-
for (let i = 0; i < points.length; i++) {
|
|
34841
|
-
const j = (i + 1) % points.length;
|
|
34842
|
-
if (points[i] && points[j]) {
|
|
34843
|
-
area += points[i][0] * points[j][1];
|
|
34844
|
-
area -= points[j][0] * points[i][1];
|
|
34845
|
-
}
|
|
34846
|
-
}
|
|
34847
|
-
const signedArea = area / 2;
|
|
34848
|
-
return signedArea <= 0;
|
|
34849
|
-
};
|
|
34850
|
-
function segmentToPoints2(p1, p2, bulge, arcSegments) {
|
|
34851
|
-
if (!bulge || Math.abs(bulge) < 1e-9) {
|
|
34852
|
-
return [];
|
|
34853
|
-
}
|
|
34854
|
-
const theta = 4 * Math.atan(bulge);
|
|
34855
|
-
const dx = p2[0] - p1[0];
|
|
34856
|
-
const dy = p2[1] - p1[1];
|
|
34857
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
34858
|
-
if (dist < 1e-9) return [];
|
|
34859
|
-
const radius = Math.abs(dist / (2 * Math.sin(theta / 2)));
|
|
34860
|
-
const m = Math.sqrt(Math.max(0, radius * radius - dist / 2 * (dist / 2)));
|
|
34861
|
-
const midPoint = [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2];
|
|
34862
|
-
const ux = dx / dist;
|
|
34863
|
-
const uy = dy / dist;
|
|
34864
|
-
const nx = -uy;
|
|
34865
|
-
const ny = ux;
|
|
34866
|
-
const centerX = midPoint[0] + nx * m * Math.sign(bulge);
|
|
34867
|
-
const centerY = midPoint[1] + ny * m * Math.sign(bulge);
|
|
34868
|
-
const startAngle = Math.atan2(p1[1] - centerY, p1[0] - centerX);
|
|
34869
|
-
const points = [];
|
|
34870
|
-
const numSteps = Math.max(
|
|
34871
|
-
2,
|
|
34872
|
-
Math.ceil(arcSegments * Math.abs(theta) / (Math.PI * 2) * 4)
|
|
34873
|
-
);
|
|
34874
|
-
const angleStep = theta / numSteps;
|
|
34875
|
-
for (let i = 1; i < numSteps; i++) {
|
|
34876
|
-
const angle = startAngle + angleStep * i;
|
|
34877
|
-
points.push([
|
|
34878
|
-
centerX + radius * Math.cos(angle),
|
|
34879
|
-
centerY + radius * Math.sin(angle)
|
|
34880
|
-
]);
|
|
34881
|
-
}
|
|
34882
|
-
return points;
|
|
34883
|
-
}
|
|
34884
|
-
function ringToPoints2(ring2, arcSegments) {
|
|
34885
|
-
const allPoints = [];
|
|
34886
|
-
const vertices = ring2.vertices;
|
|
34887
|
-
for (let i = 0; i < vertices.length; i++) {
|
|
34888
|
-
const p1 = vertices[i];
|
|
34889
|
-
const p2 = vertices[(i + 1) % vertices.length];
|
|
34890
|
-
allPoints.push([p1.x, p1.y]);
|
|
34891
|
-
if (p1.bulge) {
|
|
34892
|
-
const arcPoints = segmentToPoints2(
|
|
34893
|
-
[p1.x, p1.y],
|
|
34894
|
-
[p2.x, p2.y],
|
|
34895
|
-
p1.bulge,
|
|
34896
|
-
arcSegments
|
|
34897
|
-
);
|
|
34898
|
-
allPoints.push(...arcPoints);
|
|
34899
|
-
}
|
|
34900
|
-
}
|
|
34901
|
-
return allPoints;
|
|
34902
|
-
}
|
|
34903
|
-
function processCopperPoursForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardMaterial, holeUnion, boardClipVolume) {
|
|
34904
|
-
const copperPourGeoms = [];
|
|
34905
|
-
const copperPours = circuitJson.filter(
|
|
34906
|
-
(e) => e.type === "pcb_copper_pour"
|
|
34907
|
-
);
|
|
34908
|
-
for (const pour of copperPours) {
|
|
34909
|
-
const pourThickness = DEFAULT_SMT_PAD_THICKNESS;
|
|
34910
|
-
const layerSign = pour.layer === "bottom" ? -1 : 1;
|
|
34911
|
-
const zPos = layerSign * (pcbThickness / 2 + pourThickness / 2 + MANIFOLD_Z_OFFSET);
|
|
34912
|
-
let pourOp;
|
|
34913
|
-
if (pour.shape === "rect") {
|
|
34914
|
-
pourOp = Manifold.cube([pour.width, pour.height, pourThickness], true);
|
|
34915
|
-
manifoldInstancesForCleanup.push(pourOp);
|
|
34916
|
-
if (pour.rotation) {
|
|
34917
|
-
const rotatedOp = pourOp.rotate([0, 0, pour.rotation]);
|
|
34918
|
-
manifoldInstancesForCleanup.push(rotatedOp);
|
|
34919
|
-
pourOp = rotatedOp;
|
|
34920
|
-
}
|
|
34921
|
-
pourOp = pourOp.translate([pour.center.x, pour.center.y, zPos]);
|
|
34922
|
-
manifoldInstancesForCleanup.push(pourOp);
|
|
34923
|
-
} else if (pour.shape === "polygon") {
|
|
34924
|
-
if (pour.points.length < 3) continue;
|
|
34925
|
-
let pointsVec2 = pour.points.map((p) => [
|
|
34926
|
-
p.x,
|
|
34927
|
-
p.y
|
|
34928
|
-
]);
|
|
34929
|
-
if (arePointsClockwise4(pointsVec2)) {
|
|
34930
|
-
pointsVec2 = pointsVec2.reverse();
|
|
34931
|
-
}
|
|
34932
|
-
const crossSection = CrossSection.ofPolygons([pointsVec2]);
|
|
34933
|
-
manifoldInstancesForCleanup.push(crossSection);
|
|
34934
|
-
pourOp = Manifold.extrude(
|
|
34935
|
-
crossSection,
|
|
34936
|
-
pourThickness,
|
|
34937
|
-
0,
|
|
34938
|
-
// nDivisions
|
|
34939
|
-
0,
|
|
34940
|
-
// twistDegrees
|
|
34941
|
-
[1, 1],
|
|
34942
|
-
// scaleTop
|
|
34943
|
-
true
|
|
34944
|
-
// center extrusion
|
|
34945
|
-
).translate([0, 0, zPos]);
|
|
34946
|
-
manifoldInstancesForCleanup.push(pourOp);
|
|
34947
|
-
} else if (pour.shape === "brep") {
|
|
34948
|
-
const brepShape = pour.brep_shape;
|
|
34949
|
-
if (!brepShape || !brepShape.outer_ring) continue;
|
|
34950
|
-
let outerRingPoints = ringToPoints2(
|
|
34951
|
-
brepShape.outer_ring,
|
|
34952
|
-
SMOOTH_CIRCLE_SEGMENTS
|
|
34953
|
-
);
|
|
34954
|
-
if (arePointsClockwise4(outerRingPoints)) {
|
|
34955
|
-
outerRingPoints = outerRingPoints.reverse();
|
|
34956
|
-
}
|
|
34957
|
-
const polygons = [outerRingPoints];
|
|
34958
|
-
if (brepShape.inner_rings) {
|
|
34959
|
-
const innerRingsPoints = brepShape.inner_rings.map((ring2) => {
|
|
34960
|
-
let points = ringToPoints2(ring2, SMOOTH_CIRCLE_SEGMENTS);
|
|
34961
|
-
if (!arePointsClockwise4(points)) {
|
|
34962
|
-
points = points.reverse();
|
|
34963
|
-
}
|
|
34964
|
-
return points;
|
|
34965
|
-
});
|
|
34966
|
-
polygons.push(...innerRingsPoints);
|
|
34967
|
-
}
|
|
34968
|
-
const crossSection = CrossSection.ofPolygons(polygons);
|
|
34969
|
-
manifoldInstancesForCleanup.push(crossSection);
|
|
34970
|
-
pourOp = Manifold.extrude(
|
|
34971
|
-
crossSection,
|
|
34972
|
-
pourThickness,
|
|
34973
|
-
0,
|
|
34974
|
-
// nDivisions
|
|
34975
|
-
0,
|
|
34976
|
-
// twistDegrees
|
|
34977
|
-
[1, 1],
|
|
34978
|
-
// scaleTop
|
|
34979
|
-
true
|
|
34980
|
-
// center extrusion
|
|
34981
|
-
).translate([0, 0, zPos]);
|
|
34982
|
-
manifoldInstancesForCleanup.push(pourOp);
|
|
34983
|
-
}
|
|
34984
|
-
if (pourOp) {
|
|
34985
|
-
if (holeUnion) {
|
|
34986
|
-
const withHoles = pourOp.subtract(holeUnion);
|
|
34987
|
-
manifoldInstancesForCleanup.push(withHoles);
|
|
34988
|
-
pourOp = withHoles;
|
|
34989
|
-
}
|
|
34990
|
-
if (boardClipVolume) {
|
|
34991
|
-
const clipped = Manifold.intersection([pourOp, boardClipVolume]);
|
|
34992
|
-
manifoldInstancesForCleanup.push(clipped);
|
|
34993
|
-
pourOp = clipped;
|
|
34994
|
-
}
|
|
34995
|
-
const covered = pour.covered_with_solder_mask !== false;
|
|
34996
|
-
const pourColorArr = covered ? tracesMaterialColors[boardMaterial] ?? colors.fr4TracesWithoutMaskTan : colors.copper;
|
|
34997
|
-
const pourColor = new THREE25.Color(...pourColorArr);
|
|
34998
|
-
const threeGeom = manifoldMeshToThreeGeometry(pourOp.getMesh());
|
|
34999
|
-
copperPourGeoms.push({
|
|
35000
|
-
key: `coppour-${pour.pcb_copper_pour_id}`,
|
|
35001
|
-
geometry: threeGeom,
|
|
35002
|
-
color: pourColor
|
|
35003
|
-
});
|
|
35004
|
-
}
|
|
35005
|
-
}
|
|
35006
|
-
return { copperPourGeoms };
|
|
35007
|
-
}
|
|
35008
|
-
|
|
35009
34823
|
// src/utils/manifold/process-cutouts.ts
|
|
35010
34824
|
import { su as su13 } from "@tscircuit/circuit-json-util";
|
|
35011
34825
|
|
|
@@ -35085,7 +34899,7 @@ function createPadManifoldOp({
|
|
|
35085
34899
|
}
|
|
35086
34900
|
|
|
35087
34901
|
// src/utils/manifold/process-cutouts.ts
|
|
35088
|
-
var
|
|
34902
|
+
var arePointsClockwise4 = (points) => {
|
|
35089
34903
|
let area = 0;
|
|
35090
34904
|
for (let i = 0; i < points.length; i++) {
|
|
35091
34905
|
const j = (i + 1) % points.length;
|
|
@@ -35161,7 +34975,7 @@ function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThick
|
|
|
35161
34975
|
p.x,
|
|
35162
34976
|
p.y
|
|
35163
34977
|
]);
|
|
35164
|
-
if (
|
|
34978
|
+
if (arePointsClockwise4(pointsVec2)) {
|
|
35165
34979
|
pointsVec2 = pointsVec2.reverse();
|
|
35166
34980
|
}
|
|
35167
34981
|
const crossSection = CrossSection.ofPolygons([pointsVec2]);
|
|
@@ -35297,7 +35111,30 @@ function processNonPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, m
|
|
|
35297
35111
|
// src/utils/manifold/process-plated-holes.ts
|
|
35298
35112
|
import { su as su15 } from "@tscircuit/circuit-json-util";
|
|
35299
35113
|
import * as THREE26 from "three";
|
|
35300
|
-
|
|
35114
|
+
|
|
35115
|
+
// src/utils/manifold-mesh-to-three-geometry.ts
|
|
35116
|
+
import * as THREE25 from "three";
|
|
35117
|
+
function manifoldMeshToThreeGeometry(manifoldMesh) {
|
|
35118
|
+
const geometry = new THREE25.BufferGeometry();
|
|
35119
|
+
geometry.setAttribute(
|
|
35120
|
+
"position",
|
|
35121
|
+
new THREE25.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
|
|
35122
|
+
);
|
|
35123
|
+
geometry.setIndex(new THREE25.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
|
|
35124
|
+
if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
|
|
35125
|
+
for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
|
|
35126
|
+
const start = manifoldMesh.runIndex[i];
|
|
35127
|
+
const count3 = manifoldMesh.runIndex[i + 1] - start;
|
|
35128
|
+
geometry.addGroup(start, count3, 0);
|
|
35129
|
+
}
|
|
35130
|
+
} else {
|
|
35131
|
+
geometry.addGroup(0, manifoldMesh.triVerts.length, 0);
|
|
35132
|
+
}
|
|
35133
|
+
return geometry;
|
|
35134
|
+
}
|
|
35135
|
+
|
|
35136
|
+
// src/utils/manifold/process-plated-holes.ts
|
|
35137
|
+
var arePointsClockwise5 = (points) => {
|
|
35301
35138
|
let area = 0;
|
|
35302
35139
|
for (let i = 0; i < points.length; i++) {
|
|
35303
35140
|
const j = (i + 1) % points.length;
|
|
@@ -35344,7 +35181,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
35344
35181
|
point2.x,
|
|
35345
35182
|
point2.y
|
|
35346
35183
|
]);
|
|
35347
|
-
if (
|
|
35184
|
+
if (arePointsClockwise5(points)) {
|
|
35348
35185
|
points = points.reverse();
|
|
35349
35186
|
}
|
|
35350
35187
|
const crossSection = CrossSection.ofPolygons([points]);
|
|
@@ -35389,7 +35226,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
35389
35226
|
const height10 = Math.max(baseHeight + sizeDelta, M);
|
|
35390
35227
|
if (holeShape === "oval") {
|
|
35391
35228
|
let points = createEllipsePoints(width10, height10, SMOOTH_CIRCLE_SEGMENTS);
|
|
35392
|
-
if (
|
|
35229
|
+
if (arePointsClockwise5(points)) {
|
|
35393
35230
|
points = points.reverse();
|
|
35394
35231
|
}
|
|
35395
35232
|
const crossSection = CrossSection.ofPolygons([points]);
|
|
@@ -35704,7 +35541,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
35704
35541
|
drillH,
|
|
35705
35542
|
SMOOTH_CIRCLE_SEGMENTS
|
|
35706
35543
|
);
|
|
35707
|
-
if (
|
|
35544
|
+
if (arePointsClockwise5(boardDrillPoints)) {
|
|
35708
35545
|
boardDrillPoints = boardDrillPoints.reverse();
|
|
35709
35546
|
}
|
|
35710
35547
|
const boardDrillCrossSection = CrossSection.ofPolygons([boardDrillPoints]);
|
|
@@ -35732,7 +35569,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
35732
35569
|
outerH,
|
|
35733
35570
|
SMOOTH_CIRCLE_SEGMENTS
|
|
35734
35571
|
);
|
|
35735
|
-
if (
|
|
35572
|
+
if (arePointsClockwise5(outerPoints)) {
|
|
35736
35573
|
outerPoints = outerPoints.reverse();
|
|
35737
35574
|
}
|
|
35738
35575
|
const outerCrossSection = CrossSection.ofPolygons([outerPoints]);
|
|
@@ -35751,7 +35588,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
35751
35588
|
holeH,
|
|
35752
35589
|
SMOOTH_CIRCLE_SEGMENTS
|
|
35753
35590
|
);
|
|
35754
|
-
if (
|
|
35591
|
+
if (arePointsClockwise5(innerPoints)) {
|
|
35755
35592
|
innerPoints = innerPoints.reverse();
|
|
35756
35593
|
}
|
|
35757
35594
|
const innerCrossSection = CrossSection.ofPolygons([innerPoints]);
|
|
@@ -36035,6 +35872,397 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
|
|
|
36035
35872
|
return { viaBoardDrills, viaCopperGeoms };
|
|
36036
35873
|
}
|
|
36037
35874
|
|
|
35875
|
+
// src/textures/create-copper-pour-texture-for-layer.ts
|
|
35876
|
+
import * as THREE29 from "three";
|
|
35877
|
+
import { CircuitToCanvasDrawer } from "circuit-to-canvas";
|
|
35878
|
+
function drawPolygon({
|
|
35879
|
+
ctx,
|
|
35880
|
+
points,
|
|
35881
|
+
canvasXFromPcb,
|
|
35882
|
+
canvasYFromPcb
|
|
35883
|
+
}) {
|
|
35884
|
+
if (points.length < 3) return;
|
|
35885
|
+
ctx.beginPath();
|
|
35886
|
+
points.forEach((point2, index2) => {
|
|
35887
|
+
const canvasX = canvasXFromPcb(point2[0]);
|
|
35888
|
+
const canvasY = canvasYFromPcb(point2[1]);
|
|
35889
|
+
if (index2 === 0) {
|
|
35890
|
+
ctx.moveTo(canvasX, canvasY);
|
|
35891
|
+
} else {
|
|
35892
|
+
ctx.lineTo(canvasX, canvasY);
|
|
35893
|
+
}
|
|
35894
|
+
});
|
|
35895
|
+
ctx.closePath();
|
|
35896
|
+
ctx.fill();
|
|
35897
|
+
}
|
|
35898
|
+
function drawBrepShape({
|
|
35899
|
+
ctx,
|
|
35900
|
+
pour,
|
|
35901
|
+
canvasXFromPcb,
|
|
35902
|
+
canvasYFromPcb
|
|
35903
|
+
}) {
|
|
35904
|
+
const brepShape = pour.brep_shape;
|
|
35905
|
+
if (!brepShape || !brepShape.outer_ring) return;
|
|
35906
|
+
const outerRingPoints = ringToPoints(brepShape.outer_ring, 32);
|
|
35907
|
+
if (outerRingPoints.length >= 3) {
|
|
35908
|
+
drawPolygon({
|
|
35909
|
+
ctx,
|
|
35910
|
+
points: outerRingPoints,
|
|
35911
|
+
canvasXFromPcb,
|
|
35912
|
+
canvasYFromPcb
|
|
35913
|
+
});
|
|
35914
|
+
}
|
|
35915
|
+
if (brepShape.inner_rings && brepShape.inner_rings.length > 0) {
|
|
35916
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
35917
|
+
for (const innerRing of brepShape.inner_rings) {
|
|
35918
|
+
const innerRingPoints = ringToPoints(innerRing, 32);
|
|
35919
|
+
if (innerRingPoints.length >= 3) {
|
|
35920
|
+
drawPolygon({
|
|
35921
|
+
ctx,
|
|
35922
|
+
points: innerRingPoints,
|
|
35923
|
+
canvasXFromPcb,
|
|
35924
|
+
canvasYFromPcb
|
|
35925
|
+
});
|
|
35926
|
+
}
|
|
35927
|
+
}
|
|
35928
|
+
ctx.globalCompositeOperation = "source-over";
|
|
35929
|
+
}
|
|
35930
|
+
}
|
|
35931
|
+
function createCopperPourTextureForLayer({
|
|
35932
|
+
layer,
|
|
35933
|
+
circuitJson,
|
|
35934
|
+
boardData,
|
|
35935
|
+
traceTextureResolution = TRACE_TEXTURE_RESOLUTION
|
|
35936
|
+
}) {
|
|
35937
|
+
const copperPours = circuitJson.filter(
|
|
35938
|
+
(e) => e.type === "pcb_copper_pour"
|
|
35939
|
+
);
|
|
35940
|
+
const poursOnLayer = copperPours.filter((p) => p.layer === layer);
|
|
35941
|
+
if (poursOnLayer.length === 0) return null;
|
|
35942
|
+
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
35943
|
+
const canvas = document.createElement("canvas");
|
|
35944
|
+
const canvasWidth = Math.floor(
|
|
35945
|
+
boardOutlineBounds.width * traceTextureResolution
|
|
35946
|
+
);
|
|
35947
|
+
const canvasHeight = Math.floor(
|
|
35948
|
+
boardOutlineBounds.height * traceTextureResolution
|
|
35949
|
+
);
|
|
35950
|
+
canvas.width = canvasWidth;
|
|
35951
|
+
canvas.height = canvasHeight;
|
|
35952
|
+
const ctx = canvas.getContext("2d");
|
|
35953
|
+
if (!ctx) return null;
|
|
35954
|
+
if (layer === "bottom") {
|
|
35955
|
+
ctx.translate(0, canvasHeight);
|
|
35956
|
+
ctx.scale(1, -1);
|
|
35957
|
+
}
|
|
35958
|
+
const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
|
|
35959
|
+
const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
|
|
35960
|
+
const rectAndPolygonPours = poursOnLayer.filter(
|
|
35961
|
+
(pour) => pour.shape === "rect" || pour.shape === "polygon"
|
|
35962
|
+
);
|
|
35963
|
+
const brepPours = poursOnLayer.filter((pour) => pour.shape === "brep");
|
|
35964
|
+
if (rectAndPolygonPours.length > 0) {
|
|
35965
|
+
const drawer = new CircuitToCanvasDrawer(ctx);
|
|
35966
|
+
drawer.setCameraBounds({
|
|
35967
|
+
minX: boardOutlineBounds.minX,
|
|
35968
|
+
maxX: boardOutlineBounds.maxX,
|
|
35969
|
+
minY: boardOutlineBounds.minY,
|
|
35970
|
+
maxY: boardOutlineBounds.maxY
|
|
35971
|
+
});
|
|
35972
|
+
const coveredPours = rectAndPolygonPours.filter(
|
|
35973
|
+
(p) => p.covered_with_solder_mask !== false
|
|
35974
|
+
);
|
|
35975
|
+
const uncoveredPours = rectAndPolygonPours.filter(
|
|
35976
|
+
(p) => p.covered_with_solder_mask === false
|
|
35977
|
+
);
|
|
35978
|
+
const coveredColor = `rgb(${colors.fr4TracesWithMaskGreen.map((c) => c * 255).join(",")})`;
|
|
35979
|
+
const uncoveredColor = `rgb(${colors.copper.map((c) => c * 255).join(",")})`;
|
|
35980
|
+
if (coveredPours.length > 0) {
|
|
35981
|
+
drawer.configure({
|
|
35982
|
+
colorOverrides: {
|
|
35983
|
+
copper: {
|
|
35984
|
+
top: coveredColor,
|
|
35985
|
+
bottom: coveredColor,
|
|
35986
|
+
inner1: coveredColor,
|
|
35987
|
+
inner2: coveredColor,
|
|
35988
|
+
inner3: coveredColor,
|
|
35989
|
+
inner4: coveredColor,
|
|
35990
|
+
inner5: coveredColor,
|
|
35991
|
+
inner6: coveredColor
|
|
35992
|
+
}
|
|
35993
|
+
}
|
|
35994
|
+
});
|
|
35995
|
+
drawer.drawElements(coveredPours, { layers: [layer] });
|
|
35996
|
+
}
|
|
35997
|
+
if (uncoveredPours.length > 0) {
|
|
35998
|
+
drawer.configure({
|
|
35999
|
+
colorOverrides: {
|
|
36000
|
+
copper: {
|
|
36001
|
+
top: uncoveredColor,
|
|
36002
|
+
bottom: uncoveredColor,
|
|
36003
|
+
inner1: uncoveredColor,
|
|
36004
|
+
inner2: uncoveredColor,
|
|
36005
|
+
inner3: uncoveredColor,
|
|
36006
|
+
inner4: uncoveredColor,
|
|
36007
|
+
inner5: uncoveredColor,
|
|
36008
|
+
inner6: uncoveredColor
|
|
36009
|
+
}
|
|
36010
|
+
}
|
|
36011
|
+
});
|
|
36012
|
+
drawer.drawElements(uncoveredPours, { layers: [layer] });
|
|
36013
|
+
}
|
|
36014
|
+
}
|
|
36015
|
+
for (const pour of brepPours) {
|
|
36016
|
+
const covered = pour.covered_with_solder_mask !== false;
|
|
36017
|
+
const colorArr = covered ? colors.fr4TracesWithMaskGreen : colors.copper;
|
|
36018
|
+
const copperColor = `rgb(${colorArr[0] * 255}, ${colorArr[1] * 255}, ${colorArr[2] * 255})`;
|
|
36019
|
+
ctx.fillStyle = copperColor;
|
|
36020
|
+
drawBrepShape({ ctx, pour, canvasXFromPcb, canvasYFromPcb });
|
|
36021
|
+
}
|
|
36022
|
+
const texture = new THREE29.CanvasTexture(canvas);
|
|
36023
|
+
texture.generateMipmaps = true;
|
|
36024
|
+
texture.minFilter = THREE29.LinearMipmapLinearFilter;
|
|
36025
|
+
texture.magFilter = THREE29.LinearFilter;
|
|
36026
|
+
texture.anisotropy = 16;
|
|
36027
|
+
texture.needsUpdate = true;
|
|
36028
|
+
return texture;
|
|
36029
|
+
}
|
|
36030
|
+
|
|
36031
|
+
// src/textures/create-three-texture-meshes.ts
|
|
36032
|
+
import * as THREE30 from "three";
|
|
36033
|
+
function createTexturePlane(config, boardData) {
|
|
36034
|
+
const {
|
|
36035
|
+
texture,
|
|
36036
|
+
yOffset,
|
|
36037
|
+
isBottomLayer,
|
|
36038
|
+
textureType,
|
|
36039
|
+
usePolygonOffset = false,
|
|
36040
|
+
renderOrder = 0
|
|
36041
|
+
} = config;
|
|
36042
|
+
if (!texture) return null;
|
|
36043
|
+
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
36044
|
+
const planeGeom = new THREE30.PlaneGeometry(
|
|
36045
|
+
boardOutlineBounds.width,
|
|
36046
|
+
boardOutlineBounds.height
|
|
36047
|
+
);
|
|
36048
|
+
const material = new THREE30.MeshBasicMaterial({
|
|
36049
|
+
map: texture,
|
|
36050
|
+
transparent: true,
|
|
36051
|
+
side: THREE30.DoubleSide,
|
|
36052
|
+
depthWrite: textureType === "panel-outlines",
|
|
36053
|
+
polygonOffset: usePolygonOffset,
|
|
36054
|
+
polygonOffsetFactor: usePolygonOffset ? -4 : 0,
|
|
36055
|
+
// Increased for better z-fighting prevention
|
|
36056
|
+
polygonOffsetUnits: usePolygonOffset ? -4 : 0
|
|
36057
|
+
});
|
|
36058
|
+
const mesh = new THREE30.Mesh(planeGeom, material);
|
|
36059
|
+
mesh.position.set(
|
|
36060
|
+
boardOutlineBounds.centerX,
|
|
36061
|
+
boardOutlineBounds.centerY,
|
|
36062
|
+
yOffset
|
|
36063
|
+
);
|
|
36064
|
+
if (isBottomLayer) {
|
|
36065
|
+
mesh.rotation.set(Math.PI, 0, 0);
|
|
36066
|
+
}
|
|
36067
|
+
mesh.name = `${isBottomLayer ? "bottom" : "top"}-${textureType}-texture-plane`;
|
|
36068
|
+
mesh.renderOrder = renderOrder;
|
|
36069
|
+
return mesh;
|
|
36070
|
+
}
|
|
36071
|
+
function createTextureMeshes(textures, boardData, pcbThickness) {
|
|
36072
|
+
const meshes = [];
|
|
36073
|
+
if (!textures || !boardData || pcbThickness === null) return meshes;
|
|
36074
|
+
const topTraceMesh = createTexturePlane(
|
|
36075
|
+
{
|
|
36076
|
+
texture: textures.topTrace,
|
|
36077
|
+
yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
|
|
36078
|
+
// Use consistent copper offset
|
|
36079
|
+
isBottomLayer: false,
|
|
36080
|
+
textureType: "trace",
|
|
36081
|
+
usePolygonOffset: false,
|
|
36082
|
+
renderOrder: 2
|
|
36083
|
+
// Render after soldermask
|
|
36084
|
+
},
|
|
36085
|
+
boardData
|
|
36086
|
+
);
|
|
36087
|
+
if (topTraceMesh) meshes.push(topTraceMesh);
|
|
36088
|
+
const topTraceWithMaskMesh = createTexturePlane(
|
|
36089
|
+
{
|
|
36090
|
+
texture: textures.topTraceWithMask,
|
|
36091
|
+
yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
|
|
36092
|
+
isBottomLayer: false,
|
|
36093
|
+
textureType: "trace-with-mask",
|
|
36094
|
+
usePolygonOffset: false,
|
|
36095
|
+
renderOrder: 2
|
|
36096
|
+
// Render after soldermask
|
|
36097
|
+
},
|
|
36098
|
+
boardData
|
|
36099
|
+
);
|
|
36100
|
+
if (topTraceWithMaskMesh) meshes.push(topTraceWithMaskMesh);
|
|
36101
|
+
const topSilkscreenMesh = createTexturePlane(
|
|
36102
|
+
{
|
|
36103
|
+
texture: textures.topSilkscreen,
|
|
36104
|
+
yOffset: pcbThickness / 2 + 3e-3,
|
|
36105
|
+
// Slightly above soldermask
|
|
36106
|
+
isBottomLayer: false,
|
|
36107
|
+
textureType: "silkscreen",
|
|
36108
|
+
usePolygonOffset: false,
|
|
36109
|
+
renderOrder: 3
|
|
36110
|
+
// Render after traces
|
|
36111
|
+
},
|
|
36112
|
+
boardData
|
|
36113
|
+
);
|
|
36114
|
+
if (topSilkscreenMesh) meshes.push(topSilkscreenMesh);
|
|
36115
|
+
const bottomTraceMesh = createTexturePlane(
|
|
36116
|
+
{
|
|
36117
|
+
texture: textures.bottomTrace,
|
|
36118
|
+
yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
|
|
36119
|
+
// Use consistent copper offset
|
|
36120
|
+
isBottomLayer: true,
|
|
36121
|
+
textureType: "trace",
|
|
36122
|
+
usePolygonOffset: false,
|
|
36123
|
+
renderOrder: 2
|
|
36124
|
+
// Render after soldermask
|
|
36125
|
+
},
|
|
36126
|
+
boardData
|
|
36127
|
+
);
|
|
36128
|
+
if (bottomTraceMesh) meshes.push(bottomTraceMesh);
|
|
36129
|
+
const bottomTraceWithMaskMesh = createTexturePlane(
|
|
36130
|
+
{
|
|
36131
|
+
texture: textures.bottomTraceWithMask,
|
|
36132
|
+
yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
|
|
36133
|
+
isBottomLayer: true,
|
|
36134
|
+
textureType: "trace-with-mask",
|
|
36135
|
+
usePolygonOffset: false,
|
|
36136
|
+
renderOrder: 2
|
|
36137
|
+
// Render after soldermask
|
|
36138
|
+
},
|
|
36139
|
+
boardData
|
|
36140
|
+
);
|
|
36141
|
+
if (bottomTraceWithMaskMesh) meshes.push(bottomTraceWithMaskMesh);
|
|
36142
|
+
const bottomSilkscreenMesh = createTexturePlane(
|
|
36143
|
+
{
|
|
36144
|
+
texture: textures.bottomSilkscreen,
|
|
36145
|
+
yOffset: -pcbThickness / 2 - 3e-3,
|
|
36146
|
+
isBottomLayer: true,
|
|
36147
|
+
textureType: "silkscreen",
|
|
36148
|
+
usePolygonOffset: false,
|
|
36149
|
+
renderOrder: 3
|
|
36150
|
+
// Render after traces
|
|
36151
|
+
},
|
|
36152
|
+
boardData
|
|
36153
|
+
);
|
|
36154
|
+
if (bottomSilkscreenMesh) meshes.push(bottomSilkscreenMesh);
|
|
36155
|
+
const topSoldermaskMesh = createTexturePlane(
|
|
36156
|
+
{
|
|
36157
|
+
texture: textures.topSoldermask,
|
|
36158
|
+
yOffset: pcbThickness / 2 + 1e-3,
|
|
36159
|
+
// Just above board surface
|
|
36160
|
+
isBottomLayer: false,
|
|
36161
|
+
textureType: "soldermask",
|
|
36162
|
+
usePolygonOffset: true,
|
|
36163
|
+
// Enable polygon offset
|
|
36164
|
+
renderOrder: 1
|
|
36165
|
+
// Render after board (renderOrder)
|
|
36166
|
+
},
|
|
36167
|
+
boardData
|
|
36168
|
+
);
|
|
36169
|
+
if (topSoldermaskMesh) meshes.push(topSoldermaskMesh);
|
|
36170
|
+
const bottomSoldermaskMesh = createTexturePlane(
|
|
36171
|
+
{
|
|
36172
|
+
texture: textures.bottomSoldermask,
|
|
36173
|
+
yOffset: -pcbThickness / 2 - 1e-3,
|
|
36174
|
+
// Just below board surface (bottom side)
|
|
36175
|
+
isBottomLayer: true,
|
|
36176
|
+
textureType: "soldermask",
|
|
36177
|
+
usePolygonOffset: true,
|
|
36178
|
+
// Enable polygon offset
|
|
36179
|
+
renderOrder: 1
|
|
36180
|
+
// Render after board (renderOrder)
|
|
36181
|
+
},
|
|
36182
|
+
boardData
|
|
36183
|
+
);
|
|
36184
|
+
if (bottomSoldermaskMesh) meshes.push(bottomSoldermaskMesh);
|
|
36185
|
+
const topCopperTextMesh = createTexturePlane(
|
|
36186
|
+
{
|
|
36187
|
+
texture: textures.topCopperText,
|
|
36188
|
+
yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
|
|
36189
|
+
isBottomLayer: false,
|
|
36190
|
+
textureType: "copper-text",
|
|
36191
|
+
usePolygonOffset: false,
|
|
36192
|
+
renderOrder: 2
|
|
36193
|
+
// Render after soldermask
|
|
36194
|
+
},
|
|
36195
|
+
boardData
|
|
36196
|
+
);
|
|
36197
|
+
if (topCopperTextMesh) meshes.push(topCopperTextMesh);
|
|
36198
|
+
const bottomCopperTextMesh = createTexturePlane(
|
|
36199
|
+
{
|
|
36200
|
+
texture: textures.bottomCopperText,
|
|
36201
|
+
yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
|
|
36202
|
+
isBottomLayer: true,
|
|
36203
|
+
textureType: "copper-text",
|
|
36204
|
+
usePolygonOffset: false,
|
|
36205
|
+
renderOrder: 2
|
|
36206
|
+
// Render after soldermask
|
|
36207
|
+
},
|
|
36208
|
+
boardData
|
|
36209
|
+
);
|
|
36210
|
+
if (bottomCopperTextMesh) meshes.push(bottomCopperTextMesh);
|
|
36211
|
+
const topCopperMesh = createTexturePlane(
|
|
36212
|
+
{
|
|
36213
|
+
texture: textures.topCopper,
|
|
36214
|
+
yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
|
|
36215
|
+
isBottomLayer: false,
|
|
36216
|
+
textureType: "copper",
|
|
36217
|
+
usePolygonOffset: false,
|
|
36218
|
+
renderOrder: 2
|
|
36219
|
+
// Render after soldermask
|
|
36220
|
+
},
|
|
36221
|
+
boardData
|
|
36222
|
+
);
|
|
36223
|
+
if (topCopperMesh) meshes.push(topCopperMesh);
|
|
36224
|
+
const bottomCopperMesh = createTexturePlane(
|
|
36225
|
+
{
|
|
36226
|
+
texture: textures.bottomCopper,
|
|
36227
|
+
yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
|
|
36228
|
+
isBottomLayer: true,
|
|
36229
|
+
textureType: "copper",
|
|
36230
|
+
usePolygonOffset: false,
|
|
36231
|
+
renderOrder: 2
|
|
36232
|
+
// Render after soldermask
|
|
36233
|
+
},
|
|
36234
|
+
boardData
|
|
36235
|
+
);
|
|
36236
|
+
if (bottomCopperMesh) meshes.push(bottomCopperMesh);
|
|
36237
|
+
const topPanelOutlinesMesh = createTexturePlane(
|
|
36238
|
+
{
|
|
36239
|
+
texture: textures.topPanelOutlines,
|
|
36240
|
+
yOffset: pcbThickness / 2 + 4e-3,
|
|
36241
|
+
// Above silkscreen
|
|
36242
|
+
isBottomLayer: false,
|
|
36243
|
+
textureType: "panel-outlines",
|
|
36244
|
+
usePolygonOffset: false,
|
|
36245
|
+
renderOrder: 4
|
|
36246
|
+
},
|
|
36247
|
+
boardData
|
|
36248
|
+
);
|
|
36249
|
+
if (topPanelOutlinesMesh) meshes.push(topPanelOutlinesMesh);
|
|
36250
|
+
const bottomPanelOutlinesMesh = createTexturePlane(
|
|
36251
|
+
{
|
|
36252
|
+
texture: textures.bottomPanelOutlines,
|
|
36253
|
+
yOffset: -pcbThickness / 2 - 4e-3,
|
|
36254
|
+
// Below bottom silkscreen
|
|
36255
|
+
isBottomLayer: true,
|
|
36256
|
+
textureType: "panel-outlines",
|
|
36257
|
+
usePolygonOffset: false,
|
|
36258
|
+
renderOrder: 4
|
|
36259
|
+
},
|
|
36260
|
+
boardData
|
|
36261
|
+
);
|
|
36262
|
+
if (bottomPanelOutlinesMesh) meshes.push(bottomPanelOutlinesMesh);
|
|
36263
|
+
return meshes;
|
|
36264
|
+
}
|
|
36265
|
+
|
|
36038
36266
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
36039
36267
|
var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
36040
36268
|
const [geoms, setGeoms] = useState14(null);
|
|
@@ -36104,7 +36332,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36104
36332
|
manifoldInstancesForCleanup.current = [];
|
|
36105
36333
|
let boardManifold = null;
|
|
36106
36334
|
const currentGeoms = {};
|
|
36107
|
-
const
|
|
36335
|
+
const layerTextureMap = {};
|
|
36108
36336
|
try {
|
|
36109
36337
|
const currentPcbThickness = boardData.thickness || 1.6;
|
|
36110
36338
|
setPcbThickness(currentPcbThickness);
|
|
@@ -36203,7 +36431,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36203
36431
|
{
|
|
36204
36432
|
key: "plated-holes-union",
|
|
36205
36433
|
geometry: cutPlatedGeom,
|
|
36206
|
-
color: new
|
|
36434
|
+
color: new THREE31.Color(
|
|
36207
36435
|
colors.copper[0],
|
|
36208
36436
|
colors.copper[1],
|
|
36209
36437
|
colors.copper[2]
|
|
@@ -36233,7 +36461,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36233
36461
|
const matColorArray = boardMaterialColors[boardData.material] ?? colors.fr4Tan;
|
|
36234
36462
|
currentGeoms.board = {
|
|
36235
36463
|
geometry: finalBoardGeom,
|
|
36236
|
-
color: new
|
|
36464
|
+
color: new THREE31.Color(
|
|
36237
36465
|
matColorArray[0],
|
|
36238
36466
|
matColorArray[1],
|
|
36239
36467
|
matColorArray[2]
|
|
@@ -36251,28 +36479,17 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36251
36479
|
boardClipVolume
|
|
36252
36480
|
);
|
|
36253
36481
|
currentGeoms.smtPads = smtPadGeoms;
|
|
36254
|
-
const { copperPourGeoms } = processCopperPoursForManifold(
|
|
36255
|
-
Manifold,
|
|
36256
|
-
CrossSection,
|
|
36257
|
-
circuitJson,
|
|
36258
|
-
currentPcbThickness,
|
|
36259
|
-
manifoldInstancesForCleanup.current,
|
|
36260
|
-
boardData.material,
|
|
36261
|
-
holeUnion,
|
|
36262
|
-
boardClipVolume
|
|
36263
|
-
);
|
|
36264
|
-
currentGeoms.copperPours = copperPourGeoms;
|
|
36265
36482
|
setGeoms(currentGeoms);
|
|
36266
36483
|
const traceColorWithoutMaskArr = colors.fr4TracesWithoutMaskTan;
|
|
36267
36484
|
const traceColorWithoutMask = `rgb(${Math.round(traceColorWithoutMaskArr[0] * 255)}, ${Math.round(traceColorWithoutMaskArr[1] * 255)}, ${Math.round(traceColorWithoutMaskArr[2] * 255)})`;
|
|
36268
|
-
|
|
36485
|
+
layerTextureMap.topTrace = createTraceTextureForLayer({
|
|
36269
36486
|
layer: "top",
|
|
36270
36487
|
circuitJson,
|
|
36271
36488
|
boardData,
|
|
36272
36489
|
traceColor: traceColorWithoutMask,
|
|
36273
36490
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36274
36491
|
});
|
|
36275
|
-
|
|
36492
|
+
layerTextureMap.bottomTrace = createTraceTextureForLayer({
|
|
36276
36493
|
layer: "bottom",
|
|
36277
36494
|
circuitJson,
|
|
36278
36495
|
boardData,
|
|
@@ -36281,14 +36498,14 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36281
36498
|
});
|
|
36282
36499
|
const traceColorWithMaskArr = colors.fr4TracesWithMaskGreen;
|
|
36283
36500
|
const traceColorWithMask = `rgb(${Math.round(traceColorWithMaskArr[0] * 255)}, ${Math.round(traceColorWithMaskArr[1] * 255)}, ${Math.round(traceColorWithMaskArr[2] * 255)})`;
|
|
36284
|
-
|
|
36501
|
+
layerTextureMap.topTraceWithMask = createTraceTextureForLayer({
|
|
36285
36502
|
layer: "top",
|
|
36286
36503
|
circuitJson,
|
|
36287
36504
|
boardData,
|
|
36288
36505
|
traceColor: traceColorWithMask,
|
|
36289
36506
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36290
36507
|
});
|
|
36291
|
-
|
|
36508
|
+
layerTextureMap.bottomTraceWithMask = createTraceTextureForLayer({
|
|
36292
36509
|
layer: "bottom",
|
|
36293
36510
|
circuitJson,
|
|
36294
36511
|
boardData,
|
|
@@ -36296,14 +36513,14 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36296
36513
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36297
36514
|
});
|
|
36298
36515
|
const silkscreenColor = "rgb(255,255,255)";
|
|
36299
|
-
|
|
36516
|
+
layerTextureMap.topSilkscreen = createSilkscreenTextureForLayer({
|
|
36300
36517
|
layer: "top",
|
|
36301
36518
|
circuitJson,
|
|
36302
36519
|
boardData,
|
|
36303
36520
|
silkscreenColor,
|
|
36304
36521
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36305
36522
|
});
|
|
36306
|
-
|
|
36523
|
+
layerTextureMap.bottomSilkscreen = createSilkscreenTextureForLayer({
|
|
36307
36524
|
layer: "bottom",
|
|
36308
36525
|
circuitJson,
|
|
36309
36526
|
boardData,
|
|
@@ -36312,14 +36529,14 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36312
36529
|
});
|
|
36313
36530
|
const soldermaskColorArr = soldermaskColors[boardData.material] ?? colors.fr4SolderMaskGreen;
|
|
36314
36531
|
const soldermaskColor = `rgb(${Math.round(soldermaskColorArr[0] * 255)}, ${Math.round(soldermaskColorArr[1] * 255)}, ${Math.round(soldermaskColorArr[2] * 255)})`;
|
|
36315
|
-
|
|
36532
|
+
layerTextureMap.topSoldermask = createSoldermaskTextureForLayer({
|
|
36316
36533
|
layer: "top",
|
|
36317
36534
|
circuitJson,
|
|
36318
36535
|
boardData,
|
|
36319
36536
|
soldermaskColor,
|
|
36320
36537
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36321
36538
|
});
|
|
36322
|
-
|
|
36539
|
+
layerTextureMap.bottomSoldermask = createSoldermaskTextureForLayer({
|
|
36323
36540
|
layer: "bottom",
|
|
36324
36541
|
circuitJson,
|
|
36325
36542
|
boardData,
|
|
@@ -36328,33 +36545,45 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36328
36545
|
});
|
|
36329
36546
|
const copperColorArr = colors.copper;
|
|
36330
36547
|
const copperColor = `rgb(${Math.round(copperColorArr[0] * 255)}, ${Math.round(copperColorArr[1] * 255)}, ${Math.round(copperColorArr[2] * 255)})`;
|
|
36331
|
-
|
|
36548
|
+
layerTextureMap.topCopperText = createCopperTextTextureForLayer({
|
|
36332
36549
|
layer: "top",
|
|
36333
36550
|
circuitJson,
|
|
36334
36551
|
boardData,
|
|
36335
36552
|
copperColor,
|
|
36336
36553
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36337
36554
|
});
|
|
36338
|
-
|
|
36555
|
+
layerTextureMap.bottomCopperText = createCopperTextTextureForLayer({
|
|
36339
36556
|
layer: "bottom",
|
|
36340
36557
|
circuitJson,
|
|
36341
36558
|
boardData,
|
|
36342
36559
|
copperColor,
|
|
36343
36560
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36344
36561
|
});
|
|
36345
|
-
|
|
36562
|
+
layerTextureMap.topPanelOutlines = createPanelOutlineTextureForLayer({
|
|
36346
36563
|
layer: "top",
|
|
36347
36564
|
circuitJson,
|
|
36348
36565
|
panelData: boardData,
|
|
36349
36566
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36350
36567
|
});
|
|
36351
|
-
|
|
36568
|
+
layerTextureMap.bottomPanelOutlines = createPanelOutlineTextureForLayer({
|
|
36352
36569
|
layer: "bottom",
|
|
36353
36570
|
circuitJson,
|
|
36354
36571
|
panelData: boardData,
|
|
36355
36572
|
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36356
36573
|
});
|
|
36357
|
-
|
|
36574
|
+
layerTextureMap.topCopper = createCopperPourTextureForLayer({
|
|
36575
|
+
layer: "top",
|
|
36576
|
+
circuitJson,
|
|
36577
|
+
boardData,
|
|
36578
|
+
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36579
|
+
});
|
|
36580
|
+
layerTextureMap.bottomCopper = createCopperPourTextureForLayer({
|
|
36581
|
+
layer: "bottom",
|
|
36582
|
+
circuitJson,
|
|
36583
|
+
boardData,
|
|
36584
|
+
traceTextureResolution: TRACE_TEXTURE_RESOLUTION
|
|
36585
|
+
});
|
|
36586
|
+
setTextures(layerTextureMap);
|
|
36358
36587
|
} catch (e) {
|
|
36359
36588
|
console.error("Error processing geometry with Manifold in hook:", e);
|
|
36360
36589
|
setError(
|
|
@@ -36382,11 +36611,11 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
36382
36611
|
};
|
|
36383
36612
|
|
|
36384
36613
|
// src/utils/manifold/create-three-geometry-meshes.ts
|
|
36385
|
-
import * as
|
|
36614
|
+
import * as THREE33 from "three";
|
|
36386
36615
|
|
|
36387
36616
|
// src/utils/create-board-material.ts
|
|
36388
|
-
import * as
|
|
36389
|
-
var DEFAULT_SIDE =
|
|
36617
|
+
import * as THREE32 from "three";
|
|
36618
|
+
var DEFAULT_SIDE = THREE32.DoubleSide;
|
|
36390
36619
|
var createBoardMaterial = ({
|
|
36391
36620
|
material,
|
|
36392
36621
|
color,
|
|
@@ -36394,7 +36623,7 @@ var createBoardMaterial = ({
|
|
|
36394
36623
|
isFaux = false
|
|
36395
36624
|
}) => {
|
|
36396
36625
|
if (material === "fr4") {
|
|
36397
|
-
return new
|
|
36626
|
+
return new THREE32.MeshPhysicalMaterial({
|
|
36398
36627
|
color,
|
|
36399
36628
|
side,
|
|
36400
36629
|
metalness: 0,
|
|
@@ -36408,7 +36637,7 @@ var createBoardMaterial = ({
|
|
|
36408
36637
|
flatShading: true
|
|
36409
36638
|
});
|
|
36410
36639
|
}
|
|
36411
|
-
return new
|
|
36640
|
+
return new THREE32.MeshStandardMaterial({
|
|
36412
36641
|
color,
|
|
36413
36642
|
side,
|
|
36414
36643
|
flatShading: true,
|
|
@@ -36424,12 +36653,12 @@ function createGeometryMeshes(geoms) {
|
|
|
36424
36653
|
const meshes = [];
|
|
36425
36654
|
if (!geoms) return meshes;
|
|
36426
36655
|
if (geoms.board && geoms.board.geometry) {
|
|
36427
|
-
const mesh = new
|
|
36656
|
+
const mesh = new THREE33.Mesh(
|
|
36428
36657
|
geoms.board.geometry,
|
|
36429
36658
|
createBoardMaterial({
|
|
36430
36659
|
material: geoms.board.material,
|
|
36431
36660
|
color: geoms.board.color,
|
|
36432
|
-
side:
|
|
36661
|
+
side: THREE33.DoubleSide,
|
|
36433
36662
|
isFaux: geoms.board.isFaux
|
|
36434
36663
|
})
|
|
36435
36664
|
);
|
|
@@ -36439,11 +36668,11 @@ function createGeometryMeshes(geoms) {
|
|
|
36439
36668
|
const createMeshesFromArray = (geomArray) => {
|
|
36440
36669
|
if (geomArray) {
|
|
36441
36670
|
geomArray.forEach((comp) => {
|
|
36442
|
-
const mesh = new
|
|
36671
|
+
const mesh = new THREE33.Mesh(
|
|
36443
36672
|
comp.geometry,
|
|
36444
|
-
new
|
|
36673
|
+
new THREE33.MeshStandardMaterial({
|
|
36445
36674
|
color: comp.color,
|
|
36446
|
-
side:
|
|
36675
|
+
side: THREE33.DoubleSide,
|
|
36447
36676
|
flatShading: true,
|
|
36448
36677
|
// Consistent with board
|
|
36449
36678
|
polygonOffset: true,
|
|
@@ -36459,172 +36688,6 @@ function createGeometryMeshes(geoms) {
|
|
|
36459
36688
|
createMeshesFromArray(geoms.platedHoles);
|
|
36460
36689
|
createMeshesFromArray(geoms.smtPads);
|
|
36461
36690
|
createMeshesFromArray(geoms.vias);
|
|
36462
|
-
createMeshesFromArray(geoms.copperPours);
|
|
36463
|
-
return meshes;
|
|
36464
|
-
}
|
|
36465
|
-
|
|
36466
|
-
// src/utils/manifold/create-three-texture-meshes.ts
|
|
36467
|
-
import * as THREE32 from "three";
|
|
36468
|
-
function createTextureMeshes(textures, boardData, pcbThickness) {
|
|
36469
|
-
const meshes = [];
|
|
36470
|
-
if (!textures || !boardData || pcbThickness === null) return meshes;
|
|
36471
|
-
const createTexturePlane = (texture, yOffset, isBottomLayer, keySuffix, usePolygonOffset = false, renderOrder = 0) => {
|
|
36472
|
-
if (!texture) return null;
|
|
36473
|
-
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
36474
|
-
const planeGeom = new THREE32.PlaneGeometry(
|
|
36475
|
-
boardOutlineBounds.width,
|
|
36476
|
-
boardOutlineBounds.height
|
|
36477
|
-
);
|
|
36478
|
-
const material = new THREE32.MeshBasicMaterial({
|
|
36479
|
-
map: texture,
|
|
36480
|
-
transparent: true,
|
|
36481
|
-
side: THREE32.DoubleSide,
|
|
36482
|
-
depthWrite: keySuffix === "panel-outlines",
|
|
36483
|
-
polygonOffset: usePolygonOffset,
|
|
36484
|
-
polygonOffsetFactor: usePolygonOffset ? -4 : 0,
|
|
36485
|
-
// Increased for better z-fighting prevention
|
|
36486
|
-
polygonOffsetUnits: usePolygonOffset ? -4 : 0
|
|
36487
|
-
});
|
|
36488
|
-
const mesh = new THREE32.Mesh(planeGeom, material);
|
|
36489
|
-
mesh.position.set(
|
|
36490
|
-
boardOutlineBounds.centerX,
|
|
36491
|
-
boardOutlineBounds.centerY,
|
|
36492
|
-
yOffset
|
|
36493
|
-
);
|
|
36494
|
-
if (isBottomLayer) {
|
|
36495
|
-
mesh.rotation.set(Math.PI, 0, 0);
|
|
36496
|
-
}
|
|
36497
|
-
mesh.name = `${isBottomLayer ? "bottom" : "top"}-${keySuffix}-texture-plane`;
|
|
36498
|
-
mesh.renderOrder = renderOrder;
|
|
36499
|
-
return mesh;
|
|
36500
|
-
};
|
|
36501
|
-
const topTraceMesh = createTexturePlane(
|
|
36502
|
-
textures.topTrace,
|
|
36503
|
-
pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
|
|
36504
|
-
// Use consistent copper offset
|
|
36505
|
-
false,
|
|
36506
|
-
"trace",
|
|
36507
|
-
false,
|
|
36508
|
-
2
|
|
36509
|
-
// Render after soldermask
|
|
36510
|
-
);
|
|
36511
|
-
if (topTraceMesh) meshes.push(topTraceMesh);
|
|
36512
|
-
const topTraceWithMaskMesh = createTexturePlane(
|
|
36513
|
-
textures.topTraceWithMask,
|
|
36514
|
-
pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
|
|
36515
|
-
false,
|
|
36516
|
-
"trace-with-mask",
|
|
36517
|
-
false,
|
|
36518
|
-
2
|
|
36519
|
-
// Render after soldermask
|
|
36520
|
-
);
|
|
36521
|
-
if (topTraceWithMaskMesh) meshes.push(topTraceWithMaskMesh);
|
|
36522
|
-
const topSilkscreenMesh = createTexturePlane(
|
|
36523
|
-
textures.topSilkscreen,
|
|
36524
|
-
pcbThickness / 2 + 3e-3,
|
|
36525
|
-
// Slightly above soldermask
|
|
36526
|
-
false,
|
|
36527
|
-
"silkscreen",
|
|
36528
|
-
false,
|
|
36529
|
-
3
|
|
36530
|
-
// Render after traces
|
|
36531
|
-
);
|
|
36532
|
-
if (topSilkscreenMesh) meshes.push(topSilkscreenMesh);
|
|
36533
|
-
const bottomTraceMesh = createTexturePlane(
|
|
36534
|
-
textures.bottomTrace,
|
|
36535
|
-
-pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
|
|
36536
|
-
// Use consistent copper offset
|
|
36537
|
-
true,
|
|
36538
|
-
"trace",
|
|
36539
|
-
false,
|
|
36540
|
-
2
|
|
36541
|
-
// Render after soldermask
|
|
36542
|
-
);
|
|
36543
|
-
if (bottomTraceMesh) meshes.push(bottomTraceMesh);
|
|
36544
|
-
const bottomTraceWithMaskMesh = createTexturePlane(
|
|
36545
|
-
textures.bottomTraceWithMask,
|
|
36546
|
-
-pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
|
|
36547
|
-
true,
|
|
36548
|
-
"trace-with-mask",
|
|
36549
|
-
false,
|
|
36550
|
-
2
|
|
36551
|
-
// Render after soldermask
|
|
36552
|
-
);
|
|
36553
|
-
if (bottomTraceWithMaskMesh) meshes.push(bottomTraceWithMaskMesh);
|
|
36554
|
-
const bottomSilkscreenMesh = createTexturePlane(
|
|
36555
|
-
textures.bottomSilkscreen,
|
|
36556
|
-
-pcbThickness / 2 - 3e-3,
|
|
36557
|
-
true,
|
|
36558
|
-
"silkscreen",
|
|
36559
|
-
false,
|
|
36560
|
-
3
|
|
36561
|
-
// Render after traces
|
|
36562
|
-
);
|
|
36563
|
-
if (bottomSilkscreenMesh) meshes.push(bottomSilkscreenMesh);
|
|
36564
|
-
const topSoldermaskMesh = createTexturePlane(
|
|
36565
|
-
textures.topSoldermask,
|
|
36566
|
-
pcbThickness / 2 + 1e-3,
|
|
36567
|
-
// Just above board surface
|
|
36568
|
-
false,
|
|
36569
|
-
"soldermask",
|
|
36570
|
-
true,
|
|
36571
|
-
// Enable polygon offset
|
|
36572
|
-
1
|
|
36573
|
-
// Render after board (renderOrder)
|
|
36574
|
-
);
|
|
36575
|
-
if (topSoldermaskMesh) meshes.push(topSoldermaskMesh);
|
|
36576
|
-
const bottomSoldermaskMesh = createTexturePlane(
|
|
36577
|
-
textures.bottomSoldermask,
|
|
36578
|
-
-pcbThickness / 2 - 1e-3,
|
|
36579
|
-
// Just below board surface (bottom side)
|
|
36580
|
-
true,
|
|
36581
|
-
"soldermask",
|
|
36582
|
-
true,
|
|
36583
|
-
// Enable polygon offset
|
|
36584
|
-
1
|
|
36585
|
-
// Render after board (renderOrder)
|
|
36586
|
-
);
|
|
36587
|
-
if (bottomSoldermaskMesh) meshes.push(bottomSoldermaskMesh);
|
|
36588
|
-
const topCopperTextMesh = createTexturePlane(
|
|
36589
|
-
textures.topCopperText,
|
|
36590
|
-
pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
|
|
36591
|
-
false,
|
|
36592
|
-
"copper-text",
|
|
36593
|
-
false,
|
|
36594
|
-
2
|
|
36595
|
-
// Render after soldermask
|
|
36596
|
-
);
|
|
36597
|
-
if (topCopperTextMesh) meshes.push(topCopperTextMesh);
|
|
36598
|
-
const bottomCopperTextMesh = createTexturePlane(
|
|
36599
|
-
textures.bottomCopperText,
|
|
36600
|
-
-pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
|
|
36601
|
-
true,
|
|
36602
|
-
"copper-text",
|
|
36603
|
-
false,
|
|
36604
|
-
2
|
|
36605
|
-
// Render after soldermask
|
|
36606
|
-
);
|
|
36607
|
-
if (bottomCopperTextMesh) meshes.push(bottomCopperTextMesh);
|
|
36608
|
-
const topPanelOutlinesMesh = createTexturePlane(
|
|
36609
|
-
textures.topPanelOutlines,
|
|
36610
|
-
pcbThickness / 2 + 4e-3,
|
|
36611
|
-
// Above silkscreen
|
|
36612
|
-
false,
|
|
36613
|
-
"panel-outlines",
|
|
36614
|
-
false,
|
|
36615
|
-
4
|
|
36616
|
-
);
|
|
36617
|
-
if (topPanelOutlinesMesh) meshes.push(topPanelOutlinesMesh);
|
|
36618
|
-
const bottomPanelOutlinesMesh = createTexturePlane(
|
|
36619
|
-
textures.bottomPanelOutlines,
|
|
36620
|
-
-pcbThickness / 2 - 4e-3,
|
|
36621
|
-
// Below bottom silkscreen
|
|
36622
|
-
true,
|
|
36623
|
-
"panel-outlines",
|
|
36624
|
-
false,
|
|
36625
|
-
4
|
|
36626
|
-
);
|
|
36627
|
-
if (bottomPanelOutlinesMesh) meshes.push(bottomPanelOutlinesMesh);
|
|
36628
36691
|
return meshes;
|
|
36629
36692
|
}
|
|
36630
36693
|
|
|
@@ -36652,8 +36715,6 @@ var BoardMeshes = ({
|
|
|
36652
36715
|
}
|
|
36653
36716
|
} else if (mesh.name.includes("plated_hole") || mesh.name.includes("via")) {
|
|
36654
36717
|
shouldShow = visibility.topCopper || visibility.bottomCopper;
|
|
36655
|
-
} else if (mesh.name.includes("copper_pour")) {
|
|
36656
|
-
shouldShow = visibility.topCopper || visibility.bottomCopper;
|
|
36657
36718
|
}
|
|
36658
36719
|
if (shouldShow) {
|
|
36659
36720
|
rootObject.add(mesh);
|
|
@@ -36681,6 +36742,10 @@ var BoardMeshes = ({
|
|
|
36681
36742
|
shouldShow = visibility.topCopper;
|
|
36682
36743
|
} else if (mesh.name.includes("bottom-copper-text")) {
|
|
36683
36744
|
shouldShow = visibility.bottomCopper;
|
|
36745
|
+
} else if (mesh.name.includes("top-copper")) {
|
|
36746
|
+
shouldShow = visibility.topCopper;
|
|
36747
|
+
} else if (mesh.name.includes("bottom-copper")) {
|
|
36748
|
+
shouldShow = visibility.bottomCopper;
|
|
36684
36749
|
} else if (mesh.name.includes("panel-outlines")) {
|
|
36685
36750
|
shouldShow = visibility.boardBody;
|
|
36686
36751
|
}
|
|
@@ -43536,7 +43601,7 @@ var KeyboardShortcutsDialog = ({
|
|
|
43536
43601
|
|
|
43537
43602
|
// src/CadViewer.tsx
|
|
43538
43603
|
import { jsx as jsx37, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
43539
|
-
var DEFAULT_TARGET = new
|
|
43604
|
+
var DEFAULT_TARGET = new THREE34.Vector3(0, 0, 0);
|
|
43540
43605
|
var INITIAL_CAMERA_POSITION = [5, -5, 5];
|
|
43541
43606
|
var CadViewerInner = (props) => {
|
|
43542
43607
|
const [engine, setEngine] = useState35("manifold");
|
|
@@ -43803,11 +43868,11 @@ var CadViewer = (props) => {
|
|
|
43803
43868
|
// src/convert-circuit-json-to-3d-svg.ts
|
|
43804
43869
|
var import_debug = __toESM(require_browser(), 1);
|
|
43805
43870
|
import { su as su20 } from "@tscircuit/circuit-json-util";
|
|
43806
|
-
import * as
|
|
43871
|
+
import * as THREE38 from "three";
|
|
43807
43872
|
import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
|
|
43808
43873
|
|
|
43809
43874
|
// src/utils/create-geometry-from-polygons.ts
|
|
43810
|
-
import * as
|
|
43875
|
+
import * as THREE35 from "three";
|
|
43811
43876
|
import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute2 } from "three";
|
|
43812
43877
|
function createGeometryFromPolygons(polygons) {
|
|
43813
43878
|
const geometry = new BufferGeometry3();
|
|
@@ -43821,12 +43886,12 @@ function createGeometryFromPolygons(polygons) {
|
|
|
43821
43886
|
...polygon3.vertices[i + 1]
|
|
43822
43887
|
// Third vertex
|
|
43823
43888
|
);
|
|
43824
|
-
const v1 = new
|
|
43825
|
-
const v2 = new
|
|
43826
|
-
const v3 = new
|
|
43827
|
-
const normal = new
|
|
43828
|
-
new
|
|
43829
|
-
new
|
|
43889
|
+
const v1 = new THREE35.Vector3(...polygon3.vertices[0]);
|
|
43890
|
+
const v2 = new THREE35.Vector3(...polygon3.vertices[i]);
|
|
43891
|
+
const v3 = new THREE35.Vector3(...polygon3.vertices[i + 1]);
|
|
43892
|
+
const normal = new THREE35.Vector3().crossVectors(
|
|
43893
|
+
new THREE35.Vector3().subVectors(v2, v1),
|
|
43894
|
+
new THREE35.Vector3().subVectors(v3, v1)
|
|
43830
43895
|
).normalize();
|
|
43831
43896
|
normals.push(
|
|
43832
43897
|
normal.x,
|
|
@@ -43850,10 +43915,10 @@ function createGeometryFromPolygons(polygons) {
|
|
|
43850
43915
|
var import_modeling2 = __toESM(require_src(), 1);
|
|
43851
43916
|
var import_jscad_planner2 = __toESM(require_dist(), 1);
|
|
43852
43917
|
var jscadModeling2 = __toESM(require_src(), 1);
|
|
43853
|
-
import * as
|
|
43918
|
+
import * as THREE37 from "three";
|
|
43854
43919
|
|
|
43855
43920
|
// src/utils/load-model.ts
|
|
43856
|
-
import * as
|
|
43921
|
+
import * as THREE36 from "three";
|
|
43857
43922
|
import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
43858
43923
|
import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
|
|
43859
43924
|
import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
|
|
@@ -43861,12 +43926,12 @@ async function load3DModel(url) {
|
|
|
43861
43926
|
if (url.endsWith(".stl")) {
|
|
43862
43927
|
const loader = new STLLoader2();
|
|
43863
43928
|
const geometry = await loader.loadAsync(url);
|
|
43864
|
-
const material = new
|
|
43929
|
+
const material = new THREE36.MeshStandardMaterial({
|
|
43865
43930
|
color: 8947848,
|
|
43866
43931
|
metalness: 0.5,
|
|
43867
43932
|
roughness: 0.5
|
|
43868
43933
|
});
|
|
43869
|
-
return new
|
|
43934
|
+
return new THREE36.Mesh(geometry, material);
|
|
43870
43935
|
}
|
|
43871
43936
|
if (url.endsWith(".obj")) {
|
|
43872
43937
|
const loader = new OBJLoader2();
|
|
@@ -43899,9 +43964,9 @@ async function renderComponent(component, scene) {
|
|
|
43899
43964
|
}
|
|
43900
43965
|
if (component.rotation) {
|
|
43901
43966
|
model.rotation.set(
|
|
43902
|
-
|
|
43903
|
-
|
|
43904
|
-
|
|
43967
|
+
THREE37.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
43968
|
+
THREE37.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
43969
|
+
THREE37.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
43905
43970
|
);
|
|
43906
43971
|
}
|
|
43907
43972
|
scene.add(model);
|
|
@@ -43915,13 +43980,13 @@ async function renderComponent(component, scene) {
|
|
|
43915
43980
|
);
|
|
43916
43981
|
if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
|
|
43917
43982
|
const threeGeom = convertCSGToThreeGeom(jscadObject);
|
|
43918
|
-
const material2 = new
|
|
43983
|
+
const material2 = new THREE37.MeshStandardMaterial({
|
|
43919
43984
|
color: 8947848,
|
|
43920
43985
|
metalness: 0.5,
|
|
43921
43986
|
roughness: 0.5,
|
|
43922
|
-
side:
|
|
43987
|
+
side: THREE37.DoubleSide
|
|
43923
43988
|
});
|
|
43924
|
-
const mesh2 = new
|
|
43989
|
+
const mesh2 = new THREE37.Mesh(threeGeom, material2);
|
|
43925
43990
|
if (component.position) {
|
|
43926
43991
|
mesh2.position.set(
|
|
43927
43992
|
component.position.x ?? 0,
|
|
@@ -43931,9 +43996,9 @@ async function renderComponent(component, scene) {
|
|
|
43931
43996
|
}
|
|
43932
43997
|
if (component.rotation) {
|
|
43933
43998
|
mesh2.rotation.set(
|
|
43934
|
-
|
|
43935
|
-
|
|
43936
|
-
|
|
43999
|
+
THREE37.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
44000
|
+
THREE37.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
44001
|
+
THREE37.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
43937
44002
|
);
|
|
43938
44003
|
}
|
|
43939
44004
|
scene.add(mesh2);
|
|
@@ -43950,17 +44015,17 @@ async function renderComponent(component, scene) {
|
|
|
43950
44015
|
if (!geom || !geom.polygons && !geom.sides) {
|
|
43951
44016
|
continue;
|
|
43952
44017
|
}
|
|
43953
|
-
const color = new
|
|
44018
|
+
const color = new THREE37.Color(geomInfo.color);
|
|
43954
44019
|
color.convertLinearToSRGB();
|
|
43955
44020
|
const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
|
|
43956
44021
|
const threeGeom = convertCSGToThreeGeom(geomWithColor);
|
|
43957
|
-
const material2 = new
|
|
44022
|
+
const material2 = new THREE37.MeshStandardMaterial({
|
|
43958
44023
|
vertexColors: true,
|
|
43959
44024
|
metalness: 0.2,
|
|
43960
44025
|
roughness: 0.8,
|
|
43961
|
-
side:
|
|
44026
|
+
side: THREE37.DoubleSide
|
|
43962
44027
|
});
|
|
43963
|
-
const mesh2 = new
|
|
44028
|
+
const mesh2 = new THREE37.Mesh(threeGeom, material2);
|
|
43964
44029
|
if (component.position) {
|
|
43965
44030
|
mesh2.position.set(
|
|
43966
44031
|
component.position.x ?? 0,
|
|
@@ -43970,22 +44035,22 @@ async function renderComponent(component, scene) {
|
|
|
43970
44035
|
}
|
|
43971
44036
|
if (component.rotation) {
|
|
43972
44037
|
mesh2.rotation.set(
|
|
43973
|
-
|
|
43974
|
-
|
|
43975
|
-
|
|
44038
|
+
THREE37.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
44039
|
+
THREE37.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
44040
|
+
THREE37.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
43976
44041
|
);
|
|
43977
44042
|
}
|
|
43978
44043
|
scene.add(mesh2);
|
|
43979
44044
|
}
|
|
43980
44045
|
return;
|
|
43981
44046
|
}
|
|
43982
|
-
const geometry = new
|
|
43983
|
-
const material = new
|
|
44047
|
+
const geometry = new THREE37.BoxGeometry(0.5, 0.5, 0.5);
|
|
44048
|
+
const material = new THREE37.MeshStandardMaterial({
|
|
43984
44049
|
color: 16711680,
|
|
43985
44050
|
transparent: true,
|
|
43986
44051
|
opacity: 0.25
|
|
43987
44052
|
});
|
|
43988
|
-
const mesh = new
|
|
44053
|
+
const mesh = new THREE37.Mesh(geometry, material);
|
|
43989
44054
|
if (component.position) {
|
|
43990
44055
|
mesh.position.set(
|
|
43991
44056
|
component.position.x ?? 0,
|
|
@@ -44006,11 +44071,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
44006
44071
|
padding = 20,
|
|
44007
44072
|
zoom = 1.5
|
|
44008
44073
|
} = options;
|
|
44009
|
-
const scene = new
|
|
44074
|
+
const scene = new THREE38.Scene();
|
|
44010
44075
|
const renderer = new SVGRenderer();
|
|
44011
44076
|
renderer.setSize(width10, height10);
|
|
44012
|
-
renderer.setClearColor(new
|
|
44013
|
-
const camera = new
|
|
44077
|
+
renderer.setClearColor(new THREE38.Color(backgroundColor), 1);
|
|
44078
|
+
const camera = new THREE38.OrthographicCamera();
|
|
44014
44079
|
const aspect = width10 / height10;
|
|
44015
44080
|
const frustumSize = 100;
|
|
44016
44081
|
const halfFrustumSize = frustumSize / 2 / zoom;
|
|
@@ -44024,11 +44089,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
44024
44089
|
camera.position.set(position.x, position.y, position.z);
|
|
44025
44090
|
camera.up.set(0, 1, 0);
|
|
44026
44091
|
const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
|
|
44027
|
-
camera.lookAt(new
|
|
44092
|
+
camera.lookAt(new THREE38.Vector3(lookAt.x, lookAt.y, lookAt.z));
|
|
44028
44093
|
camera.updateProjectionMatrix();
|
|
44029
|
-
const ambientLight = new
|
|
44094
|
+
const ambientLight = new THREE38.AmbientLight(16777215, Math.PI / 2);
|
|
44030
44095
|
scene.add(ambientLight);
|
|
44031
|
-
const pointLight = new
|
|
44096
|
+
const pointLight = new THREE38.PointLight(16777215, Math.PI / 4);
|
|
44032
44097
|
pointLight.position.set(-10, -10, 10);
|
|
44033
44098
|
scene.add(pointLight);
|
|
44034
44099
|
const components = su20(circuitJson).cad_component.list();
|
|
@@ -44039,7 +44104,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
44039
44104
|
const boardGeom = createBoardGeomFromCircuitJson(circuitJson);
|
|
44040
44105
|
if (boardGeom) {
|
|
44041
44106
|
const solderMaskColor = colors.fr4SolderMaskGreen;
|
|
44042
|
-
const baseColor = new
|
|
44107
|
+
const baseColor = new THREE38.Color(
|
|
44043
44108
|
solderMaskColor[0],
|
|
44044
44109
|
solderMaskColor[1],
|
|
44045
44110
|
solderMaskColor[2]
|
|
@@ -44051,28 +44116,28 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
44051
44116
|
const material = createBoardMaterial({
|
|
44052
44117
|
material: boardData?.material,
|
|
44053
44118
|
color: baseColor,
|
|
44054
|
-
side:
|
|
44119
|
+
side: THREE38.DoubleSide
|
|
44055
44120
|
});
|
|
44056
|
-
const mesh = new
|
|
44121
|
+
const mesh = new THREE38.Mesh(geometry, material);
|
|
44057
44122
|
scene.add(mesh);
|
|
44058
44123
|
}
|
|
44059
44124
|
}
|
|
44060
|
-
const gridColor = new
|
|
44061
|
-
const gridHelper = new
|
|
44125
|
+
const gridColor = new THREE38.Color(8947848);
|
|
44126
|
+
const gridHelper = new THREE38.GridHelper(100, 100, gridColor, gridColor);
|
|
44062
44127
|
gridHelper.rotation.x = Math.PI / 2;
|
|
44063
44128
|
const materials = Array.isArray(gridHelper.material) ? gridHelper.material : [gridHelper.material];
|
|
44064
44129
|
for (const mat of materials) {
|
|
44065
44130
|
mat.transparent = true;
|
|
44066
44131
|
mat.opacity = 0.3;
|
|
44067
|
-
if (mat instanceof
|
|
44132
|
+
if (mat instanceof THREE38.LineBasicMaterial) {
|
|
44068
44133
|
mat.color = gridColor;
|
|
44069
44134
|
mat.vertexColors = false;
|
|
44070
44135
|
}
|
|
44071
44136
|
}
|
|
44072
44137
|
scene.add(gridHelper);
|
|
44073
|
-
const box = new
|
|
44074
|
-
const center = box.getCenter(new
|
|
44075
|
-
const size5 = box.getSize(new
|
|
44138
|
+
const box = new THREE38.Box3().setFromObject(scene);
|
|
44139
|
+
const center = box.getCenter(new THREE38.Vector3());
|
|
44140
|
+
const size5 = box.getSize(new THREE38.Vector3());
|
|
44076
44141
|
scene.position.sub(center);
|
|
44077
44142
|
const maxDim = Math.max(size5.x, size5.y, size5.z);
|
|
44078
44143
|
if (maxDim > 0) {
|