@tscircuit/3d-viewer 0.0.234 → 0.0.236

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.
Files changed (2) hide show
  1. package/dist/index.js +125 -12
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -16985,7 +16985,7 @@ import { Canvas, useFrame as useFrame2 } from "@react-three/fiber";
16985
16985
  // package.json
16986
16986
  var package_default = {
16987
16987
  name: "@tscircuit/3d-viewer",
16988
- version: "0.0.233",
16988
+ version: "0.0.235",
16989
16989
  main: "./dist/index.js",
16990
16990
  module: "./dist/index.js",
16991
16991
  type: "module",
@@ -17016,7 +17016,7 @@ var package_default = {
17016
17016
  "@jscad/stl-serializer": "^2.1.20",
17017
17017
  "@react-three/drei": "^9.121.4",
17018
17018
  "@react-three/fiber": "^8.17.14",
17019
- "@tscircuit/core": "^0.0.417",
17019
+ "@tscircuit/core": "^0.0.424",
17020
17020
  "@tscircuit/props": "^0.0.187",
17021
17021
  "@tscircuit/soup-util": "^0.0.41",
17022
17022
  "jscad-electronics": "^0.0.27",
@@ -18980,12 +18980,12 @@ var CadViewerJscad = forwardRef2(
18980
18980
 
18981
18981
  // src/CadViewerManifold.tsx
18982
18982
  import { useEffect as useEffect6, useState as useState8, useMemo as useMemo7 } from "react";
18983
- import { su as su12 } from "@tscircuit/soup-util";
18983
+ import { su as su13 } from "@tscircuit/soup-util";
18984
18984
  import ManifoldModule from "manifold-3d";
18985
18985
 
18986
18986
  // src/hooks/useManifoldBoardBuilder.ts
18987
18987
  import { useState as useState7, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef6 } from "react";
18988
- import { su as su11 } from "@tscircuit/soup-util";
18988
+ import { su as su12 } from "@tscircuit/soup-util";
18989
18989
  import * as THREE10 from "three";
18990
18990
 
18991
18991
  // src/utils/manifold-mesh-to-three-geometry.ts
@@ -19537,6 +19537,105 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
19537
19537
  return boardOp;
19538
19538
  }
19539
19539
 
19540
+ // src/utils/manifold/process-cutouts.ts
19541
+ import { su as su11 } from "@tscircuit/soup-util";
19542
+ var arePointsClockwise3 = (points) => {
19543
+ let area = 0;
19544
+ for (let i = 0; i < points.length; i++) {
19545
+ const j = (i + 1) % points.length;
19546
+ if (points[i] && points[j]) {
19547
+ area += points[i][0] * points[j][1];
19548
+ area -= points[j][0] * points[i][1];
19549
+ }
19550
+ }
19551
+ const signedArea = area / 2;
19552
+ return signedArea <= 0;
19553
+ };
19554
+ function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
19555
+ const cutoutOps = [];
19556
+ const pcbCutouts = su11(circuitJson).pcb_cutout.list();
19557
+ for (const cutout of pcbCutouts) {
19558
+ let cutoutOp;
19559
+ const cutoutHeight = pcbThickness * 1.5;
19560
+ switch (cutout.shape) {
19561
+ case "rect":
19562
+ cutoutOp = Manifold.cube(
19563
+ [cutout.width, cutout.height, cutoutHeight],
19564
+ true
19565
+ // centered
19566
+ );
19567
+ manifoldInstancesForCleanup.push(cutoutOp);
19568
+ if (cutout.rotation) {
19569
+ const rotationRadians = cutout.rotation * Math.PI / 180;
19570
+ const rotatedOp = cutoutOp.rotate([0, 0, cutout.rotation]);
19571
+ manifoldInstancesForCleanup.push(rotatedOp);
19572
+ cutoutOp = rotatedOp;
19573
+ }
19574
+ cutoutOp = cutoutOp.translate([
19575
+ cutout.center.x,
19576
+ cutout.center.y,
19577
+ 0
19578
+ // Centered vertically by Manifold.cube, so Z is 0 for board plane
19579
+ ]);
19580
+ manifoldInstancesForCleanup.push(cutoutOp);
19581
+ break;
19582
+ case "circle":
19583
+ cutoutOp = Manifold.cylinder(
19584
+ cutoutHeight,
19585
+ cutout.radius,
19586
+ -1,
19587
+ // default for radiusHigh
19588
+ SMOOTH_CIRCLE_SEGMENTS,
19589
+ true
19590
+ // centered
19591
+ );
19592
+ manifoldInstancesForCleanup.push(cutoutOp);
19593
+ cutoutOp = cutoutOp.translate([cutout.center.x, cutout.center.y, 0]);
19594
+ manifoldInstancesForCleanup.push(cutoutOp);
19595
+ break;
19596
+ case "polygon":
19597
+ if (cutout.points.length < 3) {
19598
+ console.warn(
19599
+ `PCB Cutout [${cutout.pcb_cutout_id}] polygon has fewer than 3 points, skipping.`
19600
+ );
19601
+ continue;
19602
+ }
19603
+ let pointsVec2 = cutout.points.map((p) => [
19604
+ p.x,
19605
+ p.y
19606
+ ]);
19607
+ if (arePointsClockwise3(pointsVec2)) {
19608
+ pointsVec2 = pointsVec2.reverse();
19609
+ }
19610
+ const crossSection = CrossSection.ofPolygons([pointsVec2]);
19611
+ manifoldInstancesForCleanup.push(crossSection);
19612
+ cutoutOp = Manifold.extrude(
19613
+ crossSection,
19614
+ cutoutHeight,
19615
+ 0,
19616
+ // nDivisions
19617
+ 0,
19618
+ // twistDegrees
19619
+ [1, 1],
19620
+ // scaleTop
19621
+ true
19622
+ // center extrusion
19623
+ );
19624
+ manifoldInstancesForCleanup.push(cutoutOp);
19625
+ break;
19626
+ default:
19627
+ console.warn(
19628
+ `Unsupported cutout shape: ${cutout.shape} for cutout ${cutout.pcb_cutout_id}`
19629
+ );
19630
+ continue;
19631
+ }
19632
+ if (cutoutOp) {
19633
+ cutoutOps.push(cutoutOp);
19634
+ }
19635
+ }
19636
+ return { cutoutOps };
19637
+ }
19638
+
19540
19639
  // src/hooks/useManifoldBoardBuilder.ts
19541
19640
  var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
19542
19641
  const [geoms, setGeoms] = useState7(null);
@@ -19547,7 +19646,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
19547
19646
  const manifoldInstancesForCleanup = useRef6([]);
19548
19647
  const boardData = useMemo6(() => {
19549
19648
  if (!circuitJson) return null;
19550
- const boards = su11(circuitJson).pcb_board.list();
19649
+ const boards = su12(circuitJson).pcb_board.list();
19551
19650
  if (boards.length === 0) {
19552
19651
  return null;
19553
19652
  }
@@ -19558,7 +19657,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
19558
19657
  setGeoms(null);
19559
19658
  setTextures(null);
19560
19659
  setPcbThickness(null);
19561
- if (circuitJson && su11(circuitJson).pcb_board.list().length === 0) {
19660
+ if (circuitJson && su12(circuitJson).pcb_board.list().length === 0) {
19562
19661
  setError("No pcb_board found in circuitJson.");
19563
19662
  }
19564
19663
  setIsLoading(false);
@@ -19610,9 +19709,23 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
19610
19709
  if (allBoardDrills.length > 0) {
19611
19710
  const unionedDrills = Manifold.union(allBoardDrills);
19612
19711
  manifoldInstancesForCleanup.current.push(unionedDrills);
19613
- const nextBoard = currentBoardOp.subtract(unionedDrills);
19614
- manifoldInstancesForCleanup.current.push(nextBoard);
19615
- currentBoardOp = nextBoard;
19712
+ const nextBoardAfterDrills = currentBoardOp.subtract(unionedDrills);
19713
+ manifoldInstancesForCleanup.current.push(nextBoardAfterDrills);
19714
+ currentBoardOp = nextBoardAfterDrills;
19715
+ }
19716
+ const { cutoutOps } = processCutoutsForManifold(
19717
+ Manifold,
19718
+ CrossSection,
19719
+ circuitJson,
19720
+ currentPcbThickness,
19721
+ manifoldInstancesForCleanup.current
19722
+ );
19723
+ if (cutoutOps.length > 0) {
19724
+ const unionedCutouts = Manifold.union(cutoutOps);
19725
+ manifoldInstancesForCleanup.current.push(unionedCutouts);
19726
+ const nextBoardAfterCutouts = currentBoardOp.subtract(unionedCutouts);
19727
+ manifoldInstancesForCleanup.current.push(nextBoardAfterCutouts);
19728
+ currentBoardOp = nextBoardAfterCutouts;
19616
19729
  }
19617
19730
  boardManifold = currentBoardOp;
19618
19731
  if (boardManifold) {
@@ -19825,7 +19938,7 @@ var CadViewerManifold = ({
19825
19938
  [textures, boardData, pcbThickness]
19826
19939
  );
19827
19940
  const cadComponents = useMemo7(
19828
- () => circuitJson ? su12(circuitJson).cad_component.list() : [],
19941
+ () => circuitJson ? su13(circuitJson).cad_component.list() : [],
19829
19942
  [circuitJson]
19830
19943
  );
19831
19944
  const initialCameraPosition = useMemo7(() => {
@@ -20128,7 +20241,7 @@ var CadViewer = (props) => {
20128
20241
 
20129
20242
  // src/convert-circuit-json-to-3d-svg.ts
20130
20243
  var import_debug = __toESM(require_browser(), 1);
20131
- import { su as su13 } from "@tscircuit/soup-util";
20244
+ import { su as su14 } from "@tscircuit/soup-util";
20132
20245
  import * as THREE16 from "three";
20133
20246
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
20134
20247
 
@@ -20343,7 +20456,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
20343
20456
  const pointLight = new THREE16.PointLight(16777215, Math.PI / 4);
20344
20457
  pointLight.position.set(-10, -10, 10);
20345
20458
  scene.add(pointLight);
20346
- const components = su13(circuitJson).cad_component.list();
20459
+ const components = su14(circuitJson).cad_component.list();
20347
20460
  for (const component of components) {
20348
20461
  await renderComponent(component, scene);
20349
20462
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.234",
3
+ "version": "0.0.236",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",
@@ -31,7 +31,7 @@
31
31
  "@jscad/stl-serializer": "^2.1.20",
32
32
  "@react-three/drei": "^9.121.4",
33
33
  "@react-three/fiber": "^8.17.14",
34
- "@tscircuit/core": "^0.0.417",
34
+ "@tscircuit/core": "^0.0.424",
35
35
  "@tscircuit/props": "^0.0.187",
36
36
  "@tscircuit/soup-util": "^0.0.41",
37
37
  "jscad-electronics": "^0.0.27",