@tscircuit/3d-viewer 0.0.519 → 0.0.521
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +223 -556
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9928,7 +9928,7 @@ var require_vectorText = __commonJS({
|
|
|
9928
9928
|
}
|
|
9929
9929
|
return line;
|
|
9930
9930
|
};
|
|
9931
|
-
var
|
|
9931
|
+
var vectorText2 = (options, text) => {
|
|
9932
9932
|
const {
|
|
9933
9933
|
xOffset,
|
|
9934
9934
|
yOffset,
|
|
@@ -9985,7 +9985,7 @@ var require_vectorText = __commonJS({
|
|
|
9985
9985
|
}
|
|
9986
9986
|
return output;
|
|
9987
9987
|
};
|
|
9988
|
-
module.exports =
|
|
9988
|
+
module.exports = vectorText2;
|
|
9989
9989
|
}
|
|
9990
9990
|
});
|
|
9991
9991
|
|
|
@@ -14248,7 +14248,7 @@ import { useState as useState36, useCallback as useCallback21, useRef as useRef2
|
|
|
14248
14248
|
import * as THREE36 from "three";
|
|
14249
14249
|
|
|
14250
14250
|
// src/CadViewerJscad.tsx
|
|
14251
|
-
import { su as
|
|
14251
|
+
import { su as su11 } from "@tscircuit/circuit-json-util";
|
|
14252
14252
|
import { forwardRef as forwardRef3, useMemo as useMemo20 } from "react";
|
|
14253
14253
|
|
|
14254
14254
|
// src/AnyCadComponent.tsx
|
|
@@ -28483,7 +28483,7 @@ import * as THREE16 from "three";
|
|
|
28483
28483
|
// package.json
|
|
28484
28484
|
var package_default = {
|
|
28485
28485
|
name: "@tscircuit/3d-viewer",
|
|
28486
|
-
version: "0.0.
|
|
28486
|
+
version: "0.0.520",
|
|
28487
28487
|
main: "./dist/index.js",
|
|
28488
28488
|
module: "./dist/index.js",
|
|
28489
28489
|
type: "module",
|
|
@@ -28513,7 +28513,7 @@ var package_default = {
|
|
|
28513
28513
|
"@jscad/regl-renderer": "^2.6.12",
|
|
28514
28514
|
"@jscad/stl-serializer": "^2.1.20",
|
|
28515
28515
|
"circuit-json": "^0.0.372",
|
|
28516
|
-
"circuit-to-canvas": "^0.0.
|
|
28516
|
+
"circuit-to-canvas": "^0.0.81",
|
|
28517
28517
|
"react-hot-toast": "^2.6.0",
|
|
28518
28518
|
three: "^0.165.0",
|
|
28519
28519
|
"three-stdlib": "^2.36.0",
|
|
@@ -31448,7 +31448,7 @@ var ThreeErrorBoundary = class extends React11.Component {
|
|
|
31448
31448
|
};
|
|
31449
31449
|
|
|
31450
31450
|
// src/three-components/JscadBoardTextures.tsx
|
|
31451
|
-
import { su as
|
|
31451
|
+
import { su as su8 } from "@tscircuit/circuit-json-util";
|
|
31452
31452
|
import { useEffect as useEffect23, useMemo as useMemo19 } from "react";
|
|
31453
31453
|
|
|
31454
31454
|
// src/textures/create-combined-board-textures.ts
|
|
@@ -32166,467 +32166,9 @@ function createPanelOutlineTextureForLayer({
|
|
|
32166
32166
|
return texture;
|
|
32167
32167
|
}
|
|
32168
32168
|
|
|
32169
|
-
// src/utils/
|
|
32170
|
-
var import_text2 = __toESM(require_text(), 1);
|
|
32169
|
+
// src/utils/trace-texture.ts
|
|
32171
32170
|
import * as THREE22 from "three";
|
|
32172
32171
|
import { su as su7 } from "@tscircuit/circuit-json-util";
|
|
32173
|
-
|
|
32174
|
-
// src/utils/units.ts
|
|
32175
|
-
var MM_PER_INCH = 25.4;
|
|
32176
|
-
var MM_PER_MIL = MM_PER_INCH / 1e3;
|
|
32177
|
-
var dimensionRegex = /^\s*(-?\d*(?:\.\d+)?)(?:\s*(mm|mil|inch|in|"))?\s*$/i;
|
|
32178
|
-
function normalizeUnit(unit) {
|
|
32179
|
-
if (!unit) return void 0;
|
|
32180
|
-
const normalized = unit.trim().toLowerCase();
|
|
32181
|
-
if (normalized === '"') return "in";
|
|
32182
|
-
if (normalized === "inch") return "in";
|
|
32183
|
-
return normalized;
|
|
32184
|
-
}
|
|
32185
|
-
function parseDimensionToMm(value) {
|
|
32186
|
-
if (value === null || value === void 0) return void 0;
|
|
32187
|
-
if (typeof value === "number") {
|
|
32188
|
-
return Number.isFinite(value) ? value : void 0;
|
|
32189
|
-
}
|
|
32190
|
-
if (typeof value !== "string") return void 0;
|
|
32191
|
-
const trimmed = value.trim();
|
|
32192
|
-
if (trimmed.length === 0) return void 0;
|
|
32193
|
-
const match = trimmed.match(dimensionRegex);
|
|
32194
|
-
if (!match) {
|
|
32195
|
-
const numeric = Number.parseFloat(trimmed);
|
|
32196
|
-
return Number.isFinite(numeric) ? numeric : void 0;
|
|
32197
|
-
}
|
|
32198
|
-
const [, magnitudeRaw, unitRaw] = match;
|
|
32199
|
-
const magnitude = Number.parseFloat(magnitudeRaw || "0");
|
|
32200
|
-
if (!Number.isFinite(magnitude)) return void 0;
|
|
32201
|
-
const unit = normalizeUnit(unitRaw);
|
|
32202
|
-
switch (unit) {
|
|
32203
|
-
case "mil":
|
|
32204
|
-
return magnitude * MM_PER_MIL;
|
|
32205
|
-
case "in":
|
|
32206
|
-
return magnitude * MM_PER_INCH;
|
|
32207
|
-
case "mm":
|
|
32208
|
-
case void 0:
|
|
32209
|
-
return magnitude;
|
|
32210
|
-
default:
|
|
32211
|
-
return magnitude;
|
|
32212
|
-
}
|
|
32213
|
-
}
|
|
32214
|
-
function coerceDimensionToMm(value, fallback) {
|
|
32215
|
-
const parsed = parseDimensionToMm(value);
|
|
32216
|
-
return parsed === void 0 ? fallback : parsed;
|
|
32217
|
-
}
|
|
32218
|
-
|
|
32219
|
-
// src/utils/silkscreen-texture.ts
|
|
32220
|
-
function parseFabricationNoteColor(colorString) {
|
|
32221
|
-
let hex = colorString;
|
|
32222
|
-
if (hex.startsWith("#")) {
|
|
32223
|
-
hex = hex.slice(1);
|
|
32224
|
-
}
|
|
32225
|
-
if (hex.length === 6) {
|
|
32226
|
-
const r = parseInt(hex.slice(0, 2), 16);
|
|
32227
|
-
const g = parseInt(hex.slice(2, 4), 16);
|
|
32228
|
-
const b = parseInt(hex.slice(4, 6), 16);
|
|
32229
|
-
return `rgb(${r}, ${g}, ${b})`;
|
|
32230
|
-
}
|
|
32231
|
-
if (colorString.startsWith("rgb")) {
|
|
32232
|
-
return colorString;
|
|
32233
|
-
}
|
|
32234
|
-
return "rgb(255, 243, 204)";
|
|
32235
|
-
}
|
|
32236
|
-
function createSilkscreenTextureForLayer({
|
|
32237
|
-
layer,
|
|
32238
|
-
circuitJson,
|
|
32239
|
-
boardData,
|
|
32240
|
-
silkscreenColor = "rgb(255,255,255)",
|
|
32241
|
-
traceTextureResolution
|
|
32242
|
-
}) {
|
|
32243
|
-
const pcbSilkscreenTexts = su7(circuitJson).pcb_silkscreen_text.list();
|
|
32244
|
-
const pcbSilkscreenPaths = su7(circuitJson).pcb_silkscreen_path.list();
|
|
32245
|
-
const pcbSilkscreenLines = su7(circuitJson).pcb_silkscreen_line.list();
|
|
32246
|
-
const pcbSilkscreenRects = su7(circuitJson).pcb_silkscreen_rect.list();
|
|
32247
|
-
const pcbSilkscreenCircles = su7(circuitJson).pcb_silkscreen_circle.list();
|
|
32248
|
-
const pcbFabricationNoteRects = su7(circuitJson).pcb_fabrication_note_rect.list();
|
|
32249
|
-
const pcbNoteLines = su7(circuitJson).pcb_note_line.list();
|
|
32250
|
-
const textsOnLayer = pcbSilkscreenTexts.filter((t) => t.layer === layer);
|
|
32251
|
-
const pathsOnLayer = pcbSilkscreenPaths.filter((p) => p.layer === layer);
|
|
32252
|
-
const linesOnLayer = pcbSilkscreenLines.filter((l) => l.layer === layer);
|
|
32253
|
-
const rectsOnLayer = pcbSilkscreenRects.filter((r) => r.layer === layer);
|
|
32254
|
-
const circlesOnLayer = pcbSilkscreenCircles.filter((c) => c.layer === layer);
|
|
32255
|
-
const fabricationNoteRectsOnLayer = pcbFabricationNoteRects.filter(
|
|
32256
|
-
(r) => r.layer === layer
|
|
32257
|
-
);
|
|
32258
|
-
const noteLinesOnLayer = pcbNoteLines.filter(
|
|
32259
|
-
(l) => l.layer === layer
|
|
32260
|
-
);
|
|
32261
|
-
if (textsOnLayer.length === 0 && pathsOnLayer.length === 0 && linesOnLayer.length === 0 && rectsOnLayer.length === 0 && circlesOnLayer.length === 0 && fabricationNoteRectsOnLayer.length === 0 && noteLinesOnLayer.length === 0) {
|
|
32262
|
-
return null;
|
|
32263
|
-
}
|
|
32264
|
-
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
32265
|
-
const canvas = document.createElement("canvas");
|
|
32266
|
-
const canvasWidth = Math.floor(
|
|
32267
|
-
boardOutlineBounds.width * traceTextureResolution
|
|
32268
|
-
);
|
|
32269
|
-
const canvasHeight = Math.floor(
|
|
32270
|
-
boardOutlineBounds.height * traceTextureResolution
|
|
32271
|
-
);
|
|
32272
|
-
canvas.width = canvasWidth;
|
|
32273
|
-
canvas.height = canvasHeight;
|
|
32274
|
-
const ctx = canvas.getContext("2d");
|
|
32275
|
-
if (!ctx) return null;
|
|
32276
|
-
if (layer === "bottom") {
|
|
32277
|
-
ctx.translate(0, canvasHeight);
|
|
32278
|
-
ctx.scale(1, -1);
|
|
32279
|
-
}
|
|
32280
|
-
ctx.strokeStyle = silkscreenColor;
|
|
32281
|
-
ctx.fillStyle = silkscreenColor;
|
|
32282
|
-
const canvasXFromPcb = (pcbX) => (pcbX - boardOutlineBounds.minX) * traceTextureResolution;
|
|
32283
|
-
const canvasYFromPcb = (pcbY) => (boardOutlineBounds.maxY - pcbY) * traceTextureResolution;
|
|
32284
|
-
linesOnLayer.forEach((lineEl) => {
|
|
32285
|
-
const startXmm = parseDimensionToMm(lineEl.x1) ?? 0;
|
|
32286
|
-
const startYmm = parseDimensionToMm(lineEl.y1) ?? 0;
|
|
32287
|
-
const endXmm = parseDimensionToMm(lineEl.x2) ?? 0;
|
|
32288
|
-
const endYmm = parseDimensionToMm(lineEl.y2) ?? 0;
|
|
32289
|
-
if (startXmm === endXmm && startYmm === endYmm) return;
|
|
32290
|
-
ctx.beginPath();
|
|
32291
|
-
ctx.lineWidth = coerceDimensionToMm(lineEl.stroke_width, 0.1) * traceTextureResolution;
|
|
32292
|
-
ctx.lineCap = "round";
|
|
32293
|
-
ctx.moveTo(canvasXFromPcb(startXmm), canvasYFromPcb(startYmm));
|
|
32294
|
-
ctx.lineTo(canvasXFromPcb(endXmm), canvasYFromPcb(endYmm));
|
|
32295
|
-
ctx.stroke();
|
|
32296
|
-
});
|
|
32297
|
-
noteLinesOnLayer.forEach((lineEl) => {
|
|
32298
|
-
const startXmm = parseDimensionToMm(lineEl.x1) ?? 0;
|
|
32299
|
-
const startYmm = parseDimensionToMm(lineEl.y1) ?? 0;
|
|
32300
|
-
const endXmm = parseDimensionToMm(lineEl.x2) ?? 0;
|
|
32301
|
-
const endYmm = parseDimensionToMm(lineEl.y2) ?? 0;
|
|
32302
|
-
if (startXmm === endXmm && startYmm === endYmm) return;
|
|
32303
|
-
ctx.save();
|
|
32304
|
-
let strokeColor = silkscreenColor;
|
|
32305
|
-
if (lineEl.color) {
|
|
32306
|
-
strokeColor = parseFabricationNoteColor(lineEl.color);
|
|
32307
|
-
} else {
|
|
32308
|
-
strokeColor = "rgb(255, 243, 204)";
|
|
32309
|
-
}
|
|
32310
|
-
ctx.strokeStyle = strokeColor;
|
|
32311
|
-
ctx.beginPath();
|
|
32312
|
-
ctx.lineWidth = coerceDimensionToMm(lineEl.stroke_width, 0.1) * traceTextureResolution;
|
|
32313
|
-
ctx.lineCap = "round";
|
|
32314
|
-
const isDashed = lineEl.is_dashed ?? false;
|
|
32315
|
-
if (isDashed) {
|
|
32316
|
-
const dashLength = Math.max(ctx.lineWidth * 2, 1);
|
|
32317
|
-
ctx.setLineDash([dashLength, dashLength]);
|
|
32318
|
-
}
|
|
32319
|
-
ctx.moveTo(canvasXFromPcb(startXmm), canvasYFromPcb(startYmm));
|
|
32320
|
-
ctx.lineTo(canvasXFromPcb(endXmm), canvasYFromPcb(endYmm));
|
|
32321
|
-
ctx.stroke();
|
|
32322
|
-
if (isDashed) {
|
|
32323
|
-
ctx.setLineDash([]);
|
|
32324
|
-
}
|
|
32325
|
-
ctx.restore();
|
|
32326
|
-
});
|
|
32327
|
-
pathsOnLayer.forEach((path) => {
|
|
32328
|
-
if (path.route.length < 2) return;
|
|
32329
|
-
ctx.beginPath();
|
|
32330
|
-
ctx.lineWidth = coerceDimensionToMm(path.stroke_width, 0.1) * traceTextureResolution;
|
|
32331
|
-
ctx.lineCap = "round";
|
|
32332
|
-
ctx.lineJoin = "round";
|
|
32333
|
-
path.route.forEach((point, index2) => {
|
|
32334
|
-
const canvasX = canvasXFromPcb(parseDimensionToMm(point.x) ?? 0);
|
|
32335
|
-
const canvasY = canvasYFromPcb(parseDimensionToMm(point.y) ?? 0);
|
|
32336
|
-
if (index2 === 0) ctx.moveTo(canvasX, canvasY);
|
|
32337
|
-
else ctx.lineTo(canvasX, canvasY);
|
|
32338
|
-
});
|
|
32339
|
-
ctx.stroke();
|
|
32340
|
-
});
|
|
32341
|
-
circlesOnLayer.forEach((circleEl) => {
|
|
32342
|
-
const radius = coerceDimensionToMm(circleEl.radius, 0);
|
|
32343
|
-
if (radius <= 0) return;
|
|
32344
|
-
const strokeWidth = coerceDimensionToMm(circleEl.stroke_width, 0.12);
|
|
32345
|
-
const hasStroke = strokeWidth > 0;
|
|
32346
|
-
const centerXmm = parseDimensionToMm(circleEl.center?.x) ?? 0;
|
|
32347
|
-
const centerYmm = parseDimensionToMm(circleEl.center?.y) ?? 0;
|
|
32348
|
-
const canvasCenterX = canvasXFromPcb(centerXmm);
|
|
32349
|
-
const canvasCenterY = canvasYFromPcb(centerYmm);
|
|
32350
|
-
const radiusPx = radius * traceTextureResolution;
|
|
32351
|
-
ctx.save();
|
|
32352
|
-
ctx.translate(canvasCenterX, canvasCenterY);
|
|
32353
|
-
if (hasStroke) {
|
|
32354
|
-
const outerRadiusPx = radiusPx + strokeWidth / 2 * traceTextureResolution;
|
|
32355
|
-
const innerRadiusPx = Math.max(
|
|
32356
|
-
0,
|
|
32357
|
-
radiusPx - strokeWidth / 2 * traceTextureResolution
|
|
32358
|
-
);
|
|
32359
|
-
if (innerRadiusPx > 0) {
|
|
32360
|
-
ctx.beginPath();
|
|
32361
|
-
ctx.arc(0, 0, outerRadiusPx, 0, 2 * Math.PI);
|
|
32362
|
-
ctx.arc(0, 0, innerRadiusPx, 0, 2 * Math.PI, true);
|
|
32363
|
-
ctx.fill("evenodd");
|
|
32364
|
-
} else {
|
|
32365
|
-
ctx.beginPath();
|
|
32366
|
-
ctx.arc(0, 0, outerRadiusPx, 0, 2 * Math.PI);
|
|
32367
|
-
ctx.fill();
|
|
32368
|
-
}
|
|
32369
|
-
} else {
|
|
32370
|
-
ctx.beginPath();
|
|
32371
|
-
ctx.arc(0, 0, radiusPx, 0, 2 * Math.PI);
|
|
32372
|
-
ctx.fill();
|
|
32373
|
-
}
|
|
32374
|
-
ctx.restore();
|
|
32375
|
-
});
|
|
32376
|
-
rectsOnLayer.forEach((rect) => {
|
|
32377
|
-
const width10 = coerceDimensionToMm(rect.width, 0);
|
|
32378
|
-
const height10 = coerceDimensionToMm(rect.height, 0);
|
|
32379
|
-
if (width10 <= 0 || height10 <= 0) return;
|
|
32380
|
-
const centerXmm = parseDimensionToMm(rect.center?.x) ?? 0;
|
|
32381
|
-
const centerYmm = parseDimensionToMm(rect.center?.y) ?? 0;
|
|
32382
|
-
const canvasCenterX = canvasXFromPcb(centerXmm);
|
|
32383
|
-
const canvasCenterY = canvasYFromPcb(centerYmm);
|
|
32384
|
-
const rawRadius = extractRectBorderRadius(rect);
|
|
32385
|
-
const borderRadiusInput = typeof rawRadius === "string" ? parseDimensionToMm(rawRadius) : rawRadius;
|
|
32386
|
-
const borderRadiusMm = clampRectBorderRadius(
|
|
32387
|
-
width10,
|
|
32388
|
-
height10,
|
|
32389
|
-
borderRadiusInput
|
|
32390
|
-
);
|
|
32391
|
-
ctx.save();
|
|
32392
|
-
ctx.translate(canvasCenterX, canvasCenterY);
|
|
32393
|
-
const halfWidthPx = width10 / 2 * traceTextureResolution;
|
|
32394
|
-
const halfHeightPx = height10 / 2 * traceTextureResolution;
|
|
32395
|
-
const borderRadiusPx = Math.min(
|
|
32396
|
-
borderRadiusMm * traceTextureResolution,
|
|
32397
|
-
halfWidthPx,
|
|
32398
|
-
halfHeightPx
|
|
32399
|
-
);
|
|
32400
|
-
const hasStroke = rect.stroke_width ?? false;
|
|
32401
|
-
const isFilled = rect.is_filled ?? true;
|
|
32402
|
-
const isDashed = rect.is_stroke_dashed ?? false;
|
|
32403
|
-
const strokeWidthPx = hasStroke ? coerceDimensionToMm(rect.stroke_width, 0.1) * traceTextureResolution : 0;
|
|
32404
|
-
const drawRoundedRectPath = (x, y, rectWidth, rectHeight, radius) => {
|
|
32405
|
-
ctx.beginPath();
|
|
32406
|
-
if (radius <= 0) {
|
|
32407
|
-
ctx.rect(x, y, rectWidth, rectHeight);
|
|
32408
|
-
} else {
|
|
32409
|
-
const r = radius;
|
|
32410
|
-
const right = x + rectWidth;
|
|
32411
|
-
const bottom = y + rectHeight;
|
|
32412
|
-
ctx.moveTo(x + r, y);
|
|
32413
|
-
ctx.lineTo(right - r, y);
|
|
32414
|
-
ctx.quadraticCurveTo(right, y, right, y + r);
|
|
32415
|
-
ctx.lineTo(right, bottom - r);
|
|
32416
|
-
ctx.quadraticCurveTo(right, bottom, right - r, bottom);
|
|
32417
|
-
ctx.lineTo(x + r, bottom);
|
|
32418
|
-
ctx.quadraticCurveTo(x, bottom, x, bottom - r);
|
|
32419
|
-
ctx.lineTo(x, y + r);
|
|
32420
|
-
ctx.quadraticCurveTo(x, y, x + r, y);
|
|
32421
|
-
ctx.closePath();
|
|
32422
|
-
}
|
|
32423
|
-
};
|
|
32424
|
-
drawRoundedRectPath(
|
|
32425
|
-
-halfWidthPx,
|
|
32426
|
-
-halfHeightPx,
|
|
32427
|
-
halfWidthPx * 2,
|
|
32428
|
-
halfHeightPx * 2,
|
|
32429
|
-
borderRadiusPx
|
|
32430
|
-
);
|
|
32431
|
-
if (isFilled) {
|
|
32432
|
-
ctx.fill();
|
|
32433
|
-
}
|
|
32434
|
-
if (hasStroke && strokeWidthPx > 0) {
|
|
32435
|
-
ctx.lineWidth = strokeWidthPx;
|
|
32436
|
-
if (isDashed) {
|
|
32437
|
-
const dashLength = Math.max(strokeWidthPx * 2, 1);
|
|
32438
|
-
ctx.setLineDash([dashLength, dashLength]);
|
|
32439
|
-
}
|
|
32440
|
-
ctx.stroke();
|
|
32441
|
-
if (isDashed) {
|
|
32442
|
-
ctx.setLineDash([]);
|
|
32443
|
-
}
|
|
32444
|
-
}
|
|
32445
|
-
ctx.restore();
|
|
32446
|
-
});
|
|
32447
|
-
fabricationNoteRectsOnLayer.forEach((rect) => {
|
|
32448
|
-
const width10 = coerceDimensionToMm(rect.width, 0);
|
|
32449
|
-
const height10 = coerceDimensionToMm(rect.height, 0);
|
|
32450
|
-
if (width10 <= 0 || height10 <= 0) return;
|
|
32451
|
-
const centerXmm = parseDimensionToMm(rect.center?.x) ?? 0;
|
|
32452
|
-
const centerYmm = parseDimensionToMm(rect.center?.y) ?? 0;
|
|
32453
|
-
const canvasCenterX = canvasXFromPcb(centerXmm);
|
|
32454
|
-
const canvasCenterY = canvasYFromPcb(centerYmm);
|
|
32455
|
-
const rawRadius = extractRectBorderRadius(rect);
|
|
32456
|
-
const borderRadiusInput = typeof rawRadius === "string" ? parseDimensionToMm(rawRadius) : rawRadius;
|
|
32457
|
-
const borderRadiusMm = clampRectBorderRadius(
|
|
32458
|
-
width10,
|
|
32459
|
-
height10,
|
|
32460
|
-
borderRadiusInput
|
|
32461
|
-
);
|
|
32462
|
-
ctx.save();
|
|
32463
|
-
ctx.translate(canvasCenterX, canvasCenterY);
|
|
32464
|
-
const halfWidthPx = width10 / 2 * traceTextureResolution;
|
|
32465
|
-
const halfHeightPx = height10 / 2 * traceTextureResolution;
|
|
32466
|
-
const borderRadiusPx = Math.min(
|
|
32467
|
-
borderRadiusMm * traceTextureResolution,
|
|
32468
|
-
halfWidthPx,
|
|
32469
|
-
halfHeightPx
|
|
32470
|
-
);
|
|
32471
|
-
const hasStroke = rect.has_stroke ?? false;
|
|
32472
|
-
const isFilled = rect.is_filled ?? true;
|
|
32473
|
-
const isDashed = rect.is_stroke_dashed ?? false;
|
|
32474
|
-
const strokeWidthPx = hasStroke ? coerceDimensionToMm(rect.stroke_width, 0.1) * traceTextureResolution : 0;
|
|
32475
|
-
let fillColor = silkscreenColor;
|
|
32476
|
-
let strokeColor = silkscreenColor;
|
|
32477
|
-
if (rect.color) {
|
|
32478
|
-
const parsedColor = parseFabricationNoteColor(rect.color);
|
|
32479
|
-
fillColor = parsedColor;
|
|
32480
|
-
strokeColor = parsedColor;
|
|
32481
|
-
} else {
|
|
32482
|
-
fillColor = "rgb(255, 243, 204)";
|
|
32483
|
-
strokeColor = "rgb(255, 243, 204)";
|
|
32484
|
-
}
|
|
32485
|
-
const drawRoundedRectPath = (x, y, rectWidth, rectHeight, radius) => {
|
|
32486
|
-
ctx.beginPath();
|
|
32487
|
-
if (radius <= 0) {
|
|
32488
|
-
ctx.rect(x, y, rectWidth, rectHeight);
|
|
32489
|
-
} else {
|
|
32490
|
-
const r = radius;
|
|
32491
|
-
const right = x + rectWidth;
|
|
32492
|
-
const bottom = y + rectHeight;
|
|
32493
|
-
ctx.moveTo(x + r, y);
|
|
32494
|
-
ctx.lineTo(right - r, y);
|
|
32495
|
-
ctx.quadraticCurveTo(right, y, right, y + r);
|
|
32496
|
-
ctx.lineTo(right, bottom - r);
|
|
32497
|
-
ctx.quadraticCurveTo(right, bottom, right - r, bottom);
|
|
32498
|
-
ctx.lineTo(x + r, bottom);
|
|
32499
|
-
ctx.quadraticCurveTo(x, bottom, x, bottom - r);
|
|
32500
|
-
ctx.lineTo(x, y + r);
|
|
32501
|
-
ctx.quadraticCurveTo(x, y, x + r, y);
|
|
32502
|
-
ctx.closePath();
|
|
32503
|
-
}
|
|
32504
|
-
};
|
|
32505
|
-
drawRoundedRectPath(
|
|
32506
|
-
-halfWidthPx,
|
|
32507
|
-
-halfHeightPx,
|
|
32508
|
-
halfWidthPx * 2,
|
|
32509
|
-
halfHeightPx * 2,
|
|
32510
|
-
borderRadiusPx
|
|
32511
|
-
);
|
|
32512
|
-
if (isFilled) {
|
|
32513
|
-
ctx.fillStyle = fillColor;
|
|
32514
|
-
ctx.fill();
|
|
32515
|
-
}
|
|
32516
|
-
if (hasStroke && strokeWidthPx > 0) {
|
|
32517
|
-
ctx.strokeStyle = strokeColor;
|
|
32518
|
-
ctx.lineWidth = strokeWidthPx;
|
|
32519
|
-
if (isDashed) {
|
|
32520
|
-
const dashLength = Math.max(strokeWidthPx * 2, 1);
|
|
32521
|
-
ctx.setLineDash([dashLength, dashLength]);
|
|
32522
|
-
}
|
|
32523
|
-
ctx.stroke();
|
|
32524
|
-
if (isDashed) {
|
|
32525
|
-
ctx.setLineDash([]);
|
|
32526
|
-
}
|
|
32527
|
-
}
|
|
32528
|
-
ctx.restore();
|
|
32529
|
-
});
|
|
32530
|
-
textsOnLayer.forEach((textS) => {
|
|
32531
|
-
const fontSize = textS.font_size || 0.25;
|
|
32532
|
-
const textStrokeWidth = Math.min(Math.max(0.01, fontSize * 0.1), fontSize * 0.05) * traceTextureResolution;
|
|
32533
|
-
ctx.lineWidth = textStrokeWidth;
|
|
32534
|
-
ctx.lineCap = "butt";
|
|
32535
|
-
ctx.lineJoin = "miter";
|
|
32536
|
-
const rawTextOutlines = (0, import_text2.vectorText)({
|
|
32537
|
-
height: fontSize * 0.45,
|
|
32538
|
-
input: textS.text
|
|
32539
|
-
});
|
|
32540
|
-
const processedTextOutlines = [];
|
|
32541
|
-
rawTextOutlines.forEach((outline) => {
|
|
32542
|
-
if (outline.length === 29) {
|
|
32543
|
-
processedTextOutlines.push(
|
|
32544
|
-
outline.slice(0, 15)
|
|
32545
|
-
);
|
|
32546
|
-
processedTextOutlines.push(
|
|
32547
|
-
outline.slice(14, 29)
|
|
32548
|
-
);
|
|
32549
|
-
} else if (outline.length === 17) {
|
|
32550
|
-
processedTextOutlines.push(
|
|
32551
|
-
outline.slice(0, 10)
|
|
32552
|
-
);
|
|
32553
|
-
processedTextOutlines.push(
|
|
32554
|
-
outline.slice(9, 17)
|
|
32555
|
-
);
|
|
32556
|
-
} else {
|
|
32557
|
-
processedTextOutlines.push(outline);
|
|
32558
|
-
}
|
|
32559
|
-
});
|
|
32560
|
-
const points = processedTextOutlines.flat();
|
|
32561
|
-
const textBounds = {
|
|
32562
|
-
minX: points.length > 0 ? Math.min(...points.map((p) => p[0])) : 0,
|
|
32563
|
-
maxX: points.length > 0 ? Math.max(...points.map((p) => p[0])) : 0,
|
|
32564
|
-
minY: points.length > 0 ? Math.min(...points.map((p) => p[1])) : 0,
|
|
32565
|
-
maxY: points.length > 0 ? Math.max(...points.map((p) => p[1])) : 0
|
|
32566
|
-
};
|
|
32567
|
-
const textCenterX = (textBounds.minX + textBounds.maxX) / 2;
|
|
32568
|
-
const textCenterY = (textBounds.minY + textBounds.maxY) / 2;
|
|
32569
|
-
let xOff = -textCenterX;
|
|
32570
|
-
let yOff = -textCenterY;
|
|
32571
|
-
const alignment = textS.anchor_alignment || "center";
|
|
32572
|
-
if (alignment.includes("left")) {
|
|
32573
|
-
xOff = -textBounds.minX;
|
|
32574
|
-
} else if (alignment.includes("right")) {
|
|
32575
|
-
xOff = -textBounds.maxX;
|
|
32576
|
-
}
|
|
32577
|
-
if (alignment.includes("top")) {
|
|
32578
|
-
yOff = -textBounds.maxY;
|
|
32579
|
-
} else if (alignment.includes("bottom")) {
|
|
32580
|
-
yOff = -textBounds.minY;
|
|
32581
|
-
}
|
|
32582
|
-
const transformMatrices = [];
|
|
32583
|
-
let rotationDeg = textS.ccw_rotation ?? 0;
|
|
32584
|
-
if (textS.layer === "bottom") {
|
|
32585
|
-
transformMatrices.push(
|
|
32586
|
-
translate6(textCenterX, textCenterY),
|
|
32587
|
-
{ a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 },
|
|
32588
|
-
translate6(-textCenterX, -textCenterY)
|
|
32589
|
-
);
|
|
32590
|
-
rotationDeg = -rotationDeg;
|
|
32591
|
-
}
|
|
32592
|
-
if (rotationDeg) {
|
|
32593
|
-
const rad = rotationDeg * Math.PI / 180;
|
|
32594
|
-
transformMatrices.push(
|
|
32595
|
-
translate6(textCenterX, textCenterY),
|
|
32596
|
-
rotate2(rad),
|
|
32597
|
-
translate6(-textCenterX, -textCenterY)
|
|
32598
|
-
);
|
|
32599
|
-
}
|
|
32600
|
-
const finalTransformMatrix = transformMatrices.length > 0 ? compose(...transformMatrices) : void 0;
|
|
32601
|
-
processedTextOutlines.forEach((segment) => {
|
|
32602
|
-
ctx.beginPath();
|
|
32603
|
-
segment.forEach((p, index2) => {
|
|
32604
|
-
let transformedP = { x: p[0], y: p[1] };
|
|
32605
|
-
if (finalTransformMatrix) {
|
|
32606
|
-
transformedP = applyToPoint(finalTransformMatrix, transformedP);
|
|
32607
|
-
}
|
|
32608
|
-
const pcbX = transformedP.x + xOff + textS.anchor_position.x;
|
|
32609
|
-
const pcbY = transformedP.y + yOff + textS.anchor_position.y;
|
|
32610
|
-
const canvasX = canvasXFromPcb(pcbX);
|
|
32611
|
-
const canvasY = canvasYFromPcb(pcbY);
|
|
32612
|
-
if (index2 === 0) ctx.moveTo(canvasX, canvasY);
|
|
32613
|
-
else ctx.lineTo(canvasX, canvasY);
|
|
32614
|
-
});
|
|
32615
|
-
ctx.stroke();
|
|
32616
|
-
});
|
|
32617
|
-
});
|
|
32618
|
-
const texture = new THREE22.CanvasTexture(canvas);
|
|
32619
|
-
texture.generateMipmaps = true;
|
|
32620
|
-
texture.minFilter = THREE22.LinearMipmapLinearFilter;
|
|
32621
|
-
texture.magFilter = THREE22.LinearFilter;
|
|
32622
|
-
texture.anisotropy = 16;
|
|
32623
|
-
texture.needsUpdate = true;
|
|
32624
|
-
return texture;
|
|
32625
|
-
}
|
|
32626
|
-
|
|
32627
|
-
// src/utils/trace-texture.ts
|
|
32628
|
-
import * as THREE23 from "three";
|
|
32629
|
-
import { su as su8 } from "@tscircuit/circuit-json-util";
|
|
32630
32172
|
function isWireRoutePoint(point) {
|
|
32631
32173
|
return point && point.route_type === "wire" && typeof point.layer === "string" && typeof point.width === "number";
|
|
32632
32174
|
}
|
|
@@ -32637,9 +32179,9 @@ function createTraceTextureForLayer({
|
|
|
32637
32179
|
traceColor,
|
|
32638
32180
|
traceTextureResolution
|
|
32639
32181
|
}) {
|
|
32640
|
-
const pcbTraces =
|
|
32641
|
-
const allPcbVias =
|
|
32642
|
-
const allPcbPlatedHoles =
|
|
32182
|
+
const pcbTraces = su7(circuitJson).pcb_trace.list();
|
|
32183
|
+
const allPcbVias = su7(circuitJson).pcb_via.list();
|
|
32184
|
+
const allPcbPlatedHoles = su7(
|
|
32643
32185
|
circuitJson
|
|
32644
32186
|
).pcb_plated_hole.list();
|
|
32645
32187
|
const tracesOnLayer = pcbTraces.filter(
|
|
@@ -32738,17 +32280,17 @@ function createTraceTextureForLayer({
|
|
|
32738
32280
|
}
|
|
32739
32281
|
});
|
|
32740
32282
|
ctx.globalCompositeOperation = "source-over";
|
|
32741
|
-
const texture = new
|
|
32283
|
+
const texture = new THREE22.CanvasTexture(canvas);
|
|
32742
32284
|
texture.generateMipmaps = true;
|
|
32743
|
-
texture.minFilter =
|
|
32744
|
-
texture.magFilter =
|
|
32285
|
+
texture.minFilter = THREE22.LinearMipmapLinearFilter;
|
|
32286
|
+
texture.magFilter = THREE22.LinearFilter;
|
|
32745
32287
|
texture.anisotropy = 16;
|
|
32746
32288
|
texture.needsUpdate = true;
|
|
32747
32289
|
return texture;
|
|
32748
32290
|
}
|
|
32749
32291
|
|
|
32750
32292
|
// src/textures/create-copper-pour-texture-for-layer.ts
|
|
32751
|
-
import * as
|
|
32293
|
+
import * as THREE23 from "three";
|
|
32752
32294
|
import { CircuitToCanvasDrawer } from "circuit-to-canvas";
|
|
32753
32295
|
|
|
32754
32296
|
// src/geoms/brep-converter.ts
|
|
@@ -32954,6 +32496,167 @@ function createCopperPourTextureForLayer({
|
|
|
32954
32496
|
ctx.fillStyle = copperColor;
|
|
32955
32497
|
drawBrepShape({ ctx, pour, canvasXFromPcb, canvasYFromPcb });
|
|
32956
32498
|
}
|
|
32499
|
+
const texture = new THREE23.CanvasTexture(canvas);
|
|
32500
|
+
texture.generateMipmaps = true;
|
|
32501
|
+
texture.minFilter = THREE23.LinearMipmapLinearFilter;
|
|
32502
|
+
texture.magFilter = THREE23.LinearFilter;
|
|
32503
|
+
texture.anisotropy = 16;
|
|
32504
|
+
texture.needsUpdate = true;
|
|
32505
|
+
return texture;
|
|
32506
|
+
}
|
|
32507
|
+
|
|
32508
|
+
// src/textures/create-silkscreen-texture-for-layer.ts
|
|
32509
|
+
import * as THREE24 from "three";
|
|
32510
|
+
|
|
32511
|
+
// src/textures/soldermask/soldermask-bounds.ts
|
|
32512
|
+
var boundsFromPanel = (panel) => ({
|
|
32513
|
+
minX: panel.center.x - panel.width / 2,
|
|
32514
|
+
maxX: panel.center.x + panel.width / 2,
|
|
32515
|
+
minY: panel.center.y - panel.height / 2,
|
|
32516
|
+
maxY: panel.center.y + panel.height / 2,
|
|
32517
|
+
width: panel.width,
|
|
32518
|
+
height: panel.height,
|
|
32519
|
+
centerX: panel.center.x,
|
|
32520
|
+
centerY: panel.center.y
|
|
32521
|
+
});
|
|
32522
|
+
var mergeBounds = (a, b) => {
|
|
32523
|
+
const minX = Math.min(a.minX, b.minX);
|
|
32524
|
+
const maxX = Math.max(a.maxX, b.maxX);
|
|
32525
|
+
const minY = Math.min(a.minY, b.minY);
|
|
32526
|
+
const maxY = Math.max(a.maxY, b.maxY);
|
|
32527
|
+
return {
|
|
32528
|
+
minX,
|
|
32529
|
+
maxX,
|
|
32530
|
+
minY,
|
|
32531
|
+
maxY,
|
|
32532
|
+
width: maxX - minX,
|
|
32533
|
+
height: maxY - minY,
|
|
32534
|
+
centerX: (minX + maxX) / 2,
|
|
32535
|
+
centerY: (minY + maxY) / 2
|
|
32536
|
+
};
|
|
32537
|
+
};
|
|
32538
|
+
var getSoldermaskRenderBounds = (circuitJson, boardData) => {
|
|
32539
|
+
const panels = circuitJson.filter(
|
|
32540
|
+
(e) => e.type === "pcb_panel"
|
|
32541
|
+
);
|
|
32542
|
+
const boards = circuitJson.filter(
|
|
32543
|
+
(e) => e.type === "pcb_board"
|
|
32544
|
+
);
|
|
32545
|
+
const activePanel = panels.find((panel) => panel.pcb_panel_id === boardData.pcb_board_id) ?? panels[0];
|
|
32546
|
+
if (activePanel && activePanel.width > 0 && activePanel.height > 0) {
|
|
32547
|
+
return boundsFromPanel(activePanel);
|
|
32548
|
+
}
|
|
32549
|
+
const boardsForBounds = boards.length > 1 ? boards : [boardData];
|
|
32550
|
+
return boardsForBounds.map((board) => calculateOutlineBounds(board)).reduce((acc, bounds) => mergeBounds(acc, bounds));
|
|
32551
|
+
};
|
|
32552
|
+
|
|
32553
|
+
// src/textures/silkscreen/silkscreen-drawing.ts
|
|
32554
|
+
import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
|
|
32555
|
+
var FABRICATION_NOTE_COLOR = "rgb(255,243,204)";
|
|
32556
|
+
var TRANSPARENT = "rgba(0,0,0,0)";
|
|
32557
|
+
var setDrawerBounds = (drawer, bounds) => {
|
|
32558
|
+
drawer.setCameraBounds({
|
|
32559
|
+
minX: bounds.minX,
|
|
32560
|
+
maxX: bounds.maxX,
|
|
32561
|
+
minY: bounds.minY,
|
|
32562
|
+
maxY: bounds.maxY
|
|
32563
|
+
});
|
|
32564
|
+
};
|
|
32565
|
+
var drawSilkscreenLayer = ({
|
|
32566
|
+
ctx,
|
|
32567
|
+
layer,
|
|
32568
|
+
bounds,
|
|
32569
|
+
elements,
|
|
32570
|
+
silkscreenColor
|
|
32571
|
+
}) => {
|
|
32572
|
+
const renderLayer = layer === "top" ? "top_silkscreen" : "bottom_silkscreen";
|
|
32573
|
+
const drawer = new CircuitToCanvasDrawer2(ctx);
|
|
32574
|
+
drawer.configure({
|
|
32575
|
+
colorOverrides: {
|
|
32576
|
+
copper: {
|
|
32577
|
+
top: TRANSPARENT,
|
|
32578
|
+
bottom: TRANSPARENT,
|
|
32579
|
+
inner1: TRANSPARENT,
|
|
32580
|
+
inner2: TRANSPARENT,
|
|
32581
|
+
inner3: TRANSPARENT,
|
|
32582
|
+
inner4: TRANSPARENT,
|
|
32583
|
+
inner5: TRANSPARENT,
|
|
32584
|
+
inner6: TRANSPARENT
|
|
32585
|
+
},
|
|
32586
|
+
copperPour: {
|
|
32587
|
+
top: TRANSPARENT,
|
|
32588
|
+
bottom: TRANSPARENT
|
|
32589
|
+
},
|
|
32590
|
+
drill: TRANSPARENT,
|
|
32591
|
+
boardOutline: TRANSPARENT,
|
|
32592
|
+
substrate: TRANSPARENT,
|
|
32593
|
+
keepout: TRANSPARENT,
|
|
32594
|
+
courtyard: {
|
|
32595
|
+
top: TRANSPARENT,
|
|
32596
|
+
bottom: TRANSPARENT
|
|
32597
|
+
},
|
|
32598
|
+
soldermask: {
|
|
32599
|
+
top: TRANSPARENT,
|
|
32600
|
+
bottom: TRANSPARENT
|
|
32601
|
+
},
|
|
32602
|
+
soldermaskWithCopperUnderneath: {
|
|
32603
|
+
top: TRANSPARENT,
|
|
32604
|
+
bottom: TRANSPARENT
|
|
32605
|
+
},
|
|
32606
|
+
soldermaskOverCopper: {
|
|
32607
|
+
top: TRANSPARENT,
|
|
32608
|
+
bottom: TRANSPARENT
|
|
32609
|
+
},
|
|
32610
|
+
silkscreen: {
|
|
32611
|
+
top: silkscreenColor,
|
|
32612
|
+
bottom: silkscreenColor
|
|
32613
|
+
},
|
|
32614
|
+
fabricationNote: FABRICATION_NOTE_COLOR
|
|
32615
|
+
}
|
|
32616
|
+
});
|
|
32617
|
+
setDrawerBounds(drawer, bounds);
|
|
32618
|
+
drawer.drawElements(elements, {
|
|
32619
|
+
layers: [renderLayer]
|
|
32620
|
+
});
|
|
32621
|
+
};
|
|
32622
|
+
|
|
32623
|
+
// src/textures/create-silkscreen-texture-for-layer.ts
|
|
32624
|
+
var isSilkscreenElement = (element, layer) => {
|
|
32625
|
+
if (!("layer" in element) || element.layer !== layer) return false;
|
|
32626
|
+
const elementType = element.type;
|
|
32627
|
+
return elementType.startsWith("pcb_silkscreen_") || elementType === "pcb_fabrication_note_rect" || elementType === "pcb_note_line";
|
|
32628
|
+
};
|
|
32629
|
+
function createSilkscreenTextureForLayer({
|
|
32630
|
+
layer,
|
|
32631
|
+
circuitJson,
|
|
32632
|
+
boardData,
|
|
32633
|
+
traceTextureResolution = TRACE_TEXTURE_RESOLUTION,
|
|
32634
|
+
silkscreenColor = "rgb(255,255,255)"
|
|
32635
|
+
}) {
|
|
32636
|
+
const elements = circuitJson.filter(
|
|
32637
|
+
(element) => isSilkscreenElement(element, layer)
|
|
32638
|
+
);
|
|
32639
|
+
if (elements.length === 0) return null;
|
|
32640
|
+
const bounds = getSoldermaskRenderBounds(circuitJson, boardData);
|
|
32641
|
+
const canvasWidth = Math.floor(bounds.width * traceTextureResolution);
|
|
32642
|
+
const canvasHeight = Math.floor(bounds.height * traceTextureResolution);
|
|
32643
|
+
if (canvasWidth <= 0 || canvasHeight <= 0) return null;
|
|
32644
|
+
const canvas = document.createElement("canvas");
|
|
32645
|
+
canvas.width = canvasWidth;
|
|
32646
|
+
canvas.height = canvasHeight;
|
|
32647
|
+
const ctx = canvas.getContext("2d");
|
|
32648
|
+
if (!ctx) return null;
|
|
32649
|
+
if (layer === "bottom") {
|
|
32650
|
+
ctx.translate(0, canvasHeight);
|
|
32651
|
+
ctx.scale(1, -1);
|
|
32652
|
+
}
|
|
32653
|
+
drawSilkscreenLayer({
|
|
32654
|
+
ctx,
|
|
32655
|
+
layer,
|
|
32656
|
+
bounds,
|
|
32657
|
+
elements,
|
|
32658
|
+
silkscreenColor
|
|
32659
|
+
});
|
|
32957
32660
|
const texture = new THREE24.CanvasTexture(canvas);
|
|
32958
32661
|
texture.generateMipmaps = true;
|
|
32959
32662
|
texture.minFilter = THREE24.LinearMipmapLinearFilter;
|
|
@@ -32967,7 +32670,7 @@ function createCopperPourTextureForLayer({
|
|
|
32967
32670
|
import * as THREE25 from "three";
|
|
32968
32671
|
|
|
32969
32672
|
// src/textures/soldermask/soldermask-drawing.ts
|
|
32970
|
-
import { CircuitToCanvasDrawer as
|
|
32673
|
+
import { CircuitToCanvasDrawer as CircuitToCanvasDrawer3 } from "circuit-to-canvas";
|
|
32971
32674
|
var toRgb = (colorArr) => {
|
|
32972
32675
|
const [r = 0, g = 0, b = 0] = colorArr;
|
|
32973
32676
|
return `rgb(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(
|
|
@@ -32986,7 +32689,7 @@ var getSoldermaskPalette = (material) => {
|
|
|
32986
32689
|
transparent: "rgba(0,0,0,0)"
|
|
32987
32690
|
};
|
|
32988
32691
|
};
|
|
32989
|
-
var
|
|
32692
|
+
var setDrawerBounds2 = (drawer, bounds) => {
|
|
32990
32693
|
drawer.setCameraBounds({
|
|
32991
32694
|
minX: bounds.minX,
|
|
32992
32695
|
maxX: bounds.maxX,
|
|
@@ -33003,7 +32706,7 @@ var drawSoldermaskLayer = ({
|
|
|
33003
32706
|
}) => {
|
|
33004
32707
|
const palette = getSoldermaskPalette(boardMaterial);
|
|
33005
32708
|
const copperRenderLayer = layer === "top" ? "top_copper" : "bottom_copper";
|
|
33006
|
-
const drawer = new
|
|
32709
|
+
const drawer = new CircuitToCanvasDrawer3(ctx);
|
|
33007
32710
|
drawer.configure({
|
|
33008
32711
|
colorOverrides: {
|
|
33009
32712
|
copper: {
|
|
@@ -33034,7 +32737,7 @@ var drawSoldermaskLayer = ({
|
|
|
33034
32737
|
}
|
|
33035
32738
|
}
|
|
33036
32739
|
});
|
|
33037
|
-
|
|
32740
|
+
setDrawerBounds2(drawer, bounds);
|
|
33038
32741
|
drawer.drawElements(elements, {
|
|
33039
32742
|
layers: [copperRenderLayer],
|
|
33040
32743
|
drawSoldermask: true,
|
|
@@ -33047,7 +32750,7 @@ var drawSoldermaskLayer = ({
|
|
|
33047
32750
|
if (uncoveredPours.length > 0) {
|
|
33048
32751
|
ctx.save();
|
|
33049
32752
|
ctx.globalCompositeOperation = "destination-out";
|
|
33050
|
-
const cutoutDrawer = new
|
|
32753
|
+
const cutoutDrawer = new CircuitToCanvasDrawer3(ctx);
|
|
33051
32754
|
cutoutDrawer.configure({
|
|
33052
32755
|
colorOverrides: {
|
|
33053
32756
|
copper: {
|
|
@@ -33062,54 +32765,12 @@ var drawSoldermaskLayer = ({
|
|
|
33062
32765
|
}
|
|
33063
32766
|
}
|
|
33064
32767
|
});
|
|
33065
|
-
|
|
32768
|
+
setDrawerBounds2(cutoutDrawer, bounds);
|
|
33066
32769
|
cutoutDrawer.drawElements(uncoveredPours, { layers: [copperRenderLayer] });
|
|
33067
32770
|
ctx.restore();
|
|
33068
32771
|
}
|
|
33069
32772
|
};
|
|
33070
32773
|
|
|
33071
|
-
// src/textures/soldermask/soldermask-bounds.ts
|
|
33072
|
-
var boundsFromPanel = (panel) => ({
|
|
33073
|
-
minX: panel.center.x - panel.width / 2,
|
|
33074
|
-
maxX: panel.center.x + panel.width / 2,
|
|
33075
|
-
minY: panel.center.y - panel.height / 2,
|
|
33076
|
-
maxY: panel.center.y + panel.height / 2,
|
|
33077
|
-
width: panel.width,
|
|
33078
|
-
height: panel.height,
|
|
33079
|
-
centerX: panel.center.x,
|
|
33080
|
-
centerY: panel.center.y
|
|
33081
|
-
});
|
|
33082
|
-
var mergeBounds = (a, b) => {
|
|
33083
|
-
const minX = Math.min(a.minX, b.minX);
|
|
33084
|
-
const maxX = Math.max(a.maxX, b.maxX);
|
|
33085
|
-
const minY = Math.min(a.minY, b.minY);
|
|
33086
|
-
const maxY = Math.max(a.maxY, b.maxY);
|
|
33087
|
-
return {
|
|
33088
|
-
minX,
|
|
33089
|
-
maxX,
|
|
33090
|
-
minY,
|
|
33091
|
-
maxY,
|
|
33092
|
-
width: maxX - minX,
|
|
33093
|
-
height: maxY - minY,
|
|
33094
|
-
centerX: (minX + maxX) / 2,
|
|
33095
|
-
centerY: (minY + maxY) / 2
|
|
33096
|
-
};
|
|
33097
|
-
};
|
|
33098
|
-
var getSoldermaskRenderBounds = (circuitJson, boardData) => {
|
|
33099
|
-
const panels = circuitJson.filter(
|
|
33100
|
-
(e) => e.type === "pcb_panel"
|
|
33101
|
-
);
|
|
33102
|
-
const boards = circuitJson.filter(
|
|
33103
|
-
(e) => e.type === "pcb_board"
|
|
33104
|
-
);
|
|
33105
|
-
const activePanel = panels.find((panel) => panel.pcb_panel_id === boardData.pcb_board_id) ?? panels[0];
|
|
33106
|
-
if (activePanel && activePanel.width > 0 && activePanel.height > 0) {
|
|
33107
|
-
return boundsFromPanel(activePanel);
|
|
33108
|
-
}
|
|
33109
|
-
const boardsForBounds = boards.length > 1 ? boards : [boardData];
|
|
33110
|
-
return boardsForBounds.map((board) => calculateOutlineBounds(board)).reduce((acc, bounds) => mergeBounds(acc, bounds));
|
|
33111
|
-
};
|
|
33112
|
-
|
|
33113
32774
|
// src/textures/create-soldermask-texture-for-layer.ts
|
|
33114
32775
|
function createSoldermaskTextureForLayer({
|
|
33115
32776
|
layer,
|
|
@@ -33385,7 +33046,7 @@ function JscadBoardTextures({
|
|
|
33385
33046
|
const panels = circuitJson.filter(
|
|
33386
33047
|
(e) => e.type === "pcb_panel"
|
|
33387
33048
|
);
|
|
33388
|
-
const boards =
|
|
33049
|
+
const boards = su8(circuitJson).pcb_board.list();
|
|
33389
33050
|
if (panels.length > 0) {
|
|
33390
33051
|
const panel = panels[0];
|
|
33391
33052
|
const firstBoardInPanel = boards.find(
|
|
@@ -33522,16 +33183,16 @@ function JscadBoardTextures({
|
|
|
33522
33183
|
}
|
|
33523
33184
|
|
|
33524
33185
|
// src/utils/preprocess-circuit-json.ts
|
|
33525
|
-
import { su as
|
|
33186
|
+
import { su as su10 } from "@tscircuit/circuit-json-util";
|
|
33526
33187
|
|
|
33527
33188
|
// src/utils/create-faux-board.ts
|
|
33528
|
-
import { su as
|
|
33189
|
+
import { su as su9, getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
|
|
33529
33190
|
function createFauxBoard(circuitJson) {
|
|
33530
|
-
const cadComponents =
|
|
33531
|
-
const pads =
|
|
33532
|
-
const holes =
|
|
33533
|
-
const platedHoles =
|
|
33534
|
-
const vias =
|
|
33191
|
+
const cadComponents = su9(circuitJson).cad_component.list();
|
|
33192
|
+
const pads = su9(circuitJson).pcb_smtpad.list();
|
|
33193
|
+
const holes = su9(circuitJson).pcb_hole.list();
|
|
33194
|
+
const platedHoles = su9(circuitJson).pcb_plated_hole.list();
|
|
33195
|
+
const vias = su9(circuitJson).pcb_via.list();
|
|
33535
33196
|
if (cadComponents.length === 0 && pads.length === 0 && holes.length === 0 && platedHoles.length === 0 && vias.length === 0) {
|
|
33536
33197
|
return null;
|
|
33537
33198
|
}
|
|
@@ -33580,7 +33241,7 @@ function createFauxBoard(circuitJson) {
|
|
|
33580
33241
|
|
|
33581
33242
|
// src/utils/preprocess-circuit-json.ts
|
|
33582
33243
|
function addFauxBoardIfNeeded(circuitJson) {
|
|
33583
|
-
const boards =
|
|
33244
|
+
const boards = su10(circuitJson).pcb_board.list();
|
|
33584
33245
|
if (boards.length > 0) {
|
|
33585
33246
|
return circuitJson;
|
|
33586
33247
|
}
|
|
@@ -33631,7 +33292,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
33631
33292
|
const initialCameraPosition = useMemo20(() => {
|
|
33632
33293
|
if (!internalCircuitJson) return [5, -5, 5];
|
|
33633
33294
|
try {
|
|
33634
|
-
const board =
|
|
33295
|
+
const board = su11(internalCircuitJson).pcb_board.list()[0];
|
|
33635
33296
|
if (!board) return [5, -5, 5];
|
|
33636
33297
|
const { width: width10, height: height10 } = board;
|
|
33637
33298
|
if (!width10 && !height10) {
|
|
@@ -33657,7 +33318,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
33657
33318
|
const isFauxBoard = useMemo20(() => {
|
|
33658
33319
|
if (!internalCircuitJson) return false;
|
|
33659
33320
|
try {
|
|
33660
|
-
const board =
|
|
33321
|
+
const board = su11(internalCircuitJson).pcb_board.list()[0];
|
|
33661
33322
|
return !!board && board.pcb_board_id === "faux-board";
|
|
33662
33323
|
} catch (e) {
|
|
33663
33324
|
return false;
|
|
@@ -33666,7 +33327,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
33666
33327
|
const boardDimensions = useMemo20(() => {
|
|
33667
33328
|
if (!internalCircuitJson) return void 0;
|
|
33668
33329
|
try {
|
|
33669
|
-
const board =
|
|
33330
|
+
const board = su11(internalCircuitJson).pcb_board.list()[0];
|
|
33670
33331
|
if (!board) return void 0;
|
|
33671
33332
|
return { width: board.width ?? 0, height: board.height ?? 0 };
|
|
33672
33333
|
} catch (e) {
|
|
@@ -33677,7 +33338,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
33677
33338
|
const boardCenter = useMemo20(() => {
|
|
33678
33339
|
if (!internalCircuitJson) return void 0;
|
|
33679
33340
|
try {
|
|
33680
|
-
const board =
|
|
33341
|
+
const board = su11(internalCircuitJson).pcb_board.list()[0];
|
|
33681
33342
|
if (!board || !board.center) return void 0;
|
|
33682
33343
|
return { x: board.center.x, y: board.center.y };
|
|
33683
33344
|
} catch (e) {
|
|
@@ -33687,7 +33348,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
33687
33348
|
}, [internalCircuitJson]);
|
|
33688
33349
|
const pcbThickness = usePcbThickness(internalCircuitJson);
|
|
33689
33350
|
const { stls: boardStls, loading } = useStlsFromGeom(boardGeom);
|
|
33690
|
-
const cad_components =
|
|
33351
|
+
const cad_components = su11(internalCircuitJson).cad_component.list();
|
|
33691
33352
|
return /* @__PURE__ */ jsxs5(
|
|
33692
33353
|
CadViewerContainer,
|
|
33693
33354
|
{
|
|
@@ -33741,12 +33402,12 @@ var CadViewerJscad = forwardRef3(
|
|
|
33741
33402
|
);
|
|
33742
33403
|
|
|
33743
33404
|
// src/CadViewerManifold.tsx
|
|
33744
|
-
import { su as
|
|
33405
|
+
import { su as su17 } from "@tscircuit/circuit-json-util";
|
|
33745
33406
|
import { useEffect as useEffect25, useMemo as useMemo22, useState as useState16 } from "react";
|
|
33746
33407
|
import * as THREE35 from "three";
|
|
33747
33408
|
|
|
33748
33409
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
33749
|
-
import { su as
|
|
33410
|
+
import { su as su16 } from "@tscircuit/circuit-json-util";
|
|
33750
33411
|
import { useEffect as useEffect24, useMemo as useMemo21, useRef as useRef9, useState as useState15 } from "react";
|
|
33751
33412
|
import * as THREE32 from "three";
|
|
33752
33413
|
|
|
@@ -33809,7 +33470,7 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
|
|
|
33809
33470
|
}
|
|
33810
33471
|
|
|
33811
33472
|
// src/utils/manifold/process-cutouts.ts
|
|
33812
|
-
import { su as
|
|
33473
|
+
import { su as su12 } from "@tscircuit/circuit-json-util";
|
|
33813
33474
|
|
|
33814
33475
|
// src/utils/pad-geoms.ts
|
|
33815
33476
|
var RECT_PAD_SEGMENTS2 = 64;
|
|
@@ -33868,7 +33529,7 @@ var arePointsClockwise3 = (points) => {
|
|
|
33868
33529
|
};
|
|
33869
33530
|
function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
|
|
33870
33531
|
const cutoutOps = [];
|
|
33871
|
-
const pcbCutouts =
|
|
33532
|
+
const pcbCutouts = su12(circuitJson).pcb_cutout.list();
|
|
33872
33533
|
for (const cutout of pcbCutouts) {
|
|
33873
33534
|
let cutoutOp;
|
|
33874
33535
|
const cutoutHeight = pcbThickness * 1.5;
|
|
@@ -33963,7 +33624,7 @@ function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThick
|
|
|
33963
33624
|
}
|
|
33964
33625
|
|
|
33965
33626
|
// src/utils/manifold/process-non-plated-holes.ts
|
|
33966
|
-
import { su as
|
|
33627
|
+
import { su as su13 } from "@tscircuit/circuit-json-util";
|
|
33967
33628
|
|
|
33968
33629
|
// src/utils/hole-geoms.ts
|
|
33969
33630
|
function createCircleHoleDrill({
|
|
@@ -34006,7 +33667,7 @@ function createPlatedHoleDrill({
|
|
|
34006
33667
|
// src/utils/manifold/process-non-plated-holes.ts
|
|
34007
33668
|
function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
|
|
34008
33669
|
const nonPlatedHoleBoardDrills = [];
|
|
34009
|
-
const pcbHoles =
|
|
33670
|
+
const pcbHoles = su13(circuitJson).pcb_hole.list();
|
|
34010
33671
|
const createPillOp = (width10, height10, depth) => {
|
|
34011
33672
|
const pillOp = createRoundedRectPrism({
|
|
34012
33673
|
Manifold,
|
|
@@ -34089,7 +33750,7 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
|
|
|
34089
33750
|
}
|
|
34090
33751
|
|
|
34091
33752
|
// src/utils/manifold/process-plated-holes.ts
|
|
34092
|
-
import { su as
|
|
33753
|
+
import { su as su14 } from "@tscircuit/circuit-json-util";
|
|
34093
33754
|
import * as THREE30 from "three";
|
|
34094
33755
|
|
|
34095
33756
|
// src/utils/manifold-mesh-to-three-geometry.ts
|
|
@@ -34141,7 +33802,7 @@ var PLATED_HOLE_SURFACE_CLEARANCE = 5e-4;
|
|
|
34141
33802
|
var PLATED_HOLE_FILL_CLEARANCE = 4e-3;
|
|
34142
33803
|
function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
|
|
34143
33804
|
const platedHoleBoardDrills = [];
|
|
34144
|
-
const pcbPlatedHoles =
|
|
33805
|
+
const pcbPlatedHoles = su14(circuitJson).pcb_plated_hole.list();
|
|
34145
33806
|
const platedHoleCopperGeoms = [];
|
|
34146
33807
|
const platedHoleCopperOpsForSubtract = [];
|
|
34147
33808
|
const createPillOp = (width10, height10, depth) => {
|
|
@@ -34875,7 +34536,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
34875
34536
|
}
|
|
34876
34537
|
|
|
34877
34538
|
// src/utils/manifold/process-vias.ts
|
|
34878
|
-
import { su as
|
|
34539
|
+
import { su as su15 } from "@tscircuit/circuit-json-util";
|
|
34879
34540
|
import * as THREE31 from "three";
|
|
34880
34541
|
|
|
34881
34542
|
// src/utils/via-geoms.ts
|
|
@@ -34932,7 +34593,7 @@ function createViaCopper2({
|
|
|
34932
34593
|
var COPPER_COLOR2 = new THREE31.Color(...colors.copper);
|
|
34933
34594
|
function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
|
|
34934
34595
|
const viaBoardDrills = [];
|
|
34935
|
-
const pcbVias =
|
|
34596
|
+
const pcbVias = su15(circuitJson).pcb_via.list();
|
|
34936
34597
|
const viaCopperGeoms = [];
|
|
34937
34598
|
pcbVias.forEach((via, index2) => {
|
|
34938
34599
|
if (typeof via.hole_diameter === "number") {
|
|
@@ -34991,7 +34652,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
|
|
|
34991
34652
|
const panels = circuitJson.filter(
|
|
34992
34653
|
(e) => e.type === "pcb_panel"
|
|
34993
34654
|
);
|
|
34994
|
-
const boards =
|
|
34655
|
+
const boards = su16(circuitJson).pcb_board.list();
|
|
34995
34656
|
if (panels.length > 0) {
|
|
34996
34657
|
const panel = panels[0];
|
|
34997
34658
|
const firstBoardInPanel = boards.find(
|
|
@@ -35012,7 +34673,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
|
|
|
35012
34673
|
return boardsNotInPanel.length > 0 ? boardsNotInPanel[0] : null;
|
|
35013
34674
|
}, [circuitJson]);
|
|
35014
34675
|
const isFauxBoard = useMemo21(() => {
|
|
35015
|
-
const boards =
|
|
34676
|
+
const boards = su16(circuitJson).pcb_board.list();
|
|
35016
34677
|
return boards.length > 0 && boards[0].pcb_board_id === "faux-board";
|
|
35017
34678
|
}, [circuitJson]);
|
|
35018
34679
|
const traceTextureResolution = useMemo21(() => {
|
|
@@ -35314,7 +34975,7 @@ var BoardMeshes = ({
|
|
|
35314
34975
|
}) => {
|
|
35315
34976
|
const { rootObject } = useThree();
|
|
35316
34977
|
const { visibility } = useLayerVisibility();
|
|
35317
|
-
const
|
|
34978
|
+
const disposeMesh = (mesh) => {
|
|
35318
34979
|
mesh.geometry.dispose();
|
|
35319
34980
|
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
|
|
35320
34981
|
for (const material of materials) {
|
|
@@ -35356,23 +35017,29 @@ var BoardMeshes = ({
|
|
|
35356
35017
|
rootObject.add(mesh);
|
|
35357
35018
|
}
|
|
35358
35019
|
});
|
|
35359
|
-
textureMeshes.forEach((mesh) => {
|
|
35360
|
-
rootObject.add(mesh);
|
|
35361
|
-
});
|
|
35362
35020
|
return () => {
|
|
35363
35021
|
geometryMeshes.forEach((mesh) => {
|
|
35364
35022
|
if (mesh.parent === rootObject) {
|
|
35365
35023
|
rootObject.remove(mesh);
|
|
35366
35024
|
}
|
|
35025
|
+
disposeMesh(mesh);
|
|
35367
35026
|
});
|
|
35027
|
+
};
|
|
35028
|
+
}, [rootObject, geometryMeshes, visibility]);
|
|
35029
|
+
useEffect25(() => {
|
|
35030
|
+
if (!rootObject) return;
|
|
35031
|
+
textureMeshes.forEach((mesh) => {
|
|
35032
|
+
rootObject.add(mesh);
|
|
35033
|
+
});
|
|
35034
|
+
return () => {
|
|
35368
35035
|
textureMeshes.forEach((mesh) => {
|
|
35369
35036
|
if (mesh.parent === rootObject) {
|
|
35370
35037
|
rootObject.remove(mesh);
|
|
35371
35038
|
}
|
|
35372
|
-
|
|
35039
|
+
disposeMesh(mesh);
|
|
35373
35040
|
});
|
|
35374
35041
|
};
|
|
35375
|
-
}, [rootObject,
|
|
35042
|
+
}, [rootObject, textureMeshes]);
|
|
35376
35043
|
return null;
|
|
35377
35044
|
};
|
|
35378
35045
|
var MANIFOLD_CDN_BASE_URL = "https://cdn.jsdelivr.net/npm/manifold-3d@3.2.1";
|
|
@@ -35470,7 +35137,7 @@ try {
|
|
|
35470
35137
|
[textures, boardData, pcbThickness, isFauxBoard]
|
|
35471
35138
|
);
|
|
35472
35139
|
const cadComponents = useMemo22(
|
|
35473
|
-
() =>
|
|
35140
|
+
() => su17(circuitJson).cad_component.list(),
|
|
35474
35141
|
[circuitJson]
|
|
35475
35142
|
);
|
|
35476
35143
|
const boardDimensions = useMemo22(() => {
|
|
@@ -42484,7 +42151,7 @@ var CadViewer = (props) => {
|
|
|
42484
42151
|
|
|
42485
42152
|
// src/convert-circuit-json-to-3d-svg.ts
|
|
42486
42153
|
var import_debug = __toESM(require_browser(), 1);
|
|
42487
|
-
import { su as
|
|
42154
|
+
import { su as su18 } from "@tscircuit/circuit-json-util";
|
|
42488
42155
|
import * as THREE40 from "three";
|
|
42489
42156
|
import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
|
|
42490
42157
|
|
|
@@ -42713,11 +42380,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
42713
42380
|
const pointLight = new THREE40.PointLight(16777215, Math.PI / 4);
|
|
42714
42381
|
pointLight.position.set(-10, -10, 10);
|
|
42715
42382
|
scene.add(pointLight);
|
|
42716
|
-
const components =
|
|
42383
|
+
const components = su18(circuitJson).cad_component.list();
|
|
42717
42384
|
for (const component of components) {
|
|
42718
42385
|
await renderComponent(component, scene);
|
|
42719
42386
|
}
|
|
42720
|
-
const boardData =
|
|
42387
|
+
const boardData = su18(circuitJson).pcb_board.list()[0];
|
|
42721
42388
|
const boardGeom = createBoardGeomFromCircuitJson(circuitJson);
|
|
42722
42389
|
if (boardGeom) {
|
|
42723
42390
|
const solderMaskColor = colors.fr4SolderMaskGreen;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/3d-viewer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.521",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@jscad/regl-renderer": "^2.6.12",
|
|
31
31
|
"@jscad/stl-serializer": "^2.1.20",
|
|
32
32
|
"circuit-json": "^0.0.372",
|
|
33
|
-
"circuit-to-canvas": "^0.0.
|
|
33
|
+
"circuit-to-canvas": "^0.0.81",
|
|
34
34
|
"react-hot-toast": "^2.6.0",
|
|
35
35
|
"three": "^0.165.0",
|
|
36
36
|
"three-stdlib": "^2.36.0",
|