@tscircuit/3d-viewer 0.0.511 → 0.0.513
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 +26 -17
- package/dist/index.js +719 -1043
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var require_flatten = __commonJS({
|
|
29
29
|
"node_modules/@jscad/modeling/src/utils/flatten.js"(exports, module) {
|
|
30
30
|
"use strict";
|
|
31
|
-
var flatten = (arr) => arr.
|
|
31
|
+
var flatten = (arr) => arr.flat(Infinity);
|
|
32
32
|
module.exports = flatten;
|
|
33
33
|
}
|
|
34
34
|
});
|
|
@@ -9255,9 +9255,10 @@ var require_extrudeWalls = __commonJS({
|
|
|
9255
9255
|
return edges;
|
|
9256
9256
|
}
|
|
9257
9257
|
const divisor = vec3.fromValues(multiple, multiple, multiple);
|
|
9258
|
+
const increment = vec3.create();
|
|
9258
9259
|
const newEdges = [];
|
|
9259
9260
|
edges.forEach((edge) => {
|
|
9260
|
-
|
|
9261
|
+
vec3.subtract(increment, edge[1], edge[0]);
|
|
9261
9262
|
vec3.divide(increment, increment, divisor);
|
|
9262
9263
|
let prev = edge[0];
|
|
9263
9264
|
for (let i = 1; i <= multiple; ++i) {
|
|
@@ -9336,7 +9337,10 @@ var require_extrudeFromSlices = __commonJS({
|
|
|
9336
9337
|
const edges = slice.toEdges(currentSlice);
|
|
9337
9338
|
if (edges.length === 0) throw new Error("the callback function must return slices with one or more edges");
|
|
9338
9339
|
if (prevSlice) {
|
|
9339
|
-
|
|
9340
|
+
const walls = extrudeWalls(prevSlice, currentSlice);
|
|
9341
|
+
for (let i = 0; i < walls.length; i++) {
|
|
9342
|
+
polygons.push(walls[i]);
|
|
9343
|
+
}
|
|
9340
9344
|
}
|
|
9341
9345
|
if (s === 0) startSlice = currentSlice;
|
|
9342
9346
|
if (s === numberOfSlices - 1) endSlice = currentSlice;
|
|
@@ -9345,15 +9349,22 @@ var require_extrudeFromSlices = __commonJS({
|
|
|
9345
9349
|
}
|
|
9346
9350
|
if (capEnd) {
|
|
9347
9351
|
const endPolygons = slice.toPolygons(endSlice);
|
|
9348
|
-
|
|
9352
|
+
for (let i = 0; i < endPolygons.length; i++) {
|
|
9353
|
+
polygons.push(endPolygons[i]);
|
|
9354
|
+
}
|
|
9349
9355
|
}
|
|
9350
9356
|
if (capStart) {
|
|
9351
9357
|
const startPolygons = slice.toPolygons(startSlice).map(poly3.invert);
|
|
9352
|
-
|
|
9358
|
+
for (let i = 0; i < startPolygons.length; i++) {
|
|
9359
|
+
polygons.push(startPolygons[i]);
|
|
9360
|
+
}
|
|
9353
9361
|
}
|
|
9354
9362
|
if (!capStart && !capEnd) {
|
|
9355
9363
|
if (close && !slice.equals(endSlice, startSlice)) {
|
|
9356
|
-
|
|
9364
|
+
const walls = extrudeWalls(endSlice, startSlice);
|
|
9365
|
+
for (let i = 0; i < walls.length; i++) {
|
|
9366
|
+
polygons.push(walls[i]);
|
|
9367
|
+
}
|
|
9357
9368
|
}
|
|
9358
9369
|
}
|
|
9359
9370
|
return geom3.create(polygons);
|
|
@@ -9429,12 +9440,15 @@ var require_extrudeRotate = __commonJS({
|
|
|
9429
9440
|
const baseSlice = slice.fromSides(geom2.toSides(geometry));
|
|
9430
9441
|
slice.reverse(baseSlice, baseSlice);
|
|
9431
9442
|
const matrix = mat4.create();
|
|
9443
|
+
const xRotationMatrix = mat4.fromXRotation(mat4.create(), TAU / 4);
|
|
9444
|
+
const zRotationMatrix = mat4.create();
|
|
9432
9445
|
const createSlice = (progress, index2, base) => {
|
|
9433
9446
|
let Zrotation = rotationPerSlice * index2 + startAngle;
|
|
9434
9447
|
if (totalRotation === TAU && index2 === segments) {
|
|
9435
9448
|
Zrotation = startAngle;
|
|
9436
9449
|
}
|
|
9437
|
-
mat4.
|
|
9450
|
+
mat4.fromZRotation(zRotationMatrix, Zrotation);
|
|
9451
|
+
mat4.multiply(matrix, zRotationMatrix, xRotationMatrix);
|
|
9438
9452
|
return slice.transform(matrix, base);
|
|
9439
9453
|
};
|
|
9440
9454
|
options = {
|
|
@@ -10323,6 +10337,7 @@ var require_reTesselateCoplanarPolygons = __commonJS({
|
|
|
10323
10337
|
const newoutpolygonrow = [];
|
|
10324
10338
|
const ycoordinate = ycoordinates[yindex];
|
|
10325
10339
|
const polygonindexeswithcorner = ycoordinatetopolygonindexes.get(ycoordinate);
|
|
10340
|
+
let removeCount = 0;
|
|
10326
10341
|
for (let activepolygonindex = 0; activepolygonindex < activepolygons.length; ++activepolygonindex) {
|
|
10327
10342
|
const activepolygon = activepolygons[activepolygonindex];
|
|
10328
10343
|
const polygonindex = activepolygon.polygonindex;
|
|
@@ -10343,8 +10358,8 @@ var require_reTesselateCoplanarPolygons = __commonJS({
|
|
|
10343
10358
|
newrightvertexindex = nextrightvertexindex;
|
|
10344
10359
|
}
|
|
10345
10360
|
if (newleftvertexindex !== activepolygon.leftvertexindex && newleftvertexindex === newrightvertexindex) {
|
|
10346
|
-
|
|
10347
|
-
|
|
10361
|
+
activepolygon._remove = true;
|
|
10362
|
+
removeCount++;
|
|
10348
10363
|
} else {
|
|
10349
10364
|
activepolygon.leftvertexindex = newleftvertexindex;
|
|
10350
10365
|
activepolygon.rightvertexindex = newrightvertexindex;
|
|
@@ -10359,6 +10374,9 @@ var require_reTesselateCoplanarPolygons = __commonJS({
|
|
|
10359
10374
|
}
|
|
10360
10375
|
}
|
|
10361
10376
|
}
|
|
10377
|
+
if (removeCount > 0) {
|
|
10378
|
+
activepolygons = activepolygons.filter((p) => !p._remove);
|
|
10379
|
+
}
|
|
10362
10380
|
let nextycoordinate;
|
|
10363
10381
|
if (yindex >= ycoordinates.length - 1) {
|
|
10364
10382
|
activepolygons = [];
|
|
@@ -10534,8 +10552,10 @@ var require_retessellate = __commonJS({
|
|
|
10534
10552
|
const destPolygons = [];
|
|
10535
10553
|
classified.forEach((group) => {
|
|
10536
10554
|
if (Array.isArray(group)) {
|
|
10537
|
-
const
|
|
10538
|
-
|
|
10555
|
+
const coplanarPolygons = reTesselateCoplanarPolygons(group);
|
|
10556
|
+
for (let i = 0; i < coplanarPolygons.length; i++) {
|
|
10557
|
+
destPolygons.push(coplanarPolygons[i]);
|
|
10558
|
+
}
|
|
10539
10559
|
} else {
|
|
10540
10560
|
destPolygons.push(group);
|
|
10541
10561
|
}
|
|
@@ -10768,6 +10788,19 @@ var require_splitPolygonByPlane = __commonJS({
|
|
|
10768
10788
|
var vec3 = require_vec3();
|
|
10769
10789
|
var poly3 = require_poly3();
|
|
10770
10790
|
var splitLineSegmentByPlane = require_splitLineSegmentByPlane();
|
|
10791
|
+
var EPS_SQUARED = EPS * EPS;
|
|
10792
|
+
var removeConsecutiveDuplicates = (vertices) => {
|
|
10793
|
+
const result = [];
|
|
10794
|
+
let prevvertex = vertices[vertices.length - 1];
|
|
10795
|
+
for (let i = 0; i < vertices.length; i++) {
|
|
10796
|
+
const vertex = vertices[i];
|
|
10797
|
+
if (vec3.squaredDistance(vertex, prevvertex) >= EPS_SQUARED) {
|
|
10798
|
+
result.push(vertex);
|
|
10799
|
+
}
|
|
10800
|
+
prevvertex = vertex;
|
|
10801
|
+
}
|
|
10802
|
+
return result;
|
|
10803
|
+
};
|
|
10771
10804
|
var splitPolygonByPlane = (splane, polygon3) => {
|
|
10772
10805
|
const result = {
|
|
10773
10806
|
type: null,
|
|
@@ -10829,34 +10862,17 @@ var require_splitPolygonByPlane = __commonJS({
|
|
|
10829
10862
|
}
|
|
10830
10863
|
isback = nextisback;
|
|
10831
10864
|
}
|
|
10832
|
-
const EPS_SQUARED = EPS * EPS;
|
|
10833
|
-
if (backvertices.length >= 3) {
|
|
10834
|
-
let prevvertex = backvertices[backvertices.length - 1];
|
|
10835
|
-
for (let vertexindex = 0; vertexindex < backvertices.length; vertexindex++) {
|
|
10836
|
-
const vertex = backvertices[vertexindex];
|
|
10837
|
-
if (vec3.squaredDistance(vertex, prevvertex) < EPS_SQUARED) {
|
|
10838
|
-
backvertices.splice(vertexindex, 1);
|
|
10839
|
-
vertexindex--;
|
|
10840
|
-
}
|
|
10841
|
-
prevvertex = vertex;
|
|
10842
|
-
}
|
|
10843
|
-
}
|
|
10844
10865
|
if (frontvertices.length >= 3) {
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
if (vec3.squaredDistance(vertex, prevvertex) < EPS_SQUARED) {
|
|
10849
|
-
frontvertices.splice(vertexindex, 1);
|
|
10850
|
-
vertexindex--;
|
|
10851
|
-
}
|
|
10852
|
-
prevvertex = vertex;
|
|
10866
|
+
const frontFiltered = removeConsecutiveDuplicates(frontvertices);
|
|
10867
|
+
if (frontFiltered.length >= 3) {
|
|
10868
|
+
result.front = poly3.fromPointsAndPlane(frontFiltered, pplane);
|
|
10853
10869
|
}
|
|
10854
10870
|
}
|
|
10855
|
-
if (frontvertices.length >= 3) {
|
|
10856
|
-
result.front = poly3.fromPointsAndPlane(frontvertices, pplane);
|
|
10857
|
-
}
|
|
10858
10871
|
if (backvertices.length >= 3) {
|
|
10859
|
-
|
|
10872
|
+
const backFiltered = removeConsecutiveDuplicates(backvertices);
|
|
10873
|
+
if (backFiltered.length >= 3) {
|
|
10874
|
+
result.back = poly3.fromPointsAndPlane(backFiltered, pplane);
|
|
10875
|
+
}
|
|
10860
10876
|
}
|
|
10861
10877
|
}
|
|
10862
10878
|
}
|
|
@@ -10900,10 +10916,6 @@ var require_PolygonTreeNode = __commonJS({
|
|
|
10900
10916
|
if (!this.removed) {
|
|
10901
10917
|
this.removed = true;
|
|
10902
10918
|
this.polygon = null;
|
|
10903
|
-
const parentschildren = this.parent.children;
|
|
10904
|
-
const i = parentschildren.indexOf(this);
|
|
10905
|
-
if (i < 0) throw new Error("Assertion failed");
|
|
10906
|
-
parentschildren.splice(i, 1);
|
|
10907
10919
|
this.parent.recursivelyInvalidatePolygon();
|
|
10908
10920
|
}
|
|
10909
10921
|
}
|
|
@@ -10923,6 +10935,13 @@ var require_PolygonTreeNode = __commonJS({
|
|
|
10923
10935
|
return this.polygon;
|
|
10924
10936
|
}
|
|
10925
10937
|
getPolygons(result) {
|
|
10938
|
+
if (this.isRootNode() && this.children.length > 0) {
|
|
10939
|
+
const compacted = [];
|
|
10940
|
+
for (let i2 = 0; i2 < this.children.length; i2++) {
|
|
10941
|
+
if (!this.children[i2].removed) compacted.push(this.children[i2]);
|
|
10942
|
+
}
|
|
10943
|
+
this.children = compacted;
|
|
10944
|
+
}
|
|
10926
10945
|
let children = [this];
|
|
10927
10946
|
const queue = [children];
|
|
10928
10947
|
let i, j, l, node;
|
|
@@ -14226,7 +14245,7 @@ var require_browser = __commonJS({
|
|
|
14226
14245
|
|
|
14227
14246
|
// src/CadViewer.tsx
|
|
14228
14247
|
import { useState as useState36, useCallback as useCallback21, useRef as useRef26, useEffect as useEffect44 } from "react";
|
|
14229
|
-
import * as
|
|
14248
|
+
import * as THREE36 from "three";
|
|
14230
14249
|
|
|
14231
14250
|
// src/CadViewerJscad.tsx
|
|
14232
14251
|
import { su as su12 } from "@tscircuit/circuit-json-util";
|
|
@@ -28338,9 +28357,9 @@ var AnyCadComponent = ({
|
|
|
28338
28357
|
if (!cad_component.position) return void 0;
|
|
28339
28358
|
let z18;
|
|
28340
28359
|
if (layer === "top") {
|
|
28341
|
-
z18 =
|
|
28360
|
+
z18 = cad_component.position.z;
|
|
28342
28361
|
} else if (layer === "bottom") {
|
|
28343
|
-
z18 = -(
|
|
28362
|
+
z18 = -(cad_component.position.z + pcbThickness);
|
|
28344
28363
|
} else {
|
|
28345
28364
|
z18 = cad_component.position.z;
|
|
28346
28365
|
}
|
|
@@ -28464,7 +28483,7 @@ import * as THREE16 from "three";
|
|
|
28464
28483
|
// package.json
|
|
28465
28484
|
var package_default = {
|
|
28466
28485
|
name: "@tscircuit/3d-viewer",
|
|
28467
|
-
version: "0.0.
|
|
28486
|
+
version: "0.0.512",
|
|
28468
28487
|
main: "./dist/index.js",
|
|
28469
28488
|
module: "./dist/index.js",
|
|
28470
28489
|
type: "module",
|
|
@@ -31543,529 +31562,12 @@ var ThreeErrorBoundary = class extends React11.Component {
|
|
|
31543
31562
|
import { su as su9 } from "@tscircuit/circuit-json-util";
|
|
31544
31563
|
import { useEffect as useEffect23, useMemo as useMemo19 } from "react";
|
|
31545
31564
|
|
|
31546
|
-
// src/textures/create-
|
|
31547
|
-
import * as
|
|
31548
|
-
import { CircuitToCanvasDrawer } from "circuit-to-canvas";
|
|
31549
|
-
|
|
31550
|
-
// node_modules/@tscircuit/math-utils/dist/chunk-5N7UJNVK.js
|
|
31551
|
-
var getBoundsFromPoints = (points) => {
|
|
31552
|
-
if (points.length === 0) {
|
|
31553
|
-
return null;
|
|
31554
|
-
}
|
|
31555
|
-
let minX = points[0].x;
|
|
31556
|
-
let minY = points[0].y;
|
|
31557
|
-
let maxX = points[0].x;
|
|
31558
|
-
let maxY = points[0].y;
|
|
31559
|
-
for (let i = 1; i < points.length; i++) {
|
|
31560
|
-
const point = points[i];
|
|
31561
|
-
if (point.x < minX) minX = point.x;
|
|
31562
|
-
if (point.y < minY) minY = point.y;
|
|
31563
|
-
if (point.x > maxX) maxX = point.x;
|
|
31564
|
-
if (point.y > maxY) maxY = point.y;
|
|
31565
|
-
}
|
|
31566
|
-
return { minX, minY, maxX, maxY };
|
|
31567
|
-
};
|
|
31568
|
-
|
|
31569
|
-
// src/utils/outline-bounds.ts
|
|
31570
|
-
function calculateOutlineBounds(boardData) {
|
|
31571
|
-
if (boardData.outline && boardData.outline.length >= 3) {
|
|
31572
|
-
const bounds2 = getBoundsFromPoints(boardData.outline);
|
|
31573
|
-
return {
|
|
31574
|
-
...bounds2,
|
|
31575
|
-
width: bounds2.maxX - bounds2.minX,
|
|
31576
|
-
height: bounds2.maxY - bounds2.minY,
|
|
31577
|
-
centerX: (bounds2.minX + bounds2.maxX) / 2,
|
|
31578
|
-
centerY: (bounds2.minY + bounds2.maxY) / 2
|
|
31579
|
-
};
|
|
31580
|
-
}
|
|
31581
|
-
const boardWidth = boardData.width ?? 0;
|
|
31582
|
-
const boardHeight = boardData.height ?? 0;
|
|
31583
|
-
const boardCenterX = boardData.center?.x ?? 0;
|
|
31584
|
-
const boardCenterY = boardData.center?.y ?? 0;
|
|
31585
|
-
const bounds = {
|
|
31586
|
-
minX: boardCenterX - boardWidth / 2,
|
|
31587
|
-
maxX: boardCenterX + boardWidth / 2,
|
|
31588
|
-
minY: boardCenterY - boardHeight / 2,
|
|
31589
|
-
maxY: boardCenterY + boardHeight / 2
|
|
31590
|
-
};
|
|
31591
|
-
return {
|
|
31592
|
-
...bounds,
|
|
31593
|
-
width: boardWidth,
|
|
31594
|
-
height: boardHeight,
|
|
31595
|
-
centerX: boardCenterX,
|
|
31596
|
-
centerY: boardCenterY
|
|
31597
|
-
};
|
|
31598
|
-
}
|
|
31599
|
-
|
|
31600
|
-
// src/geoms/brep-converter.ts
|
|
31601
|
-
var import_primitives7 = __toESM(require_primitives(), 1);
|
|
31602
|
-
var import_booleans5 = __toESM(require_booleans(), 1);
|
|
31603
|
-
function segmentToPoints(p1, p2, bulge, arcSegments) {
|
|
31604
|
-
if (!bulge || Math.abs(bulge) < 1e-9) {
|
|
31605
|
-
return [];
|
|
31606
|
-
}
|
|
31607
|
-
const theta = 4 * Math.atan(bulge);
|
|
31608
|
-
const dx = p2[0] - p1[0];
|
|
31609
|
-
const dy = p2[1] - p1[1];
|
|
31610
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
31611
|
-
if (dist < 1e-9) return [];
|
|
31612
|
-
const radius = Math.abs(dist / (2 * Math.sin(theta / 2)));
|
|
31613
|
-
const m = Math.sqrt(Math.max(0, radius * radius - dist / 2 * (dist / 2)));
|
|
31614
|
-
const midPoint = [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2];
|
|
31615
|
-
const ux = dx / dist;
|
|
31616
|
-
const uy = dy / dist;
|
|
31617
|
-
const nx = -uy;
|
|
31618
|
-
const ny = ux;
|
|
31619
|
-
const centerX = midPoint[0] + nx * m * Math.sign(bulge);
|
|
31620
|
-
const centerY = midPoint[1] + ny * m * Math.sign(bulge);
|
|
31621
|
-
const startAngle = Math.atan2(p1[1] - centerY, p1[0] - centerX);
|
|
31622
|
-
const points = [];
|
|
31623
|
-
const numSteps = Math.max(
|
|
31624
|
-
2,
|
|
31625
|
-
Math.ceil(arcSegments * Math.abs(theta) / (Math.PI * 2) * 4)
|
|
31626
|
-
);
|
|
31627
|
-
const angleStep = theta / numSteps;
|
|
31628
|
-
for (let i = 1; i < numSteps; i++) {
|
|
31629
|
-
const angle = startAngle + angleStep * i;
|
|
31630
|
-
points.push([
|
|
31631
|
-
centerX + radius * Math.cos(angle),
|
|
31632
|
-
centerY + radius * Math.sin(angle)
|
|
31633
|
-
]);
|
|
31634
|
-
}
|
|
31635
|
-
return points;
|
|
31636
|
-
}
|
|
31637
|
-
function ringToPoints(ring, arcSegments) {
|
|
31638
|
-
const allPoints = [];
|
|
31639
|
-
const vertices = ring.vertices;
|
|
31640
|
-
for (let i = 0; i < vertices.length; i++) {
|
|
31641
|
-
const p1 = vertices[i];
|
|
31642
|
-
const p2 = vertices[(i + 1) % vertices.length];
|
|
31643
|
-
allPoints.push([p1.x, p1.y]);
|
|
31644
|
-
if (p1.bulge) {
|
|
31645
|
-
const arcPoints = segmentToPoints(
|
|
31646
|
-
[p1.x, p1.y],
|
|
31647
|
-
[p2.x, p2.y],
|
|
31648
|
-
p1.bulge,
|
|
31649
|
-
arcSegments
|
|
31650
|
-
);
|
|
31651
|
-
allPoints.push(...arcPoints);
|
|
31652
|
-
}
|
|
31653
|
-
}
|
|
31654
|
-
return allPoints;
|
|
31655
|
-
}
|
|
31656
|
-
|
|
31657
|
-
// src/textures/create-copper-pour-texture-for-layer.ts
|
|
31658
|
-
function drawPolygon({
|
|
31659
|
-
ctx,
|
|
31660
|
-
points,
|
|
31661
|
-
canvasXFromPcb,
|
|
31662
|
-
canvasYFromPcb
|
|
31663
|
-
}) {
|
|
31664
|
-
if (points.length < 3) return;
|
|
31665
|
-
ctx.beginPath();
|
|
31666
|
-
points.forEach((point, index2) => {
|
|
31667
|
-
const canvasX = canvasXFromPcb(point[0]);
|
|
31668
|
-
const canvasY = canvasYFromPcb(point[1]);
|
|
31669
|
-
if (index2 === 0) {
|
|
31670
|
-
ctx.moveTo(canvasX, canvasY);
|
|
31671
|
-
} else {
|
|
31672
|
-
ctx.lineTo(canvasX, canvasY);
|
|
31673
|
-
}
|
|
31674
|
-
});
|
|
31675
|
-
ctx.closePath();
|
|
31676
|
-
ctx.fill();
|
|
31677
|
-
}
|
|
31678
|
-
function drawBrepShape({
|
|
31679
|
-
ctx,
|
|
31680
|
-
pour,
|
|
31681
|
-
canvasXFromPcb,
|
|
31682
|
-
canvasYFromPcb
|
|
31683
|
-
}) {
|
|
31684
|
-
const brepShape = pour.brep_shape;
|
|
31685
|
-
if (!brepShape || !brepShape.outer_ring) return;
|
|
31686
|
-
const outerRingPoints = ringToPoints(brepShape.outer_ring, 32);
|
|
31687
|
-
if (outerRingPoints.length >= 3) {
|
|
31688
|
-
drawPolygon({
|
|
31689
|
-
ctx,
|
|
31690
|
-
points: outerRingPoints,
|
|
31691
|
-
canvasXFromPcb,
|
|
31692
|
-
canvasYFromPcb
|
|
31693
|
-
});
|
|
31694
|
-
}
|
|
31695
|
-
if (brepShape.inner_rings && brepShape.inner_rings.length > 0) {
|
|
31696
|
-
ctx.globalCompositeOperation = "destination-out";
|
|
31697
|
-
for (const innerRing of brepShape.inner_rings) {
|
|
31698
|
-
const innerRingPoints = ringToPoints(innerRing, 32);
|
|
31699
|
-
if (innerRingPoints.length >= 3) {
|
|
31700
|
-
drawPolygon({
|
|
31701
|
-
ctx,
|
|
31702
|
-
points: innerRingPoints,
|
|
31703
|
-
canvasXFromPcb,
|
|
31704
|
-
canvasYFromPcb
|
|
31705
|
-
});
|
|
31706
|
-
}
|
|
31707
|
-
}
|
|
31708
|
-
ctx.globalCompositeOperation = "source-over";
|
|
31709
|
-
}
|
|
31710
|
-
}
|
|
31711
|
-
function createCopperPourTextureForLayer({
|
|
31712
|
-
layer,
|
|
31713
|
-
circuitJson,
|
|
31714
|
-
boardData,
|
|
31715
|
-
traceTextureResolution = TRACE_TEXTURE_RESOLUTION
|
|
31716
|
-
}) {
|
|
31717
|
-
const copperPours = circuitJson.filter(
|
|
31718
|
-
(e) => e.type === "pcb_copper_pour"
|
|
31719
|
-
);
|
|
31720
|
-
const pcbRenderLayer = layer === "top" ? "top_copper" : "bottom_copper";
|
|
31721
|
-
const poursOnLayer = copperPours.filter((p) => p.layer === layer);
|
|
31722
|
-
if (poursOnLayer.length === 0) return null;
|
|
31723
|
-
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
31724
|
-
const canvas = document.createElement("canvas");
|
|
31725
|
-
const canvasWidth = Math.floor(
|
|
31726
|
-
boardOutlineBounds.width * traceTextureResolution
|
|
31727
|
-
);
|
|
31728
|
-
const canvasHeight = Math.floor(
|
|
31729
|
-
boardOutlineBounds.height * traceTextureResolution
|
|
31730
|
-
);
|
|
31731
|
-
canvas.width = canvasWidth;
|
|
31732
|
-
canvas.height = canvasHeight;
|
|
31733
|
-
const ctx = canvas.getContext("2d");
|
|
31734
|
-
if (!ctx) return null;
|
|
31735
|
-
if (layer === "bottom") {
|
|
31736
|
-
ctx.translate(0, canvasHeight);
|
|
31737
|
-
ctx.scale(1, -1);
|
|
31738
|
-
}
|
|
31739
|
-
const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
|
|
31740
|
-
const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
|
|
31741
|
-
const rectAndPolygonPours = poursOnLayer.filter(
|
|
31742
|
-
(pour) => pour.shape === "rect" || pour.shape === "polygon"
|
|
31743
|
-
);
|
|
31744
|
-
const brepPours = poursOnLayer.filter((pour) => pour.shape === "brep");
|
|
31745
|
-
if (rectAndPolygonPours.length > 0) {
|
|
31746
|
-
const drawer = new CircuitToCanvasDrawer(ctx);
|
|
31747
|
-
drawer.setCameraBounds({
|
|
31748
|
-
minX: boardOutlineBounds.minX,
|
|
31749
|
-
maxX: boardOutlineBounds.maxX,
|
|
31750
|
-
minY: boardOutlineBounds.minY,
|
|
31751
|
-
maxY: boardOutlineBounds.maxY
|
|
31752
|
-
});
|
|
31753
|
-
const coveredPours = rectAndPolygonPours.filter(
|
|
31754
|
-
(p) => p.covered_with_solder_mask !== false
|
|
31755
|
-
);
|
|
31756
|
-
const uncoveredPours = rectAndPolygonPours.filter(
|
|
31757
|
-
(p) => p.covered_with_solder_mask === false
|
|
31758
|
-
);
|
|
31759
|
-
const coveredColor = `rgb(${colors.fr4TracesWithMaskGreen.map((c) => c * 255).join(",")})`;
|
|
31760
|
-
const uncoveredColor = `rgb(${colors.copper.map((c) => c * 255).join(",")})`;
|
|
31761
|
-
if (coveredPours.length > 0) {
|
|
31762
|
-
drawer.configure({
|
|
31763
|
-
colorOverrides: {
|
|
31764
|
-
copper: {
|
|
31765
|
-
top: coveredColor,
|
|
31766
|
-
bottom: coveredColor,
|
|
31767
|
-
inner1: coveredColor,
|
|
31768
|
-
inner2: coveredColor,
|
|
31769
|
-
inner3: coveredColor,
|
|
31770
|
-
inner4: coveredColor,
|
|
31771
|
-
inner5: coveredColor,
|
|
31772
|
-
inner6: coveredColor
|
|
31773
|
-
}
|
|
31774
|
-
}
|
|
31775
|
-
});
|
|
31776
|
-
drawer.drawElements(coveredPours, { layers: [pcbRenderLayer] });
|
|
31777
|
-
}
|
|
31778
|
-
if (uncoveredPours.length > 0) {
|
|
31779
|
-
drawer.configure({
|
|
31780
|
-
colorOverrides: {
|
|
31781
|
-
copper: {
|
|
31782
|
-
top: uncoveredColor,
|
|
31783
|
-
bottom: uncoveredColor,
|
|
31784
|
-
inner1: uncoveredColor,
|
|
31785
|
-
inner2: uncoveredColor,
|
|
31786
|
-
inner3: uncoveredColor,
|
|
31787
|
-
inner4: uncoveredColor,
|
|
31788
|
-
inner5: uncoveredColor,
|
|
31789
|
-
inner6: uncoveredColor
|
|
31790
|
-
}
|
|
31791
|
-
}
|
|
31792
|
-
});
|
|
31793
|
-
drawer.drawElements(uncoveredPours, { layers: [pcbRenderLayer] });
|
|
31794
|
-
}
|
|
31795
|
-
}
|
|
31796
|
-
for (const pour of brepPours) {
|
|
31797
|
-
const covered = pour.covered_with_solder_mask !== false;
|
|
31798
|
-
const colorArr = covered ? colors.fr4TracesWithMaskGreen : colors.copper;
|
|
31799
|
-
const copperColor = `rgb(${colorArr[0] * 255}, ${colorArr[1] * 255}, ${colorArr[2] * 255})`;
|
|
31800
|
-
ctx.fillStyle = copperColor;
|
|
31801
|
-
drawBrepShape({ ctx, pour, canvasXFromPcb, canvasYFromPcb });
|
|
31802
|
-
}
|
|
31803
|
-
const texture = new THREE19.CanvasTexture(canvas);
|
|
31804
|
-
texture.generateMipmaps = true;
|
|
31805
|
-
texture.minFilter = THREE19.LinearMipmapLinearFilter;
|
|
31806
|
-
texture.magFilter = THREE19.LinearFilter;
|
|
31807
|
-
texture.anisotropy = 16;
|
|
31808
|
-
texture.needsUpdate = true;
|
|
31809
|
-
return texture;
|
|
31810
|
-
}
|
|
31811
|
-
|
|
31812
|
-
// src/textures/create-three-texture-meshes.ts
|
|
31813
|
-
import * as THREE20 from "three";
|
|
31814
|
-
function createTexturePlane(config, boardData) {
|
|
31815
|
-
const {
|
|
31816
|
-
texture,
|
|
31817
|
-
yOffset,
|
|
31818
|
-
isBottomLayer,
|
|
31819
|
-
textureType,
|
|
31820
|
-
usePolygonOffset = false,
|
|
31821
|
-
renderOrder = 0,
|
|
31822
|
-
isFaux = false
|
|
31823
|
-
} = config;
|
|
31824
|
-
if (!texture) return null;
|
|
31825
|
-
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
31826
|
-
const planeGeom = new THREE20.PlaneGeometry(
|
|
31827
|
-
boardOutlineBounds.width,
|
|
31828
|
-
boardOutlineBounds.height
|
|
31829
|
-
);
|
|
31830
|
-
const material = new THREE20.MeshBasicMaterial({
|
|
31831
|
-
map: texture,
|
|
31832
|
-
transparent: true,
|
|
31833
|
-
side: THREE20.DoubleSide,
|
|
31834
|
-
depthWrite: textureType === "panel-outlines",
|
|
31835
|
-
polygonOffset: usePolygonOffset,
|
|
31836
|
-
polygonOffsetFactor: usePolygonOffset ? -4 : 0,
|
|
31837
|
-
// Increased for better z-fighting prevention
|
|
31838
|
-
polygonOffsetUnits: usePolygonOffset ? -4 : 0,
|
|
31839
|
-
opacity: isFaux ? FAUX_BOARD_OPACITY : 1
|
|
31840
|
-
});
|
|
31841
|
-
const mesh = new THREE20.Mesh(planeGeom, material);
|
|
31842
|
-
mesh.position.set(
|
|
31843
|
-
boardOutlineBounds.centerX,
|
|
31844
|
-
boardOutlineBounds.centerY,
|
|
31845
|
-
yOffset
|
|
31846
|
-
);
|
|
31847
|
-
if (isBottomLayer) {
|
|
31848
|
-
mesh.rotation.set(Math.PI, 0, 0);
|
|
31849
|
-
}
|
|
31850
|
-
mesh.name = `${isBottomLayer ? "bottom" : "top"}-${textureType}-texture-plane`;
|
|
31851
|
-
mesh.renderOrder = renderOrder;
|
|
31852
|
-
return mesh;
|
|
31853
|
-
}
|
|
31854
|
-
function createTextureMeshes(textures, boardData, pcbThickness, isFaux = false) {
|
|
31855
|
-
const meshes = [];
|
|
31856
|
-
if (!textures || !boardData || pcbThickness === null) return meshes;
|
|
31857
|
-
const topTraceMesh = createTexturePlane(
|
|
31858
|
-
{
|
|
31859
|
-
texture: textures.topTrace,
|
|
31860
|
-
yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
|
|
31861
|
-
// Use consistent copper offset
|
|
31862
|
-
isBottomLayer: false,
|
|
31863
|
-
textureType: "trace",
|
|
31864
|
-
usePolygonOffset: false,
|
|
31865
|
-
renderOrder: 2,
|
|
31866
|
-
// Render after soldermask
|
|
31867
|
-
isFaux
|
|
31868
|
-
},
|
|
31869
|
-
boardData
|
|
31870
|
-
);
|
|
31871
|
-
if (topTraceMesh) meshes.push(topTraceMesh);
|
|
31872
|
-
const topTraceWithMaskMesh = createTexturePlane(
|
|
31873
|
-
{
|
|
31874
|
-
texture: textures.topTraceWithMask,
|
|
31875
|
-
yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces,
|
|
31876
|
-
isBottomLayer: false,
|
|
31877
|
-
textureType: "trace-with-mask",
|
|
31878
|
-
usePolygonOffset: false,
|
|
31879
|
-
renderOrder: 2,
|
|
31880
|
-
// Render after soldermask
|
|
31881
|
-
isFaux
|
|
31882
|
-
},
|
|
31883
|
-
boardData
|
|
31884
|
-
);
|
|
31885
|
-
if (topTraceWithMaskMesh) meshes.push(topTraceWithMaskMesh);
|
|
31886
|
-
const topSilkscreenMesh = createTexturePlane(
|
|
31887
|
-
{
|
|
31888
|
-
texture: textures.topSilkscreen,
|
|
31889
|
-
yOffset: pcbThickness / 2 + 3e-3,
|
|
31890
|
-
// Slightly above soldermask
|
|
31891
|
-
isBottomLayer: false,
|
|
31892
|
-
textureType: "silkscreen",
|
|
31893
|
-
usePolygonOffset: false,
|
|
31894
|
-
renderOrder: 3,
|
|
31895
|
-
// Render after traces
|
|
31896
|
-
isFaux
|
|
31897
|
-
},
|
|
31898
|
-
boardData
|
|
31899
|
-
);
|
|
31900
|
-
if (topSilkscreenMesh) meshes.push(topSilkscreenMesh);
|
|
31901
|
-
const bottomTraceMesh = createTexturePlane(
|
|
31902
|
-
{
|
|
31903
|
-
texture: textures.bottomTrace,
|
|
31904
|
-
yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
|
|
31905
|
-
// Use consistent copper offset
|
|
31906
|
-
isBottomLayer: true,
|
|
31907
|
-
textureType: "trace",
|
|
31908
|
-
usePolygonOffset: false,
|
|
31909
|
-
renderOrder: 2,
|
|
31910
|
-
// Render after soldermask
|
|
31911
|
-
isFaux
|
|
31912
|
-
},
|
|
31913
|
-
boardData
|
|
31914
|
-
);
|
|
31915
|
-
if (bottomTraceMesh) meshes.push(bottomTraceMesh);
|
|
31916
|
-
const bottomTraceWithMaskMesh = createTexturePlane(
|
|
31917
|
-
{
|
|
31918
|
-
texture: textures.bottomTraceWithMask,
|
|
31919
|
-
yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces,
|
|
31920
|
-
isBottomLayer: true,
|
|
31921
|
-
textureType: "trace-with-mask",
|
|
31922
|
-
usePolygonOffset: false,
|
|
31923
|
-
renderOrder: 2,
|
|
31924
|
-
// Render after soldermask
|
|
31925
|
-
isFaux
|
|
31926
|
-
},
|
|
31927
|
-
boardData
|
|
31928
|
-
);
|
|
31929
|
-
if (bottomTraceWithMaskMesh) meshes.push(bottomTraceWithMaskMesh);
|
|
31930
|
-
const bottomSilkscreenMesh = createTexturePlane(
|
|
31931
|
-
{
|
|
31932
|
-
texture: textures.bottomSilkscreen,
|
|
31933
|
-
yOffset: -pcbThickness / 2 - 3e-3,
|
|
31934
|
-
isBottomLayer: true,
|
|
31935
|
-
textureType: "silkscreen",
|
|
31936
|
-
usePolygonOffset: false,
|
|
31937
|
-
renderOrder: 3,
|
|
31938
|
-
// Render after traces
|
|
31939
|
-
isFaux
|
|
31940
|
-
},
|
|
31941
|
-
boardData
|
|
31942
|
-
);
|
|
31943
|
-
if (bottomSilkscreenMesh) meshes.push(bottomSilkscreenMesh);
|
|
31944
|
-
const topSoldermaskMesh = createTexturePlane(
|
|
31945
|
-
{
|
|
31946
|
-
texture: textures.topSoldermask,
|
|
31947
|
-
yOffset: pcbThickness / 2 + 1e-3,
|
|
31948
|
-
// Just above board surface
|
|
31949
|
-
isBottomLayer: false,
|
|
31950
|
-
textureType: "soldermask",
|
|
31951
|
-
usePolygonOffset: true,
|
|
31952
|
-
// Enable polygon offset
|
|
31953
|
-
renderOrder: 1,
|
|
31954
|
-
// Render after board (renderOrder)
|
|
31955
|
-
isFaux
|
|
31956
|
-
},
|
|
31957
|
-
boardData
|
|
31958
|
-
);
|
|
31959
|
-
if (topSoldermaskMesh) meshes.push(topSoldermaskMesh);
|
|
31960
|
-
const bottomSoldermaskMesh = createTexturePlane(
|
|
31961
|
-
{
|
|
31962
|
-
texture: textures.bottomSoldermask,
|
|
31963
|
-
yOffset: -pcbThickness / 2 - 1e-3,
|
|
31964
|
-
// Just below board surface (bottom side)
|
|
31965
|
-
isBottomLayer: true,
|
|
31966
|
-
textureType: "soldermask",
|
|
31967
|
-
usePolygonOffset: true,
|
|
31968
|
-
// Enable polygon offset
|
|
31969
|
-
renderOrder: 1,
|
|
31970
|
-
// Render after board (renderOrder)
|
|
31971
|
-
isFaux
|
|
31972
|
-
},
|
|
31973
|
-
boardData
|
|
31974
|
-
);
|
|
31975
|
-
if (bottomSoldermaskMesh) meshes.push(bottomSoldermaskMesh);
|
|
31976
|
-
const topCopperTextMesh = createTexturePlane(
|
|
31977
|
-
{
|
|
31978
|
-
texture: textures.topCopperText,
|
|
31979
|
-
yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
|
|
31980
|
-
isBottomLayer: false,
|
|
31981
|
-
textureType: "copper-text",
|
|
31982
|
-
usePolygonOffset: true,
|
|
31983
|
-
renderOrder: 2,
|
|
31984
|
-
// Render after soldermask
|
|
31985
|
-
isFaux
|
|
31986
|
-
},
|
|
31987
|
-
boardData
|
|
31988
|
-
);
|
|
31989
|
-
if (topCopperTextMesh) meshes.push(topCopperTextMesh);
|
|
31990
|
-
const bottomCopperTextMesh = createTexturePlane(
|
|
31991
|
-
{
|
|
31992
|
-
texture: textures.bottomCopperText,
|
|
31993
|
-
yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
|
|
31994
|
-
isBottomLayer: true,
|
|
31995
|
-
textureType: "copper-text",
|
|
31996
|
-
usePolygonOffset: true,
|
|
31997
|
-
renderOrder: 2,
|
|
31998
|
-
// Render after soldermask
|
|
31999
|
-
isFaux
|
|
32000
|
-
},
|
|
32001
|
-
boardData
|
|
32002
|
-
);
|
|
32003
|
-
if (bottomCopperTextMesh) meshes.push(bottomCopperTextMesh);
|
|
32004
|
-
const topCopperMesh = createTexturePlane(
|
|
32005
|
-
{
|
|
32006
|
-
texture: textures.topCopper,
|
|
32007
|
-
yOffset: pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
|
|
32008
|
-
isBottomLayer: false,
|
|
32009
|
-
textureType: "copper",
|
|
32010
|
-
usePolygonOffset: true,
|
|
32011
|
-
renderOrder: 2,
|
|
32012
|
-
// Render after soldermask
|
|
32013
|
-
isFaux
|
|
32014
|
-
},
|
|
32015
|
-
boardData
|
|
32016
|
-
);
|
|
32017
|
-
if (topCopperMesh) meshes.push(topCopperMesh);
|
|
32018
|
-
const bottomCopperMesh = createTexturePlane(
|
|
32019
|
-
{
|
|
32020
|
-
texture: textures.bottomCopper,
|
|
32021
|
-
yOffset: -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
|
|
32022
|
-
isBottomLayer: true,
|
|
32023
|
-
textureType: "copper",
|
|
32024
|
-
usePolygonOffset: true,
|
|
32025
|
-
renderOrder: 2,
|
|
32026
|
-
// Render after soldermask
|
|
32027
|
-
isFaux
|
|
32028
|
-
},
|
|
32029
|
-
boardData
|
|
32030
|
-
);
|
|
32031
|
-
if (bottomCopperMesh) meshes.push(bottomCopperMesh);
|
|
32032
|
-
const topPanelOutlinesMesh = createTexturePlane(
|
|
32033
|
-
{
|
|
32034
|
-
texture: textures.topPanelOutlines,
|
|
32035
|
-
yOffset: pcbThickness / 2 + 4e-3,
|
|
32036
|
-
// Above silkscreen
|
|
32037
|
-
isBottomLayer: false,
|
|
32038
|
-
textureType: "panel-outlines",
|
|
32039
|
-
usePolygonOffset: false,
|
|
32040
|
-
renderOrder: 4,
|
|
32041
|
-
isFaux
|
|
32042
|
-
},
|
|
32043
|
-
boardData
|
|
32044
|
-
);
|
|
32045
|
-
if (topPanelOutlinesMesh) meshes.push(topPanelOutlinesMesh);
|
|
32046
|
-
const bottomPanelOutlinesMesh = createTexturePlane(
|
|
32047
|
-
{
|
|
32048
|
-
texture: textures.bottomPanelOutlines,
|
|
32049
|
-
yOffset: -pcbThickness / 2 - 4e-3,
|
|
32050
|
-
// Below bottom silkscreen
|
|
32051
|
-
isBottomLayer: true,
|
|
32052
|
-
textureType: "panel-outlines",
|
|
32053
|
-
usePolygonOffset: false,
|
|
32054
|
-
renderOrder: 4,
|
|
32055
|
-
isFaux
|
|
32056
|
-
},
|
|
32057
|
-
boardData
|
|
32058
|
-
);
|
|
32059
|
-
if (bottomPanelOutlinesMesh) meshes.push(bottomPanelOutlinesMesh);
|
|
32060
|
-
return meshes;
|
|
32061
|
-
}
|
|
32062
|
-
|
|
32063
|
-
// src/three-components/JscadBoardTextures.tsx
|
|
32064
|
-
import * as THREE26 from "three";
|
|
31565
|
+
// src/textures/create-combined-board-textures.ts
|
|
31566
|
+
import * as THREE25 from "three";
|
|
32065
31567
|
|
|
32066
31568
|
// src/utils/copper-text-texture.ts
|
|
32067
31569
|
var import_text = __toESM(require_text(), 1);
|
|
32068
|
-
import * as
|
|
31570
|
+
import * as THREE19 from "three";
|
|
32069
31571
|
|
|
32070
31572
|
// node_modules/transformation-matrix/src/applyToPoint.js
|
|
32071
31573
|
function applyToPoint(matrix, point) {
|
|
@@ -32277,6 +31779,56 @@ peg$SyntaxError.buildMessage = function(expected, found) {
|
|
|
32277
31779
|
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
|
|
32278
31780
|
};
|
|
32279
31781
|
|
|
31782
|
+
// node_modules/@tscircuit/math-utils/dist/chunk-5N7UJNVK.js
|
|
31783
|
+
var getBoundsFromPoints = (points) => {
|
|
31784
|
+
if (points.length === 0) {
|
|
31785
|
+
return null;
|
|
31786
|
+
}
|
|
31787
|
+
let minX = points[0].x;
|
|
31788
|
+
let minY = points[0].y;
|
|
31789
|
+
let maxX = points[0].x;
|
|
31790
|
+
let maxY = points[0].y;
|
|
31791
|
+
for (let i = 1; i < points.length; i++) {
|
|
31792
|
+
const point = points[i];
|
|
31793
|
+
if (point.x < minX) minX = point.x;
|
|
31794
|
+
if (point.y < minY) minY = point.y;
|
|
31795
|
+
if (point.x > maxX) maxX = point.x;
|
|
31796
|
+
if (point.y > maxY) maxY = point.y;
|
|
31797
|
+
}
|
|
31798
|
+
return { minX, minY, maxX, maxY };
|
|
31799
|
+
};
|
|
31800
|
+
|
|
31801
|
+
// src/utils/outline-bounds.ts
|
|
31802
|
+
function calculateOutlineBounds(boardData) {
|
|
31803
|
+
if (boardData.outline && boardData.outline.length >= 3) {
|
|
31804
|
+
const bounds2 = getBoundsFromPoints(boardData.outline);
|
|
31805
|
+
return {
|
|
31806
|
+
...bounds2,
|
|
31807
|
+
width: bounds2.maxX - bounds2.minX,
|
|
31808
|
+
height: bounds2.maxY - bounds2.minY,
|
|
31809
|
+
centerX: (bounds2.minX + bounds2.maxX) / 2,
|
|
31810
|
+
centerY: (bounds2.minY + bounds2.maxY) / 2
|
|
31811
|
+
};
|
|
31812
|
+
}
|
|
31813
|
+
const boardWidth = boardData.width ?? 0;
|
|
31814
|
+
const boardHeight = boardData.height ?? 0;
|
|
31815
|
+
const boardCenterX = boardData.center?.x ?? 0;
|
|
31816
|
+
const boardCenterY = boardData.center?.y ?? 0;
|
|
31817
|
+
const bounds = {
|
|
31818
|
+
minX: boardCenterX - boardWidth / 2,
|
|
31819
|
+
maxX: boardCenterX + boardWidth / 2,
|
|
31820
|
+
minY: boardCenterY - boardHeight / 2,
|
|
31821
|
+
maxY: boardCenterY + boardHeight / 2
|
|
31822
|
+
};
|
|
31823
|
+
return {
|
|
31824
|
+
...bounds,
|
|
31825
|
+
width: boardWidth,
|
|
31826
|
+
height: boardHeight,
|
|
31827
|
+
centerX: boardCenterX,
|
|
31828
|
+
centerY: boardCenterY
|
|
31829
|
+
};
|
|
31830
|
+
}
|
|
31831
|
+
|
|
32280
31832
|
// src/utils/copper-text-texture.ts
|
|
32281
31833
|
function parseDimension2(value, defaultValue) {
|
|
32282
31834
|
if (value === void 0) return defaultValue;
|
|
@@ -32516,17 +32068,17 @@ function createCopperTextTextureForLayer({
|
|
|
32516
32068
|
);
|
|
32517
32069
|
}
|
|
32518
32070
|
});
|
|
32519
|
-
const texture = new
|
|
32071
|
+
const texture = new THREE19.CanvasTexture(canvas);
|
|
32520
32072
|
texture.generateMipmaps = true;
|
|
32521
|
-
texture.minFilter =
|
|
32522
|
-
texture.magFilter =
|
|
32073
|
+
texture.minFilter = THREE19.LinearMipmapLinearFilter;
|
|
32074
|
+
texture.magFilter = THREE19.LinearFilter;
|
|
32523
32075
|
texture.anisotropy = 16;
|
|
32524
32076
|
texture.needsUpdate = true;
|
|
32525
32077
|
return texture;
|
|
32526
32078
|
}
|
|
32527
32079
|
|
|
32528
32080
|
// src/utils/panel-outline-texture.ts
|
|
32529
|
-
import * as
|
|
32081
|
+
import * as THREE20 from "three";
|
|
32530
32082
|
import { su as su5 } from "@tscircuit/circuit-json-util";
|
|
32531
32083
|
function createPanelOutlineTextureForLayer({
|
|
32532
32084
|
layer,
|
|
@@ -32582,10 +32134,10 @@ function createPanelOutlineTextureForLayer({
|
|
|
32582
32134
|
);
|
|
32583
32135
|
}
|
|
32584
32136
|
});
|
|
32585
|
-
const texture = new
|
|
32137
|
+
const texture = new THREE20.CanvasTexture(canvas);
|
|
32586
32138
|
texture.generateMipmaps = true;
|
|
32587
|
-
texture.minFilter =
|
|
32588
|
-
texture.magFilter =
|
|
32139
|
+
texture.minFilter = THREE20.LinearMipmapLinearFilter;
|
|
32140
|
+
texture.magFilter = THREE20.LinearFilter;
|
|
32589
32141
|
texture.anisotropy = 16;
|
|
32590
32142
|
texture.needsUpdate = true;
|
|
32591
32143
|
return texture;
|
|
@@ -32593,7 +32145,7 @@ function createPanelOutlineTextureForLayer({
|
|
|
32593
32145
|
|
|
32594
32146
|
// src/utils/silkscreen-texture.ts
|
|
32595
32147
|
var import_text2 = __toESM(require_text(), 1);
|
|
32596
|
-
import * as
|
|
32148
|
+
import * as THREE21 from "three";
|
|
32597
32149
|
import { su as su6 } from "@tscircuit/circuit-json-util";
|
|
32598
32150
|
|
|
32599
32151
|
// src/utils/units.ts
|
|
@@ -33040,10 +32592,10 @@ function createSilkscreenTextureForLayer({
|
|
|
33040
32592
|
ctx.stroke();
|
|
33041
32593
|
});
|
|
33042
32594
|
});
|
|
33043
|
-
const texture = new
|
|
32595
|
+
const texture = new THREE21.CanvasTexture(canvas);
|
|
33044
32596
|
texture.generateMipmaps = true;
|
|
33045
|
-
texture.minFilter =
|
|
33046
|
-
texture.magFilter =
|
|
32597
|
+
texture.minFilter = THREE21.LinearMipmapLinearFilter;
|
|
32598
|
+
texture.magFilter = THREE21.LinearFilter;
|
|
33047
32599
|
texture.anisotropy = 16;
|
|
33048
32600
|
texture.needsUpdate = true;
|
|
33049
32601
|
return texture;
|
|
@@ -33051,7 +32603,7 @@ function createSilkscreenTextureForLayer({
|
|
|
33051
32603
|
|
|
33052
32604
|
// src/utils/soldermask-texture.ts
|
|
33053
32605
|
import { su as su7 } from "@tscircuit/circuit-json-util";
|
|
33054
|
-
import * as
|
|
32606
|
+
import * as THREE22 from "three";
|
|
33055
32607
|
function createSoldermaskTextureForLayer({
|
|
33056
32608
|
layer,
|
|
33057
32609
|
circuitJson,
|
|
@@ -33616,17 +33168,17 @@ function createSoldermaskTextureForLayer({
|
|
|
33616
33168
|
}
|
|
33617
33169
|
});
|
|
33618
33170
|
ctx.globalCompositeOperation = "source-over";
|
|
33619
|
-
const texture = new
|
|
33171
|
+
const texture = new THREE22.CanvasTexture(canvas);
|
|
33620
33172
|
texture.generateMipmaps = true;
|
|
33621
|
-
texture.minFilter =
|
|
33622
|
-
texture.magFilter =
|
|
33173
|
+
texture.minFilter = THREE22.LinearMipmapLinearFilter;
|
|
33174
|
+
texture.magFilter = THREE22.LinearFilter;
|
|
33623
33175
|
texture.anisotropy = 16;
|
|
33624
33176
|
texture.needsUpdate = true;
|
|
33625
33177
|
return texture;
|
|
33626
33178
|
}
|
|
33627
33179
|
|
|
33628
33180
|
// src/utils/trace-texture.ts
|
|
33629
|
-
import * as
|
|
33181
|
+
import * as THREE23 from "three";
|
|
33630
33182
|
import { su as su8 } from "@tscircuit/circuit-json-util";
|
|
33631
33183
|
function isWireRoutePoint(point) {
|
|
33632
33184
|
return point && point.route_type === "wire" && typeof point.layer === "string" && typeof point.width === "number";
|
|
@@ -33739,15 +33291,422 @@ function createTraceTextureForLayer({
|
|
|
33739
33291
|
}
|
|
33740
33292
|
});
|
|
33741
33293
|
ctx.globalCompositeOperation = "source-over";
|
|
33742
|
-
const texture = new
|
|
33294
|
+
const texture = new THREE23.CanvasTexture(canvas);
|
|
33743
33295
|
texture.generateMipmaps = true;
|
|
33744
|
-
texture.minFilter =
|
|
33745
|
-
texture.magFilter =
|
|
33296
|
+
texture.minFilter = THREE23.LinearMipmapLinearFilter;
|
|
33297
|
+
texture.magFilter = THREE23.LinearFilter;
|
|
33746
33298
|
texture.anisotropy = 16;
|
|
33747
33299
|
texture.needsUpdate = true;
|
|
33748
33300
|
return texture;
|
|
33749
33301
|
}
|
|
33750
33302
|
|
|
33303
|
+
// src/textures/create-copper-pour-texture-for-layer.ts
|
|
33304
|
+
import * as THREE24 from "three";
|
|
33305
|
+
import { CircuitToCanvasDrawer } from "circuit-to-canvas";
|
|
33306
|
+
|
|
33307
|
+
// src/geoms/brep-converter.ts
|
|
33308
|
+
var import_primitives7 = __toESM(require_primitives(), 1);
|
|
33309
|
+
var import_booleans5 = __toESM(require_booleans(), 1);
|
|
33310
|
+
function segmentToPoints(p1, p2, bulge, arcSegments) {
|
|
33311
|
+
if (!bulge || Math.abs(bulge) < 1e-9) {
|
|
33312
|
+
return [];
|
|
33313
|
+
}
|
|
33314
|
+
const theta = 4 * Math.atan(bulge);
|
|
33315
|
+
const dx = p2[0] - p1[0];
|
|
33316
|
+
const dy = p2[1] - p1[1];
|
|
33317
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
33318
|
+
if (dist < 1e-9) return [];
|
|
33319
|
+
const radius = Math.abs(dist / (2 * Math.sin(theta / 2)));
|
|
33320
|
+
const m = Math.sqrt(Math.max(0, radius * radius - dist / 2 * (dist / 2)));
|
|
33321
|
+
const midPoint = [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2];
|
|
33322
|
+
const ux = dx / dist;
|
|
33323
|
+
const uy = dy / dist;
|
|
33324
|
+
const nx = -uy;
|
|
33325
|
+
const ny = ux;
|
|
33326
|
+
const centerX = midPoint[0] + nx * m * Math.sign(bulge);
|
|
33327
|
+
const centerY = midPoint[1] + ny * m * Math.sign(bulge);
|
|
33328
|
+
const startAngle = Math.atan2(p1[1] - centerY, p1[0] - centerX);
|
|
33329
|
+
const points = [];
|
|
33330
|
+
const numSteps = Math.max(
|
|
33331
|
+
2,
|
|
33332
|
+
Math.ceil(arcSegments * Math.abs(theta) / (Math.PI * 2) * 4)
|
|
33333
|
+
);
|
|
33334
|
+
const angleStep = theta / numSteps;
|
|
33335
|
+
for (let i = 1; i < numSteps; i++) {
|
|
33336
|
+
const angle = startAngle + angleStep * i;
|
|
33337
|
+
points.push([
|
|
33338
|
+
centerX + radius * Math.cos(angle),
|
|
33339
|
+
centerY + radius * Math.sin(angle)
|
|
33340
|
+
]);
|
|
33341
|
+
}
|
|
33342
|
+
return points;
|
|
33343
|
+
}
|
|
33344
|
+
function ringToPoints(ring, arcSegments) {
|
|
33345
|
+
const allPoints = [];
|
|
33346
|
+
const vertices = ring.vertices;
|
|
33347
|
+
for (let i = 0; i < vertices.length; i++) {
|
|
33348
|
+
const p1 = vertices[i];
|
|
33349
|
+
const p2 = vertices[(i + 1) % vertices.length];
|
|
33350
|
+
allPoints.push([p1.x, p1.y]);
|
|
33351
|
+
if (p1.bulge) {
|
|
33352
|
+
const arcPoints = segmentToPoints(
|
|
33353
|
+
[p1.x, p1.y],
|
|
33354
|
+
[p2.x, p2.y],
|
|
33355
|
+
p1.bulge,
|
|
33356
|
+
arcSegments
|
|
33357
|
+
);
|
|
33358
|
+
allPoints.push(...arcPoints);
|
|
33359
|
+
}
|
|
33360
|
+
}
|
|
33361
|
+
return allPoints;
|
|
33362
|
+
}
|
|
33363
|
+
|
|
33364
|
+
// src/textures/create-copper-pour-texture-for-layer.ts
|
|
33365
|
+
function drawPolygon({
|
|
33366
|
+
ctx,
|
|
33367
|
+
points,
|
|
33368
|
+
canvasXFromPcb,
|
|
33369
|
+
canvasYFromPcb
|
|
33370
|
+
}) {
|
|
33371
|
+
if (points.length < 3) return;
|
|
33372
|
+
ctx.beginPath();
|
|
33373
|
+
points.forEach((point, index2) => {
|
|
33374
|
+
const canvasX = canvasXFromPcb(point[0]);
|
|
33375
|
+
const canvasY = canvasYFromPcb(point[1]);
|
|
33376
|
+
if (index2 === 0) {
|
|
33377
|
+
ctx.moveTo(canvasX, canvasY);
|
|
33378
|
+
} else {
|
|
33379
|
+
ctx.lineTo(canvasX, canvasY);
|
|
33380
|
+
}
|
|
33381
|
+
});
|
|
33382
|
+
ctx.closePath();
|
|
33383
|
+
ctx.fill();
|
|
33384
|
+
}
|
|
33385
|
+
function drawBrepShape({
|
|
33386
|
+
ctx,
|
|
33387
|
+
pour,
|
|
33388
|
+
canvasXFromPcb,
|
|
33389
|
+
canvasYFromPcb
|
|
33390
|
+
}) {
|
|
33391
|
+
const brepShape = pour.brep_shape;
|
|
33392
|
+
if (!brepShape || !brepShape.outer_ring) return;
|
|
33393
|
+
const outerRingPoints = ringToPoints(brepShape.outer_ring, 32);
|
|
33394
|
+
if (outerRingPoints.length >= 3) {
|
|
33395
|
+
drawPolygon({
|
|
33396
|
+
ctx,
|
|
33397
|
+
points: outerRingPoints,
|
|
33398
|
+
canvasXFromPcb,
|
|
33399
|
+
canvasYFromPcb
|
|
33400
|
+
});
|
|
33401
|
+
}
|
|
33402
|
+
if (brepShape.inner_rings && brepShape.inner_rings.length > 0) {
|
|
33403
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
33404
|
+
for (const innerRing of brepShape.inner_rings) {
|
|
33405
|
+
const innerRingPoints = ringToPoints(innerRing, 32);
|
|
33406
|
+
if (innerRingPoints.length >= 3) {
|
|
33407
|
+
drawPolygon({
|
|
33408
|
+
ctx,
|
|
33409
|
+
points: innerRingPoints,
|
|
33410
|
+
canvasXFromPcb,
|
|
33411
|
+
canvasYFromPcb
|
|
33412
|
+
});
|
|
33413
|
+
}
|
|
33414
|
+
}
|
|
33415
|
+
ctx.globalCompositeOperation = "source-over";
|
|
33416
|
+
}
|
|
33417
|
+
}
|
|
33418
|
+
function createCopperPourTextureForLayer({
|
|
33419
|
+
layer,
|
|
33420
|
+
circuitJson,
|
|
33421
|
+
boardData,
|
|
33422
|
+
traceTextureResolution = TRACE_TEXTURE_RESOLUTION
|
|
33423
|
+
}) {
|
|
33424
|
+
const copperPours = circuitJson.filter(
|
|
33425
|
+
(e) => e.type === "pcb_copper_pour"
|
|
33426
|
+
);
|
|
33427
|
+
const pcbRenderLayer = layer === "top" ? "top_copper" : "bottom_copper";
|
|
33428
|
+
const poursOnLayer = copperPours.filter((p) => p.layer === layer);
|
|
33429
|
+
if (poursOnLayer.length === 0) return null;
|
|
33430
|
+
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
33431
|
+
const canvas = document.createElement("canvas");
|
|
33432
|
+
const canvasWidth = Math.floor(
|
|
33433
|
+
boardOutlineBounds.width * traceTextureResolution
|
|
33434
|
+
);
|
|
33435
|
+
const canvasHeight = Math.floor(
|
|
33436
|
+
boardOutlineBounds.height * traceTextureResolution
|
|
33437
|
+
);
|
|
33438
|
+
canvas.width = canvasWidth;
|
|
33439
|
+
canvas.height = canvasHeight;
|
|
33440
|
+
const ctx = canvas.getContext("2d");
|
|
33441
|
+
if (!ctx) return null;
|
|
33442
|
+
if (layer === "bottom") {
|
|
33443
|
+
ctx.translate(0, canvasHeight);
|
|
33444
|
+
ctx.scale(1, -1);
|
|
33445
|
+
}
|
|
33446
|
+
const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
|
|
33447
|
+
const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
|
|
33448
|
+
const rectAndPolygonPours = poursOnLayer.filter(
|
|
33449
|
+
(pour) => pour.shape === "rect" || pour.shape === "polygon"
|
|
33450
|
+
);
|
|
33451
|
+
const brepPours = poursOnLayer.filter((pour) => pour.shape === "brep");
|
|
33452
|
+
if (rectAndPolygonPours.length > 0) {
|
|
33453
|
+
const drawer = new CircuitToCanvasDrawer(ctx);
|
|
33454
|
+
drawer.setCameraBounds({
|
|
33455
|
+
minX: boardOutlineBounds.minX,
|
|
33456
|
+
maxX: boardOutlineBounds.maxX,
|
|
33457
|
+
minY: boardOutlineBounds.minY,
|
|
33458
|
+
maxY: boardOutlineBounds.maxY
|
|
33459
|
+
});
|
|
33460
|
+
const coveredPours = rectAndPolygonPours.filter(
|
|
33461
|
+
(p) => p.covered_with_solder_mask !== false
|
|
33462
|
+
);
|
|
33463
|
+
const uncoveredPours = rectAndPolygonPours.filter(
|
|
33464
|
+
(p) => p.covered_with_solder_mask === false
|
|
33465
|
+
);
|
|
33466
|
+
const coveredColor = `rgb(${colors.fr4TracesWithMaskGreen.map((c) => c * 255).join(",")})`;
|
|
33467
|
+
const uncoveredColor = `rgb(${colors.copper.map((c) => c * 255).join(",")})`;
|
|
33468
|
+
if (coveredPours.length > 0) {
|
|
33469
|
+
drawer.configure({
|
|
33470
|
+
colorOverrides: {
|
|
33471
|
+
copper: {
|
|
33472
|
+
top: coveredColor,
|
|
33473
|
+
bottom: coveredColor,
|
|
33474
|
+
inner1: coveredColor,
|
|
33475
|
+
inner2: coveredColor,
|
|
33476
|
+
inner3: coveredColor,
|
|
33477
|
+
inner4: coveredColor,
|
|
33478
|
+
inner5: coveredColor,
|
|
33479
|
+
inner6: coveredColor
|
|
33480
|
+
}
|
|
33481
|
+
}
|
|
33482
|
+
});
|
|
33483
|
+
drawer.drawElements(coveredPours, { layers: [pcbRenderLayer] });
|
|
33484
|
+
}
|
|
33485
|
+
if (uncoveredPours.length > 0) {
|
|
33486
|
+
drawer.configure({
|
|
33487
|
+
colorOverrides: {
|
|
33488
|
+
copper: {
|
|
33489
|
+
top: uncoveredColor,
|
|
33490
|
+
bottom: uncoveredColor,
|
|
33491
|
+
inner1: uncoveredColor,
|
|
33492
|
+
inner2: uncoveredColor,
|
|
33493
|
+
inner3: uncoveredColor,
|
|
33494
|
+
inner4: uncoveredColor,
|
|
33495
|
+
inner5: uncoveredColor,
|
|
33496
|
+
inner6: uncoveredColor
|
|
33497
|
+
}
|
|
33498
|
+
}
|
|
33499
|
+
});
|
|
33500
|
+
drawer.drawElements(uncoveredPours, { layers: [pcbRenderLayer] });
|
|
33501
|
+
}
|
|
33502
|
+
}
|
|
33503
|
+
for (const pour of brepPours) {
|
|
33504
|
+
const covered = pour.covered_with_solder_mask !== false;
|
|
33505
|
+
const colorArr = covered ? colors.fr4TracesWithMaskGreen : colors.copper;
|
|
33506
|
+
const copperColor = `rgb(${colorArr[0] * 255}, ${colorArr[1] * 255}, ${colorArr[2] * 255})`;
|
|
33507
|
+
ctx.fillStyle = copperColor;
|
|
33508
|
+
drawBrepShape({ ctx, pour, canvasXFromPcb, canvasYFromPcb });
|
|
33509
|
+
}
|
|
33510
|
+
const texture = new THREE24.CanvasTexture(canvas);
|
|
33511
|
+
texture.generateMipmaps = true;
|
|
33512
|
+
texture.minFilter = THREE24.LinearMipmapLinearFilter;
|
|
33513
|
+
texture.magFilter = THREE24.LinearFilter;
|
|
33514
|
+
texture.anisotropy = 16;
|
|
33515
|
+
texture.needsUpdate = true;
|
|
33516
|
+
return texture;
|
|
33517
|
+
}
|
|
33518
|
+
|
|
33519
|
+
// src/textures/create-combined-board-textures.ts
|
|
33520
|
+
var toRgb = (colorArr) => {
|
|
33521
|
+
const [r = 0, g = 0, b = 0] = colorArr;
|
|
33522
|
+
return `rgb(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(
|
|
33523
|
+
b * 255
|
|
33524
|
+
)})`;
|
|
33525
|
+
};
|
|
33526
|
+
var createCombinedTexture = ({
|
|
33527
|
+
textures,
|
|
33528
|
+
boardData,
|
|
33529
|
+
traceTextureResolution
|
|
33530
|
+
}) => {
|
|
33531
|
+
const hasImage = textures.some((texture) => texture?.image);
|
|
33532
|
+
if (!hasImage) return null;
|
|
33533
|
+
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
33534
|
+
const canvasWidth = Math.floor(
|
|
33535
|
+
boardOutlineBounds.width * traceTextureResolution
|
|
33536
|
+
);
|
|
33537
|
+
const canvasHeight = Math.floor(
|
|
33538
|
+
boardOutlineBounds.height * traceTextureResolution
|
|
33539
|
+
);
|
|
33540
|
+
if (canvasWidth <= 0 || canvasHeight <= 0) return null;
|
|
33541
|
+
const canvas = document.createElement("canvas");
|
|
33542
|
+
canvas.width = canvasWidth;
|
|
33543
|
+
canvas.height = canvasHeight;
|
|
33544
|
+
const ctx = canvas.getContext("2d");
|
|
33545
|
+
if (!ctx) return null;
|
|
33546
|
+
textures.forEach((texture) => {
|
|
33547
|
+
if (!texture?.image) return;
|
|
33548
|
+
const image = texture.image;
|
|
33549
|
+
ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight);
|
|
33550
|
+
});
|
|
33551
|
+
const combinedTexture = new THREE25.CanvasTexture(canvas);
|
|
33552
|
+
combinedTexture.generateMipmaps = true;
|
|
33553
|
+
combinedTexture.minFilter = THREE25.LinearMipmapLinearFilter;
|
|
33554
|
+
combinedTexture.magFilter = THREE25.LinearFilter;
|
|
33555
|
+
combinedTexture.anisotropy = 16;
|
|
33556
|
+
combinedTexture.needsUpdate = true;
|
|
33557
|
+
return combinedTexture;
|
|
33558
|
+
};
|
|
33559
|
+
function createCombinedBoardTextures({
|
|
33560
|
+
circuitJson,
|
|
33561
|
+
boardData,
|
|
33562
|
+
traceTextureResolution,
|
|
33563
|
+
visibility
|
|
33564
|
+
}) {
|
|
33565
|
+
const soldermaskColor = toRgb(
|
|
33566
|
+
soldermaskColors[boardData.material] ?? colors.fr4SolderMaskGreen
|
|
33567
|
+
);
|
|
33568
|
+
const traceColorWithMask = toRgb(colors.fr4TracesWithMaskGreen);
|
|
33569
|
+
const traceColorWithoutMask = toRgb(colors.fr4TracesWithoutMaskTan);
|
|
33570
|
+
const silkscreenColor = "rgb(255,255,255)";
|
|
33571
|
+
const copperColor = toRgb(colors.copper);
|
|
33572
|
+
const showBoardBody = visibility?.boardBody ?? true;
|
|
33573
|
+
const buildForLayer = (layer) => {
|
|
33574
|
+
const showMask = (layer === "top" ? visibility?.topMask : visibility?.bottomMask) ?? true;
|
|
33575
|
+
const showCopper = (layer === "top" ? visibility?.topCopper : visibility?.bottomCopper) ?? true;
|
|
33576
|
+
const showSilkscreen = (layer === "top" ? visibility?.topSilkscreen : visibility?.bottomSilkscreen) ?? true;
|
|
33577
|
+
const soldermaskTexture = showMask ? createSoldermaskTextureForLayer({
|
|
33578
|
+
layer,
|
|
33579
|
+
circuitJson,
|
|
33580
|
+
boardData,
|
|
33581
|
+
soldermaskColor,
|
|
33582
|
+
traceTextureResolution
|
|
33583
|
+
}) : null;
|
|
33584
|
+
const traceTexture = showCopper ? createTraceTextureForLayer({
|
|
33585
|
+
layer,
|
|
33586
|
+
circuitJson,
|
|
33587
|
+
boardData,
|
|
33588
|
+
traceColor: showMask ? traceColorWithMask : traceColorWithoutMask,
|
|
33589
|
+
traceTextureResolution
|
|
33590
|
+
}) : null;
|
|
33591
|
+
const copperTextTexture = showCopper ? createCopperTextTextureForLayer({
|
|
33592
|
+
layer,
|
|
33593
|
+
circuitJson,
|
|
33594
|
+
boardData,
|
|
33595
|
+
copperColor,
|
|
33596
|
+
traceTextureResolution
|
|
33597
|
+
}) : null;
|
|
33598
|
+
const copperPourTexture = showCopper ? createCopperPourTextureForLayer({
|
|
33599
|
+
layer,
|
|
33600
|
+
circuitJson,
|
|
33601
|
+
boardData,
|
|
33602
|
+
traceTextureResolution
|
|
33603
|
+
}) : null;
|
|
33604
|
+
const silkscreenTexture = showSilkscreen ? createSilkscreenTextureForLayer({
|
|
33605
|
+
layer,
|
|
33606
|
+
circuitJson,
|
|
33607
|
+
boardData,
|
|
33608
|
+
silkscreenColor,
|
|
33609
|
+
traceTextureResolution
|
|
33610
|
+
}) : null;
|
|
33611
|
+
const panelOutlineTexture = showBoardBody ? createPanelOutlineTextureForLayer({
|
|
33612
|
+
layer,
|
|
33613
|
+
circuitJson,
|
|
33614
|
+
panelData: boardData,
|
|
33615
|
+
traceTextureResolution
|
|
33616
|
+
}) : null;
|
|
33617
|
+
return createCombinedTexture({
|
|
33618
|
+
textures: [
|
|
33619
|
+
soldermaskTexture,
|
|
33620
|
+
copperPourTexture,
|
|
33621
|
+
traceTexture,
|
|
33622
|
+
copperTextTexture,
|
|
33623
|
+
silkscreenTexture,
|
|
33624
|
+
panelOutlineTexture
|
|
33625
|
+
],
|
|
33626
|
+
boardData,
|
|
33627
|
+
traceTextureResolution
|
|
33628
|
+
});
|
|
33629
|
+
};
|
|
33630
|
+
return {
|
|
33631
|
+
topBoard: buildForLayer("top"),
|
|
33632
|
+
bottomBoard: buildForLayer("bottom")
|
|
33633
|
+
};
|
|
33634
|
+
}
|
|
33635
|
+
|
|
33636
|
+
// src/textures/create-three-texture-meshes.ts
|
|
33637
|
+
import * as THREE26 from "three";
|
|
33638
|
+
function createTexturePlane(config, boardData) {
|
|
33639
|
+
const {
|
|
33640
|
+
texture,
|
|
33641
|
+
yOffset,
|
|
33642
|
+
isBottomLayer,
|
|
33643
|
+
usePolygonOffset = false,
|
|
33644
|
+
renderOrder = 0,
|
|
33645
|
+
isFaux = false
|
|
33646
|
+
} = config;
|
|
33647
|
+
if (!texture) return null;
|
|
33648
|
+
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
33649
|
+
const planeGeom = new THREE26.PlaneGeometry(
|
|
33650
|
+
boardOutlineBounds.width,
|
|
33651
|
+
boardOutlineBounds.height
|
|
33652
|
+
);
|
|
33653
|
+
const material = new THREE26.MeshBasicMaterial({
|
|
33654
|
+
map: texture,
|
|
33655
|
+
transparent: true,
|
|
33656
|
+
side: THREE26.DoubleSide,
|
|
33657
|
+
depthWrite: false,
|
|
33658
|
+
polygonOffset: usePolygonOffset,
|
|
33659
|
+
polygonOffsetFactor: usePolygonOffset ? -4 : 0,
|
|
33660
|
+
// Increased for better z-fighting prevention
|
|
33661
|
+
polygonOffsetUnits: usePolygonOffset ? -4 : 0,
|
|
33662
|
+
opacity: isFaux ? FAUX_BOARD_OPACITY : 1
|
|
33663
|
+
});
|
|
33664
|
+
const mesh = new THREE26.Mesh(planeGeom, material);
|
|
33665
|
+
mesh.position.set(
|
|
33666
|
+
boardOutlineBounds.centerX,
|
|
33667
|
+
boardOutlineBounds.centerY,
|
|
33668
|
+
yOffset
|
|
33669
|
+
);
|
|
33670
|
+
if (isBottomLayer) {
|
|
33671
|
+
mesh.rotation.set(Math.PI, 0, 0);
|
|
33672
|
+
}
|
|
33673
|
+
mesh.name = `${isBottomLayer ? "bottom" : "top"}-board-texture-plane`;
|
|
33674
|
+
mesh.renderOrder = renderOrder;
|
|
33675
|
+
return mesh;
|
|
33676
|
+
}
|
|
33677
|
+
function createTextureMeshes(textures, boardData, pcbThickness, isFaux = false) {
|
|
33678
|
+
const meshes = [];
|
|
33679
|
+
if (!textures || !boardData || pcbThickness === null) return meshes;
|
|
33680
|
+
const topBoardMesh = createTexturePlane(
|
|
33681
|
+
{
|
|
33682
|
+
texture: textures.topBoard,
|
|
33683
|
+
yOffset: pcbThickness / 2 + 1e-3,
|
|
33684
|
+
isBottomLayer: false,
|
|
33685
|
+
usePolygonOffset: true,
|
|
33686
|
+
renderOrder: 1,
|
|
33687
|
+
isFaux
|
|
33688
|
+
},
|
|
33689
|
+
boardData
|
|
33690
|
+
);
|
|
33691
|
+
if (topBoardMesh) meshes.push(topBoardMesh);
|
|
33692
|
+
const bottomBoardMesh = createTexturePlane(
|
|
33693
|
+
{
|
|
33694
|
+
texture: textures.bottomBoard,
|
|
33695
|
+
yOffset: -pcbThickness / 2 - 1e-3,
|
|
33696
|
+
isBottomLayer: true,
|
|
33697
|
+
usePolygonOffset: true,
|
|
33698
|
+
renderOrder: 1,
|
|
33699
|
+
isFaux
|
|
33700
|
+
},
|
|
33701
|
+
boardData
|
|
33702
|
+
);
|
|
33703
|
+
if (bottomBoardMesh) meshes.push(bottomBoardMesh);
|
|
33704
|
+
return meshes;
|
|
33705
|
+
}
|
|
33706
|
+
|
|
33707
|
+
// src/three-components/JscadBoardTextures.tsx
|
|
33708
|
+
import * as THREE27 from "three";
|
|
33709
|
+
|
|
33751
33710
|
// src/utils/layer-texture-resolution.ts
|
|
33752
33711
|
var DEFAULT_MAX_TEXTURE_PIXELS = 4e6;
|
|
33753
33712
|
var DEFAULT_MAX_TEXTURE_DIMENSION = 4096;
|
|
@@ -33815,114 +33774,57 @@ function JscadBoardTextures({
|
|
|
33815
33774
|
}, [boardData]);
|
|
33816
33775
|
const textures = useMemo19(() => {
|
|
33817
33776
|
if (!boardData || !boardData.width || !boardData.height) return null;
|
|
33818
|
-
|
|
33819
|
-
|
|
33820
|
-
|
|
33821
|
-
|
|
33822
|
-
|
|
33823
|
-
|
|
33824
|
-
|
|
33825
|
-
layer: "top",
|
|
33826
|
-
circuitJson,
|
|
33827
|
-
boardData,
|
|
33828
|
-
soldermaskColor,
|
|
33829
|
-
traceTextureResolution
|
|
33830
|
-
}),
|
|
33831
|
-
bottomSoldermask: createSoldermaskTextureForLayer({
|
|
33832
|
-
layer: "bottom",
|
|
33833
|
-
circuitJson,
|
|
33834
|
-
boardData,
|
|
33835
|
-
soldermaskColor,
|
|
33836
|
-
traceTextureResolution
|
|
33837
|
-
}),
|
|
33838
|
-
topSilkscreen: createSilkscreenTextureForLayer({
|
|
33839
|
-
layer: "top",
|
|
33840
|
-
circuitJson,
|
|
33841
|
-
boardData,
|
|
33842
|
-
silkscreenColor,
|
|
33843
|
-
traceTextureResolution
|
|
33844
|
-
}),
|
|
33845
|
-
bottomSilkscreen: createSilkscreenTextureForLayer({
|
|
33846
|
-
layer: "bottom",
|
|
33847
|
-
circuitJson,
|
|
33848
|
-
boardData,
|
|
33849
|
-
silkscreenColor,
|
|
33850
|
-
traceTextureResolution
|
|
33851
|
-
}),
|
|
33852
|
-
topTraceWithMask: createTraceTextureForLayer({
|
|
33853
|
-
layer: "top",
|
|
33854
|
-
circuitJson,
|
|
33855
|
-
boardData,
|
|
33856
|
-
traceColor: traceColorWithMask,
|
|
33857
|
-
traceTextureResolution
|
|
33858
|
-
}),
|
|
33859
|
-
bottomTraceWithMask: createTraceTextureForLayer({
|
|
33860
|
-
layer: "bottom",
|
|
33861
|
-
circuitJson,
|
|
33862
|
-
boardData,
|
|
33863
|
-
traceColor: traceColorWithMask,
|
|
33864
|
-
traceTextureResolution
|
|
33865
|
-
}),
|
|
33866
|
-
topCopperText: createCopperTextTextureForLayer({
|
|
33867
|
-
layer: "top",
|
|
33868
|
-
circuitJson,
|
|
33869
|
-
boardData,
|
|
33870
|
-
copperColor: `rgb(${Math.round(colors.copper[0] * 255)}, ${Math.round(colors.copper[1] * 255)}, ${Math.round(colors.copper[2] * 255)})`,
|
|
33871
|
-
traceTextureResolution
|
|
33872
|
-
}),
|
|
33873
|
-
bottomCopperText: createCopperTextTextureForLayer({
|
|
33874
|
-
layer: "bottom",
|
|
33875
|
-
circuitJson,
|
|
33876
|
-
boardData,
|
|
33877
|
-
copperColor: `rgb(${Math.round(colors.copper[0] * 255)}, ${Math.round(colors.copper[1] * 255)}, ${Math.round(colors.copper[2] * 255)})`,
|
|
33878
|
-
traceTextureResolution
|
|
33879
|
-
}),
|
|
33880
|
-
topPanelOutlines: createPanelOutlineTextureForLayer({
|
|
33881
|
-
layer: "top",
|
|
33882
|
-
circuitJson,
|
|
33883
|
-
panelData: boardData,
|
|
33884
|
-
traceTextureResolution
|
|
33885
|
-
}),
|
|
33886
|
-
bottomPanelOutlines: createPanelOutlineTextureForLayer({
|
|
33887
|
-
layer: "bottom",
|
|
33888
|
-
circuitJson,
|
|
33889
|
-
panelData: boardData,
|
|
33890
|
-
traceTextureResolution
|
|
33891
|
-
}),
|
|
33892
|
-
topCopper: createCopperPourTextureForLayer({
|
|
33893
|
-
layer: "top",
|
|
33894
|
-
circuitJson,
|
|
33895
|
-
boardData,
|
|
33896
|
-
traceTextureResolution
|
|
33897
|
-
}),
|
|
33898
|
-
bottomCopper: createCopperPourTextureForLayer({
|
|
33899
|
-
layer: "bottom",
|
|
33900
|
-
circuitJson,
|
|
33901
|
-
boardData,
|
|
33902
|
-
traceTextureResolution
|
|
33903
|
-
})
|
|
33904
|
-
};
|
|
33905
|
-
}, [circuitJson, boardData, traceTextureResolution]);
|
|
33777
|
+
return createCombinedBoardTextures({
|
|
33778
|
+
circuitJson,
|
|
33779
|
+
boardData,
|
|
33780
|
+
traceTextureResolution,
|
|
33781
|
+
visibility
|
|
33782
|
+
});
|
|
33783
|
+
}, [circuitJson, boardData, traceTextureResolution, visibility]);
|
|
33906
33784
|
useEffect23(() => {
|
|
33907
33785
|
if (!rootObject || !boardData || !textures) return;
|
|
33908
33786
|
const meshes = [];
|
|
33787
|
+
const disposeTextureMaterial = (material) => {
|
|
33788
|
+
const textureProps = [
|
|
33789
|
+
"map",
|
|
33790
|
+
"alphaMap",
|
|
33791
|
+
"aoMap",
|
|
33792
|
+
"bumpMap",
|
|
33793
|
+
"displacementMap",
|
|
33794
|
+
"emissiveMap",
|
|
33795
|
+
"lightMap",
|
|
33796
|
+
"metalnessMap",
|
|
33797
|
+
"normalMap",
|
|
33798
|
+
"roughnessMap",
|
|
33799
|
+
"specularMap"
|
|
33800
|
+
];
|
|
33801
|
+
const typedMaterial = material;
|
|
33802
|
+
for (const prop of textureProps) {
|
|
33803
|
+
const texture = typedMaterial[prop];
|
|
33804
|
+
if (texture && texture instanceof THREE27.Texture) {
|
|
33805
|
+
texture.dispose();
|
|
33806
|
+
typedMaterial[prop] = null;
|
|
33807
|
+
}
|
|
33808
|
+
}
|
|
33809
|
+
material.dispose();
|
|
33810
|
+
};
|
|
33909
33811
|
const createTexturePlane2 = (texture, zOffset, isBottomLayer, name, usePolygonOffset = false, depthWrite = false) => {
|
|
33910
33812
|
if (!texture) return null;
|
|
33911
33813
|
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
33912
|
-
const planeGeom = new
|
|
33814
|
+
const planeGeom = new THREE27.PlaneGeometry(
|
|
33913
33815
|
boardOutlineBounds.width,
|
|
33914
33816
|
boardOutlineBounds.height
|
|
33915
33817
|
);
|
|
33916
|
-
const material = new
|
|
33818
|
+
const material = new THREE27.MeshBasicMaterial({
|
|
33917
33819
|
map: texture,
|
|
33918
33820
|
transparent: true,
|
|
33919
|
-
side:
|
|
33821
|
+
side: THREE27.DoubleSide,
|
|
33920
33822
|
depthWrite,
|
|
33921
33823
|
polygonOffset: usePolygonOffset,
|
|
33922
33824
|
polygonOffsetUnits: usePolygonOffset ? -0.8 : 0,
|
|
33923
33825
|
opacity: isFaux ? FAUX_BOARD_OPACITY : 1
|
|
33924
33826
|
});
|
|
33925
|
-
const mesh = new
|
|
33827
|
+
const mesh = new THREE27.Mesh(planeGeom, material);
|
|
33926
33828
|
mesh.position.set(
|
|
33927
33829
|
boardOutlineBounds.centerX,
|
|
33928
33830
|
boardOutlineBounds.centerY,
|
|
@@ -33935,159 +33837,27 @@ function JscadBoardTextures({
|
|
|
33935
33837
|
return mesh;
|
|
33936
33838
|
};
|
|
33937
33839
|
const SURFACE_OFFSET = 1e-3;
|
|
33938
|
-
|
|
33939
|
-
|
|
33940
|
-
|
|
33941
|
-
|
|
33942
|
-
|
|
33943
|
-
|
|
33944
|
-
|
|
33945
|
-
|
|
33946
|
-
|
|
33947
|
-
|
|
33948
|
-
|
|
33949
|
-
|
|
33950
|
-
|
|
33951
|
-
|
|
33952
|
-
|
|
33953
|
-
|
|
33954
|
-
|
|
33955
|
-
|
|
33956
|
-
|
|
33957
|
-
|
|
33958
|
-
);
|
|
33959
|
-
if (bottomSoldermaskMesh) {
|
|
33960
|
-
meshes.push(bottomSoldermaskMesh);
|
|
33961
|
-
rootObject.add(bottomSoldermaskMesh);
|
|
33962
|
-
}
|
|
33963
|
-
}
|
|
33964
|
-
if (visibility.topCopper && visibility.topMask) {
|
|
33965
|
-
const topTraceWithMaskMesh = createTexturePlane2(
|
|
33966
|
-
textures.topTraceWithMask,
|
|
33967
|
-
pcbThickness / 2 + BOARD_SURFACE_OFFSET.traces + 4e-3,
|
|
33968
|
-
false,
|
|
33969
|
-
"jscad-top-trace-with-mask"
|
|
33970
|
-
);
|
|
33971
|
-
if (topTraceWithMaskMesh) {
|
|
33972
|
-
meshes.push(topTraceWithMaskMesh);
|
|
33973
|
-
rootObject.add(topTraceWithMaskMesh);
|
|
33974
|
-
}
|
|
33975
|
-
}
|
|
33976
|
-
if (visibility.bottomCopper && visibility.bottomMask) {
|
|
33977
|
-
const bottomTraceWithMaskMesh = createTexturePlane2(
|
|
33978
|
-
textures.bottomTraceWithMask,
|
|
33979
|
-
-pcbThickness / 2 - BOARD_SURFACE_OFFSET.traces - 5e-3,
|
|
33980
|
-
true,
|
|
33981
|
-
"jscad-bottom-trace-with-mask"
|
|
33982
|
-
);
|
|
33983
|
-
if (bottomTraceWithMaskMesh) {
|
|
33984
|
-
meshes.push(bottomTraceWithMaskMesh);
|
|
33985
|
-
rootObject.add(bottomTraceWithMaskMesh);
|
|
33986
|
-
}
|
|
33987
|
-
}
|
|
33988
|
-
if (visibility.topSilkscreen) {
|
|
33989
|
-
const topSilkscreenMesh = createTexturePlane2(
|
|
33990
|
-
textures.topSilkscreen,
|
|
33991
|
-
pcbThickness / 2 + SURFACE_OFFSET + 2e-3,
|
|
33992
|
-
false,
|
|
33993
|
-
"jscad-top-silkscreen"
|
|
33994
|
-
);
|
|
33995
|
-
if (topSilkscreenMesh) {
|
|
33996
|
-
meshes.push(topSilkscreenMesh);
|
|
33997
|
-
rootObject.add(topSilkscreenMesh);
|
|
33998
|
-
}
|
|
33999
|
-
}
|
|
34000
|
-
if (visibility.bottomSilkscreen) {
|
|
34001
|
-
const bottomSilkscreenMesh = createTexturePlane2(
|
|
34002
|
-
textures.bottomSilkscreen,
|
|
34003
|
-
-pcbThickness / 2 - SURFACE_OFFSET - 2e-3,
|
|
34004
|
-
true,
|
|
34005
|
-
"jscad-bottom-silkscreen"
|
|
34006
|
-
);
|
|
34007
|
-
if (bottomSilkscreenMesh) {
|
|
34008
|
-
meshes.push(bottomSilkscreenMesh);
|
|
34009
|
-
rootObject.add(bottomSilkscreenMesh);
|
|
34010
|
-
}
|
|
34011
|
-
}
|
|
34012
|
-
if (visibility.topCopper) {
|
|
34013
|
-
const topCopperTextMesh = createTexturePlane2(
|
|
34014
|
-
textures.topCopperText,
|
|
34015
|
-
pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
|
|
34016
|
-
false,
|
|
34017
|
-
"jscad-top-copper-text",
|
|
34018
|
-
true
|
|
34019
|
-
);
|
|
34020
|
-
if (topCopperTextMesh) {
|
|
34021
|
-
meshes.push(topCopperTextMesh);
|
|
34022
|
-
rootObject.add(topCopperTextMesh);
|
|
34023
|
-
}
|
|
34024
|
-
}
|
|
34025
|
-
if (visibility.bottomCopper) {
|
|
34026
|
-
const bottomCopperTextMesh = createTexturePlane2(
|
|
34027
|
-
textures.bottomCopperText,
|
|
34028
|
-
-pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
|
|
34029
|
-
true,
|
|
34030
|
-
"jscad-bottom-copper-text",
|
|
34031
|
-
true
|
|
34032
|
-
);
|
|
34033
|
-
if (bottomCopperTextMesh) {
|
|
34034
|
-
meshes.push(bottomCopperTextMesh);
|
|
34035
|
-
rootObject.add(bottomCopperTextMesh);
|
|
34036
|
-
}
|
|
34037
|
-
}
|
|
34038
|
-
if (visibility.topCopper) {
|
|
34039
|
-
const topCopperMesh = createTexturePlane2(
|
|
34040
|
-
textures.topCopper,
|
|
34041
|
-
pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper,
|
|
34042
|
-
false,
|
|
34043
|
-
"jscad-top-copper-pour",
|
|
34044
|
-
true
|
|
34045
|
-
);
|
|
34046
|
-
if (topCopperMesh) {
|
|
34047
|
-
meshes.push(topCopperMesh);
|
|
34048
|
-
rootObject.add(topCopperMesh);
|
|
34049
|
-
}
|
|
34050
|
-
}
|
|
34051
|
-
if (visibility.bottomCopper) {
|
|
34052
|
-
const bottomCopperMesh = createTexturePlane2(
|
|
34053
|
-
textures.bottomCopper,
|
|
34054
|
-
-pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper,
|
|
34055
|
-
true,
|
|
34056
|
-
"jscad-bottom-copper-pour",
|
|
34057
|
-
true
|
|
34058
|
-
);
|
|
34059
|
-
if (bottomCopperMesh) {
|
|
34060
|
-
meshes.push(bottomCopperMesh);
|
|
34061
|
-
rootObject.add(bottomCopperMesh);
|
|
34062
|
-
}
|
|
34063
|
-
}
|
|
34064
|
-
if (visibility.boardBody) {
|
|
34065
|
-
const topPanelOutlinesMesh = createTexturePlane2(
|
|
34066
|
-
textures.topPanelOutlines,
|
|
34067
|
-
pcbThickness / 2 + SURFACE_OFFSET + 3e-3,
|
|
34068
|
-
// Above silkscreen
|
|
34069
|
-
false,
|
|
34070
|
-
"jscad-top-panel-outlines",
|
|
34071
|
-
false,
|
|
34072
|
-
true
|
|
34073
|
-
);
|
|
34074
|
-
if (topPanelOutlinesMesh) {
|
|
34075
|
-
meshes.push(topPanelOutlinesMesh);
|
|
34076
|
-
rootObject.add(topPanelOutlinesMesh);
|
|
34077
|
-
}
|
|
34078
|
-
const bottomPanelOutlinesMesh = createTexturePlane2(
|
|
34079
|
-
textures.bottomPanelOutlines,
|
|
34080
|
-
-pcbThickness / 2 - SURFACE_OFFSET - 3e-3,
|
|
34081
|
-
// Below bottom silkscreen
|
|
34082
|
-
true,
|
|
34083
|
-
"jscad-bottom-panel-outlines",
|
|
34084
|
-
false,
|
|
34085
|
-
true
|
|
34086
|
-
);
|
|
34087
|
-
if (bottomPanelOutlinesMesh) {
|
|
34088
|
-
meshes.push(bottomPanelOutlinesMesh);
|
|
34089
|
-
rootObject.add(bottomPanelOutlinesMesh);
|
|
34090
|
-
}
|
|
33840
|
+
const topBoardMesh = createTexturePlane2(
|
|
33841
|
+
textures.topBoard,
|
|
33842
|
+
pcbThickness / 2 + SURFACE_OFFSET,
|
|
33843
|
+
false,
|
|
33844
|
+
"jscad-top-board-texture",
|
|
33845
|
+
true
|
|
33846
|
+
);
|
|
33847
|
+
if (topBoardMesh) {
|
|
33848
|
+
meshes.push(topBoardMesh);
|
|
33849
|
+
rootObject.add(topBoardMesh);
|
|
33850
|
+
}
|
|
33851
|
+
const bottomBoardMesh = createTexturePlane2(
|
|
33852
|
+
textures.bottomBoard,
|
|
33853
|
+
-pcbThickness / 2 - SURFACE_OFFSET,
|
|
33854
|
+
true,
|
|
33855
|
+
"jscad-bottom-board-texture",
|
|
33856
|
+
true
|
|
33857
|
+
);
|
|
33858
|
+
if (bottomBoardMesh) {
|
|
33859
|
+
meshes.push(bottomBoardMesh);
|
|
33860
|
+
rootObject.add(bottomBoardMesh);
|
|
34091
33861
|
}
|
|
34092
33862
|
return () => {
|
|
34093
33863
|
meshes.forEach((mesh) => {
|
|
@@ -34095,12 +33865,16 @@ function JscadBoardTextures({
|
|
|
34095
33865
|
rootObject.remove(mesh);
|
|
34096
33866
|
}
|
|
34097
33867
|
mesh.geometry.dispose();
|
|
34098
|
-
if (mesh.material
|
|
34099
|
-
mesh.material.
|
|
33868
|
+
if (Array.isArray(mesh.material)) {
|
|
33869
|
+
mesh.material.forEach((material) => disposeTextureMaterial(material));
|
|
33870
|
+
} else if (mesh.material instanceof THREE27.Material) {
|
|
33871
|
+
disposeTextureMaterial(mesh.material);
|
|
34100
33872
|
}
|
|
34101
33873
|
});
|
|
33874
|
+
textures.topBoard?.dispose();
|
|
33875
|
+
textures.bottomBoard?.dispose();
|
|
34102
33876
|
};
|
|
34103
|
-
}, [rootObject, boardData, textures, pcbThickness
|
|
33877
|
+
}, [rootObject, boardData, textures, pcbThickness]);
|
|
34104
33878
|
return null;
|
|
34105
33879
|
}
|
|
34106
33880
|
|
|
@@ -34326,11 +34100,12 @@ var CadViewerJscad = forwardRef3(
|
|
|
34326
34100
|
// src/CadViewerManifold.tsx
|
|
34327
34101
|
import { su as su19 } from "@tscircuit/circuit-json-util";
|
|
34328
34102
|
import { useEffect as useEffect25, useMemo as useMemo22, useState as useState16 } from "react";
|
|
34103
|
+
import * as THREE35 from "three";
|
|
34329
34104
|
|
|
34330
34105
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
34331
34106
|
import { useState as useState15, useEffect as useEffect24, useMemo as useMemo21, useRef as useRef9 } from "react";
|
|
34332
34107
|
import { su as su18 } from "@tscircuit/circuit-json-util";
|
|
34333
|
-
import * as
|
|
34108
|
+
import * as THREE32 from "three";
|
|
34334
34109
|
|
|
34335
34110
|
// src/utils/manifold/create-manifold-board.ts
|
|
34336
34111
|
var arePointsClockwise2 = (points) => {
|
|
@@ -34705,17 +34480,17 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
|
|
|
34705
34480
|
|
|
34706
34481
|
// src/utils/manifold/process-plated-holes.ts
|
|
34707
34482
|
import { su as su15 } from "@tscircuit/circuit-json-util";
|
|
34708
|
-
import * as
|
|
34483
|
+
import * as THREE29 from "three";
|
|
34709
34484
|
|
|
34710
34485
|
// src/utils/manifold-mesh-to-three-geometry.ts
|
|
34711
|
-
import * as
|
|
34486
|
+
import * as THREE28 from "three";
|
|
34712
34487
|
function manifoldMeshToThreeGeometry(manifoldMesh) {
|
|
34713
|
-
const geometry = new
|
|
34488
|
+
const geometry = new THREE28.BufferGeometry();
|
|
34714
34489
|
geometry.setAttribute(
|
|
34715
34490
|
"position",
|
|
34716
|
-
new
|
|
34491
|
+
new THREE28.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
|
|
34717
34492
|
);
|
|
34718
|
-
geometry.setIndex(new
|
|
34493
|
+
geometry.setIndex(new THREE28.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
|
|
34719
34494
|
if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
|
|
34720
34495
|
for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
|
|
34721
34496
|
const start = manifoldMesh.runIndex[i];
|
|
@@ -34749,7 +34524,7 @@ var createEllipsePoints = (width10, height10, segments) => {
|
|
|
34749
34524
|
}
|
|
34750
34525
|
return points;
|
|
34751
34526
|
};
|
|
34752
|
-
var COPPER_COLOR = new
|
|
34527
|
+
var COPPER_COLOR = new THREE29.Color(...colors.copper);
|
|
34753
34528
|
var PLATED_HOLE_LIP_HEIGHT = 0.05;
|
|
34754
34529
|
function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
|
|
34755
34530
|
const platedHoleBoardDrills = [];
|
|
@@ -35455,8 +35230,8 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
35455
35230
|
|
|
35456
35231
|
// src/utils/manifold/process-smt-pads.ts
|
|
35457
35232
|
import { su as su16 } from "@tscircuit/circuit-json-util";
|
|
35458
|
-
import * as
|
|
35459
|
-
var COPPER_COLOR2 = new
|
|
35233
|
+
import * as THREE30 from "three";
|
|
35234
|
+
var COPPER_COLOR2 = new THREE30.Color(...colors.copper);
|
|
35460
35235
|
function processSmtPadsForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, holeUnion, boardClipVolume) {
|
|
35461
35236
|
const smtPadGeoms = [];
|
|
35462
35237
|
const smtPads = su16(circuitJson).pcb_smtpad.list();
|
|
@@ -35495,7 +35270,7 @@ function processSmtPadsForManifold(Manifold, circuitJson, pcbThickness, manifold
|
|
|
35495
35270
|
|
|
35496
35271
|
// src/utils/manifold/process-vias.ts
|
|
35497
35272
|
import { su as su17 } from "@tscircuit/circuit-json-util";
|
|
35498
|
-
import * as
|
|
35273
|
+
import * as THREE31 from "three";
|
|
35499
35274
|
|
|
35500
35275
|
// src/utils/via-geoms.ts
|
|
35501
35276
|
function createViaCopper2({
|
|
@@ -35548,7 +35323,7 @@ function createViaCopper2({
|
|
|
35548
35323
|
}
|
|
35549
35324
|
|
|
35550
35325
|
// src/utils/manifold/process-vias.ts
|
|
35551
|
-
var COPPER_COLOR3 = new
|
|
35326
|
+
var COPPER_COLOR3 = new THREE31.Color(...colors.copper);
|
|
35552
35327
|
function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
|
|
35553
35328
|
const viaBoardDrills = [];
|
|
35554
35329
|
const pcbVias = su17(circuitJson).pcb_via.list();
|
|
@@ -35600,9 +35375,8 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
|
|
|
35600
35375
|
}
|
|
35601
35376
|
|
|
35602
35377
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
35603
|
-
var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
35378
|
+
var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
|
|
35604
35379
|
const [geoms, setGeoms] = useState15(null);
|
|
35605
|
-
const [textures, setTextures] = useState15(null);
|
|
35606
35380
|
const [pcbThickness, setPcbThickness] = useState15(null);
|
|
35607
35381
|
const [error, setError] = useState15(null);
|
|
35608
35382
|
const [isLoading, setIsLoading] = useState15(true);
|
|
@@ -35642,14 +35416,12 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
35642
35416
|
useEffect24(() => {
|
|
35643
35417
|
if (!manifoldJSModule || !boardData) {
|
|
35644
35418
|
setGeoms(null);
|
|
35645
|
-
setTextures(null);
|
|
35646
35419
|
setPcbThickness(null);
|
|
35647
35420
|
setIsLoading(false);
|
|
35648
35421
|
return;
|
|
35649
35422
|
}
|
|
35650
35423
|
if ((boardData.width === 0 || !boardData.width) && (boardData.height === 0 || !boardData.height) && (!boardData.outline || boardData.outline.length < 3)) {
|
|
35651
35424
|
setGeoms({ platedHoles: [], smtPads: [], vias: [] });
|
|
35652
|
-
setTextures({});
|
|
35653
35425
|
setPcbThickness(boardData.thickness ?? 0);
|
|
35654
35426
|
setIsLoading(false);
|
|
35655
35427
|
return;
|
|
@@ -35672,7 +35444,6 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
35672
35444
|
manifoldInstancesForCleanup.current = [];
|
|
35673
35445
|
let boardManifold = null;
|
|
35674
35446
|
const currentGeoms = {};
|
|
35675
|
-
const layerTextureMap = {};
|
|
35676
35447
|
try {
|
|
35677
35448
|
const currentPcbThickness = boardData.thickness || 1.4;
|
|
35678
35449
|
setPcbThickness(currentPcbThickness);
|
|
@@ -35772,7 +35543,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
35772
35543
|
{
|
|
35773
35544
|
key: "plated-holes-union",
|
|
35774
35545
|
geometry: cutPlatedGeom,
|
|
35775
|
-
color: new
|
|
35546
|
+
color: new THREE32.Color(
|
|
35776
35547
|
colors.copper[0],
|
|
35777
35548
|
colors.copper[1],
|
|
35778
35549
|
colors.copper[2]
|
|
@@ -35802,7 +35573,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
35802
35573
|
const matColorArray = boardMaterialColors[boardData.material] ?? colors.fr4Tan;
|
|
35803
35574
|
currentGeoms.board = {
|
|
35804
35575
|
geometry: finalBoardGeom,
|
|
35805
|
-
color: new
|
|
35576
|
+
color: new THREE32.Color(
|
|
35806
35577
|
matColorArray[0],
|
|
35807
35578
|
matColorArray[1],
|
|
35808
35579
|
matColorArray[2]
|
|
@@ -35821,117 +35592,12 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
35821
35592
|
);
|
|
35822
35593
|
currentGeoms.smtPads = smtPadGeoms;
|
|
35823
35594
|
setGeoms(currentGeoms);
|
|
35824
|
-
const traceColorWithoutMaskArr = colors.fr4TracesWithoutMaskTan;
|
|
35825
|
-
const traceColorWithoutMask = `rgb(${Math.round(traceColorWithoutMaskArr[0] * 255)}, ${Math.round(traceColorWithoutMaskArr[1] * 255)}, ${Math.round(traceColorWithoutMaskArr[2] * 255)})`;
|
|
35826
|
-
layerTextureMap.topTrace = createTraceTextureForLayer({
|
|
35827
|
-
layer: "top",
|
|
35828
|
-
circuitJson,
|
|
35829
|
-
boardData,
|
|
35830
|
-
traceColor: traceColorWithoutMask,
|
|
35831
|
-
traceTextureResolution
|
|
35832
|
-
});
|
|
35833
|
-
layerTextureMap.bottomTrace = createTraceTextureForLayer({
|
|
35834
|
-
layer: "bottom",
|
|
35835
|
-
circuitJson,
|
|
35836
|
-
boardData,
|
|
35837
|
-
traceColor: traceColorWithoutMask,
|
|
35838
|
-
traceTextureResolution
|
|
35839
|
-
});
|
|
35840
|
-
const traceColorWithMaskArr = colors.fr4TracesWithMaskGreen;
|
|
35841
|
-
const traceColorWithMask = `rgb(${Math.round(traceColorWithMaskArr[0] * 255)}, ${Math.round(traceColorWithMaskArr[1] * 255)}, ${Math.round(traceColorWithMaskArr[2] * 255)})`;
|
|
35842
|
-
layerTextureMap.topTraceWithMask = createTraceTextureForLayer({
|
|
35843
|
-
layer: "top",
|
|
35844
|
-
circuitJson,
|
|
35845
|
-
boardData,
|
|
35846
|
-
traceColor: traceColorWithMask,
|
|
35847
|
-
traceTextureResolution
|
|
35848
|
-
});
|
|
35849
|
-
layerTextureMap.bottomTraceWithMask = createTraceTextureForLayer({
|
|
35850
|
-
layer: "bottom",
|
|
35851
|
-
circuitJson,
|
|
35852
|
-
boardData,
|
|
35853
|
-
traceColor: traceColorWithMask,
|
|
35854
|
-
traceTextureResolution
|
|
35855
|
-
});
|
|
35856
|
-
const silkscreenColor = "rgb(255,255,255)";
|
|
35857
|
-
layerTextureMap.topSilkscreen = createSilkscreenTextureForLayer({
|
|
35858
|
-
layer: "top",
|
|
35859
|
-
circuitJson,
|
|
35860
|
-
boardData,
|
|
35861
|
-
silkscreenColor,
|
|
35862
|
-
traceTextureResolution
|
|
35863
|
-
});
|
|
35864
|
-
layerTextureMap.bottomSilkscreen = createSilkscreenTextureForLayer({
|
|
35865
|
-
layer: "bottom",
|
|
35866
|
-
circuitJson,
|
|
35867
|
-
boardData,
|
|
35868
|
-
silkscreenColor,
|
|
35869
|
-
traceTextureResolution
|
|
35870
|
-
});
|
|
35871
|
-
const soldermaskColorArr = soldermaskColors[boardData.material] ?? colors.fr4SolderMaskGreen;
|
|
35872
|
-
const soldermaskColor = `rgb(${Math.round(soldermaskColorArr[0] * 255)}, ${Math.round(soldermaskColorArr[1] * 255)}, ${Math.round(soldermaskColorArr[2] * 255)})`;
|
|
35873
|
-
layerTextureMap.topSoldermask = createSoldermaskTextureForLayer({
|
|
35874
|
-
layer: "top",
|
|
35875
|
-
circuitJson,
|
|
35876
|
-
boardData,
|
|
35877
|
-
soldermaskColor,
|
|
35878
|
-
traceTextureResolution
|
|
35879
|
-
});
|
|
35880
|
-
layerTextureMap.bottomSoldermask = createSoldermaskTextureForLayer({
|
|
35881
|
-
layer: "bottom",
|
|
35882
|
-
circuitJson,
|
|
35883
|
-
boardData,
|
|
35884
|
-
soldermaskColor,
|
|
35885
|
-
traceTextureResolution
|
|
35886
|
-
});
|
|
35887
|
-
const copperColorArr = colors.copper;
|
|
35888
|
-
const copperColor = `rgb(${Math.round(copperColorArr[0] * 255)}, ${Math.round(copperColorArr[1] * 255)}, ${Math.round(copperColorArr[2] * 255)})`;
|
|
35889
|
-
layerTextureMap.topCopperText = createCopperTextTextureForLayer({
|
|
35890
|
-
layer: "top",
|
|
35891
|
-
circuitJson,
|
|
35892
|
-
boardData,
|
|
35893
|
-
copperColor,
|
|
35894
|
-
traceTextureResolution
|
|
35895
|
-
});
|
|
35896
|
-
layerTextureMap.bottomCopperText = createCopperTextTextureForLayer({
|
|
35897
|
-
layer: "bottom",
|
|
35898
|
-
circuitJson,
|
|
35899
|
-
boardData,
|
|
35900
|
-
copperColor,
|
|
35901
|
-
traceTextureResolution
|
|
35902
|
-
});
|
|
35903
|
-
layerTextureMap.topPanelOutlines = createPanelOutlineTextureForLayer({
|
|
35904
|
-
layer: "top",
|
|
35905
|
-
circuitJson,
|
|
35906
|
-
panelData: boardData,
|
|
35907
|
-
traceTextureResolution
|
|
35908
|
-
});
|
|
35909
|
-
layerTextureMap.bottomPanelOutlines = createPanelOutlineTextureForLayer({
|
|
35910
|
-
layer: "bottom",
|
|
35911
|
-
circuitJson,
|
|
35912
|
-
panelData: boardData,
|
|
35913
|
-
traceTextureResolution
|
|
35914
|
-
});
|
|
35915
|
-
layerTextureMap.topCopper = createCopperPourTextureForLayer({
|
|
35916
|
-
layer: "top",
|
|
35917
|
-
circuitJson,
|
|
35918
|
-
boardData,
|
|
35919
|
-
traceTextureResolution
|
|
35920
|
-
});
|
|
35921
|
-
layerTextureMap.bottomCopper = createCopperPourTextureForLayer({
|
|
35922
|
-
layer: "bottom",
|
|
35923
|
-
circuitJson,
|
|
35924
|
-
boardData,
|
|
35925
|
-
traceTextureResolution
|
|
35926
|
-
});
|
|
35927
|
-
setTextures(layerTextureMap);
|
|
35928
35595
|
} catch (e) {
|
|
35929
35596
|
console.error("Error processing geometry with Manifold in hook:", e);
|
|
35930
35597
|
setError(
|
|
35931
35598
|
e.message || "An unknown error occurred while processing geometry in hook."
|
|
35932
35599
|
);
|
|
35933
35600
|
setGeoms(null);
|
|
35934
|
-
setTextures(null);
|
|
35935
35601
|
} finally {
|
|
35936
35602
|
setIsLoading(false);
|
|
35937
35603
|
}
|
|
@@ -35939,7 +35605,16 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
35939
35605
|
manifoldInstancesForCleanup.current.forEach(safeDelete);
|
|
35940
35606
|
manifoldInstancesForCleanup.current = [];
|
|
35941
35607
|
};
|
|
35942
|
-
}, [manifoldJSModule, circuitJson, boardData
|
|
35608
|
+
}, [manifoldJSModule, circuitJson, boardData]);
|
|
35609
|
+
const textures = useMemo21(() => {
|
|
35610
|
+
if (!boardData || !traceTextureResolution) return null;
|
|
35611
|
+
return createCombinedBoardTextures({
|
|
35612
|
+
circuitJson,
|
|
35613
|
+
boardData,
|
|
35614
|
+
traceTextureResolution,
|
|
35615
|
+
visibility
|
|
35616
|
+
});
|
|
35617
|
+
}, [circuitJson, boardData, traceTextureResolution, visibility]);
|
|
35943
35618
|
return {
|
|
35944
35619
|
geoms,
|
|
35945
35620
|
textures,
|
|
@@ -35952,11 +35627,11 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
|
|
|
35952
35627
|
};
|
|
35953
35628
|
|
|
35954
35629
|
// src/utils/manifold/create-three-geometry-meshes.ts
|
|
35955
|
-
import * as
|
|
35630
|
+
import * as THREE34 from "three";
|
|
35956
35631
|
|
|
35957
35632
|
// src/utils/create-board-material.ts
|
|
35958
|
-
import * as
|
|
35959
|
-
var DEFAULT_SIDE =
|
|
35633
|
+
import * as THREE33 from "three";
|
|
35634
|
+
var DEFAULT_SIDE = THREE33.DoubleSide;
|
|
35960
35635
|
var createBoardMaterial = ({
|
|
35961
35636
|
material,
|
|
35962
35637
|
color,
|
|
@@ -35964,7 +35639,7 @@ var createBoardMaterial = ({
|
|
|
35964
35639
|
isFaux = false
|
|
35965
35640
|
}) => {
|
|
35966
35641
|
if (material === "fr4") {
|
|
35967
|
-
return new
|
|
35642
|
+
return new THREE33.MeshPhysicalMaterial({
|
|
35968
35643
|
color,
|
|
35969
35644
|
side,
|
|
35970
35645
|
metalness: 0,
|
|
@@ -35978,7 +35653,7 @@ var createBoardMaterial = ({
|
|
|
35978
35653
|
flatShading: true
|
|
35979
35654
|
});
|
|
35980
35655
|
}
|
|
35981
|
-
return new
|
|
35656
|
+
return new THREE33.MeshStandardMaterial({
|
|
35982
35657
|
color,
|
|
35983
35658
|
side,
|
|
35984
35659
|
flatShading: true,
|
|
@@ -35994,12 +35669,12 @@ function createGeometryMeshes(geoms) {
|
|
|
35994
35669
|
const meshes = [];
|
|
35995
35670
|
if (!geoms) return meshes;
|
|
35996
35671
|
if (geoms.board && geoms.board.geometry) {
|
|
35997
|
-
const mesh = new
|
|
35672
|
+
const mesh = new THREE34.Mesh(
|
|
35998
35673
|
geoms.board.geometry,
|
|
35999
35674
|
createBoardMaterial({
|
|
36000
35675
|
material: geoms.board.material,
|
|
36001
35676
|
color: geoms.board.color,
|
|
36002
|
-
side:
|
|
35677
|
+
side: THREE34.DoubleSide,
|
|
36003
35678
|
isFaux: geoms.board.isFaux
|
|
36004
35679
|
})
|
|
36005
35680
|
);
|
|
@@ -36009,11 +35684,11 @@ function createGeometryMeshes(geoms) {
|
|
|
36009
35684
|
const createMeshesFromArray = (geomArray) => {
|
|
36010
35685
|
if (geomArray) {
|
|
36011
35686
|
geomArray.forEach((comp) => {
|
|
36012
|
-
const mesh = new
|
|
35687
|
+
const mesh = new THREE34.Mesh(
|
|
36013
35688
|
comp.geometry,
|
|
36014
|
-
new
|
|
35689
|
+
new THREE34.MeshStandardMaterial({
|
|
36015
35690
|
color: comp.color,
|
|
36016
|
-
side:
|
|
35691
|
+
side: THREE34.DoubleSide,
|
|
36017
35692
|
flatShading: true,
|
|
36018
35693
|
// Consistent with board
|
|
36019
35694
|
polygonOffset: true,
|
|
@@ -36040,6 +35715,35 @@ var BoardMeshes = ({
|
|
|
36040
35715
|
}) => {
|
|
36041
35716
|
const { rootObject } = useThree();
|
|
36042
35717
|
const { visibility } = useLayerVisibility();
|
|
35718
|
+
const disposeTextureMesh = (mesh) => {
|
|
35719
|
+
mesh.geometry.dispose();
|
|
35720
|
+
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
|
|
35721
|
+
for (const material of materials) {
|
|
35722
|
+
if (!material) continue;
|
|
35723
|
+
const textureProps = [
|
|
35724
|
+
"map",
|
|
35725
|
+
"alphaMap",
|
|
35726
|
+
"aoMap",
|
|
35727
|
+
"bumpMap",
|
|
35728
|
+
"displacementMap",
|
|
35729
|
+
"emissiveMap",
|
|
35730
|
+
"lightMap",
|
|
35731
|
+
"metalnessMap",
|
|
35732
|
+
"normalMap",
|
|
35733
|
+
"roughnessMap",
|
|
35734
|
+
"specularMap"
|
|
35735
|
+
];
|
|
35736
|
+
const typedMaterial = material;
|
|
35737
|
+
for (const prop of textureProps) {
|
|
35738
|
+
const texture = typedMaterial[prop];
|
|
35739
|
+
if (texture && texture instanceof THREE35.Texture) {
|
|
35740
|
+
texture.dispose();
|
|
35741
|
+
typedMaterial[prop] = null;
|
|
35742
|
+
}
|
|
35743
|
+
}
|
|
35744
|
+
material.dispose();
|
|
35745
|
+
}
|
|
35746
|
+
};
|
|
36043
35747
|
useEffect25(() => {
|
|
36044
35748
|
if (!rootObject) return;
|
|
36045
35749
|
geometryMeshes.forEach((mesh) => {
|
|
@@ -36062,37 +35766,7 @@ var BoardMeshes = ({
|
|
|
36062
35766
|
}
|
|
36063
35767
|
});
|
|
36064
35768
|
textureMeshes.forEach((mesh) => {
|
|
36065
|
-
|
|
36066
|
-
if (mesh.name.includes("top-trace-texture-plane") && !mesh.name.includes("with-mask")) {
|
|
36067
|
-
shouldShow = visibility.topCopper && !visibility.topMask;
|
|
36068
|
-
} else if (mesh.name.includes("top-trace-with-mask")) {
|
|
36069
|
-
shouldShow = visibility.topCopper && visibility.topMask;
|
|
36070
|
-
} else if (mesh.name.includes("bottom-trace-texture-plane") && !mesh.name.includes("with-mask")) {
|
|
36071
|
-
shouldShow = visibility.bottomCopper && !visibility.bottomMask;
|
|
36072
|
-
} else if (mesh.name.includes("bottom-trace-with-mask")) {
|
|
36073
|
-
shouldShow = visibility.bottomCopper && visibility.bottomMask;
|
|
36074
|
-
} else if (mesh.name.includes("top-silkscreen")) {
|
|
36075
|
-
shouldShow = visibility.topSilkscreen;
|
|
36076
|
-
} else if (mesh.name.includes("bottom-silkscreen")) {
|
|
36077
|
-
shouldShow = visibility.bottomSilkscreen;
|
|
36078
|
-
} else if (mesh.name.includes("top-soldermask")) {
|
|
36079
|
-
shouldShow = visibility.topMask;
|
|
36080
|
-
} else if (mesh.name.includes("bottom-soldermask")) {
|
|
36081
|
-
shouldShow = visibility.bottomMask;
|
|
36082
|
-
} else if (mesh.name.includes("top-copper-text")) {
|
|
36083
|
-
shouldShow = visibility.topCopper;
|
|
36084
|
-
} else if (mesh.name.includes("bottom-copper-text")) {
|
|
36085
|
-
shouldShow = visibility.bottomCopper;
|
|
36086
|
-
} else if (mesh.name.includes("top-copper")) {
|
|
36087
|
-
shouldShow = visibility.topCopper;
|
|
36088
|
-
} else if (mesh.name.includes("bottom-copper")) {
|
|
36089
|
-
shouldShow = visibility.bottomCopper;
|
|
36090
|
-
} else if (mesh.name.includes("panel-outlines")) {
|
|
36091
|
-
shouldShow = visibility.boardBody;
|
|
36092
|
-
}
|
|
36093
|
-
if (shouldShow) {
|
|
36094
|
-
rootObject.add(mesh);
|
|
36095
|
-
}
|
|
35769
|
+
rootObject.add(mesh);
|
|
36096
35770
|
});
|
|
36097
35771
|
return () => {
|
|
36098
35772
|
geometryMeshes.forEach((mesh) => {
|
|
@@ -36104,6 +35778,7 @@ var BoardMeshes = ({
|
|
|
36104
35778
|
if (mesh.parent === rootObject) {
|
|
36105
35779
|
rootObject.remove(mesh);
|
|
36106
35780
|
}
|
|
35781
|
+
disposeTextureMesh(mesh);
|
|
36107
35782
|
});
|
|
36108
35783
|
};
|
|
36109
35784
|
}, [rootObject, geometryMeshes, textureMeshes, visibility]);
|
|
@@ -36126,6 +35801,7 @@ var CadViewerManifold = ({
|
|
|
36126
35801
|
}, [circuitJsonProp, childrenCircuitJson]);
|
|
36127
35802
|
const [manifoldJSModule, setManifoldJSModule] = useState16(null);
|
|
36128
35803
|
const [manifoldLoadingError, setManifoldLoadingError] = useState16(null);
|
|
35804
|
+
const { visibility } = useLayerVisibility();
|
|
36129
35805
|
useEffect25(() => {
|
|
36130
35806
|
if (window.ManifoldModule && typeof window.ManifoldModule === "object" && window.ManifoldModule.setup) {
|
|
36131
35807
|
setManifoldJSModule(window.ManifoldModule);
|
|
@@ -36196,7 +35872,7 @@ try {
|
|
|
36196
35872
|
isLoading: builderIsLoading,
|
|
36197
35873
|
boardData,
|
|
36198
35874
|
isFauxBoard
|
|
36199
|
-
} = useManifoldBoardBuilder(manifoldJSModule, circuitJson);
|
|
35875
|
+
} = useManifoldBoardBuilder(manifoldJSModule, circuitJson, visibility);
|
|
36200
35876
|
const geometryMeshes = useMemo22(() => createGeometryMeshes(geoms), [geoms]);
|
|
36201
35877
|
const textureMeshes = useMemo22(
|
|
36202
35878
|
() => createTextureMeshes(textures, boardData, pcbThickness, isFauxBoard),
|
|
@@ -42951,7 +42627,7 @@ var KeyboardShortcutsDialog = ({
|
|
|
42951
42627
|
|
|
42952
42628
|
// src/CadViewer.tsx
|
|
42953
42629
|
import { jsx as jsx38, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
42954
|
-
var DEFAULT_TARGET = new
|
|
42630
|
+
var DEFAULT_TARGET = new THREE36.Vector3(0, 0, 0);
|
|
42955
42631
|
var INITIAL_CAMERA_POSITION = [5, -5, 5];
|
|
42956
42632
|
var CadViewerInner = (props) => {
|
|
42957
42633
|
const [engine, setEngine] = useState36("manifold");
|
|
@@ -43218,11 +42894,11 @@ var CadViewer = (props) => {
|
|
|
43218
42894
|
// src/convert-circuit-json-to-3d-svg.ts
|
|
43219
42895
|
var import_debug = __toESM(require_browser(), 1);
|
|
43220
42896
|
import { su as su20 } from "@tscircuit/circuit-json-util";
|
|
43221
|
-
import * as
|
|
42897
|
+
import * as THREE40 from "three";
|
|
43222
42898
|
import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
|
|
43223
42899
|
|
|
43224
42900
|
// src/utils/create-geometry-from-polygons.ts
|
|
43225
|
-
import * as
|
|
42901
|
+
import * as THREE37 from "three";
|
|
43226
42902
|
import { BufferGeometry as BufferGeometry4, Float32BufferAttribute as Float32BufferAttribute3 } from "three";
|
|
43227
42903
|
function createGeometryFromPolygons(polygons) {
|
|
43228
42904
|
const geometry = new BufferGeometry4();
|
|
@@ -43236,12 +42912,12 @@ function createGeometryFromPolygons(polygons) {
|
|
|
43236
42912
|
...polygon3.vertices[i + 1]
|
|
43237
42913
|
// Third vertex
|
|
43238
42914
|
);
|
|
43239
|
-
const v1 = new
|
|
43240
|
-
const v2 = new
|
|
43241
|
-
const v3 = new
|
|
43242
|
-
const normal = new
|
|
43243
|
-
new
|
|
43244
|
-
new
|
|
42915
|
+
const v1 = new THREE37.Vector3(...polygon3.vertices[0]);
|
|
42916
|
+
const v2 = new THREE37.Vector3(...polygon3.vertices[i]);
|
|
42917
|
+
const v3 = new THREE37.Vector3(...polygon3.vertices[i + 1]);
|
|
42918
|
+
const normal = new THREE37.Vector3().crossVectors(
|
|
42919
|
+
new THREE37.Vector3().subVectors(v2, v1),
|
|
42920
|
+
new THREE37.Vector3().subVectors(v3, v1)
|
|
43245
42921
|
).normalize();
|
|
43246
42922
|
normals.push(
|
|
43247
42923
|
normal.x,
|
|
@@ -43265,10 +42941,10 @@ function createGeometryFromPolygons(polygons) {
|
|
|
43265
42941
|
var import_modeling2 = __toESM(require_src(), 1);
|
|
43266
42942
|
var import_jscad_planner2 = __toESM(require_dist(), 1);
|
|
43267
42943
|
var jscadModeling2 = __toESM(require_src(), 1);
|
|
43268
|
-
import * as
|
|
42944
|
+
import * as THREE39 from "three";
|
|
43269
42945
|
|
|
43270
42946
|
// src/utils/load-model.ts
|
|
43271
|
-
import * as
|
|
42947
|
+
import * as THREE38 from "three";
|
|
43272
42948
|
import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
43273
42949
|
import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
|
|
43274
42950
|
import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
|
|
@@ -43276,12 +42952,12 @@ async function load3DModel(url) {
|
|
|
43276
42952
|
if (url.endsWith(".stl")) {
|
|
43277
42953
|
const loader = new STLLoader2();
|
|
43278
42954
|
const geometry = await loader.loadAsync(url);
|
|
43279
|
-
const material = new
|
|
42955
|
+
const material = new THREE38.MeshStandardMaterial({
|
|
43280
42956
|
color: 8947848,
|
|
43281
42957
|
metalness: 0.5,
|
|
43282
42958
|
roughness: 0.5
|
|
43283
42959
|
});
|
|
43284
|
-
return new
|
|
42960
|
+
return new THREE38.Mesh(geometry, material);
|
|
43285
42961
|
}
|
|
43286
42962
|
if (url.endsWith(".obj")) {
|
|
43287
42963
|
const loader = new OBJLoader2();
|
|
@@ -43314,9 +42990,9 @@ async function renderComponent(component, scene) {
|
|
|
43314
42990
|
}
|
|
43315
42991
|
if (component.rotation) {
|
|
43316
42992
|
model.rotation.set(
|
|
43317
|
-
|
|
43318
|
-
|
|
43319
|
-
|
|
42993
|
+
THREE39.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
42994
|
+
THREE39.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
42995
|
+
THREE39.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
43320
42996
|
);
|
|
43321
42997
|
}
|
|
43322
42998
|
scene.add(model);
|
|
@@ -43330,13 +43006,13 @@ async function renderComponent(component, scene) {
|
|
|
43330
43006
|
);
|
|
43331
43007
|
if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
|
|
43332
43008
|
const threeGeom = convertCSGToThreeGeom(jscadObject);
|
|
43333
|
-
const material2 = new
|
|
43009
|
+
const material2 = new THREE39.MeshStandardMaterial({
|
|
43334
43010
|
color: 8947848,
|
|
43335
43011
|
metalness: 0.5,
|
|
43336
43012
|
roughness: 0.5,
|
|
43337
|
-
side:
|
|
43013
|
+
side: THREE39.DoubleSide
|
|
43338
43014
|
});
|
|
43339
|
-
const mesh2 = new
|
|
43015
|
+
const mesh2 = new THREE39.Mesh(threeGeom, material2);
|
|
43340
43016
|
if (component.position) {
|
|
43341
43017
|
mesh2.position.set(
|
|
43342
43018
|
component.position.x ?? 0,
|
|
@@ -43346,9 +43022,9 @@ async function renderComponent(component, scene) {
|
|
|
43346
43022
|
}
|
|
43347
43023
|
if (component.rotation) {
|
|
43348
43024
|
mesh2.rotation.set(
|
|
43349
|
-
|
|
43350
|
-
|
|
43351
|
-
|
|
43025
|
+
THREE39.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
43026
|
+
THREE39.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
43027
|
+
THREE39.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
43352
43028
|
);
|
|
43353
43029
|
}
|
|
43354
43030
|
scene.add(mesh2);
|
|
@@ -43365,17 +43041,17 @@ async function renderComponent(component, scene) {
|
|
|
43365
43041
|
if (!geom || !geom.polygons && !geom.sides) {
|
|
43366
43042
|
continue;
|
|
43367
43043
|
}
|
|
43368
|
-
const color = new
|
|
43044
|
+
const color = new THREE39.Color(geomInfo.color);
|
|
43369
43045
|
color.convertLinearToSRGB();
|
|
43370
43046
|
const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
|
|
43371
43047
|
const threeGeom = convertCSGToThreeGeom(geomWithColor);
|
|
43372
|
-
const material2 = new
|
|
43048
|
+
const material2 = new THREE39.MeshStandardMaterial({
|
|
43373
43049
|
vertexColors: true,
|
|
43374
43050
|
metalness: 0.2,
|
|
43375
43051
|
roughness: 0.8,
|
|
43376
|
-
side:
|
|
43052
|
+
side: THREE39.DoubleSide
|
|
43377
43053
|
});
|
|
43378
|
-
const mesh2 = new
|
|
43054
|
+
const mesh2 = new THREE39.Mesh(threeGeom, material2);
|
|
43379
43055
|
if (component.position) {
|
|
43380
43056
|
mesh2.position.set(
|
|
43381
43057
|
component.position.x ?? 0,
|
|
@@ -43385,22 +43061,22 @@ async function renderComponent(component, scene) {
|
|
|
43385
43061
|
}
|
|
43386
43062
|
if (component.rotation) {
|
|
43387
43063
|
mesh2.rotation.set(
|
|
43388
|
-
|
|
43389
|
-
|
|
43390
|
-
|
|
43064
|
+
THREE39.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
43065
|
+
THREE39.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
43066
|
+
THREE39.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
43391
43067
|
);
|
|
43392
43068
|
}
|
|
43393
43069
|
scene.add(mesh2);
|
|
43394
43070
|
}
|
|
43395
43071
|
return;
|
|
43396
43072
|
}
|
|
43397
|
-
const geometry = new
|
|
43398
|
-
const material = new
|
|
43073
|
+
const geometry = new THREE39.BoxGeometry(0.5, 0.5, 0.5);
|
|
43074
|
+
const material = new THREE39.MeshStandardMaterial({
|
|
43399
43075
|
color: 16711680,
|
|
43400
43076
|
transparent: true,
|
|
43401
43077
|
opacity: 0.25
|
|
43402
43078
|
});
|
|
43403
|
-
const mesh = new
|
|
43079
|
+
const mesh = new THREE39.Mesh(geometry, material);
|
|
43404
43080
|
if (component.position) {
|
|
43405
43081
|
mesh.position.set(
|
|
43406
43082
|
component.position.x ?? 0,
|
|
@@ -43421,11 +43097,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
43421
43097
|
padding = 20,
|
|
43422
43098
|
zoom = 1.5
|
|
43423
43099
|
} = options;
|
|
43424
|
-
const scene = new
|
|
43100
|
+
const scene = new THREE40.Scene();
|
|
43425
43101
|
const renderer = new SVGRenderer();
|
|
43426
43102
|
renderer.setSize(width10, height10);
|
|
43427
|
-
renderer.setClearColor(new
|
|
43428
|
-
const camera = new
|
|
43103
|
+
renderer.setClearColor(new THREE40.Color(backgroundColor), 1);
|
|
43104
|
+
const camera = new THREE40.OrthographicCamera();
|
|
43429
43105
|
const aspect = width10 / height10;
|
|
43430
43106
|
const frustumSize = 100;
|
|
43431
43107
|
const halfFrustumSize = frustumSize / 2 / zoom;
|
|
@@ -43439,11 +43115,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
43439
43115
|
camera.position.set(position.x, position.y, position.z);
|
|
43440
43116
|
camera.up.set(0, 1, 0);
|
|
43441
43117
|
const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
|
|
43442
|
-
camera.lookAt(new
|
|
43118
|
+
camera.lookAt(new THREE40.Vector3(lookAt.x, lookAt.y, lookAt.z));
|
|
43443
43119
|
camera.updateProjectionMatrix();
|
|
43444
|
-
const ambientLight = new
|
|
43120
|
+
const ambientLight = new THREE40.AmbientLight(16777215, Math.PI / 2);
|
|
43445
43121
|
scene.add(ambientLight);
|
|
43446
|
-
const pointLight = new
|
|
43122
|
+
const pointLight = new THREE40.PointLight(16777215, Math.PI / 4);
|
|
43447
43123
|
pointLight.position.set(-10, -10, 10);
|
|
43448
43124
|
scene.add(pointLight);
|
|
43449
43125
|
const components = su20(circuitJson).cad_component.list();
|
|
@@ -43454,7 +43130,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
43454
43130
|
const boardGeom = createBoardGeomFromCircuitJson(circuitJson);
|
|
43455
43131
|
if (boardGeom) {
|
|
43456
43132
|
const solderMaskColor = colors.fr4SolderMaskGreen;
|
|
43457
|
-
const baseColor = new
|
|
43133
|
+
const baseColor = new THREE40.Color(
|
|
43458
43134
|
solderMaskColor[0],
|
|
43459
43135
|
solderMaskColor[1],
|
|
43460
43136
|
solderMaskColor[2]
|
|
@@ -43466,28 +43142,28 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
43466
43142
|
const material = createBoardMaterial({
|
|
43467
43143
|
material: boardData?.material,
|
|
43468
43144
|
color: baseColor,
|
|
43469
|
-
side:
|
|
43145
|
+
side: THREE40.DoubleSide
|
|
43470
43146
|
});
|
|
43471
|
-
const mesh = new
|
|
43147
|
+
const mesh = new THREE40.Mesh(geometry, material);
|
|
43472
43148
|
scene.add(mesh);
|
|
43473
43149
|
}
|
|
43474
43150
|
}
|
|
43475
|
-
const gridColor = new
|
|
43476
|
-
const gridHelper = new
|
|
43151
|
+
const gridColor = new THREE40.Color(8947848);
|
|
43152
|
+
const gridHelper = new THREE40.GridHelper(100, 100, gridColor, gridColor);
|
|
43477
43153
|
gridHelper.rotation.x = Math.PI / 2;
|
|
43478
43154
|
const materials = Array.isArray(gridHelper.material) ? gridHelper.material : [gridHelper.material];
|
|
43479
43155
|
for (const mat of materials) {
|
|
43480
43156
|
mat.transparent = true;
|
|
43481
43157
|
mat.opacity = 0.3;
|
|
43482
|
-
if (mat instanceof
|
|
43158
|
+
if (mat instanceof THREE40.LineBasicMaterial) {
|
|
43483
43159
|
mat.color = gridColor;
|
|
43484
43160
|
mat.vertexColors = false;
|
|
43485
43161
|
}
|
|
43486
43162
|
}
|
|
43487
43163
|
scene.add(gridHelper);
|
|
43488
|
-
const box = new
|
|
43489
|
-
const center = box.getCenter(new
|
|
43490
|
-
const size4 = box.getSize(new
|
|
43164
|
+
const box = new THREE40.Box3().setFromObject(scene);
|
|
43165
|
+
const center = box.getCenter(new THREE40.Vector3());
|
|
43166
|
+
const size4 = box.getSize(new THREE40.Vector3());
|
|
43491
43167
|
scene.position.sub(center);
|
|
43492
43168
|
const maxDim = Math.max(size4.x, size4.y, size4.z);
|
|
43493
43169
|
if (maxDim > 0) {
|