circuit-json-to-tscircuit 0.0.92 → 0.0.93

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.
@@ -504,9 +504,9 @@ function getCadModelPlacementAttributes({
504
504
  if (cadComponent.size !== void 0) {
505
505
  attributes.push(`size={${formatPointProp(cadComponent.size)}}`);
506
506
  }
507
- if (cadComponent.show_as_translucent_model === true) {
508
- attributes.push("showAsTranslucentModel");
509
- }
507
+ attributes.push(
508
+ `showAsTranslucentModel={${cadComponent.show_as_translucent_model === true}}`
509
+ );
510
510
  return attributes;
511
511
  }
512
512
 
@@ -539,48 +539,397 @@ function generateCadModelTsx({
539
539
  return `<cadmodel ${attributes.join(" ")} />`;
540
540
  }
541
541
 
542
- // lib/generate-board-cad-models-tsx/generate-jscad-cad-model-tsx.ts
543
- function generateJscadCadModelTsx({
542
+ // lib/generate-board-cad-models-tsx/get-jscad-operation-fit-scale-factors.ts
543
+ import jscad2 from "@jscad/modeling";
544
+
545
+ // lib/generate-board-cad-models-tsx/execute-jscad-operation.ts
546
+ import jscad from "@jscad/modeling";
547
+ import { executeJscadOperations } from "jscad-planner";
548
+ function executeJscadOperation(operation) {
549
+ return executeJscadOperations(jscad, operation);
550
+ }
551
+
552
+ // lib/generate-board-cad-models-tsx/get-jscad-operation-fit-scale-factors.ts
553
+ var identityScaleFactors = { x: 1, y: 1, z: 1 };
554
+ function getSafeScaleFactor({
555
+ sourceLength,
556
+ targetLength
557
+ }) {
558
+ return sourceLength > 0 ? targetLength / sourceLength : 1;
559
+ }
560
+ function getJscadOperationFitScaleFactors({
561
+ cadComponent,
562
+ operation
563
+ }) {
564
+ if (cadComponent.size === void 0) return identityScaleFactors;
565
+ const geometry = executeJscadOperation(operation);
566
+ if (!jscad2.geometries.geom3.isA(geometry)) return identityScaleFactors;
567
+ const [minimumPoint, maximumPoint] = jscad2.measurements.measureBoundingBox(geometry);
568
+ const modelUnitToMmScaleFactor = cadComponent.model_unit_to_mm_scale_factor ?? 1;
569
+ const axisScaleFactors = {
570
+ x: getSafeScaleFactor({
571
+ sourceLength: maximumPoint[0] - minimumPoint[0],
572
+ targetLength: cadComponent.size.x * modelUnitToMmScaleFactor
573
+ }),
574
+ y: getSafeScaleFactor({
575
+ sourceLength: maximumPoint[1] - minimumPoint[1],
576
+ targetLength: cadComponent.size.y * modelUnitToMmScaleFactor
577
+ }),
578
+ z: getSafeScaleFactor({
579
+ sourceLength: maximumPoint[2] - minimumPoint[2],
580
+ targetLength: cadComponent.size.z * modelUnitToMmScaleFactor
581
+ })
582
+ };
583
+ if (cadComponent.model_object_fit === "fill_bounds") {
584
+ return axisScaleFactors;
585
+ }
586
+ const uniformScaleFactor = Math.min(
587
+ axisScaleFactors.x,
588
+ axisScaleFactors.y,
589
+ axisScaleFactors.z
590
+ );
591
+ return {
592
+ x: uniformScaleFactor,
593
+ y: uniformScaleFactor,
594
+ z: uniformScaleFactor
595
+ };
596
+ }
597
+
598
+ // lib/generate-board-cad-models-tsx/get-jscad-operation-in-base-model-frame.ts
599
+ var degreesToRadians = (angleDegrees) => angleDegrees * Math.PI / 180;
600
+ var getCadComponentRotation = (cadComponent) => cadComponent.rotation ?? { x: 0, y: 0, z: 0 };
601
+ var getModelOriginPosition = (cadComponent) => cadComponent.model_origin_position ?? { x: 0, y: 0, z: 0 };
602
+ var getBoardNormalRotation = (cadComponent) => {
603
+ switch (cadComponent.model_board_normal_direction ?? "z+") {
604
+ case "x+":
605
+ return { x: 0, y: -90, z: 0 };
606
+ case "x-":
607
+ return { x: 0, y: 90, z: 0 };
608
+ case "y+":
609
+ return { x: 90, y: 0, z: 0 };
610
+ case "y-":
611
+ return { x: -90, y: 0, z: 0 };
612
+ case "z-":
613
+ return { x: 180, y: 0, z: 0 };
614
+ case "z+":
615
+ return { x: 0, y: 0, z: 0 };
616
+ }
617
+ };
618
+ var rotateOperation = ({
619
+ operation,
620
+ rotationDegrees
621
+ }) => {
622
+ let rotatedOperation = operation;
623
+ for (const [axis, angleDegrees] of [
624
+ ["Z", rotationDegrees.z],
625
+ ["Y", rotationDegrees.y],
626
+ ["X", rotationDegrees.x]
627
+ ]) {
628
+ if (angleDegrees === 0) continue;
629
+ rotatedOperation = {
630
+ type: `rotate${axis}`,
631
+ angle: degreesToRadians(angleDegrees),
632
+ shape: rotatedOperation
633
+ };
634
+ }
635
+ return rotatedOperation;
636
+ };
637
+ var rotateOperationByInverse = ({
638
+ operation,
639
+ rotationDegrees
640
+ }) => {
641
+ let rotatedOperation = operation;
642
+ for (const [axis, angleDegrees] of [
643
+ ["X", rotationDegrees.x],
644
+ ["Y", rotationDegrees.y],
645
+ ["Z", rotationDegrees.z]
646
+ ]) {
647
+ if (angleDegrees === 0) continue;
648
+ rotatedOperation = {
649
+ type: `rotate${axis}`,
650
+ angle: degreesToRadians(-angleDegrees),
651
+ shape: rotatedOperation
652
+ };
653
+ }
654
+ return rotatedOperation;
655
+ };
656
+ var translateOperation = ({
657
+ operation,
658
+ translation
659
+ }) => {
660
+ if (translation.x === 0 && translation.y === 0 && translation.z === 0) {
661
+ return operation;
662
+ }
663
+ return {
664
+ type: "translate",
665
+ vector: [translation.x, translation.y, translation.z],
666
+ shape: operation
667
+ };
668
+ };
669
+ var scaleOperation = ({
670
+ operation,
671
+ scaleFactors
672
+ }) => {
673
+ if (scaleFactors.x === 1 && scaleFactors.y === 1 && scaleFactors.z === 1) {
674
+ return operation;
675
+ }
676
+ return {
677
+ type: "scale",
678
+ factors: [scaleFactors.x, scaleFactors.y, scaleFactors.z],
679
+ shape: operation
680
+ };
681
+ };
682
+ function getJscadOperationInBaseModelFrame({
683
+ baseCadComponent,
684
+ basePositionOffset,
685
+ cadComponent,
686
+ positionOffset
687
+ }) {
688
+ if (cadComponent.model_jscad === void 0) return void 0;
689
+ const modelOriginPosition = getModelOriginPosition(cadComponent);
690
+ const cadRotationDegrees = getCadComponentRotation(cadComponent);
691
+ const baseCadRotationDegrees = getCadComponentRotation(baseCadComponent);
692
+ const modelUnitToMmScaleFactor = cadComponent.model_unit_to_mm_scale_factor ?? 1;
693
+ let operation = cadComponent.model_jscad;
694
+ operation = scaleOperation({
695
+ operation,
696
+ scaleFactors: {
697
+ x: modelUnitToMmScaleFactor,
698
+ y: modelUnitToMmScaleFactor,
699
+ z: modelUnitToMmScaleFactor
700
+ }
701
+ });
702
+ operation = translateOperation({
703
+ operation,
704
+ translation: {
705
+ x: -modelOriginPosition.x,
706
+ y: -modelOriginPosition.y,
707
+ z: -modelOriginPosition.z
708
+ }
709
+ });
710
+ operation = rotateOperation({
711
+ operation,
712
+ rotationDegrees: getBoardNormalRotation(cadComponent)
713
+ });
714
+ operation = scaleOperation({
715
+ operation,
716
+ scaleFactors: getJscadOperationFitScaleFactors({
717
+ cadComponent,
718
+ operation
719
+ })
720
+ });
721
+ operation = rotateOperation({
722
+ operation,
723
+ rotationDegrees: cadRotationDegrees
724
+ });
725
+ operation = translateOperation({
726
+ operation,
727
+ translation: {
728
+ x: positionOffset.x - basePositionOffset.x,
729
+ y: positionOffset.y - basePositionOffset.y,
730
+ z: positionOffset.z - basePositionOffset.z
731
+ }
732
+ });
733
+ return rotateOperationByInverse({
734
+ operation,
735
+ rotationDegrees: baseCadRotationDegrees
736
+ });
737
+ }
738
+
739
+ // lib/generate-board-cad-models-tsx/pack-jscad-operations.ts
740
+ import jscad3 from "@jscad/modeling";
741
+ import "jscad-planner";
742
+ var copyPolygon = ({
743
+ polygon,
744
+ geometryColor
745
+ }) => ({
746
+ vertices: polygon.vertices.map(([x, y, z]) => [x, y, z]),
747
+ color: polygon.color ?? geometryColor
748
+ });
749
+ var getPackedJscadSize = (polygons) => {
750
+ const vertices = polygons.flatMap((polygon) => polygon.vertices);
751
+ if (vertices.length === 0) return void 0;
752
+ const [firstVertex, ...remainingVertices] = vertices;
753
+ let minX = firstVertex[0];
754
+ let minY = firstVertex[1];
755
+ let minZ = firstVertex[2];
756
+ let maxX = firstVertex[0];
757
+ let maxY = firstVertex[1];
758
+ let maxZ = firstVertex[2];
759
+ for (const [x, y, z] of remainingVertices) {
760
+ minX = Math.min(minX, x);
761
+ minY = Math.min(minY, y);
762
+ minZ = Math.min(minZ, z);
763
+ maxX = Math.max(maxX, x);
764
+ maxY = Math.max(maxY, y);
765
+ maxZ = Math.max(maxZ, z);
766
+ }
767
+ return { x: maxX - minX, y: maxY - minY, z: maxZ - minZ };
768
+ };
769
+ var packJscadOperations = (operations) => {
770
+ const polygons = [];
771
+ for (const operation of operations) {
772
+ const geometry = executeJscadOperation(operation);
773
+ if (!jscad3.geometries.geom3.isA(geometry)) return void 0;
774
+ polygons.push(
775
+ ...jscad3.geometries.geom3.toPolygons(geometry).map(
776
+ (polygon) => copyPolygon({
777
+ polygon,
778
+ geometryColor: geometry.color
779
+ })
780
+ )
781
+ );
782
+ }
783
+ return {
784
+ jscad: { type: "createGeom3", polygons },
785
+ size: getPackedJscadSize(polygons)
786
+ };
787
+ };
788
+
789
+ // lib/generate-board-cad-models-tsx/generate-jscad-cad-model-prop-tsx.ts
790
+ function generateSingleJscadCadModelPropTsx({
544
791
  cadComponent,
545
792
  parentPlacement,
546
793
  pcbBoard
547
794
  }) {
548
- if (cadComponent.model_jscad === void 0) return void 0;
549
- const attributes = [
550
- `jscad={${JSON.stringify(cadComponent.model_jscad)}}`,
551
- ...getCadModelPlacementAttributes({
795
+ const placement = getCadModelPlacement({
796
+ cadComponent,
797
+ parentPlacement,
798
+ pcbBoard
799
+ });
800
+ const properties = [
801
+ `jscad: ${JSON.stringify(cadComponent.model_jscad)}`,
802
+ `positionOffset: ${formatPointProp(placement.positionOffset)}`,
803
+ `rotationOffset: ${formatPointProp(placement.ccwRotationOffsetDegrees)}`
804
+ ];
805
+ const modelOriginPosition = getCadModelOriginPosition(cadComponent);
806
+ if (modelOriginPosition !== void 0) {
807
+ properties.push(
808
+ `modelOriginPosition: ${formatPointProp(modelOriginPosition)}`
809
+ );
810
+ }
811
+ if (cadComponent.model_unit_to_mm_scale_factor !== void 0) {
812
+ properties.push(
813
+ `modelUnitToMmScale: ${cadComponent.model_unit_to_mm_scale_factor}`
814
+ );
815
+ }
816
+ if (cadComponent.model_board_normal_direction !== void 0) {
817
+ properties.push(
818
+ `modelBoardNormalDirection: ${JSON.stringify(cadComponent.model_board_normal_direction)}`
819
+ );
820
+ }
821
+ if (cadComponent.size !== void 0) {
822
+ properties.push(`size: ${formatPointProp(cadComponent.size)}`);
823
+ }
824
+ return `{ ${properties.join(", ")} }`;
825
+ }
826
+ function generateJscadCadModelPropTsx({
827
+ cadComponents,
828
+ parentPlacement,
829
+ pcbBoard
830
+ }) {
831
+ const baseCadComponent = cadComponents[0];
832
+ if (!baseCadComponent || baseCadComponent.model_jscad === void 0) {
833
+ return void 0;
834
+ }
835
+ if (cadComponents.length === 1) {
836
+ return generateSingleJscadCadModelPropTsx({
837
+ cadComponent: baseCadComponent,
838
+ parentPlacement,
839
+ pcbBoard
840
+ });
841
+ }
842
+ const basePlacement = getCadModelPlacement({
843
+ cadComponent: baseCadComponent,
844
+ parentPlacement,
845
+ pcbBoard
846
+ });
847
+ const shapes = cadComponents.flatMap((cadComponent) => {
848
+ const placement = getCadModelPlacement({
552
849
  cadComponent,
553
850
  parentPlacement,
554
851
  pcbBoard
555
- })
852
+ });
853
+ const operation = getJscadOperationInBaseModelFrame({
854
+ baseCadComponent,
855
+ basePositionOffset: basePlacement.positionOffset,
856
+ cadComponent,
857
+ positionOffset: placement.positionOffset
858
+ });
859
+ return operation ? [operation] : [];
860
+ });
861
+ if (shapes.length === 0) return void 0;
862
+ const packedJscadOperations = packJscadOperations(shapes);
863
+ const jscad4 = packedJscadOperations?.jscad ?? {
864
+ type: "union",
865
+ shapes
866
+ };
867
+ const properties = [
868
+ `jscad: ${JSON.stringify(jscad4)}`,
869
+ `positionOffset: ${formatPointProp(basePlacement.positionOffset)}`,
870
+ `rotationOffset: ${formatPointProp(basePlacement.ccwRotationOffsetDegrees)}`,
871
+ `modelOriginPosition: ${formatPointProp({ x: 0, y: 0, z: 0 })}`,
872
+ "modelUnitToMmScale: 1",
873
+ 'modelBoardNormalDirection: "z+"'
556
874
  ];
557
- return `<cadmodel ${attributes.join(" ")} />`;
875
+ if (packedJscadOperations?.size !== void 0) {
876
+ properties.push(`size: ${formatPointProp(packedJscadOperations.size)}`);
877
+ }
878
+ return `{ ${properties.join(", ")} }`;
558
879
  }
559
880
 
560
881
  // lib/generate-board-cad-models-tsx/generate-cad-model-group-model-tsx.ts
561
- var generateCadModelElementsTsx = ({
882
+ var generateUrlCadModelElementsTsx = ({
562
883
  cadModelGroup,
563
884
  pcbBoard
564
885
  }) => cadModelGroup.cadComponents.flatMap((cadComponent) => {
565
- const modelElementGenerator = cadComponent.model_jscad === void 0 ? generateCadModelTsx : generateJscadCadModelTsx;
566
- const modelElement = modelElementGenerator({
886
+ if (getCadModelUrl(cadComponent) === void 0) return [];
887
+ const modelElement = generateCadModelTsx({
567
888
  cadComponent,
568
889
  parentPlacement: cadModelGroup.parentPlacement,
569
890
  pcbBoard
570
891
  });
571
892
  return modelElement ? [modelElement] : [];
572
893
  });
894
+ var getJscadCadComponents = (cadModelGroup) => cadModelGroup.cadComponents.filter(
895
+ (cadComponent) => cadComponent.model_jscad !== void 0
896
+ );
573
897
  function generateCadModelGroupModelTsx({
574
898
  cadModelGroup,
575
899
  pcbBoard
576
900
  }) {
577
- const modelElements = generateCadModelElementsTsx({
901
+ const jscadCadComponents = getJscadCadComponents(cadModelGroup);
902
+ if (jscadCadComponents.length > 0) {
903
+ return generateJscadCadModelPropTsx({
904
+ cadComponents: jscadCadComponents,
905
+ parentPlacement: cadModelGroup.parentPlacement,
906
+ pcbBoard
907
+ });
908
+ }
909
+ const urlCadModelElementsTsx = generateUrlCadModelElementsTsx({
578
910
  cadModelGroup,
579
911
  pcbBoard
580
912
  });
581
- if (modelElements.length === 0) return void 0;
582
- if (modelElements.length === 1) return modelElements[0];
583
- return `<cadassembly>${modelElements.join("\n")}</cadassembly>`;
913
+ if (urlCadModelElementsTsx.length === 0) return void 0;
914
+ if (urlCadModelElementsTsx.length === 1) return urlCadModelElementsTsx[0];
915
+ return `<cadassembly>${urlCadModelElementsTsx.join("\n")}</cadassembly>`;
916
+ }
917
+ function generateCadModelGroupChildrenTsx({
918
+ cadModelGroup,
919
+ pcbBoard
920
+ }) {
921
+ if (getJscadCadComponents(cadModelGroup).length === 0) return [];
922
+ return generateUrlCadModelElementsTsx({ cadModelGroup, pcbBoard });
923
+ }
924
+
925
+ // lib/generate-board-cad-models-tsx/is-jscad-cad-model-group-translucent.ts
926
+ function isJscadCadModelGroupTranslucent(cadModelGroup) {
927
+ const jscadCadComponents = cadModelGroup.cadComponents.filter(
928
+ (cadComponent) => cadComponent.model_jscad !== void 0
929
+ );
930
+ return jscadCadComponents.length > 0 && jscadCadComponents.every(
931
+ (cadComponent) => cadComponent.show_as_translucent_model === true
932
+ );
584
933
  }
585
934
 
586
935
  // lib/generate-board-cad-models-tsx/generate-cad-model-group-tsx.ts
@@ -606,7 +955,17 @@ function generateCadModelGroupTsx({
606
955
  "footprint={<footprint />}",
607
956
  `cadModel={${cadModelTsx}}`
608
957
  ];
609
- return `<chip ${attributes.join(" ")} />`;
958
+ if (isJscadCadModelGroupTranslucent(cadModelGroup)) {
959
+ attributes.push("showAsTranslucentModel");
960
+ }
961
+ const childModelElementsTsx = generateCadModelGroupChildrenTsx({
962
+ cadModelGroup,
963
+ pcbBoard
964
+ });
965
+ if (childModelElementsTsx.length === 0) {
966
+ return `<chip ${attributes.join(" ")} />`;
967
+ }
968
+ return `<chip ${attributes.join(" ")}>${childModelElementsTsx.join("\n")}</chip>`;
610
969
  }
611
970
 
612
971
  // lib/board-converter/stages/convert-board-cad-models.ts
@@ -3513,6 +3872,10 @@ var convertPcbComponents = ({
3513
3872
  cadModelGroup: localizedCadModelGroup,
3514
3873
  pcbBoard
3515
3874
  }) : void 0;
3875
+ const childModelElementsTsx = localizedCadModelGroup ? generateCadModelGroupChildrenTsx({
3876
+ cadModelGroup: localizedCadModelGroup,
3877
+ pcbBoard
3878
+ }) : [];
3516
3879
  const componentProps = [
3517
3880
  `name=${formatJsxStringAttribute(componentName)}`,
3518
3881
  `pcbX={${componentPosition.x}}`,
@@ -3524,6 +3887,9 @@ var convertPcbComponents = ({
3524
3887
  if (cadModelTsx) {
3525
3888
  componentProps.push(`cadModel={${cadModelTsx}}`);
3526
3889
  }
3890
+ if (localizedCadModelGroup && isJscadCadModelGroupTranslucent(localizedCadModelGroup)) {
3891
+ componentProps.push("showAsTranslucentModel");
3892
+ }
3527
3893
  if (pinLabels) {
3528
3894
  componentProps.push(`pinLabels={${JSON.stringify(pinLabels)}}`);
3529
3895
  }
@@ -3543,8 +3909,9 @@ var convertPcbComponents = ({
3543
3909
  if (pcbComponent.obstructs_within_bounds === false) {
3544
3910
  componentProps.push("obstructsWithinBounds={false}");
3545
3911
  }
3912
+ const chipOpeningTsx = `<chip ${componentProps.join(" ")} footprint={${footprintTsx ?? "<footprint />"}}`;
3546
3913
  boardChildren.push(
3547
- `<chip ${componentProps.join(" ")} footprint={${footprintTsx ?? "<footprint />"}} />`
3914
+ childModelElementsTsx.length === 0 ? `${chipOpeningTsx} />` : `${chipOpeningTsx}>${childModelElementsTsx.join("\n")}</chip>`
3548
3915
  );
3549
3916
  }
3550
3917
  };
package/dist/cli/main.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  convertCircuitJsonToTscircuit
4
- } from "../chunk-GAMHGAGS.js";
4
+ } from "../chunk-B7377FUZ.js";
5
5
 
6
6
  // cli/main.ts
7
7
  import { Command } from "commander";
@@ -16,7 +16,7 @@ var package_default = {
16
16
  "./cli": "./dist/cli/main.js"
17
17
  },
18
18
  type: "module",
19
- version: "0.0.91",
19
+ version: "0.0.92",
20
20
  repository: {
21
21
  type: "git",
22
22
  url: "https://github.com/tscircuit/circuit-json-to-tscircuit.git"
@@ -58,10 +58,6 @@ var package_default = {
58
58
  },
59
59
  peerDependencies: {
60
60
  typescript: "^5.0.0"
61
- },
62
- overrides: {
63
- "@tscircuit/core": "https://pkg.pr.new/tscircuit/core/@tscircuit/core@3013d38",
64
- "@tscircuit/props": "https://pkg.pr.new/@tscircuit/props@074b67d"
65
61
  }
66
62
  };
67
63
 
package/dist/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  convertCircuitJsonToTscircuit
3
- } from "../chunk-GAMHGAGS.js";
3
+ } from "../chunk-B7377FUZ.js";
4
4
  export {
5
5
  convertCircuitJsonToTscircuit
6
6
  };
@@ -2,8 +2,12 @@ import type { AnyCircuitElement, PcbComponent } from "circuit-json"
2
2
  import type { BoardConversionContext as FootprintConversionContext } from "../../board-conversion-context"
3
3
  import { formatJsxStringAttribute } from "../../format-jsx-string-attribute"
4
4
  import type { CadModelGroup } from "../../generate-board-cad-models-tsx/converter-types"
5
- import { generateCadModelGroupModelTsx } from "../../generate-board-cad-models-tsx/generate-cad-model-group-model-tsx"
5
+ import {
6
+ generateCadModelGroupChildrenTsx,
7
+ generateCadModelGroupModelTsx,
8
+ } from "../../generate-board-cad-models-tsx/generate-cad-model-group-model-tsx"
6
9
  import { getCadModelGroups } from "../../generate-board-cad-models-tsx/get-cad-model-groups"
10
+ import { isJscadCadModelGroupTranslucent } from "../../generate-board-cad-models-tsx/is-jscad-cad-model-group-translucent"
7
11
  import { generateFootprintTsx } from "../../generate-footprint-tsx"
8
12
  import type { BoardConverterStage } from "../BoardConverterContext"
9
13
  import { getPcbComponentRenderPlacement } from "../get-pcb-component-render-placement"
@@ -130,6 +134,12 @@ export const convertPcbComponents: BoardConverterStage = ({
130
134
  pcbBoard,
131
135
  })
132
136
  : undefined
137
+ const childModelElementsTsx = localizedCadModelGroup
138
+ ? generateCadModelGroupChildrenTsx({
139
+ cadModelGroup: localizedCadModelGroup,
140
+ pcbBoard,
141
+ })
142
+ : []
133
143
  const componentProps = [
134
144
  `name=${formatJsxStringAttribute(componentName)}`,
135
145
  `pcbX={${componentPosition.x}}`,
@@ -142,6 +152,12 @@ export const convertPcbComponents: BoardConverterStage = ({
142
152
  if (cadModelTsx) {
143
153
  componentProps.push(`cadModel={${cadModelTsx}}`)
144
154
  }
155
+ if (
156
+ localizedCadModelGroup &&
157
+ isJscadCadModelGroupTranslucent(localizedCadModelGroup)
158
+ ) {
159
+ componentProps.push("showAsTranslucentModel")
160
+ }
145
161
  if (pinLabels) {
146
162
  componentProps.push(`pinLabels={${JSON.stringify(pinLabels)}}`)
147
163
  }
@@ -164,8 +180,11 @@ export const convertPcbComponents: BoardConverterStage = ({
164
180
  if (pcbComponent.obstructs_within_bounds === false) {
165
181
  componentProps.push("obstructsWithinBounds={false}")
166
182
  }
183
+ const chipOpeningTsx = `<chip ${componentProps.join(" ")} footprint={${footprintTsx ?? "<footprint />"}}`
167
184
  boardChildren.push(
168
- `<chip ${componentProps.join(" ")} footprint={${footprintTsx ?? "<footprint />"}} />`,
185
+ childModelElementsTsx.length === 0
186
+ ? `${chipOpeningTsx} />`
187
+ : `${chipOpeningTsx}>${childModelElementsTsx.join("\n")}</chip>`,
169
188
  )
170
189
  }
171
190
  }
@@ -1,5 +1,11 @@
1
1
  import type { CadComponent, PcbComponent } from "circuit-json"
2
2
 
3
+ export interface Point3 {
4
+ x: number
5
+ y: number
6
+ z: number
7
+ }
8
+
3
9
  export interface CadModelUrl {
4
10
  format: "glb" | "gltf" | "obj" | "step" | "stl" | "wrl"
5
11
  url: string
@@ -0,0 +1,7 @@
1
+ import jscad from "@jscad/modeling"
2
+ import { executeJscadOperations, type JscadOperation } from "jscad-planner"
3
+
4
+ export function executeJscadOperation(operation: JscadOperation): unknown {
5
+ // @ts-expect-error @jscad/modeling overloads differ from the planner adapter.
6
+ return executeJscadOperations(jscad, operation)
7
+ }
@@ -1,9 +1,10 @@
1
1
  import type { PcbBoard } from "circuit-json"
2
2
  import type { CadModelGroup } from "./converter-types"
3
3
  import { generateCadModelTsx } from "./generate-cad-model-tsx"
4
- import { generateJscadCadModelTsx } from "./generate-jscad-cad-model-tsx"
4
+ import { generateJscadCadModelPropTsx } from "./generate-jscad-cad-model-prop-tsx"
5
+ import { getCadModelUrl } from "./get-cad-model-url"
5
6
 
6
- const generateCadModelElementsTsx = ({
7
+ const generateUrlCadModelElementsTsx = ({
7
8
  cadModelGroup,
8
9
  pcbBoard,
9
10
  }: {
@@ -11,11 +12,9 @@ const generateCadModelElementsTsx = ({
11
12
  pcbBoard: PcbBoard
12
13
  }): string[] =>
13
14
  cadModelGroup.cadComponents.flatMap((cadComponent) => {
14
- const modelElementGenerator =
15
- cadComponent.model_jscad === undefined
16
- ? generateCadModelTsx
17
- : generateJscadCadModelTsx
18
- const modelElement = modelElementGenerator({
15
+ if (getCadModelUrl(cadComponent) === undefined) return []
16
+
17
+ const modelElement = generateCadModelTsx({
19
18
  cadComponent,
20
19
  parentPlacement: cadModelGroup.parentPlacement,
21
20
  pcbBoard,
@@ -23,6 +22,13 @@ const generateCadModelElementsTsx = ({
23
22
  return modelElement ? [modelElement] : []
24
23
  })
25
24
 
25
+ const getJscadCadComponents = (
26
+ cadModelGroup: CadModelGroup,
27
+ ): CadModelGroup["cadComponents"] =>
28
+ cadModelGroup.cadComponents.filter(
29
+ (cadComponent) => cadComponent.model_jscad !== undefined,
30
+ )
31
+
26
32
  export function generateCadModelGroupModelTsx({
27
33
  cadModelGroup,
28
34
  pcbBoard,
@@ -30,12 +36,33 @@ export function generateCadModelGroupModelTsx({
30
36
  cadModelGroup: CadModelGroup
31
37
  pcbBoard: PcbBoard
32
38
  }): string | undefined {
33
- const modelElements = generateCadModelElementsTsx({
39
+ const jscadCadComponents = getJscadCadComponents(cadModelGroup)
40
+ if (jscadCadComponents.length > 0) {
41
+ return generateJscadCadModelPropTsx({
42
+ cadComponents: jscadCadComponents,
43
+ parentPlacement: cadModelGroup.parentPlacement,
44
+ pcbBoard,
45
+ })
46
+ }
47
+
48
+ const urlCadModelElementsTsx = generateUrlCadModelElementsTsx({
34
49
  cadModelGroup,
35
50
  pcbBoard,
36
51
  })
37
- if (modelElements.length === 0) return undefined
38
- if (modelElements.length === 1) return modelElements[0]
52
+ if (urlCadModelElementsTsx.length === 0) return undefined
53
+ if (urlCadModelElementsTsx.length === 1) return urlCadModelElementsTsx[0]
54
+
55
+ return `<cadassembly>${urlCadModelElementsTsx.join("\n")}</cadassembly>`
56
+ }
57
+
58
+ export function generateCadModelGroupChildrenTsx({
59
+ cadModelGroup,
60
+ pcbBoard,
61
+ }: {
62
+ cadModelGroup: CadModelGroup
63
+ pcbBoard: PcbBoard
64
+ }): string[] {
65
+ if (getJscadCadComponents(cadModelGroup).length === 0) return []
39
66
 
40
- return `<cadassembly>${modelElements.join("\n")}</cadassembly>`
67
+ return generateUrlCadModelElementsTsx({ cadModelGroup, pcbBoard })
41
68
  }
@@ -1,6 +1,10 @@
1
1
  import type { PcbBoard } from "circuit-json"
2
2
  import type { CadModelGroup } from "./converter-types"
3
- import { generateCadModelGroupModelTsx } from "./generate-cad-model-group-model-tsx"
3
+ import {
4
+ generateCadModelGroupChildrenTsx,
5
+ generateCadModelGroupModelTsx,
6
+ } from "./generate-cad-model-group-model-tsx"
7
+ import { isJscadCadModelGroupTranslucent } from "./is-jscad-cad-model-group-translucent"
4
8
 
5
9
  export function generateCadModelGroupTsx({
6
10
  cadModelGroup,
@@ -29,5 +33,16 @@ export function generateCadModelGroupTsx({
29
33
  "footprint={<footprint />}",
30
34
  `cadModel={${cadModelTsx}}`,
31
35
  ]
32
- return `<chip ${attributes.join(" ")} />`
36
+ if (isJscadCadModelGroupTranslucent(cadModelGroup)) {
37
+ attributes.push("showAsTranslucentModel")
38
+ }
39
+ const childModelElementsTsx = generateCadModelGroupChildrenTsx({
40
+ cadModelGroup,
41
+ pcbBoard,
42
+ })
43
+ if (childModelElementsTsx.length === 0) {
44
+ return `<chip ${attributes.join(" ")} />`
45
+ }
46
+
47
+ return `<chip ${attributes.join(" ")}>${childModelElementsTsx.join("\n")}</chip>`
33
48
  }