circuit-json-to-tscircuit 0.0.92 → 0.0.94

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 (45) hide show
  1. package/dist/{chunk-GAMHGAGS.js → chunk-WQVP4ME2.js} +1100 -166
  2. package/dist/cli/main.js +3 -7
  3. package/dist/lib/index.js +1 -1
  4. package/lib/board-converter/stages/convert-pcb-components.ts +21 -2
  5. package/lib/generate-board-cad-models-tsx/converter-types.ts +6 -0
  6. package/lib/generate-board-cad-models-tsx/execute-jscad-operation.ts +7 -0
  7. package/lib/generate-board-cad-models-tsx/generate-cad-model-group-model-tsx.ts +38 -11
  8. package/lib/generate-board-cad-models-tsx/generate-cad-model-group-tsx.ts +17 -2
  9. package/lib/generate-board-cad-models-tsx/generate-jscad-cad-model-prop-tsx.ts +113 -0
  10. package/lib/generate-board-cad-models-tsx/get-cad-model-placement-attributes.ts +3 -3
  11. package/lib/generate-board-cad-models-tsx/get-jscad-operation-fit-scale-factors.ts +66 -0
  12. package/lib/generate-board-cad-models-tsx/get-jscad-operation-in-base-model-frame.ts +179 -0
  13. package/lib/generate-board-cad-models-tsx/is-jscad-cad-model-group-translucent.ts +15 -0
  14. package/lib/generate-board-cad-models-tsx/pack-jscad-operations.ts +69 -0
  15. package/lib/generate-board-schematic-tsx/convert-components.ts +67 -12
  16. package/lib/generate-board-schematic-tsx/convert-native-symbol-pin-numbers.ts +81 -0
  17. package/lib/generate-board-schematic-tsx/convert-primitives.ts +28 -5
  18. package/lib/generate-board-schematic-tsx/convert-symbol-primitives.ts +65 -22
  19. package/lib/generate-board-schematic-tsx/get-native-symbol-port-matching-inputs.ts +131 -0
  20. package/lib/generate-board-schematic-tsx/get-native-symbol-text-replacement-candidate.ts +153 -0
  21. package/lib/generate-board-schematic-tsx/get-native-symbol-text-replacements.ts +82 -0
  22. package/lib/generate-board-schematic-tsx/get-nearest-schematic-text.ts +104 -0
  23. package/lib/generate-board-schematic-tsx/get-replaced-schematic-component-ids.ts +21 -0
  24. package/lib/generate-board-schematic-tsx/get-schematic-primitive-paint.ts +2 -2
  25. package/lib/generate-board-schematic-tsx/get-schematic-primitives-in-render-order.ts +9 -2
  26. package/lib/generate-board-schematic-tsx/get-symbol-to-schematic-transform.ts +8 -1
  27. package/lib/generate-board-schematic-tsx/has-multiple-native-symbol-units.ts +23 -0
  28. package/lib/generate-board-schematic-tsx/has-preserved-package-value-text.ts +32 -0
  29. package/lib/generate-board-schematic-tsx/is-pin-designator-for-port.ts +32 -0
  30. package/lib/generate-board-schematic-tsx/match-symbol-ports-by-pin-identity.ts +9 -1
  31. package/lib/generate-board-schematic-tsx/resolve-native-schematic-symbol-name.ts +114 -0
  32. package/package.json +2 -6
  33. package/tests/board-grouped-jscad-cad-model-fit.test.ts +111 -0
  34. package/tests/board-grouped-jscad-cad-model.test.ts +28 -38
  35. package/tests/board-jscad-cad-model.test.ts +12 -2
  36. package/tests/board-mixed-url-and-jscad-cad-models.test.ts +31 -2
  37. package/tests/explicit-native-symbol-content.test.ts +60 -0
  38. package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip-schematic-comparison.snap.svg +2 -2
  39. package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip.test.tsx.snap +16 -20
  40. package/tests/ti-evms/__snapshots__/ti-lm5155evm-fly-roundtrip-schematic-comparison.snap.svg +1 -1
  41. package/tests/ti-evms/__snapshots__/ti-lmg342x-bb-evm-roundtrip-schematic-comparison.snap.svg +1 -1
  42. package/tests/ti-evms/__snapshots__/ti-lmg342x-bb-evm-roundtrip.test.tsx.snap +80 -128
  43. package/tests/ti-evms/ti-lm5155evm-fly-roundtrip.test.tsx +42 -81
  44. package/tests/ti-native-symbols.test.ts +528 -0
  45. package/lib/generate-board-cad-models-tsx/generate-jscad-cad-model-tsx.ts +0 -26
@@ -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
@@ -767,55 +1126,6 @@ ${schematicElements.join("\n")}
767
1126
  // lib/generate-board-schematic-tsx/convert-primitives.ts
768
1127
  import { schematic_text } from "circuit-json";
769
1128
 
770
- // lib/generate-board-schematic-tsx/convert-rect.ts
771
- import {
772
- applyToPoint,
773
- compose,
774
- rotateDEG,
775
- translate
776
- } from "transformation-matrix";
777
-
778
- // lib/generate-board-schematic-tsx/format-attributes.ts
779
- var formatAttributes = (attributes) => Object.entries(attributes).filter(([, attribute]) => attribute !== void 0 && attribute !== null).map(([name, attribute]) => `${name}={${JSON.stringify(attribute)}}`).join(" ");
780
- var formatElement = (tagName, attributes) => `<${tagName} ${formatAttributes(attributes)} />`;
781
-
782
- // lib/generate-board-schematic-tsx/convert-rect.ts
783
- var DEFAULT_SCHEMATIC_STROKE_WIDTH = 0.02;
784
- var DASH_LENGTH_TO_STROKE_WIDTH_RATIO = 3;
785
- var convertRect = ({
786
- center,
787
- width,
788
- height,
789
- ccwRotationDegrees,
790
- strokeWidth,
791
- color,
792
- fillColor,
793
- isFilled,
794
- isDashed
795
- }) => {
796
- const rectToSchematicTransform = compose(
797
- translate(center.x, center.y),
798
- rotateDEG(ccwRotationDegrees ?? 0)
799
- );
800
- const points = [
801
- { x: -width / 2, y: -height / 2 },
802
- { x: width / 2, y: -height / 2 },
803
- { x: width / 2, y: height / 2 },
804
- { x: -width / 2, y: height / 2 },
805
- { x: -width / 2, y: -height / 2 }
806
- ].map((point) => applyToPoint(rectToSchematicTransform, point));
807
- const dashLength = isDashed ? (strokeWidth ?? DEFAULT_SCHEMATIC_STROKE_WIDTH) * DASH_LENGTH_TO_STROKE_WIDTH_RATIO : void 0;
808
- return formatElement("schematicpath", {
809
- points,
810
- strokeWidth,
811
- strokeColor: color,
812
- fillColor,
813
- isFilled,
814
- dashLength,
815
- dashGap: dashLength
816
- });
817
- };
818
-
819
1129
  // lib/generate-symbol-tsx.ts
820
1130
  import { su } from "@tscircuit/soup-util";
821
1131
  var escapeJsxText = (text) => text.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -1035,46 +1345,381 @@ var generateSymbolTsx = (circuitJson) => {
1035
1345
  `.trim();
1036
1346
  };
1037
1347
 
1038
- // lib/generate-board-schematic-tsx/get-schematic-primitives-in-render-order.ts
1039
- var isSchematicPrimitive = (element) => element.type === "schematic_text" || element.type === "schematic_path" || element.type === "schematic_rect" || element.type === "schematic_line" || element.type === "schematic_circle" || element.type === "schematic_arc" || element.type === "schematic_box";
1040
- var isCustomComponentBody = ({
1041
- component,
1042
- rect
1043
- }) => component.is_box_with_pins === false && rect.is_filled && rect.center.x === component.center.x && rect.center.y === component.center.y && rect.width === component.size.width && rect.height === component.size.height;
1044
- var getSchematicPrimitivesInRenderOrder = (circuitJson) => {
1045
- const customComponentById = /* @__PURE__ */ new Map();
1046
- for (const element of circuitJson) {
1047
- if (element.type === "schematic_component" && element.is_box_with_pins === false) {
1048
- customComponentById.set(element.schematic_component_id, element);
1049
- }
1348
+ // lib/generate-board-schematic-tsx/convert-rect.ts
1349
+ import {
1350
+ applyToPoint,
1351
+ compose,
1352
+ rotateDEG,
1353
+ translate
1354
+ } from "transformation-matrix";
1355
+
1356
+ // lib/generate-board-schematic-tsx/format-attributes.ts
1357
+ var formatAttributes = (attributes) => Object.entries(attributes).filter(([, attribute]) => attribute !== void 0 && attribute !== null).map(([name, attribute]) => `${name}={${JSON.stringify(attribute)}}`).join(" ");
1358
+ var formatElement = (tagName, attributes) => `<${tagName} ${formatAttributes(attributes)} />`;
1359
+
1360
+ // lib/generate-board-schematic-tsx/convert-rect.ts
1361
+ var DEFAULT_SCHEMATIC_STROKE_WIDTH = 0.02;
1362
+ var DASH_LENGTH_TO_STROKE_WIDTH_RATIO = 3;
1363
+ var convertRect = ({
1364
+ center,
1365
+ width,
1366
+ height,
1367
+ ccwRotationDegrees,
1368
+ strokeWidth,
1369
+ color,
1370
+ fillColor,
1371
+ isFilled,
1372
+ isDashed
1373
+ }) => {
1374
+ const rectToSchematicTransform = compose(
1375
+ translate(center.x, center.y),
1376
+ rotateDEG(ccwRotationDegrees ?? 0)
1377
+ );
1378
+ const points = [
1379
+ { x: -width / 2, y: -height / 2 },
1380
+ { x: width / 2, y: -height / 2 },
1381
+ { x: width / 2, y: height / 2 },
1382
+ { x: -width / 2, y: height / 2 },
1383
+ { x: -width / 2, y: -height / 2 }
1384
+ ].map((point) => applyToPoint(rectToSchematicTransform, point));
1385
+ const dashLength = isDashed ? (strokeWidth ?? DEFAULT_SCHEMATIC_STROKE_WIDTH) * DASH_LENGTH_TO_STROKE_WIDTH_RATIO : void 0;
1386
+ return formatElement("schematicpath", {
1387
+ points,
1388
+ strokeWidth,
1389
+ strokeColor: color,
1390
+ fillColor,
1391
+ isFilled,
1392
+ dashLength,
1393
+ dashGap: dashLength
1394
+ });
1395
+ };
1396
+
1397
+ // lib/generate-board-schematic-tsx/get-nearest-schematic-text.ts
1398
+ var DEGREES_TO_RADIANS = Math.PI / 180;
1399
+ var distanceFromComponentCenter = ({
1400
+ schematicText,
1401
+ schematicComponent
1402
+ }) => Math.hypot(
1403
+ schematicText.position.x - schematicComponent.center.x,
1404
+ schematicText.position.y - schematicComponent.center.y
1405
+ );
1406
+ var getNearestSchematicText = ({
1407
+ schematicTexts,
1408
+ schematicComponent
1409
+ }) => schematicTexts.toSorted(
1410
+ (firstText, secondText) => distanceFromComponentCenter({
1411
+ schematicText: firstText,
1412
+ schematicComponent
1413
+ }) - distanceFromComponentCenter({
1414
+ schematicText: secondText,
1415
+ schematicComponent
1416
+ })
1417
+ )[0];
1418
+ var getSchematicTextAxisDistances = ({
1419
+ schematicText,
1420
+ schematicComponent
1421
+ }) => {
1422
+ const rotationRadians = schematicText.rotation * DEGREES_TO_RADIANS;
1423
+ const deltaX = schematicComponent.center.x - schematicText.position.x;
1424
+ const deltaY = schematicComponent.center.y - schematicText.position.y;
1425
+ return {
1426
+ alongAxis: deltaX * Math.cos(rotationRadians) + deltaY * Math.sin(rotationRadians),
1427
+ acrossAxis: Math.abs(
1428
+ -deltaX * Math.sin(rotationRadians) + deltaY * Math.cos(rotationRadians)
1429
+ )
1430
+ };
1431
+ };
1432
+ var getSchematicTextAxisRange = ({
1433
+ schematicText,
1434
+ maximumDistance
1435
+ }) => {
1436
+ const maximumTextAdvance = Array.from(schematicText.text).length * schematicText.font_size;
1437
+ if (schematicText.anchor.includes("left")) {
1438
+ return {
1439
+ minimum: -maximumDistance,
1440
+ maximum: maximumTextAdvance + maximumDistance
1441
+ };
1050
1442
  }
1051
- const primitives = circuitJson.filter(isSchematicPrimitive);
1052
- const componentBodyById = /* @__PURE__ */ new Map();
1053
- for (const primitive of primitives) {
1054
- if (primitive.type !== "schematic_rect" || !primitive.schematic_component_id) {
1055
- continue;
1056
- }
1057
- const component = customComponentById.get(primitive.schematic_component_id);
1058
- if (component && isCustomComponentBody({ component, rect: primitive })) {
1059
- componentBodyById.set(primitive.schematic_component_id, primitive);
1060
- }
1443
+ if (schematicText.anchor.includes("right")) {
1444
+ return {
1445
+ minimum: -maximumTextAdvance - maximumDistance,
1446
+ maximum: maximumDistance
1447
+ };
1061
1448
  }
1062
- const emittedComponentBodies = /* @__PURE__ */ new Set();
1063
- const result = [];
1064
- for (const primitive of primitives) {
1065
- const componentId = primitive.schematic_component_id;
1066
- const componentBody = componentId ? componentBodyById.get(componentId) : void 0;
1067
- if (!componentId || !componentBody) {
1068
- result.push(primitive);
1069
- continue;
1070
- }
1071
- if (!emittedComponentBodies.has(componentId)) {
1072
- result.push(componentBody);
1073
- emittedComponentBodies.add(componentId);
1449
+ return {
1450
+ minimum: -maximumTextAdvance / 2 - maximumDistance,
1451
+ maximum: maximumTextAdvance / 2 + maximumDistance
1452
+ };
1453
+ };
1454
+ var isSchematicTextWithinComponentLabelRange = ({
1455
+ schematicText,
1456
+ schematicComponent,
1457
+ maximumDistance
1458
+ }) => {
1459
+ const distance = getSchematicTextAxisDistances({
1460
+ schematicText,
1461
+ schematicComponent
1462
+ });
1463
+ const textAxisRange = getSchematicTextAxisRange({
1464
+ schematicText,
1465
+ maximumDistance
1466
+ });
1467
+ return distance.alongAxis >= textAxisRange.minimum && distance.alongAxis <= textAxisRange.maximum && distance.acrossAxis <= maximumDistance;
1468
+ };
1469
+
1470
+ // lib/generate-board-schematic-tsx/resolve-native-schematic-symbol-name.ts
1471
+ var normalizePortName = (portName) => portName.toLowerCase().replace(/[^a-z0-9]/gu, "");
1472
+ var hasExactPortNames = (sourcePortNames, expectedPortNames) => sourcePortNames.size === expectedPortNames.length && expectedPortNames.every((portName) => sourcePortNames.has(portName));
1473
+ var resolveNativeSchematicSymbolName = ({
1474
+ circuitJson,
1475
+ schematicComponent
1476
+ }) => {
1477
+ if (schematicComponent.symbol_name) return schematicComponent.symbol_name;
1478
+ const sourceComponent = circuitJson.find(
1479
+ (element) => element.type === "source_component" && element.source_component_id === schematicComponent.source_component_id
1480
+ );
1481
+ if (sourceComponent?.type !== "source_component") return void 0;
1482
+ const sourcePorts = circuitJson.filter(
1483
+ (element) => element.type === "source_port" && element.source_component_id === sourceComponent.source_component_id
1484
+ );
1485
+ const sourcePortNames = new Set(
1486
+ sourcePorts.map((sourcePort) => normalizePortName(sourcePort.name))
1487
+ );
1488
+ const schematicPorts = circuitJson.filter(
1489
+ (element) => element.type === "schematic_port" && element.schematic_component_id === schematicComponent.schematic_component_id
1490
+ );
1491
+ const schematicSourcePortNames = new Set(
1492
+ schematicPorts.flatMap((schematicPort) => {
1493
+ const sourcePort = sourcePorts.find(
1494
+ (candidate) => candidate.source_port_id === schematicPort.source_port_id
1495
+ );
1496
+ return sourcePort ? [normalizePortName(sourcePort.name)] : [];
1497
+ })
1498
+ );
1499
+ const logicPortNames = new Set(
1500
+ [...schematicSourcePortNames].map(
1501
+ (portName) => portName.replace(/^\d+([aby])$/u, "$1")
1502
+ )
1503
+ );
1504
+ const designator = sourceComponent.display_name ?? "";
1505
+ const componentValue = sourceComponent.display_value?.toUpperCase() ?? "";
1506
+ if (componentValue.startsWith("SN74LVC2G08") && hasExactPortNames(logicPortNames, ["a", "b", "y"])) {
1507
+ return "and_gate_right";
1508
+ }
1509
+ if (/^SN74LVC[23]G14/u.test(componentValue) && hasExactPortNames(logicPortNames, ["a", "y"])) {
1510
+ return "schmitt_trigger_inverter_right";
1511
+ }
1512
+ if (designator.startsWith("U") && hasExactPortNames(sourcePortNames, ["a", "k", "c", "e"])) {
1513
+ return "phototransistor_optocoupler_right";
1514
+ }
1515
+ if (designator.startsWith("T") && hasExactPortNames(sourcePortNames, [
1516
+ "1",
1517
+ "2",
1518
+ "3",
1519
+ "5",
1520
+ "6",
1521
+ "7",
1522
+ "9",
1523
+ "10"
1524
+ ])) {
1525
+ return "transformer_4_winding_right";
1526
+ }
1527
+ if (designator.startsWith("D") && hasExactPortNames(sourcePortNames, ["1anode", "2cathode", "1cathode2anode"])) {
1528
+ return "dual_series_schottky_diode_right";
1529
+ }
1530
+ return void 0;
1531
+ };
1532
+
1533
+ // lib/generate-board-schematic-tsx/has-multiple-native-symbol-units.ts
1534
+ var hasMultipleNativeSymbolUnits = ({
1535
+ circuitJson,
1536
+ schematicComponent,
1537
+ symbolName
1538
+ }) => circuitJson.filter(
1539
+ (candidate) => candidate.type === "schematic_component" && candidate.source_component_id === schematicComponent.source_component_id && !candidate.symbol_name && resolveNativeSchematicSymbolName({
1540
+ circuitJson,
1541
+ schematicComponent: candidate
1542
+ }) === symbolName
1543
+ ).length > 1;
1544
+
1545
+ // lib/generate-board-schematic-tsx/has-preserved-package-value-text.ts
1546
+ var hasPreservedPackageValueText = ({
1547
+ circuitJson,
1548
+ schematicComponent,
1549
+ schematicComponents,
1550
+ replacedSchematicComponentIds,
1551
+ displayTexts
1552
+ }) => circuitJson.some((candidate) => {
1553
+ if (candidate.type !== "schematic_text" || !candidate.schematic_component_id || !displayTexts.has(candidate.text) || replacedSchematicComponentIds.has(candidate.schematic_component_id)) {
1554
+ return false;
1555
+ }
1556
+ return schematicComponents.some(
1557
+ (component) => component.schematic_component_id === candidate.schematic_component_id && component.source_component_id === schematicComponent.source_component_id
1558
+ );
1559
+ });
1560
+
1561
+ // lib/generate-board-schematic-tsx/is-pin-designator-for-port.ts
1562
+ var isPinDesignatorForPort = ({
1563
+ schematicText,
1564
+ schematicPort,
1565
+ schematicComponent
1566
+ }) => {
1567
+ if (schematicText.text !== String(schematicPort.pin_number)) return false;
1568
+ const portToCenter = {
1569
+ x: schematicComponent.center.x - schematicPort.center.x,
1570
+ y: schematicComponent.center.y - schematicPort.center.y
1571
+ };
1572
+ const portToText = {
1573
+ x: schematicText.position.x - schematicPort.center.x,
1574
+ y: schematicText.position.y - schematicPort.center.y
1575
+ };
1576
+ const portDistance = Math.hypot(portToCenter.x, portToCenter.y);
1577
+ const textDistance = Math.hypot(portToText.x, portToText.y);
1578
+ const pointsTowardComponent = portToCenter.x * portToText.x + portToCenter.y * portToText.y >= 0;
1579
+ return pointsTowardComponent && textDistance <= Math.min(0.3, portDistance * 0.6);
1580
+ };
1581
+
1582
+ // lib/generate-board-schematic-tsx/get-native-symbol-text-replacement-candidate.ts
1583
+ var distanceBetween = (firstPoint, secondPoint) => Math.hypot(firstPoint.x - secondPoint.x, firstPoint.y - secondPoint.y);
1584
+ var getNativeSymbolTextReplacementCandidate = (context) => {
1585
+ const { circuitJson, schematicComponent, unownedSchematicTexts } = context;
1586
+ if (schematicComponent.symbol_name) return void 0;
1587
+ const symbolName = resolveNativeSchematicSymbolName({
1588
+ circuitJson,
1589
+ schematicComponent
1590
+ });
1591
+ if (!symbolName) return void 0;
1592
+ const sourceComponent = circuitJson.find(
1593
+ (candidate) => candidate.type === "source_component" && candidate.source_component_id === schematicComponent.source_component_id
1594
+ );
1595
+ const reference = sourceComponent?.display_name ?? sourceComponent?.name;
1596
+ const displayTexts = new Set(
1597
+ [
1598
+ sourceComponent?.display_value,
1599
+ schematicComponent.symbol_display_value
1600
+ ].filter((displayText) => Boolean(displayText))
1601
+ );
1602
+ const labelSearchDistance = Math.max(schematicComponent.size.width, schematicComponent.size.height) / 2 + 0.3;
1603
+ const referenceTexts = unownedSchematicTexts.filter(
1604
+ (schematicText) => schematicText.text === reference && distanceBetween(schematicText.position, schematicComponent.center) <= labelSearchDistance
1605
+ );
1606
+ const displayValueTextsInRange = unownedSchematicTexts.filter(
1607
+ (schematicText) => displayTexts.has(schematicText.text) && isSchematicTextWithinComponentLabelRange({
1608
+ schematicText,
1609
+ schematicComponent,
1610
+ maximumDistance: labelSearchDistance
1611
+ })
1612
+ );
1613
+ const nearestDisplayValueText = getNearestSchematicText({
1614
+ schematicTexts: displayValueTextsInRange,
1615
+ schematicComponent
1616
+ });
1617
+ const displayValueTexts = nearestDisplayValueText ? [nearestDisplayValueText] : [];
1618
+ const schematicPorts = circuitJson.filter(
1619
+ (candidate) => candidate.type === "schematic_port" && candidate.schematic_component_id === schematicComponent.schematic_component_id
1620
+ );
1621
+ const replacedPinPortIds = /* @__PURE__ */ new Set();
1622
+ const pinDesignatorTexts = schematicPorts.flatMap((schematicPort) => {
1623
+ const matches = unownedSchematicTexts.filter(
1624
+ (schematicText) => isPinDesignatorForPort({
1625
+ schematicText,
1626
+ schematicPort,
1627
+ schematicComponent
1628
+ })
1629
+ );
1630
+ if (matches.length > 0)
1631
+ replacedPinPortIds.add(schematicPort.schematic_port_id);
1632
+ return matches;
1633
+ });
1634
+ return {
1635
+ schematicComponentId: schematicComponent.schematic_component_id,
1636
+ importedTextIds: new Set(
1637
+ [...referenceTexts, ...displayValueTexts, ...pinDesignatorTexts].map(
1638
+ (schematicText) => schematicText.schematic_text_id
1639
+ )
1640
+ ),
1641
+ replacedPinPortIds,
1642
+ replacesReference: referenceTexts.length > 0,
1643
+ includeNativeDisplayText: false,
1644
+ referenceFontSize: getNearestSchematicText({
1645
+ schematicTexts: referenceTexts,
1646
+ schematicComponent
1647
+ })?.font_size,
1648
+ displayTextFontSize: nearestDisplayValueText?.font_size,
1649
+ sourceComponentId: schematicComponent.source_component_id,
1650
+ symbolName,
1651
+ displayValueTextIds: new Set(
1652
+ displayValueTexts.map((schematicText) => schematicText.schematic_text_id)
1653
+ ),
1654
+ isMultiUnitSymbol: hasMultipleNativeSymbolUnits({
1655
+ circuitJson,
1656
+ schematicComponent,
1657
+ symbolName
1658
+ }),
1659
+ hasPreservedPackageValueText: hasPreservedPackageValueText({
1660
+ circuitJson,
1661
+ schematicComponent,
1662
+ schematicComponents: context.schematicComponents,
1663
+ replacedSchematicComponentIds: context.replacedSchematicComponentIds,
1664
+ displayTexts
1665
+ })
1666
+ };
1667
+ };
1668
+
1669
+ // lib/generate-board-schematic-tsx/get-replaced-schematic-component-ids.ts
1670
+ import { symbols } from "schematic-symbols";
1671
+ var getReplacedSchematicComponentIds = (circuitJson) => {
1672
+ const replacedSchematicComponentIds = /* @__PURE__ */ new Set();
1673
+ for (const element of circuitJson) {
1674
+ if (element.type !== "schematic_component" || element.symbol_name) continue;
1675
+ const inferredSymbolName = resolveNativeSchematicSymbolName({
1676
+ circuitJson,
1677
+ schematicComponent: element
1678
+ });
1679
+ if (inferredSymbolName && inferredSymbolName in symbols) {
1680
+ replacedSchematicComponentIds.add(element.schematic_component_id);
1074
1681
  }
1075
- if (primitive !== componentBody) result.push(primitive);
1076
1682
  }
1077
- return result;
1683
+ return replacedSchematicComponentIds;
1684
+ };
1685
+
1686
+ // lib/generate-board-schematic-tsx/get-native-symbol-text-replacements.ts
1687
+ var isFirstUnitWithDisplayValue = ({
1688
+ candidate,
1689
+ allCandidates
1690
+ }) => allCandidates.find(
1691
+ (otherCandidate) => otherCandidate.sourceComponentId === candidate.sourceComponentId && otherCandidate.symbolName === candidate.symbolName && otherCandidate.displayValueTextIds.size > 0
1692
+ )?.schematicComponentId === candidate.schematicComponentId;
1693
+ var getNativeSymbolTextReplacements = (circuitJson) => {
1694
+ const unownedSchematicTexts = circuitJson.filter(
1695
+ (element) => element.type === "schematic_text" && element.schematic_component_id === void 0
1696
+ );
1697
+ const replacedSchematicComponentIds = getReplacedSchematicComponentIds(circuitJson);
1698
+ const schematicComponents = circuitJson.filter(
1699
+ (element) => element.type === "schematic_component"
1700
+ );
1701
+ const candidates = schematicComponents.flatMap((schematicComponent) => {
1702
+ const candidate = getNativeSymbolTextReplacementCandidate({
1703
+ circuitJson,
1704
+ schematicComponent,
1705
+ unownedSchematicTexts,
1706
+ replacedSchematicComponentIds,
1707
+ schematicComponents
1708
+ });
1709
+ return candidate ? [candidate] : [];
1710
+ });
1711
+ return candidates.map((candidate) => ({
1712
+ schematicComponentId: candidate.schematicComponentId,
1713
+ importedTextIds: candidate.importedTextIds,
1714
+ replacedPinPortIds: candidate.replacedPinPortIds,
1715
+ replacesReference: candidate.replacesReference,
1716
+ includeNativeDisplayText: candidate.displayValueTextIds.size > 0 && (!candidate.isMultiUnitSymbol || !candidate.hasPreservedPackageValueText && isFirstUnitWithDisplayValue({
1717
+ candidate,
1718
+ allCandidates: candidates
1719
+ })),
1720
+ referenceFontSize: candidate.referenceFontSize,
1721
+ displayTextFontSize: candidate.displayTextFontSize
1722
+ }));
1078
1723
  };
1079
1724
 
1080
1725
  // lib/generate-board-schematic-tsx/get-schematic-primitive-paint.ts
@@ -1159,14 +1804,71 @@ var getSchematicPrimitivePaint = (primitive) => {
1159
1804
  };
1160
1805
  };
1161
1806
 
1807
+ // lib/generate-board-schematic-tsx/get-schematic-primitives-in-render-order.ts
1808
+ var isSchematicPrimitive = (element) => element.type === "schematic_text" || element.type === "schematic_path" || element.type === "schematic_rect" || element.type === "schematic_line" || element.type === "schematic_circle" || element.type === "schematic_arc" || element.type === "schematic_box";
1809
+ var isCustomComponentBody = ({
1810
+ component,
1811
+ rect
1812
+ }) => component.is_box_with_pins === false && rect.is_filled && rect.center.x === component.center.x && rect.center.y === component.center.y && rect.width === component.size.width && rect.height === component.size.height;
1813
+ var getSchematicPrimitivesInRenderOrder = (circuitJson, nativeComponentIds = /* @__PURE__ */ new Set()) => {
1814
+ const customComponentById = /* @__PURE__ */ new Map();
1815
+ for (const element of circuitJson) {
1816
+ if (element.type === "schematic_component" && element.is_box_with_pins === false) {
1817
+ customComponentById.set(element.schematic_component_id, element);
1818
+ }
1819
+ }
1820
+ const primitives = circuitJson.filter(isSchematicPrimitive).filter(
1821
+ (primitive) => !primitive.schematic_component_id || !nativeComponentIds.has(primitive.schematic_component_id)
1822
+ );
1823
+ const componentBodyById = /* @__PURE__ */ new Map();
1824
+ for (const primitive of primitives) {
1825
+ if (primitive.type !== "schematic_rect" || !primitive.schematic_component_id) {
1826
+ continue;
1827
+ }
1828
+ const component = customComponentById.get(primitive.schematic_component_id);
1829
+ if (component && isCustomComponentBody({ component, rect: primitive })) {
1830
+ componentBodyById.set(primitive.schematic_component_id, primitive);
1831
+ }
1832
+ }
1833
+ const emittedComponentBodies = /* @__PURE__ */ new Set();
1834
+ const result = [];
1835
+ for (const primitive of primitives) {
1836
+ const componentId = primitive.schematic_component_id;
1837
+ const componentBody = componentId ? componentBodyById.get(componentId) : void 0;
1838
+ if (!componentId || !componentBody) {
1839
+ result.push(primitive);
1840
+ continue;
1841
+ }
1842
+ if (!emittedComponentBodies.has(componentId)) {
1843
+ result.push(componentBody);
1844
+ emittedComponentBodies.add(componentId);
1845
+ }
1846
+ if (primitive !== componentBody) result.push(primitive);
1847
+ }
1848
+ return result;
1849
+ };
1850
+
1162
1851
  // lib/generate-board-schematic-tsx/convert-primitives.ts
1852
+ var getRenderablePrimitives = (circuitJson) => {
1853
+ const replacedTextIds = new Set(
1854
+ getNativeSymbolTextReplacements(circuitJson).flatMap((replacement) => [
1855
+ ...replacement.importedTextIds
1856
+ ])
1857
+ );
1858
+ return getSchematicPrimitivesInRenderOrder(
1859
+ circuitJson,
1860
+ getReplacedSchematicComponentIds(circuitJson)
1861
+ ).filter(
1862
+ (primitive) => primitive.type !== "schematic_text" || !replacedTextIds.has(primitive.schematic_text_id)
1863
+ );
1864
+ };
1163
1865
  var convertPrimitives = (circuitJson) => [
1164
1866
  ...generateSymbolElements(
1165
1867
  circuitJson.filter(
1166
1868
  (element) => element.type === "schematic_table" || element.type === "schematic_table_cell"
1167
1869
  )
1168
1870
  ),
1169
- ...getSchematicPrimitivesInRenderOrder(circuitJson).flatMap((element) => {
1871
+ ...getRenderablePrimitives(circuitJson).flatMap((element) => {
1170
1872
  const paint = getSchematicPrimitivePaint(element);
1171
1873
  switch (element.type) {
1172
1874
  case "schematic_text":
@@ -1264,7 +1966,7 @@ var convertPrimitives = (circuitJson) => [
1264
1966
 
1265
1967
  // lib/generate-board-schematic-tsx/convert-components.ts
1266
1968
  import { su as su3 } from "@tscircuit/soup-util";
1267
- import { symbols } from "schematic-symbols";
1969
+ import { symbols as symbols2 } from "schematic-symbols";
1268
1970
 
1269
1971
  // lib/generate-board-schematic-tsx/get-symbol-to-schematic-transform.ts
1270
1972
  import { fromTriangles as fromTriangles2 } from "transformation-matrix";
@@ -1442,18 +2144,21 @@ var isRigidUniformTransform = (transform) => {
1442
2144
  };
1443
2145
 
1444
2146
  // lib/generate-board-schematic-tsx/match-symbol-ports-by-pin-identity.ts
2147
+ var getLogicUnitPortAlias = (portName) => portName?.match(/^\d*([aby])$/iu)?.[1]?.toLowerCase();
1445
2148
  var matchSymbolPortsByPinIdentity = ({
1446
2149
  schematicPorts,
1447
2150
  sourcePorts,
1448
- symbol
2151
+ symbol,
2152
+ includeSchematicPinNumbers = true
1449
2153
  }) => symbol.ports.flatMap((symbolPort) => {
1450
2154
  const candidates = schematicPorts.filter((schematicPort) => {
1451
2155
  const sourcePort = sourcePorts.find(
1452
2156
  (port) => port.source_port_id === schematicPort.source_port_id
1453
2157
  );
1454
- const pinNumber = schematicPort.pin_number ?? sourcePort?.pin_number;
2158
+ const pinNumber = includeSchematicPinNumbers ? schematicPort.pin_number ?? sourcePort?.pin_number : sourcePort?.pin_number;
1455
2159
  const portIdentities = [
1456
2160
  sourcePort?.name,
2161
+ getLogicUnitPortAlias(sourcePort?.name),
1457
2162
  ...sourcePort?.port_hints ?? [],
1458
2163
  ...pinNumber === void 0 ? [] : [String(pinNumber), `pin${pinNumber}`]
1459
2164
  ];
@@ -1469,12 +2174,17 @@ var getSymbolToSchematicTransform = ({
1469
2174
  symbol,
1470
2175
  schematicComponent,
1471
2176
  schematicPorts,
1472
- sourcePorts
2177
+ sourcePorts,
2178
+ includeSchematicPinNumbers
1473
2179
  }) => {
2180
+ const componentSourcePorts = sourcePorts.filter(
2181
+ (sourcePort) => sourcePort.source_component_id === schematicComponent.source_component_id
2182
+ );
1474
2183
  const pinIdentityMatches = matchSymbolPortsByPinIdentity({
1475
2184
  schematicPorts,
1476
- sourcePorts,
1477
- symbol
2185
+ sourcePorts: componentSourcePorts,
2186
+ symbol,
2187
+ includeSchematicPinNumbers
1478
2188
  });
1479
2189
  const rigidPinIdentityTransform = getRigidPinIdentityTransform(pinIdentityMatches);
1480
2190
  if (rigidPinIdentityTransform) return rigidPinIdentityTransform;
@@ -1510,6 +2220,17 @@ var getSymbolToSchematicTransform = ({
1510
2220
  import { schematic_text as schematic_text2 } from "circuit-json";
1511
2221
  import { applyToPoint as applyToPoint4 } from "transformation-matrix";
1512
2222
  var SYMBOL_OUTLINE_STROKE_WIDTH = 0.02;
2223
+ var MINIMUM_FILL_AREA = 1e-12;
2224
+ var pathHasFillArea = (points) => {
2225
+ if (points.length < 3) return false;
2226
+ let doubledArea = 0;
2227
+ for (const [pointIndex, point] of points.entries()) {
2228
+ const nextPoint = points[(pointIndex + 1) % points.length];
2229
+ if (!nextPoint) continue;
2230
+ doubledArea += point.x * nextPoint.y - nextPoint.x * point.y;
2231
+ }
2232
+ return Math.abs(doubledArea) > MINIMUM_FILL_AREA;
2233
+ };
1513
2234
  var anchors = {
1514
2235
  middle_top: "top_center",
1515
2236
  middle_bottom: "bottom_center",
@@ -1525,8 +2246,13 @@ var convertSymbolPrimitives = ({
1525
2246
  symbol,
1526
2247
  symbolToSchematicTransform,
1527
2248
  reference,
1528
- displayText
1529
- }) => symbol.primitives.map((primitive) => {
2249
+ displayText,
2250
+ includeReference = true,
2251
+ includeDisplayText = true,
2252
+ referenceFontSize,
2253
+ displayTextFontSize,
2254
+ filledPrimitiveColor
2255
+ }) => symbol.primitives.flatMap((primitive) => {
1530
2256
  if (primitive.type === "path") {
1531
2257
  const points = primitive.points.map(
1532
2258
  (point) => applyToPoint4(symbolToSchematicTransform, point)
@@ -1535,19 +2261,25 @@ var convertSymbolPrimitives = ({
1535
2261
  return formatElement("schematicpath", {
1536
2262
  points,
1537
2263
  strokeWidth: SYMBOL_OUTLINE_STROKE_WIDTH,
2264
+ fillColor: primitive.fill && pathHasFillArea(points) ? filledPrimitiveColor : void 0,
1538
2265
  isFilled: primitive.fill
1539
2266
  });
1540
2267
  }
1541
2268
  const center = applyToPoint4(symbolToSchematicTransform, primitive);
1542
2269
  if (primitive.type === "text") {
2270
+ if (!includeReference && primitive.text === "{REF}") return [];
2271
+ if (!includeDisplayText && primitive.text === "{VAL}") return [];
1543
2272
  const text = primitive.text === "{REF}" ? reference : primitive.text === "{VAL}" ? displayText : primitive.text;
1544
- return formatElement("schematictext", {
1545
- text,
1546
- schX: center.x,
1547
- schY: center.y,
1548
- anchor: anchors[primitive.anchor],
1549
- fontSize: primitive.fontSize ?? schematic_text2.shape.font_size.parse(void 0)
1550
- });
2273
+ const importedFontSize = primitive.text === "{REF}" ? referenceFontSize : primitive.text === "{VAL}" ? displayTextFontSize : void 0;
2274
+ return [
2275
+ formatElement("schematictext", {
2276
+ text,
2277
+ schX: center.x,
2278
+ schY: center.y,
2279
+ anchor: anchors[primitive.anchor],
2280
+ fontSize: importedFontSize ?? primitive.fontSize ?? schematic_text2.shape.font_size.parse(void 0)
2281
+ })
2282
+ ];
1551
2283
  }
1552
2284
  const symbolToSchematicVectorTransform = {
1553
2285
  ...symbolToSchematicTransform,
@@ -1559,12 +2291,15 @@ var convertSymbolPrimitives = ({
1559
2291
  x: primitive.radius,
1560
2292
  y: 0
1561
2293
  });
1562
- return formatElement("schematiccircle", {
1563
- center,
1564
- radius: Math.hypot(radiusVector.x, radiusVector.y),
1565
- strokeWidth: SYMBOL_OUTLINE_STROKE_WIDTH,
1566
- isFilled: primitive.fill
1567
- });
2294
+ return [
2295
+ formatElement("schematiccircle", {
2296
+ center,
2297
+ radius: Math.hypot(radiusVector.x, radiusVector.y),
2298
+ strokeWidth: SYMBOL_OUTLINE_STROKE_WIDTH,
2299
+ fillColor: primitive.fill ? filledPrimitiveColor : void 0,
2300
+ isFilled: primitive.fill
2301
+ })
2302
+ ];
1568
2303
  }
1569
2304
  const widthVector = applyToPoint4(symbolToSchematicVectorTransform, {
1570
2305
  x: primitive.width,
@@ -1575,13 +2310,15 @@ var convertSymbolPrimitives = ({
1575
2310
  y: primitive.height
1576
2311
  });
1577
2312
  const ccwRotationDegrees = Math.atan2(widthVector.y, widthVector.x) * 180 / Math.PI;
1578
- return formatElement("schematicrect", {
1579
- schX: center.x,
1580
- schY: center.y,
1581
- width: Math.hypot(widthVector.x, widthVector.y),
1582
- height: Math.hypot(heightVector.x, heightVector.y),
1583
- rotation: ccwRotationDegrees
1584
- });
2313
+ return [
2314
+ formatElement("schematicrect", {
2315
+ schX: center.x,
2316
+ schY: center.y,
2317
+ width: Math.hypot(widthVector.x, widthVector.y),
2318
+ height: Math.hypot(heightVector.x, heightVector.y),
2319
+ rotation: ccwRotationDegrees
2320
+ })
2321
+ ];
1585
2322
  });
1586
2323
 
1587
2324
  // lib/generate-board-schematic-tsx/convert-box-components.ts
@@ -1812,33 +2549,222 @@ var convertBoxComponent = ({
1812
2549
  return primitives;
1813
2550
  };
1814
2551
 
1815
- // lib/generate-board-schematic-tsx/convert-components.ts
1816
- var convertComponents = (circuitJson) => su3(circuitJson).schematic_component.list().flatMap((schematicComponent) => {
1817
- const symbolName = schematicComponent.symbol_name;
1818
- if (symbolName && symbolName in symbols) {
1819
- const symbol = symbols[symbolName];
1820
- if (!symbol) return [];
1821
- const sourceComponent = su3(circuitJson).source_component.get(
1822
- schematicComponent.source_component_id ?? ""
1823
- );
1824
- const symbolToSchematicTransform = getSymbolToSchematicTransform({
1825
- symbol,
1826
- schematicComponent,
1827
- schematicPorts: su3(circuitJson).schematic_port.list({
1828
- schematic_component_id: schematicComponent.schematic_component_id
1829
- }),
1830
- sourcePorts: su3(circuitJson).source_port.list()
1831
- });
1832
- return convertSymbolPrimitives({
1833
- symbol,
1834
- symbolToSchematicTransform,
1835
- reference: sourceComponent?.display_name ?? sourceComponent?.name ?? "",
1836
- displayText: schematicComponent.symbol_display_value ?? ""
1837
- });
2552
+ // lib/generate-board-schematic-tsx/convert-native-symbol-pin-numbers.ts
2553
+ import { applyToPoint as applyToPoint5 } from "transformation-matrix";
2554
+ var PIN_TEXT_FONT_SIZE = 0.15;
2555
+ var PIN_TEXT_COLOR = "#a90000";
2556
+ var PIN_NUMBER_BASELINE_OFFSET = 0.02;
2557
+ var SYMBOL_POINT_TOLERANCE = 1e-6;
2558
+ var pointsMatch = (firstPoint, secondPoint) => Math.hypot(firstPoint.x - secondPoint.x, firstPoint.y - secondPoint.y) < SYMBOL_POINT_TOLERANCE;
2559
+ var getPortLeadInnerPoint = ({
2560
+ symbol,
2561
+ symbolPort
2562
+ }) => {
2563
+ for (const primitive of symbol.primitives) {
2564
+ if (primitive.type !== "path" || primitive.points.length < 2) continue;
2565
+ const firstPoint = primitive.points[0];
2566
+ const lastPoint = primitive.points.at(-1);
2567
+ if (pointsMatch(firstPoint, symbolPort)) return primitive.points[1];
2568
+ if (pointsMatch(lastPoint, symbolPort)) return primitive.points.at(-2);
1838
2569
  }
1839
- return schematicComponent.is_box_with_pins ? convertBoxComponent({ circuitJson, schematicComponent }) : [];
2570
+ return void 0;
2571
+ };
2572
+ var convertNativeSymbolPinNumbers = ({
2573
+ symbol,
2574
+ symbolToSchematicTransform,
2575
+ portMatches,
2576
+ replacedPinPortIds
2577
+ }) => portMatches.flatMap(({ schematicPort, symbolPort }) => {
2578
+ if (schematicPort.pin_number === void 0 || !replacedPinPortIds.has(schematicPort.schematic_port_id)) {
2579
+ return [];
2580
+ }
2581
+ const leadInnerPoint = getPortLeadInnerPoint({ symbol, symbolPort });
2582
+ if (!leadInnerPoint) return [];
2583
+ const portCenter = applyToPoint5(symbolToSchematicTransform, symbolPort);
2584
+ const leadInnerCenter = applyToPoint5(
2585
+ symbolToSchematicTransform,
2586
+ leadInnerPoint
2587
+ );
2588
+ const pinNumberPosition = {
2589
+ x: (portCenter.x + leadInnerCenter.x) / 2,
2590
+ y: (portCenter.y + leadInnerCenter.y) / 2
2591
+ };
2592
+ const isVerticalLead = Math.abs(leadInnerCenter.y - portCenter.y) > Math.abs(leadInnerCenter.x - portCenter.x);
2593
+ if (isVerticalLead) pinNumberPosition.x -= PIN_NUMBER_BASELINE_OFFSET;
2594
+ else pinNumberPosition.y += PIN_NUMBER_BASELINE_OFFSET;
2595
+ return [
2596
+ formatElement("schematictext", {
2597
+ text: String(schematicPort.pin_number),
2598
+ schX: pinNumberPosition.x,
2599
+ schY: pinNumberPosition.y,
2600
+ anchor: "bottom_center",
2601
+ fontSize: PIN_TEXT_FONT_SIZE,
2602
+ color: PIN_TEXT_COLOR,
2603
+ schRotation: isVerticalLead ? -90 : void 0
2604
+ })
2605
+ ];
1840
2606
  });
1841
2607
 
2608
+ // lib/generate-board-schematic-tsx/get-native-symbol-port-matching-inputs.ts
2609
+ var getNumericPortHint = (sourcePort) => {
2610
+ const numericPortHint = sourcePort.port_hints?.find(
2611
+ (portHint) => /^(?:pin)?\d+$/.test(portHint)
2612
+ );
2613
+ return numericPortHint?.replace(/^pin/, "");
2614
+ };
2615
+ var getNumericPortName = (sourcePort) => /^\d+$/.test(sourcePort.name) ? sourcePort.name : void 0;
2616
+ var getSourcePinNumber = ({
2617
+ sourcePort,
2618
+ schematicPorts
2619
+ }) => {
2620
+ const linkedSchematicPort = schematicPorts.find(
2621
+ (schematicPort) => schematicPort.source_port_id === sourcePort.source_port_id
2622
+ );
2623
+ const sourcePinNumber = sourcePort.pin_number ?? linkedSchematicPort?.pin_number ?? getNumericPortHint(sourcePort) ?? getNumericPortName(sourcePort);
2624
+ return sourcePinNumber === void 0 ? void 0 : String(sourcePinNumber);
2625
+ };
2626
+ var getFourWindingTransformerAlias = (sourcePinNumber) => {
2627
+ switch (sourcePinNumber) {
2628
+ case "1":
2629
+ return "primary_end";
2630
+ case "2":
2631
+ return "primary_start";
2632
+ case "5":
2633
+ return "auxiliary_end";
2634
+ case "3":
2635
+ return "auxiliary_start";
2636
+ case "9":
2637
+ return "secondary1_end";
2638
+ case "10":
2639
+ return "secondary1_start";
2640
+ case "6":
2641
+ return "secondary2_end";
2642
+ case "7":
2643
+ return "secondary2_start";
2644
+ default:
2645
+ return void 0;
2646
+ }
2647
+ };
2648
+ var getDualSeriesSchottkyAlias = (sourcePinNumber) => {
2649
+ switch (sourcePinNumber) {
2650
+ case "1":
2651
+ return "anode";
2652
+ case "2":
2653
+ return "cathode";
2654
+ case "3":
2655
+ return "common";
2656
+ default:
2657
+ return void 0;
2658
+ }
2659
+ };
2660
+ var getInferredPortAlias = ({
2661
+ symbolName,
2662
+ sourcePinNumber
2663
+ }) => {
2664
+ if (symbolName === "transformer_4_winding_right") {
2665
+ return getFourWindingTransformerAlias(sourcePinNumber);
2666
+ }
2667
+ if (symbolName === "dual_series_schottky_diode_right") {
2668
+ return getDualSeriesSchottkyAlias(sourcePinNumber);
2669
+ }
2670
+ return void 0;
2671
+ };
2672
+ var getNativeSymbolPortMatchingInputs = ({
2673
+ symbolName,
2674
+ sourcePorts,
2675
+ schematicPorts,
2676
+ isInferredSymbol
2677
+ }) => {
2678
+ const usesInferredPortAliases = symbolName === "transformer_4_winding_right" || symbolName === "dual_series_schottky_diode_right";
2679
+ if (!isInferredSymbol || !usesInferredPortAliases) {
2680
+ return { sourcePorts, includeSchematicPinNumbers: true };
2681
+ }
2682
+ const aliasedSourcePorts = sourcePorts.map((sourcePort) => {
2683
+ const sourcePinNumber = getSourcePinNumber({ sourcePort, schematicPorts });
2684
+ if (!sourcePinNumber) return sourcePort;
2685
+ const inferredPortAlias = getInferredPortAlias({
2686
+ symbolName,
2687
+ sourcePinNumber
2688
+ });
2689
+ if (!inferredPortAlias) return sourcePort;
2690
+ return {
2691
+ ...sourcePort,
2692
+ name: inferredPortAlias,
2693
+ port_hints: [inferredPortAlias],
2694
+ pin_number: void 0
2695
+ };
2696
+ });
2697
+ return {
2698
+ sourcePorts: aliasedSourcePorts,
2699
+ includeSchematicPinNumbers: false
2700
+ };
2701
+ };
2702
+
2703
+ // lib/generate-board-schematic-tsx/convert-components.ts
2704
+ var convertComponents = (circuitJson) => {
2705
+ const textReplacements = getNativeSymbolTextReplacements(circuitJson);
2706
+ return su3(circuitJson).schematic_component.list().flatMap((schematicComponent) => {
2707
+ const symbolName = resolveNativeSchematicSymbolName({
2708
+ circuitJson,
2709
+ schematicComponent
2710
+ });
2711
+ if (symbolName && symbolName in symbols2) {
2712
+ const symbol = symbols2[symbolName];
2713
+ if (!symbol) return [];
2714
+ const isInferredSymbol = !schematicComponent.symbol_name;
2715
+ const sourceComponent = su3(circuitJson).source_component.get(
2716
+ schematicComponent.source_component_id ?? ""
2717
+ );
2718
+ const schematicPorts = su3(circuitJson).schematic_port.list({
2719
+ schematic_component_id: schematicComponent.schematic_component_id
2720
+ });
2721
+ const sourcePorts = su3(circuitJson).source_port.list({
2722
+ source_component_id: schematicComponent.source_component_id
2723
+ });
2724
+ const portMatchingInputs = getNativeSymbolPortMatchingInputs({
2725
+ symbolName,
2726
+ sourcePorts,
2727
+ schematicPorts,
2728
+ isInferredSymbol
2729
+ });
2730
+ const symbolToSchematicTransform = getSymbolToSchematicTransform({
2731
+ symbol,
2732
+ schematicComponent,
2733
+ schematicPorts,
2734
+ ...portMatchingInputs
2735
+ });
2736
+ const textReplacement = textReplacements.find(
2737
+ (replacement) => replacement.schematicComponentId === schematicComponent.schematic_component_id
2738
+ );
2739
+ const portMatches = matchSymbolPortsByPinIdentity({
2740
+ schematicPorts,
2741
+ symbol,
2742
+ ...portMatchingInputs
2743
+ });
2744
+ return [
2745
+ ...convertSymbolPrimitives({
2746
+ symbol,
2747
+ symbolToSchematicTransform,
2748
+ reference: sourceComponent?.display_name ?? sourceComponent?.name ?? "",
2749
+ displayText: isInferredSymbol ? sourceComponent?.display_value ?? schematicComponent.symbol_display_value ?? "" : schematicComponent.symbol_display_value ?? "",
2750
+ includeReference: !isInferredSymbol || textReplacement?.replacesReference,
2751
+ includeDisplayText: !isInferredSymbol || textReplacement?.includeNativeDisplayText,
2752
+ referenceFontSize: textReplacement?.referenceFontSize,
2753
+ displayTextFontSize: textReplacement?.displayTextFontSize,
2754
+ filledPrimitiveColor: isInferredSymbol ? COMPONENT_OUTLINE_COLOR : void 0
2755
+ }),
2756
+ ...isInferredSymbol && textReplacement ? convertNativeSymbolPinNumbers({
2757
+ symbol,
2758
+ symbolToSchematicTransform,
2759
+ portMatches,
2760
+ replacedPinPortIds: textReplacement.replacedPinPortIds
2761
+ }) : []
2762
+ ];
2763
+ }
2764
+ return schematicComponent.is_box_with_pins ? convertBoxComponent({ circuitJson, schematicComponent }) : [];
2765
+ });
2766
+ };
2767
+
1842
2768
  // lib/generate-board-schematic-tsx/convert-schematic-graphics.ts
1843
2769
  var convertSchematicGraphics = (circuitJson) => circuitJson.flatMap((element) => {
1844
2770
  if (element.type !== "schematic_graphic") return [];
@@ -1855,7 +2781,7 @@ var convertSchematicGraphics = (circuitJson) => circuitJson.flatMap((element) =>
1855
2781
  // lib/generate-board-schematic-tsx/convert-net-labels.ts
1856
2782
  import { su as su4 } from "@tscircuit/soup-util";
1857
2783
  import { schematic_text as schematic_text3 } from "circuit-json";
1858
- import { symbols as symbols2 } from "schematic-symbols";
2784
+ import { symbols as symbols3 } from "schematic-symbols";
1859
2785
 
1860
2786
  // lib/generate-board-schematic-tsx/get-net-label-symbol-to-schematic-transform.ts
1861
2787
  import {
@@ -1884,8 +2810,8 @@ function canRenderNativeNetLabel(name) {
1884
2810
  var convertNetLabels = (circuitJson) => su4(circuitJson).schematic_net_label.list().flatMap((schematicNetLabel) => {
1885
2811
  const anchorPosition = schematicNetLabel.anchor_position ?? schematicNetLabel.center;
1886
2812
  const symbolName = schematicNetLabel.symbol_name;
1887
- if (symbolName && symbolName in symbols2) {
1888
- const symbol = symbols2[symbolName];
2813
+ if (symbolName && symbolName in symbols3) {
2814
+ const symbol = symbols3[symbolName];
1889
2815
  if (symbol)
1890
2816
  return convertSymbolPrimitives({
1891
2817
  symbol,
@@ -3094,7 +4020,7 @@ var generateFootprintTsx = (circuitJson, context) => {
3094
4020
 
3095
4021
  // lib/board-converter/get-pcb-component-render-placement.ts
3096
4022
  import { getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
3097
- import { applyToPoint as applyToPoint5, inverse, translate as translate5 } from "transformation-matrix";
4023
+ import { applyToPoint as applyToPoint6, inverse, translate as translate5 } from "transformation-matrix";
3098
4024
  var physicalPcbElementTypes = /* @__PURE__ */ new Set([
3099
4025
  "pcb_copper_text",
3100
4026
  "pcb_cutout",
@@ -3120,7 +4046,7 @@ var getPcbComponentRenderPlacement = ({
3120
4046
  pcbBoard,
3121
4047
  pcbComponent
3122
4048
  }) => {
3123
- const componentPosition = applyToPoint5(
4049
+ const componentPosition = applyToPoint6(
3124
4050
  inverse(translate5(pcbBoard.center.x, pcbBoard.center.y)),
3125
4051
  pcbComponent.center
3126
4052
  );
@@ -3235,7 +4161,7 @@ var getSchematicComponentsForPcbComponent = ({
3235
4161
  // lib/board-converter/localize-pcb-component-elements.ts
3236
4162
  import { transformPCBElements } from "@tscircuit/circuit-json-util";
3237
4163
  import {
3238
- applyToPoint as applyToPoint6,
4164
+ applyToPoint as applyToPoint7,
3239
4165
  compose as compose4,
3240
4166
  decomposeTSR,
3241
4167
  flipY,
@@ -3277,13 +4203,13 @@ var transformSilkscreenGraphic = ({
3277
4203
  }) => {
3278
4204
  if (graphic.shape !== "brep") return;
3279
4205
  graphic.brep_shape.outer_ring.vertices = graphic.brep_shape.outer_ring.vertices.map(
3280
- (vertex) => applyToPoint6(absoluteToComponentLocalTransform, vertex)
4206
+ (vertex) => applyToPoint7(absoluteToComponentLocalTransform, vertex)
3281
4207
  );
3282
4208
  graphic.brep_shape.inner_rings = graphic.brep_shape.inner_rings.map(
3283
4209
  (ring) => ({
3284
4210
  ...ring,
3285
4211
  vertices: ring.vertices.map(
3286
- (vertex) => applyToPoint6(absoluteToComponentLocalTransform, vertex)
4212
+ (vertex) => applyToPoint7(absoluteToComponentLocalTransform, vertex)
3287
4213
  )
3288
4214
  })
3289
4215
  );
@@ -3513,6 +4439,10 @@ var convertPcbComponents = ({
3513
4439
  cadModelGroup: localizedCadModelGroup,
3514
4440
  pcbBoard
3515
4441
  }) : void 0;
4442
+ const childModelElementsTsx = localizedCadModelGroup ? generateCadModelGroupChildrenTsx({
4443
+ cadModelGroup: localizedCadModelGroup,
4444
+ pcbBoard
4445
+ }) : [];
3516
4446
  const componentProps = [
3517
4447
  `name=${formatJsxStringAttribute(componentName)}`,
3518
4448
  `pcbX={${componentPosition.x}}`,
@@ -3524,6 +4454,9 @@ var convertPcbComponents = ({
3524
4454
  if (cadModelTsx) {
3525
4455
  componentProps.push(`cadModel={${cadModelTsx}}`);
3526
4456
  }
4457
+ if (localizedCadModelGroup && isJscadCadModelGroupTranslucent(localizedCadModelGroup)) {
4458
+ componentProps.push("showAsTranslucentModel");
4459
+ }
3527
4460
  if (pinLabels) {
3528
4461
  componentProps.push(`pinLabels={${JSON.stringify(pinLabels)}}`);
3529
4462
  }
@@ -3543,8 +4476,9 @@ var convertPcbComponents = ({
3543
4476
  if (pcbComponent.obstructs_within_bounds === false) {
3544
4477
  componentProps.push("obstructsWithinBounds={false}");
3545
4478
  }
4479
+ const chipOpeningTsx = `<chip ${componentProps.join(" ")} footprint={${footprintTsx ?? "<footprint />"}}`;
3546
4480
  boardChildren.push(
3547
- `<chip ${componentProps.join(" ")} footprint={${footprintTsx ?? "<footprint />"}} />`
4481
+ childModelElementsTsx.length === 0 ? `${chipOpeningTsx} />` : `${chipOpeningTsx}>${childModelElementsTsx.join("\n")}</chip>`
3548
4482
  );
3549
4483
  }
3550
4484
  };