@tscircuit/3d-viewer 0.0.456 → 0.0.458
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 +164 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28509,7 +28509,7 @@ import * as THREE15 from "three";
|
|
|
28509
28509
|
// package.json
|
|
28510
28510
|
var package_default = {
|
|
28511
28511
|
name: "@tscircuit/3d-viewer",
|
|
28512
|
-
version: "0.0.
|
|
28512
|
+
version: "0.0.457",
|
|
28513
28513
|
main: "./dist/index.js",
|
|
28514
28514
|
module: "./dist/index.js",
|
|
28515
28515
|
type: "module",
|
|
@@ -34164,6 +34164,76 @@ function createSoldermaskTextureForLayer({
|
|
|
34164
34164
|
ctx.ellipse(canvasX, canvasY, radiusX, radiusY, 0, 0, 2 * Math.PI);
|
|
34165
34165
|
ctx.fill();
|
|
34166
34166
|
}
|
|
34167
|
+
} else if (hole.shape === "hole_with_polygon_pad") {
|
|
34168
|
+
const holeShape = hole.hole_shape || "circle";
|
|
34169
|
+
const holeOffsetX = hole.hole_offset_x || 0;
|
|
34170
|
+
const holeOffsetY = hole.hole_offset_y || 0;
|
|
34171
|
+
const adjustedCanvasX = canvasXFromPcb(hole.x + holeOffsetX);
|
|
34172
|
+
const adjustedCanvasY = canvasYFromPcb(hole.y + holeOffsetY);
|
|
34173
|
+
if (holeShape === "pill" || holeShape === "rotated_pill") {
|
|
34174
|
+
const width10 = (hole.outer_width ?? hole.outer_diameter ?? hole.hole_width) * traceTextureResolution;
|
|
34175
|
+
const height10 = (hole.outer_height ?? hole.outer_diameter ?? hole.hole_height) * traceTextureResolution;
|
|
34176
|
+
const radius = Math.min(width10, height10) / 2;
|
|
34177
|
+
let rotation2 = hole.ccw_rotation || 0;
|
|
34178
|
+
if (layer === "bottom") {
|
|
34179
|
+
rotation2 = -rotation2;
|
|
34180
|
+
}
|
|
34181
|
+
if (rotation2) {
|
|
34182
|
+
ctx.save();
|
|
34183
|
+
ctx.translate(adjustedCanvasX, adjustedCanvasY);
|
|
34184
|
+
ctx.rotate(rotation2 * Math.PI / 180);
|
|
34185
|
+
ctx.beginPath();
|
|
34186
|
+
ctx.roundRect(-width10 / 2, -height10 / 2, width10, height10, radius);
|
|
34187
|
+
ctx.fill();
|
|
34188
|
+
ctx.restore();
|
|
34189
|
+
} else {
|
|
34190
|
+
ctx.beginPath();
|
|
34191
|
+
ctx.roundRect(
|
|
34192
|
+
adjustedCanvasX - width10 / 2,
|
|
34193
|
+
adjustedCanvasY - height10 / 2,
|
|
34194
|
+
width10,
|
|
34195
|
+
height10,
|
|
34196
|
+
radius
|
|
34197
|
+
);
|
|
34198
|
+
ctx.fill();
|
|
34199
|
+
}
|
|
34200
|
+
} else if (holeShape === "oval") {
|
|
34201
|
+
const width10 = (hole.outer_width ?? hole.outer_diameter ?? hole.hole_width) * traceTextureResolution;
|
|
34202
|
+
const height10 = (hole.outer_height ?? hole.outer_diameter ?? hole.hole_height) * traceTextureResolution;
|
|
34203
|
+
const radiusX = width10 / 2;
|
|
34204
|
+
const radiusY = height10 / 2;
|
|
34205
|
+
let rotation2 = hole.ccw_rotation || 0;
|
|
34206
|
+
if (rotation2) {
|
|
34207
|
+
rotation2 = -rotation2;
|
|
34208
|
+
}
|
|
34209
|
+
if (rotation2) {
|
|
34210
|
+
ctx.save();
|
|
34211
|
+
ctx.translate(adjustedCanvasX, adjustedCanvasY);
|
|
34212
|
+
ctx.rotate(rotation2 * Math.PI / 180);
|
|
34213
|
+
ctx.beginPath();
|
|
34214
|
+
ctx.ellipse(0, 0, radiusX, radiusY, 0, 0, 2 * Math.PI);
|
|
34215
|
+
ctx.fill();
|
|
34216
|
+
ctx.restore();
|
|
34217
|
+
} else {
|
|
34218
|
+
ctx.beginPath();
|
|
34219
|
+
ctx.ellipse(
|
|
34220
|
+
adjustedCanvasX,
|
|
34221
|
+
adjustedCanvasY,
|
|
34222
|
+
radiusX,
|
|
34223
|
+
radiusY,
|
|
34224
|
+
0,
|
|
34225
|
+
0,
|
|
34226
|
+
2 * Math.PI
|
|
34227
|
+
);
|
|
34228
|
+
ctx.fill();
|
|
34229
|
+
}
|
|
34230
|
+
} else if (holeShape === "circle") {
|
|
34231
|
+
const outerDiameter = (hole.outer_diameter ?? hole.hole_diameter ?? 0) * traceTextureResolution;
|
|
34232
|
+
const canvasRadius = outerDiameter / 2;
|
|
34233
|
+
ctx.beginPath();
|
|
34234
|
+
ctx.arc(adjustedCanvasX, adjustedCanvasY, canvasRadius, 0, 2 * Math.PI);
|
|
34235
|
+
ctx.fill();
|
|
34236
|
+
}
|
|
34167
34237
|
}
|
|
34168
34238
|
});
|
|
34169
34239
|
const pcbHoles = su13(circuitJson).pcb_hole.list();
|
|
@@ -34234,6 +34304,99 @@ function createSoldermaskTextureForLayer({
|
|
|
34234
34304
|
ctx.fill();
|
|
34235
34305
|
}
|
|
34236
34306
|
});
|
|
34307
|
+
const pcbCutouts = su13(circuitJson).pcb_cutout.list();
|
|
34308
|
+
pcbCutouts.forEach((cutout) => {
|
|
34309
|
+
switch (cutout.shape) {
|
|
34310
|
+
case "rect": {
|
|
34311
|
+
const canvasX = canvasXFromPcb(cutout.center.x);
|
|
34312
|
+
const canvasY = canvasYFromPcb(cutout.center.y);
|
|
34313
|
+
const width10 = cutout.width * traceTextureResolution;
|
|
34314
|
+
const height10 = cutout.height * traceTextureResolution;
|
|
34315
|
+
const rectCornerRadius = extractRectBorderRadius(cutout);
|
|
34316
|
+
const borderRadius = clampRectBorderRadius(
|
|
34317
|
+
cutout.width,
|
|
34318
|
+
cutout.height,
|
|
34319
|
+
rectCornerRadius
|
|
34320
|
+
);
|
|
34321
|
+
if (cutout.rotation) {
|
|
34322
|
+
ctx.save();
|
|
34323
|
+
ctx.translate(canvasX, canvasY);
|
|
34324
|
+
const rotation2 = layer === "bottom" ? -cutout.rotation * (Math.PI / 180) : cutout.rotation * (Math.PI / 180);
|
|
34325
|
+
ctx.rotate(rotation2);
|
|
34326
|
+
if (borderRadius > 0) {
|
|
34327
|
+
ctx.beginPath();
|
|
34328
|
+
ctx.roundRect(
|
|
34329
|
+
-width10 / 2,
|
|
34330
|
+
-height10 / 2,
|
|
34331
|
+
width10,
|
|
34332
|
+
height10,
|
|
34333
|
+
borderRadius * traceTextureResolution
|
|
34334
|
+
);
|
|
34335
|
+
ctx.fill();
|
|
34336
|
+
} else {
|
|
34337
|
+
ctx.fillRect(-width10 / 2, -height10 / 2, width10, height10);
|
|
34338
|
+
}
|
|
34339
|
+
ctx.restore();
|
|
34340
|
+
} else {
|
|
34341
|
+
if (borderRadius > 0) {
|
|
34342
|
+
ctx.beginPath();
|
|
34343
|
+
ctx.roundRect(
|
|
34344
|
+
canvasX - width10 / 2,
|
|
34345
|
+
canvasY - height10 / 2,
|
|
34346
|
+
width10,
|
|
34347
|
+
height10,
|
|
34348
|
+
borderRadius * traceTextureResolution
|
|
34349
|
+
);
|
|
34350
|
+
ctx.fill();
|
|
34351
|
+
} else {
|
|
34352
|
+
ctx.fillRect(
|
|
34353
|
+
canvasX - width10 / 2,
|
|
34354
|
+
canvasY - height10 / 2,
|
|
34355
|
+
width10,
|
|
34356
|
+
height10
|
|
34357
|
+
);
|
|
34358
|
+
}
|
|
34359
|
+
}
|
|
34360
|
+
break;
|
|
34361
|
+
}
|
|
34362
|
+
case "circle": {
|
|
34363
|
+
const canvasX = canvasXFromPcb(cutout.center.x);
|
|
34364
|
+
const canvasY = canvasYFromPcb(cutout.center.y);
|
|
34365
|
+
const canvasRadius = cutout.radius * traceTextureResolution;
|
|
34366
|
+
ctx.beginPath();
|
|
34367
|
+
ctx.arc(canvasX, canvasY, canvasRadius, 0, 2 * Math.PI);
|
|
34368
|
+
ctx.fill();
|
|
34369
|
+
break;
|
|
34370
|
+
}
|
|
34371
|
+
case "polygon": {
|
|
34372
|
+
if (!cutout.points || cutout.points.length < 3) {
|
|
34373
|
+
console.warn(
|
|
34374
|
+
`PCB Cutout [${cutout.pcb_cutout_id}] polygon has fewer than 3 points, skipping in soldermask texture.`
|
|
34375
|
+
);
|
|
34376
|
+
break;
|
|
34377
|
+
}
|
|
34378
|
+
ctx.beginPath();
|
|
34379
|
+
cutout.points.forEach(
|
|
34380
|
+
(point2, index2) => {
|
|
34381
|
+
const px = canvasXFromPcb(point2.x);
|
|
34382
|
+
const py = canvasYFromPcb(point2.y);
|
|
34383
|
+
if (index2 === 0) {
|
|
34384
|
+
ctx.moveTo(px, py);
|
|
34385
|
+
} else {
|
|
34386
|
+
ctx.lineTo(px, py);
|
|
34387
|
+
}
|
|
34388
|
+
}
|
|
34389
|
+
);
|
|
34390
|
+
ctx.closePath();
|
|
34391
|
+
ctx.fill();
|
|
34392
|
+
break;
|
|
34393
|
+
}
|
|
34394
|
+
default:
|
|
34395
|
+
console.warn(
|
|
34396
|
+
`Unsupported cutout shape: ${cutout.shape} for cutout ${cutout.pcb_cutout_id} in soldermask texture.`
|
|
34397
|
+
);
|
|
34398
|
+
}
|
|
34399
|
+
});
|
|
34237
34400
|
ctx.globalCompositeOperation = "source-over";
|
|
34238
34401
|
const texture = new THREE24.CanvasTexture(canvas);
|
|
34239
34402
|
texture.generateMipmaps = true;
|