circuit-json-to-tscircuit 0.0.73 → 0.0.74

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.
@@ -572,6 +572,104 @@ var convertSymbolPrimitives = ({
572
572
  import { su as su2 } from "@tscircuit/soup-util";
573
573
  import "circuit-json";
574
574
 
575
+ // lib/generate-board-schematic-tsx/convert-box-port-markers.ts
576
+ var ARROW_SIZE = 0.1;
577
+ var ARROW_HALF_ANGLE_RADIANS = Math.PI / 6;
578
+ var ARROW_AXIAL_LENGTH = ARROW_SIZE * Math.cos(ARROW_HALF_ANGLE_RADIANS);
579
+ var ARROW_HALF_WIDTH = ARROW_SIZE * Math.sin(ARROW_HALF_ANGLE_RADIANS);
580
+ var MARKER_STROKE_WIDTH = 0.02 / 3;
581
+ var MARKER_STROKE_COLOR = "#840000";
582
+ var MARKER_FILL_COLOR = "#ffffff";
583
+ var INVERSION_BUBBLE_RADIUS = 0.06;
584
+ var getOutwardDirection = (side) => {
585
+ switch (side) {
586
+ case "left":
587
+ return { x: -1, y: 0 };
588
+ case "right":
589
+ return { x: 1, y: 0 };
590
+ case "top":
591
+ return { x: 0, y: 1 };
592
+ case "bottom":
593
+ return { x: 0, y: -1 };
594
+ default:
595
+ return null;
596
+ }
597
+ };
598
+ var createArrowPath = ({
599
+ tip,
600
+ direction
601
+ }) => {
602
+ const base = {
603
+ x: tip.x - direction.x * ARROW_AXIAL_LENGTH,
604
+ y: tip.y - direction.y * ARROW_AXIAL_LENGTH
605
+ };
606
+ const perpendicular = { x: -direction.y, y: direction.x };
607
+ const firstBaseCorner = {
608
+ x: base.x + perpendicular.x * ARROW_HALF_WIDTH,
609
+ y: base.y + perpendicular.y * ARROW_HALF_WIDTH
610
+ };
611
+ const secondBaseCorner = {
612
+ x: base.x - perpendicular.x * ARROW_HALF_WIDTH,
613
+ y: base.y - perpendicular.y * ARROW_HALF_WIDTH
614
+ };
615
+ return formatElement("schematicpath", {
616
+ points: [tip, firstBaseCorner, secondBaseCorner, tip],
617
+ strokeWidth: MARKER_STROKE_WIDTH,
618
+ strokeColor: MARKER_STROKE_COLOR,
619
+ fillColor: MARKER_FILL_COLOR,
620
+ isFilled: true
621
+ });
622
+ };
623
+ var convertBoxPortMarkers = ({
624
+ schematicPort,
625
+ edge
626
+ }) => {
627
+ const outward = getOutwardDirection(schematicPort.side_of_component);
628
+ if (!outward) return { markers: [], pinLineStart: edge };
629
+ const inversionOffset = schematicPort.is_drawn_with_inversion_circle ? INVERSION_BUBBLE_RADIUS * 2 : 0;
630
+ const pinLineStart = {
631
+ x: edge.x + outward.x * inversionOffset,
632
+ y: edge.y + outward.y * inversionOffset
633
+ };
634
+ const markers = [];
635
+ if (schematicPort.is_drawn_with_inversion_circle) {
636
+ markers.push(
637
+ formatElement("schematiccircle", {
638
+ center: {
639
+ x: edge.x + outward.x * INVERSION_BUBBLE_RADIUS,
640
+ y: edge.y + outward.y * INVERSION_BUBBLE_RADIUS
641
+ },
642
+ radius: INVERSION_BUBBLE_RADIUS,
643
+ strokeWidth: MARKER_STROKE_WIDTH * 3,
644
+ color: MARKER_STROKE_COLOR,
645
+ fillColor: MARKER_FILL_COLOR,
646
+ isFilled: true
647
+ })
648
+ );
649
+ }
650
+ if (schematicPort.has_input_arrow) {
651
+ markers.push(
652
+ createArrowPath({
653
+ tip: pinLineStart,
654
+ direction: { x: -outward.x, y: -outward.y }
655
+ })
656
+ );
657
+ }
658
+ if (schematicPort.has_output_arrow) {
659
+ const separation = schematicPort.has_input_arrow ? ARROW_AXIAL_LENGTH : 0;
660
+ markers.push(
661
+ createArrowPath({
662
+ tip: {
663
+ x: pinLineStart.x + outward.x * (separation + ARROW_SIZE),
664
+ y: pinLineStart.y + outward.y * (separation + ARROW_SIZE)
665
+ },
666
+ direction: outward
667
+ })
668
+ );
669
+ }
670
+ return { markers, pinLineStart };
671
+ };
672
+
575
673
  // lib/generate-board-schematic-tsx/get-box-pin-display-label.ts
576
674
  var getBoxPinDisplayLabel = ({
577
675
  schematicPort,
@@ -624,16 +722,21 @@ var convertBoxComponent = ({
624
722
  edge.y = schematicComponent.center.y - schematicComponent.size.height / 2;
625
723
  break;
626
724
  }
725
+ const { markers, pinLineStart } = convertBoxPortMarkers({
726
+ schematicPort,
727
+ edge
728
+ });
627
729
  primitives.push(
628
730
  formatElement("schematicline", {
629
- x1: edge.x,
630
- y1: edge.y,
731
+ x1: pinLineStart.x,
732
+ y1: pinLineStart.y,
631
733
  x2: schematicPort.center.x,
632
734
  y2: schematicPort.center.y,
633
735
  strokeWidth: DEFAULT_BOX_BODY_STROKE_WIDTH,
634
736
  color: DEFAULT_BOX_BODY_STROKE_COLOR
635
737
  })
636
738
  );
739
+ primitives.push(...markers);
637
740
  const sourcePort = su2(circuitJson).source_port.get(
638
741
  schematicPort.source_port_id
639
742
  );
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-5YQBNWPZ.js";
4
+ } from "../chunk-KDQXBFSE.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.72",
19
+ version: "0.0.73",
20
20
  repository: {
21
21
  type: "git",
22
22
  url: "https://github.com/tscircuit/circuit-json-to-tscircuit.git"
package/dist/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  convertCircuitJsonToTscircuit
3
- } from "../chunk-5YQBNWPZ.js";
3
+ } from "../chunk-KDQXBFSE.js";
4
4
  export {
5
5
  convertCircuitJsonToTscircuit
6
6
  };
@@ -1,6 +1,7 @@
1
1
  import { su } from "@tscircuit/soup-util"
2
2
  import { type AnyCircuitElement, type SchematicComponent } from "circuit-json"
3
3
  import { convertRect } from "./convert-rect"
4
+ import { convertBoxPortMarkers } from "./convert-box-port-markers"
4
5
  import { formatElement } from "./format-attributes"
5
6
  import { getBoxPinDisplayLabel } from "./get-box-pin-display-label"
6
7
 
@@ -55,16 +56,21 @@ export const convertBoxComponent = ({
55
56
  schematicComponent.center.y - schematicComponent.size.height / 2
56
57
  break
57
58
  }
59
+ const { markers, pinLineStart } = convertBoxPortMarkers({
60
+ schematicPort,
61
+ edge,
62
+ })
58
63
  primitives.push(
59
64
  formatElement("schematicline", {
60
- x1: edge.x,
61
- y1: edge.y,
65
+ x1: pinLineStart.x,
66
+ y1: pinLineStart.y,
62
67
  x2: schematicPort.center.x,
63
68
  y2: schematicPort.center.y,
64
69
  strokeWidth: DEFAULT_BOX_BODY_STROKE_WIDTH,
65
70
  color: DEFAULT_BOX_BODY_STROKE_COLOR,
66
71
  }),
67
72
  )
73
+ primitives.push(...markers)
68
74
  const sourcePort = su(circuitJson).source_port.get(
69
75
  schematicPort.source_port_id,
70
76
  )
@@ -0,0 +1,114 @@
1
+ import type { Point, SchematicPort } from "circuit-json"
2
+ import { formatElement } from "./format-attributes"
3
+
4
+ const ARROW_SIZE = 0.1
5
+ const ARROW_HALF_ANGLE_RADIANS = Math.PI / 6
6
+ const ARROW_AXIAL_LENGTH = ARROW_SIZE * Math.cos(ARROW_HALF_ANGLE_RADIANS)
7
+ const ARROW_HALF_WIDTH = ARROW_SIZE * Math.sin(ARROW_HALF_ANGLE_RADIANS)
8
+ const MARKER_STROKE_WIDTH = 0.02 / 3
9
+ const MARKER_STROKE_COLOR = "#840000"
10
+ const MARKER_FILL_COLOR = "#ffffff"
11
+ const INVERSION_BUBBLE_RADIUS = 0.06
12
+
13
+ const getOutwardDirection = (
14
+ side: SchematicPort["side_of_component"],
15
+ ): Point | null => {
16
+ switch (side) {
17
+ case "left":
18
+ return { x: -1, y: 0 }
19
+ case "right":
20
+ return { x: 1, y: 0 }
21
+ case "top":
22
+ return { x: 0, y: 1 }
23
+ case "bottom":
24
+ return { x: 0, y: -1 }
25
+ default:
26
+ return null
27
+ }
28
+ }
29
+
30
+ const createArrowPath = ({
31
+ tip,
32
+ direction,
33
+ }: {
34
+ tip: Point
35
+ direction: Point
36
+ }): string => {
37
+ const base = {
38
+ x: tip.x - direction.x * ARROW_AXIAL_LENGTH,
39
+ y: tip.y - direction.y * ARROW_AXIAL_LENGTH,
40
+ }
41
+ const perpendicular = { x: -direction.y, y: direction.x }
42
+ const firstBaseCorner = {
43
+ x: base.x + perpendicular.x * ARROW_HALF_WIDTH,
44
+ y: base.y + perpendicular.y * ARROW_HALF_WIDTH,
45
+ }
46
+ const secondBaseCorner = {
47
+ x: base.x - perpendicular.x * ARROW_HALF_WIDTH,
48
+ y: base.y - perpendicular.y * ARROW_HALF_WIDTH,
49
+ }
50
+ return formatElement("schematicpath", {
51
+ points: [tip, firstBaseCorner, secondBaseCorner, tip],
52
+ strokeWidth: MARKER_STROKE_WIDTH,
53
+ strokeColor: MARKER_STROKE_COLOR,
54
+ fillColor: MARKER_FILL_COLOR,
55
+ isFilled: true,
56
+ })
57
+ }
58
+
59
+ export const convertBoxPortMarkers = ({
60
+ schematicPort,
61
+ edge,
62
+ }: {
63
+ schematicPort: SchematicPort
64
+ edge: Point
65
+ }): { markers: string[]; pinLineStart: Point } => {
66
+ const outward = getOutwardDirection(schematicPort.side_of_component)
67
+ if (!outward) return { markers: [], pinLineStart: edge }
68
+
69
+ const inversionOffset = schematicPort.is_drawn_with_inversion_circle
70
+ ? INVERSION_BUBBLE_RADIUS * 2
71
+ : 0
72
+ const pinLineStart = {
73
+ x: edge.x + outward.x * inversionOffset,
74
+ y: edge.y + outward.y * inversionOffset,
75
+ }
76
+ const markers: string[] = []
77
+
78
+ if (schematicPort.is_drawn_with_inversion_circle) {
79
+ markers.push(
80
+ formatElement("schematiccircle", {
81
+ center: {
82
+ x: edge.x + outward.x * INVERSION_BUBBLE_RADIUS,
83
+ y: edge.y + outward.y * INVERSION_BUBBLE_RADIUS,
84
+ },
85
+ radius: INVERSION_BUBBLE_RADIUS,
86
+ strokeWidth: MARKER_STROKE_WIDTH * 3,
87
+ color: MARKER_STROKE_COLOR,
88
+ fillColor: MARKER_FILL_COLOR,
89
+ isFilled: true,
90
+ }),
91
+ )
92
+ }
93
+ if (schematicPort.has_input_arrow) {
94
+ markers.push(
95
+ createArrowPath({
96
+ tip: pinLineStart,
97
+ direction: { x: -outward.x, y: -outward.y },
98
+ }),
99
+ )
100
+ }
101
+ if (schematicPort.has_output_arrow) {
102
+ const separation = schematicPort.has_input_arrow ? ARROW_AXIAL_LENGTH : 0
103
+ markers.push(
104
+ createArrowPath({
105
+ tip: {
106
+ x: pinLineStart.x + outward.x * (separation + ARROW_SIZE),
107
+ y: pinLineStart.y + outward.y * (separation + ARROW_SIZE),
108
+ },
109
+ direction: outward,
110
+ }),
111
+ )
112
+ }
113
+ return { markers, pinLineStart }
114
+ }
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "./cli": "./dist/cli/main.js"
7
7
  },
8
8
  "type": "module",
9
- "version": "0.0.73",
9
+ "version": "0.0.74",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "https://github.com/tscircuit/circuit-json-to-tscircuit.git"
@@ -0,0 +1,103 @@
1
+ import { expect, test } from "bun:test"
2
+ import type { CircuitJson } from "circuit-json"
3
+ import { convertCircuitJsonToTscircuit } from "lib"
4
+ import { runTscircuitCode } from "tscircuit"
5
+
6
+ test("preserves input and output arrows on imported box pins", async () => {
7
+ const circuitJson: CircuitJson = [
8
+ {
9
+ type: "pcb_board",
10
+ pcb_board_id: "board",
11
+ center: { x: 0, y: 0 },
12
+ width: 10,
13
+ height: 10,
14
+ num_layers: 2,
15
+ thickness: 1.6,
16
+ material: "fr4",
17
+ },
18
+ {
19
+ type: "schematic_component",
20
+ schematic_component_id: "controller",
21
+ center: { x: 0, y: 0 },
22
+ size: { width: 2, height: 2 },
23
+ is_box_with_pins: true,
24
+ },
25
+ {
26
+ type: "schematic_port",
27
+ schematic_port_id: "output",
28
+ source_port_id: "output_source",
29
+ schematic_component_id: "controller",
30
+ center: { x: -1.4, y: 0 },
31
+ side_of_component: "left",
32
+ facing_direction: "left",
33
+ has_output_arrow: true,
34
+ is_drawn_with_inversion_circle: true,
35
+ pin_number: 1,
36
+ },
37
+ {
38
+ type: "schematic_port",
39
+ schematic_port_id: "input",
40
+ source_port_id: "input_source",
41
+ schematic_component_id: "controller",
42
+ center: { x: 1.4, y: 0.4 },
43
+ side_of_component: "right",
44
+ facing_direction: "right",
45
+ has_input_arrow: true,
46
+ is_drawn_with_inversion_circle: true,
47
+ pin_number: 2,
48
+ },
49
+ ]
50
+ const renderedCircuitJson = await runTscircuitCode(
51
+ convertCircuitJsonToTscircuit(circuitJson, {
52
+ componentName: "ArrowPinBoard",
53
+ }),
54
+ )
55
+ const arrowPaths = renderedCircuitJson.flatMap((element) =>
56
+ element.type === "schematic_path" &&
57
+ element.is_filled &&
58
+ element.fill_color === "#ffffff"
59
+ ? [element]
60
+ : [],
61
+ )
62
+
63
+ expect(arrowPaths).toHaveLength(2)
64
+ expect(
65
+ arrowPaths.some((path) =>
66
+ path.points.some(
67
+ (point) => Math.abs(point.x + 1.22) < 0.000001 && point.y === 0,
68
+ ),
69
+ ),
70
+ ).toBe(true)
71
+ expect(
72
+ arrowPaths.some((path) =>
73
+ path.points.some(
74
+ (point) =>
75
+ Math.abs(point.x - 1.12) < 0.000001 &&
76
+ Math.abs(point.y - 0.4) < 0.000001,
77
+ ),
78
+ ),
79
+ ).toBe(true)
80
+
81
+ const inversionCircles = renderedCircuitJson.flatMap((element) =>
82
+ element.type === "schematic_circle" &&
83
+ element.is_filled &&
84
+ element.fill_color === "#ffffff" &&
85
+ element.radius === 0.06
86
+ ? [element]
87
+ : [],
88
+ )
89
+ expect(inversionCircles).toHaveLength(2)
90
+ expect(inversionCircles.map((circle) => circle.center.x).sort()).toEqual([
91
+ -1.06, 1.06,
92
+ ])
93
+
94
+ const shiftedPinLines = renderedCircuitJson.flatMap((element) =>
95
+ element.type === "schematic_line" &&
96
+ ((Math.abs(element.x1 + 1.12) < 0.000001 && element.y1 === 0) ||
97
+ (Math.abs(element.x1 - 1.12) < 0.000001 &&
98
+ Math.abs(element.y1 - 0.4) < 0.000001))
99
+ ? [element]
100
+ : [],
101
+ )
102
+ expect(shiftedPinLines).toHaveLength(2)
103
+ })