circuit-json-to-tscircuit 0.0.31 → 0.0.32

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.
@@ -9,6 +9,7 @@ var formatOptionalMmAttr = (attrName, value) => {
9
9
  if (value === void 0) return "";
10
10
  return ` ${attrName}="${mmStr(value)}"`;
11
11
  };
12
+ var formatSolderMaskAttrs = (platedHole) => `${platedHole.is_covered_with_solder_mask === void 0 ? "" : ` coveredWithSolderMask={${platedHole.is_covered_with_solder_mask}}`}${formatOptionalMmAttr("solderMaskMargin", platedHole.soldermask_margin)}`;
12
13
  var formatPcbRotationAttr = (rotation, attrName = "pcbRotation") => {
13
14
  if (rotation === void 0) return "";
14
15
  const formatted = typeof rotation === "number" ? `${rotation}deg` : rotation;
@@ -381,24 +382,26 @@ var convertPlatedHoles = (circuitJson) => {
381
382
  for (const platedHole of platedHoles) {
382
383
  if (platedHole.shape === "oval" || platedHole.shape === "pill") {
383
384
  elementStrings.push(
384
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" outerHeight="${mmStr3(platedHole.outer_height)}" outerWidth="${mmStr3(platedHole.outer_width)}" holeHeight="${mmStr3(platedHole.hole_height)}" holeWidth="${mmStr3(platedHole.hole_width)}" height="${mmStr3(platedHole.hole_height)}" shape="${platedHole.shape}"${formatPcbRotationAttr("ccw_rotation" in platedHole ? platedHole.ccw_rotation : void 0)} />`
385
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}"${formatSolderMaskAttrs(platedHole)} outerHeight="${mmStr3(platedHole.outer_height)}" outerWidth="${mmStr3(platedHole.outer_width)}" holeHeight="${mmStr3(platedHole.hole_height)}" holeWidth="${mmStr3(platedHole.hole_width)}" height="${mmStr3(platedHole.hole_height)}" shape="${platedHole.shape}"${formatPcbRotationAttr("ccw_rotation" in platedHole ? platedHole.ccw_rotation : void 0)} />`
385
386
  );
386
387
  } else if (platedHole.shape === "circle") {
387
388
  elementStrings.push(
388
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" outerDiameter="${mmStr3(platedHole.outer_diameter)}" holeDiameter="${mmStr3(platedHole.hole_diameter)}" shape="circle" />`
389
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}"${formatSolderMaskAttrs(platedHole)} outerDiameter="${mmStr3(platedHole.outer_diameter)}" holeDiameter="${mmStr3(platedHole.hole_diameter)}" shape="circle" />`
389
390
  );
390
391
  } else if (platedHole.shape === "circular_hole_with_rect_pad") {
391
392
  elementStrings.push(
392
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" holeDiameter="${mmStr3(platedHole.hole_diameter)}" rectPadWidth="${mmStr3(platedHole.rect_pad_width)}" rectPadHeight="${mmStr3(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)} shape="circular_hole_with_rect_pad" />`
393
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}"${platedHole.hole_shape === void 0 ? "" : ` holeShape="${platedHole.hole_shape}"`}${platedHole.pad_shape === void 0 ? "" : ` padShape="${platedHole.pad_shape}"`}${formatSolderMaskAttrs(platedHole)} holeDiameter="${mmStr3(platedHole.hole_diameter)}" rectPadWidth="${mmStr3(platedHole.rect_pad_width)}" rectPadHeight="${mmStr3(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)}${formatPcbRotationAttr(platedHole.rect_ccw_rotation)} shape="circular_hole_with_rect_pad" />`
393
394
  );
394
- } else if (platedHole.shape === "pill_hole_with_rect_pad") {
395
+ } else if (platedHole.shape === "pill_hole_with_rect_pad" || platedHole.shape === "rotated_pill_hole_with_rect_pad") {
396
+ const holeShape = platedHole.shape === "rotated_pill_hole_with_rect_pad" ? "pill" : platedHole.hole_shape;
397
+ const rotation = platedHole.shape === "rotated_pill_hole_with_rect_pad" ? platedHole.hole_ccw_rotation : void 0;
395
398
  elementStrings.push(
396
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" holeWidth="${mmStr3(platedHole.hole_width)}" holeHeight="${mmStr3(platedHole.hole_height)}" rectPadWidth="${mmStr3(platedHole.rect_pad_width)}" rectPadHeight="${mmStr3(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)} shape="pill_hole_with_rect_pad" />`
399
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}"${holeShape === void 0 ? "" : ` holeShape="${holeShape}"`}${platedHole.pad_shape === void 0 ? "" : ` padShape="${platedHole.pad_shape}"`}${formatSolderMaskAttrs(platedHole)} holeWidth="${mmStr3(platedHole.hole_width)}" holeHeight="${mmStr3(platedHole.hole_height)}" rectPadWidth="${mmStr3(platedHole.rect_pad_width)}" rectPadHeight="${mmStr3(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)}${formatPcbRotationAttr(rotation)} shape="pill_hole_with_rect_pad" />`
397
400
  );
398
401
  } else if (platedHole.shape === "hole_with_polygon_pad") {
399
402
  const holeSizeAttrs = platedHole.hole_shape === "circle" ? ` holeDiameter="${mmStr3(platedHole.hole_diameter ?? 0)}"` : `${formatOptionalMmAttr("holeWidth", platedHole.hole_width)}${formatOptionalMmAttr("holeHeight", platedHole.hole_height)}`;
400
403
  elementStrings.push(
401
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}" holeShape="${platedHole.hole_shape}"${holeSizeAttrs} padOutline={${JSON.stringify(platedHole.pad_outline)}} holeOffsetX="${mmStr3(platedHole.hole_offset_x)}" holeOffsetY="${mmStr3(platedHole.hole_offset_y)}" shape="hole_with_polygon_pad" />`
404
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr3(platedHole.x)}" pcbY="${mmStr3(platedHole.y)}"${platedHole.hole_shape === void 0 ? "" : ` holeShape="${platedHole.hole_shape}"`}${formatSolderMaskAttrs(platedHole)}${holeSizeAttrs} padOutline={${JSON.stringify(platedHole.pad_outline)}} holeOffsetX="${mmStr3(platedHole.hole_offset_x ?? 0)}" holeOffsetY="${mmStr3(platedHole.hole_offset_y ?? 0)}" shape="hole_with_polygon_pad" />`
402
405
  );
403
406
  }
404
407
  }
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-JVWZSO65.js";
4
+ } from "../chunk-Z6C3I2GJ.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.30",
19
+ version: "0.0.31",
20
20
  scripts: {
21
21
  build: "tsup-node lib/index.ts cli/main.ts --format esm --dts",
22
22
  test: "bun test",
package/dist/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  convertCircuitJsonToTscircuit
3
- } from "../chunk-JVWZSO65.js";
3
+ } from "../chunk-Z6C3I2GJ.js";
4
4
  export {
5
5
  convertCircuitJsonToTscircuit
6
6
  };
@@ -1,7 +1,11 @@
1
1
  import { su } from "@tscircuit/soup-util"
2
2
  import { mmStr } from "@tscircuit/mm"
3
3
  import type { FootprintElementConverter } from "./converter-types"
4
- import { formatOptionalMmAttr, formatPcbRotationAttr } from "./helpers"
4
+ import {
5
+ formatOptionalMmAttr,
6
+ formatPcbRotationAttr,
7
+ formatSolderMaskAttrs,
8
+ } from "./helpers"
5
9
 
6
10
  export const convertPlatedHoles: FootprintElementConverter = (circuitJson) => {
7
11
  const platedHoles = su(circuitJson).pcb_plated_hole.list()
@@ -10,19 +14,45 @@ export const convertPlatedHoles: FootprintElementConverter = (circuitJson) => {
10
14
  for (const platedHole of platedHoles) {
11
15
  if (platedHole.shape === "oval" || platedHole.shape === "pill") {
12
16
  elementStrings.push(
13
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" outerHeight="${mmStr(platedHole.outer_height)}" outerWidth="${mmStr(platedHole.outer_width)}" holeHeight="${mmStr(platedHole.hole_height)}" holeWidth="${mmStr(platedHole.hole_width)}" height="${mmStr(platedHole.hole_height)}" shape="${platedHole.shape}"${formatPcbRotationAttr("ccw_rotation" in platedHole ? platedHole.ccw_rotation : undefined)} />`,
17
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}"${formatSolderMaskAttrs(platedHole)} outerHeight="${mmStr(platedHole.outer_height)}" outerWidth="${mmStr(platedHole.outer_width)}" holeHeight="${mmStr(platedHole.hole_height)}" holeWidth="${mmStr(platedHole.hole_width)}" height="${mmStr(platedHole.hole_height)}" shape="${platedHole.shape}"${formatPcbRotationAttr("ccw_rotation" in platedHole ? platedHole.ccw_rotation : undefined)} />`,
14
18
  )
15
19
  } else if (platedHole.shape === "circle") {
16
20
  elementStrings.push(
17
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" outerDiameter="${mmStr(platedHole.outer_diameter)}" holeDiameter="${mmStr(platedHole.hole_diameter)}" shape="circle" />`,
21
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}"${formatSolderMaskAttrs(platedHole)} outerDiameter="${mmStr(platedHole.outer_diameter)}" holeDiameter="${mmStr(platedHole.hole_diameter)}" shape="circle" />`,
18
22
  )
19
23
  } else if (platedHole.shape === "circular_hole_with_rect_pad") {
20
24
  elementStrings.push(
21
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" holeDiameter="${mmStr(platedHole.hole_diameter)}" rectPadWidth="${mmStr(platedHole.rect_pad_width)}" rectPadHeight="${mmStr(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)} shape="circular_hole_with_rect_pad" />`,
25
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}"${
26
+ platedHole.hole_shape === undefined
27
+ ? ""
28
+ : ` holeShape="${platedHole.hole_shape}"`
29
+ }${
30
+ platedHole.pad_shape === undefined
31
+ ? ""
32
+ : ` padShape="${platedHole.pad_shape}"`
33
+ }${formatSolderMaskAttrs(platedHole)} holeDiameter="${mmStr(platedHole.hole_diameter)}" rectPadWidth="${mmStr(platedHole.rect_pad_width)}" rectPadHeight="${mmStr(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)}${formatPcbRotationAttr(platedHole.rect_ccw_rotation)} shape="circular_hole_with_rect_pad" />`,
22
34
  )
23
- } else if (platedHole.shape === "pill_hole_with_rect_pad") {
35
+ } else if (
36
+ platedHole.shape === "pill_hole_with_rect_pad" ||
37
+ platedHole.shape === "rotated_pill_hole_with_rect_pad"
38
+ ) {
39
+ const holeShape =
40
+ platedHole.shape === "rotated_pill_hole_with_rect_pad"
41
+ ? "pill"
42
+ : platedHole.hole_shape
43
+ const rotation =
44
+ platedHole.shape === "rotated_pill_hole_with_rect_pad"
45
+ ? platedHole.hole_ccw_rotation
46
+ : undefined
47
+
24
48
  elementStrings.push(
25
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" holeWidth="${mmStr(platedHole.hole_width)}" holeHeight="${mmStr(platedHole.hole_height)}" rectPadWidth="${mmStr(platedHole.rect_pad_width)}" rectPadHeight="${mmStr(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)} shape="pill_hole_with_rect_pad" />`,
49
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}"${
50
+ holeShape === undefined ? "" : ` holeShape="${holeShape}"`
51
+ }${
52
+ platedHole.pad_shape === undefined
53
+ ? ""
54
+ : ` padShape="${platedHole.pad_shape}"`
55
+ }${formatSolderMaskAttrs(platedHole)} holeWidth="${mmStr(platedHole.hole_width)}" holeHeight="${mmStr(platedHole.hole_height)}" rectPadWidth="${mmStr(platedHole.rect_pad_width)}" rectPadHeight="${mmStr(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)}${formatPcbRotationAttr(rotation)} shape="pill_hole_with_rect_pad" />`,
26
56
  )
27
57
  } else if (platedHole.shape === "hole_with_polygon_pad") {
28
58
  const holeSizeAttrs =
@@ -31,7 +61,11 @@ export const convertPlatedHoles: FootprintElementConverter = (circuitJson) => {
31
61
  : `${formatOptionalMmAttr("holeWidth", platedHole.hole_width)}${formatOptionalMmAttr("holeHeight", platedHole.hole_height)}`
32
62
 
33
63
  elementStrings.push(
34
- `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}" holeShape="${platedHole.hole_shape}"${holeSizeAttrs} padOutline={${JSON.stringify(platedHole.pad_outline)}} holeOffsetX="${mmStr(platedHole.hole_offset_x)}" holeOffsetY="${mmStr(platedHole.hole_offset_y)}" shape="hole_with_polygon_pad" />`,
64
+ `<platedhole portHints={${JSON.stringify(platedHole.port_hints)}} pcbX="${mmStr(platedHole.x)}" pcbY="${mmStr(platedHole.y)}"${
65
+ platedHole.hole_shape === undefined
66
+ ? ""
67
+ : ` holeShape="${platedHole.hole_shape}"`
68
+ }${formatSolderMaskAttrs(platedHole)}${holeSizeAttrs} padOutline={${JSON.stringify(platedHole.pad_outline)}} holeOffsetX="${mmStr(platedHole.hole_offset_x ?? 0)}" holeOffsetY="${mmStr(platedHole.hole_offset_y ?? 0)}" shape="hole_with_polygon_pad" />`,
35
69
  )
36
70
  }
37
71
  }
@@ -13,6 +13,16 @@ export const formatOptionalMmAttr = (
13
13
  return ` ${attrName}="${mmStr(value)}"`
14
14
  }
15
15
 
16
+ export const formatSolderMaskAttrs = (platedHole: {
17
+ is_covered_with_solder_mask?: boolean
18
+ soldermask_margin?: number
19
+ }): string =>
20
+ `${
21
+ platedHole.is_covered_with_solder_mask === undefined
22
+ ? ""
23
+ : ` coveredWithSolderMask={${platedHole.is_covered_with_solder_mask}}`
24
+ }${formatOptionalMmAttr("solderMaskMargin", platedHole.soldermask_margin)}`
25
+
16
26
  export const formatPcbRotationAttr = (
17
27
  rotation: string | number | undefined,
18
28
  attrName = "pcbRotation",
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.31",
9
+ "version": "0.0.32",
10
10
  "scripts": {
11
11
  "build": "tsup-node lib/index.ts cli/main.ts --format esm --dts",
12
12
  "test": "bun test",
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.1300"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="127.27272727272725" y="27.272727272727252" width="545.4545454545455" height="545.4545454545455" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 127.27272727272725 572.7272727272727 L 672.7272727272727 572.7272727272727 L 672.7272727272727 27.272727272727252 L 127.27272727272725 27.272727272727252 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="2.7272727272727275" data-type="pcb_board" data-pcb-layer="board"/><g data-type="pcb_plated_hole" data-pcb-layer="through"><path class="pcb-hole-outer" fill="rgb(200, 52, 52)" d="M-15,-16.363636363636363 h30 a16.363636363636363,16.363636363636363 0 0 1 0,32.72727272727273 h-30 a16.363636363636363,16.363636363636363 0 0 1 0,-32.72727272727273 z" transform="translate(296.0909090909091 300) rotate(-90)" data-type="pcb_plated_hole" data-pcb-layer="top"/><path class="pcb-hole-inner" fill="#FF26E2" d="M-11.59090909090909,-8.863636363636363 h23.18181818181818 a8.863636363636363,8.863636363636363 0 0 1 0,17.727272727272727 h-23.18181818181818 a8.863636363636363,8.863636363636363 0 0 1 0,-17.727272727272727 z" transform="translate(296.0909090909091 300) rotate(-90)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><ellipse class="pcb-hole-outer" fill="rgb(200, 52, 52)" cx="0" cy="0" rx="32.72727272727273" ry="19.09090909090909" transform="translate(400 300) rotate(-90)" data-type="pcb_plated_hole" data-pcb-layer="top"/><ellipse class="pcb-hole-inner" fill="#FF26E2" cx="0" cy="0" rx="20.454545454545453" ry="10.90909090909091" transform="translate(400 300) rotate(-90)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="475.27272727272725" y="278.1818181818182" width="57.27272727272727" height="43.63636363636364" rx="6.818181818181818" ry="6.818181818181818" data-type="pcb_plated_hole" data-pcb-layer="top"/><circle class="pcb-hole-inner" fill="#FF26E2" cx="503.9090909090909" cy="300" r="13.636363636363637" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="315.45454545454544" y="211.63636363636363" width="65.45454545454545" height="38.18181818181818" rx="6.818181818181818" ry="6.818181818181818" data-type="pcb_plated_hole" data-pcb-layer="top"/><rect class="pcb-hole-inner" fill="#FF26E2" x="331.8181818181818" y="221.1818181818182" width="43.63636363636364" height="19.09090909090909" rx="9.545454545454545" ry="9.545454545454545" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><polygon class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" points="419.09090909090907,230.72727272727272 442.27272727272725,208.9090909090909 470.9090909090909,208.9090909090909 484.5454545454545,230.72727272727272 470.9090909090909,252.54545454545456 442.27272727272725,252.54545454545456" data-type="pcb_plated_hole" data-pcb-layer="top"/><ellipse class="pcb-hole-inner" fill="#FF26E2" cx="451.8181818181818" cy="230.72727272727272" rx="19.09090909090909" ry="10.227272727272727" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><path class="pcb-hole-outer" fill="rgb(200, 52, 52)" d="M-15,-16.363636363636363 h30 a16.363636363636363,16.363636363636363 0 0 1 0,32.72727272727273 h-30 a16.363636363636363,16.363636363636363 0 0 1 0,-32.72727272727273 z" transform="translate(296.0909090909091 300) rotate(-90)" data-type="pcb_plated_hole" data-pcb-layer="top"/><path class="pcb-hole-inner" fill="#FF26E2" d="M-11.59090909090909,-8.863636363636363 h23.18181818181818 a8.863636363636363,8.863636363636363 0 0 1 0,17.727272727272727 h-23.18181818181818 a8.863636363636363,8.863636363636363 0 0 1 0,-17.727272727272727 z" transform="translate(296.0909090909091 300) rotate(-90)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><ellipse class="pcb-hole-outer" fill="rgb(200, 52, 52)" cx="0" cy="0" rx="32.72727272727273" ry="19.09090909090909" transform="translate(400 300) rotate(-90)" data-type="pcb_plated_hole" data-pcb-layer="top"/><ellipse class="pcb-hole-inner" fill="#FF26E2" cx="0" cy="0" rx="20.454545454545453" ry="10.90909090909091" transform="translate(400 300) rotate(-90)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="475.27272727272725" y="278.1818181818182" width="57.27272727272727" height="43.63636363636364" rx="6.818181818181818" ry="6.818181818181818" data-type="pcb_plated_hole" data-pcb-layer="top"/><circle class="pcb-hole-inner" fill="#FF26E2" cx="503.9090909090909" cy="300" r="13.636363636363637" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="315.45454545454544" y="211.63636363636363" width="65.45454545454545" height="38.18181818181818" rx="6.818181818181818" ry="6.818181818181818" data-type="pcb_plated_hole" data-pcb-layer="top"/><rect class="pcb-hole-inner" fill="#FF26E2" x="331.8181818181818" y="221.1818181818182" width="43.63636363636364" height="19.09090909090909" rx="9.545454545454545" ry="9.545454545454545" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><polygon class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" points="419.09090909090907,230.72727272727272 442.27272727272725,208.9090909090909 470.9090909090909,208.9090909090909 484.5454545454545,230.72727272727272 470.9090909090909,252.54545454545456 442.27272727272725,252.54545454545456" data-type="pcb_plated_hole" data-pcb-layer="top"/><ellipse class="pcb-hole-inner" fill="#FF26E2" cx="451.8181818181818" cy="230.72727272727272" rx="19.09090909090909" ry="10.227272727272727" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.1306"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="127.27272727272725" y="27.272727272727252" width="545.4545454545455" height="545.4545454545455" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 127.27272727272725 572.7272727272727 L 672.7272727272727 572.7272727272727 L 672.7272727272727 27.272727272727252 L 127.27272727272725 27.272727272727252 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="2.7272727272727275" data-type="pcb_board" data-pcb-layer="board"/><g data-type="pcb_plated_hole" data-pcb-layer="through"><path class="pcb-hole-outer" fill="rgb(200, 52, 52)" d="M-15,-16.363636363636363 h30 a16.363636363636363,16.363636363636363 0 0 1 0,32.72727272727273 h-30 a16.363636363636363,16.363636363636363 0 0 1 0,-32.72727272727273 z" transform="translate(296.0909090909091 300) rotate(-90)" data-type="pcb_plated_hole" data-pcb-layer="top"/><path class="pcb-hole-inner" fill="#FF26E2" d="M-11.59090909090909,-8.863636363636363 h23.18181818181818 a8.863636363636363,8.863636363636363 0 0 1 0,17.727272727272727 h-23.18181818181818 a8.863636363636363,8.863636363636363 0 0 1 0,-17.727272727272727 z" transform="translate(296.0909090909091 300) rotate(-90)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><ellipse class="pcb-hole-outer" fill="rgb(200, 52, 52)" cx="0" cy="0" rx="32.72727272727273" ry="19.09090909090909" transform="translate(400 300) rotate(-90)" data-type="pcb_plated_hole" data-pcb-layer="top"/><ellipse class="pcb-hole-inner" fill="#FF26E2" cx="0" cy="0" rx="20.454545454545453" ry="10.90909090909091" transform="translate(400 300) rotate(-90)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="475.27272727272725" y="278.1818181818182" width="57.27272727272727" height="43.63636363636364" rx="6.818181818181818" ry="6.818181818181818" data-type="pcb_plated_hole" data-pcb-layer="top"/><circle class="pcb-hole-inner" fill="#FF26E2" cx="503.9090909090909" cy="300" r="13.636363636363637" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="315.45454545454544" y="211.63636363636363" width="65.45454545454545" height="38.18181818181818" rx="6.818181818181818" ry="6.818181818181818" data-type="pcb_plated_hole" data-pcb-layer="top"/><rect class="pcb-hole-inner" fill="#FF26E2" x="331.8181818181818" y="221.1818181818182" width="43.63636363636364" height="19.09090909090909" rx="9.545454545454545" ry="9.545454545454545" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><polygon class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" points="419.09090909090907,230.72727272727272 442.27272727272725,208.9090909090909 470.9090909090909,208.9090909090909 484.5454545454545,230.72727272727272 470.9090909090909,252.54545454545456 442.27272727272725,252.54545454545456" data-type="pcb_plated_hole" data-pcb-layer="top"/><ellipse class="pcb-hole-inner" fill="#FF26E2" cx="451.8181818181818" cy="230.72727272727272" rx="19.09090909090909" ry="10.227272727272727" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="-31.363636363636363" y="-20.454545454545453" width="62.72727272727273" height="40.90909090909091" transform="translate(400 169.0909090909091) rotate(-35)" rx="5.454545454545455" ry="5.454545454545455" data-type="pcb_plated_hole" data-pcb-layer="top"/><rect class="pcb-hole-inner" fill="#FF26E2" x="-20.454545454545453" y="-8.181818181818182" width="40.90909090909091" height="16.363636363636363" rx="8.181818181818182" ry="8.181818181818182" transform="translate(404.09090909090907 170.45454545454544) rotate(-35)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><path class="pcb-hole-outer" fill="rgb(200, 52, 52)" d="M-15,-16.363636363636363 h30 a16.363636363636363,16.363636363636363 0 0 1 0,32.72727272727273 h-30 a16.363636363636363,16.363636363636363 0 0 1 0,-32.72727272727273 z" transform="translate(296.0909090909091 300) rotate(-90)" data-type="pcb_plated_hole" data-pcb-layer="top"/><path class="pcb-hole-inner" fill="#FF26E2" d="M-11.59090909090909,-8.863636363636363 h23.18181818181818 a8.863636363636363,8.863636363636363 0 0 1 0,17.727272727272727 h-23.18181818181818 a8.863636363636363,8.863636363636363 0 0 1 0,-17.727272727272727 z" transform="translate(296.0909090909091 300) rotate(-90)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><ellipse class="pcb-hole-outer" fill="rgb(200, 52, 52)" cx="0" cy="0" rx="32.72727272727273" ry="19.09090909090909" transform="translate(400 300) rotate(-90)" data-type="pcb_plated_hole" data-pcb-layer="top"/><ellipse class="pcb-hole-inner" fill="#FF26E2" cx="0" cy="0" rx="20.454545454545453" ry="10.90909090909091" transform="translate(400 300) rotate(-90)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="475.27272727272725" y="278.1818181818182" width="57.27272727272727" height="43.63636363636364" rx="6.818181818181818" ry="6.818181818181818" data-type="pcb_plated_hole" data-pcb-layer="top"/><circle class="pcb-hole-inner" fill="#FF26E2" cx="503.9090909090909" cy="300" r="13.636363636363637" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="315.45454545454544" y="211.63636363636363" width="65.45454545454545" height="38.18181818181818" rx="6.818181818181818" ry="6.818181818181818" data-type="pcb_plated_hole" data-pcb-layer="top"/><rect class="pcb-hole-inner" fill="#FF26E2" x="331.8181818181818" y="221.1818181818182" width="43.63636363636364" height="19.09090909090909" rx="9.545454545454545" ry="9.545454545454545" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><polygon class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" points="419.09090909090907,230.72727272727272 442.27272727272725,208.9090909090909 470.9090909090909,208.9090909090909 484.5454545454545,230.72727272727272 470.9090909090909,252.54545454545456 442.27272727272725,252.54545454545456" data-type="pcb_plated_hole" data-pcb-layer="top"/><ellipse class="pcb-hole-inner" fill="#FF26E2" cx="451.8181818181818" cy="230.72727272727272" rx="19.09090909090909" ry="10.227272727272727" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g><g data-type="pcb_plated_hole" data-pcb-layer="through"><rect class="pcb-hole-outer-pad" fill="rgb(200, 52, 52)" x="-31.363636363636363" y="-20.454545454545453" width="62.72727272727273" height="40.90909090909091" transform="translate(400 169.0909090909091) rotate(-35)" rx="5.454545454545455" ry="5.454545454545455" data-type="pcb_plated_hole" data-pcb-layer="top"/><rect class="pcb-hole-inner" fill="#FF26E2" x="-20.454545454545453" y="-8.181818181818182" width="40.90909090909091" height="16.363636363636363" rx="8.181818181818182" ry="8.181818181818182" transform="translate(404.09090909090907 170.45454545454544) rotate(-35)" data-type="pcb_plated_hole_drill" data-pcb-layer="drill"/></g></svg>
@@ -1,5 +1,5 @@
1
1
  import { test, expect } from "bun:test"
2
- import type { AnyCircuitElement } from "circuit-json"
2
+ import type { AnyCircuitElement, PcbPlatedHole } from "circuit-json"
3
3
  import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
4
4
  import { convertCircuitJsonToTscircuit } from "lib/index"
5
5
  import { runTscircuitCode } from "tscircuit"
@@ -18,6 +18,8 @@ test("test plated hole conversion", async () => {
18
18
  hole_height: 0.65,
19
19
  ccw_rotation: 90,
20
20
  layers: ["top", "bottom"],
21
+ is_covered_with_solder_mask: true,
22
+ soldermask_margin: 0.05,
21
23
  port_hints: ["1"],
22
24
  },
23
25
  {
@@ -32,6 +34,8 @@ test("test plated hole conversion", async () => {
32
34
  hole_height: 0.8,
33
35
  ccw_rotation: 90,
34
36
  layers: ["top", "bottom"],
37
+ is_covered_with_solder_mask: true,
38
+ soldermask_margin: 0.06,
35
39
  port_hints: ["2"],
36
40
  },
37
41
  {
@@ -49,6 +53,8 @@ test("test plated hole conversion", async () => {
49
53
  hole_offset_x: 0,
50
54
  hole_offset_y: 0,
51
55
  layers: ["top", "bottom"],
56
+ is_covered_with_solder_mask: true,
57
+ soldermask_margin: 0.07,
52
58
  port_hints: ["3"],
53
59
  },
54
60
  {
@@ -67,6 +73,8 @@ test("test plated hole conversion", async () => {
67
73
  hole_offset_x: 0.2,
68
74
  hole_offset_y: 0,
69
75
  layers: ["top", "bottom"],
76
+ is_covered_with_solder_mask: true,
77
+ soldermask_margin: 0.08,
70
78
  port_hints: ["4"],
71
79
  },
72
80
  {
@@ -89,8 +97,32 @@ test("test plated hole conversion", async () => {
89
97
  hole_offset_x: 0,
90
98
  hole_offset_y: 0,
91
99
  layers: ["top", "bottom"],
100
+ is_covered_with_solder_mask: true,
101
+ soldermask_margin: 0.09,
92
102
  port_hints: ["5"],
93
103
  },
104
+ {
105
+ type: "pcb_plated_hole",
106
+ pcb_plated_hole_id: "ph_rotated_rect_pill",
107
+ shape: "rotated_pill_hole_with_rect_pad",
108
+ x: 0,
109
+ y: 4.8,
110
+ hole_shape: "rotated_pill",
111
+ pad_shape: "rect",
112
+ hole_width: 1.5,
113
+ hole_height: 0.6,
114
+ hole_ccw_rotation: 35,
115
+ rect_pad_width: 2.3,
116
+ rect_pad_height: 1.5,
117
+ rect_border_radius: 0.2,
118
+ rect_ccw_rotation: 35,
119
+ hole_offset_x: 0.15,
120
+ hole_offset_y: -0.05,
121
+ layers: ["top", "bottom"],
122
+ is_covered_with_solder_mask: true,
123
+ soldermask_margin: 0.1,
124
+ port_hints: ["6"],
125
+ },
94
126
  ]
95
127
 
96
128
  const tscircuit = convertCircuitJsonToTscircuit(circuitJson, {
@@ -102,11 +134,12 @@ test("test plated hole conversion", async () => {
102
134
  export const PlatedHoleComponent = (props: ChipProps) => (
103
135
  <chip
104
136
  footprint={<footprint>
105
- <platedhole portHints={["1"]} pcbX="-3.81mm" pcbY="0mm" outerHeight="1.2mm" outerWidth="2.3mm" holeHeight="0.65mm" holeWidth="1.5mm" height="0.65mm" shape="pill" pcbRotation="90deg" />
106
- <platedhole portHints={["2"]} pcbX="0mm" pcbY="0mm" outerHeight="1.4mm" outerWidth="2.4mm" holeHeight="0.8mm" holeWidth="1.5mm" height="0.8mm" shape="oval" pcbRotation="90deg" />
107
- <platedhole portHints={["3"]} pcbX="3.81mm" pcbY="0mm" holeDiameter="1mm" rectPadWidth="2.1mm" rectPadHeight="1.6mm" rectBorderRadius="0.25mm" holeOffsetX="0mm" holeOffsetY="0mm" shape="circular_hole_with_rect_pad" />
108
- <platedhole portHints={["4"]} pcbX="-1.9mm" pcbY="2.54mm" holeWidth="1.6mm" holeHeight="0.7mm" rectPadWidth="2.4mm" rectPadHeight="1.4mm" rectBorderRadius="0.25mm" holeOffsetX="0.2mm" holeOffsetY="0mm" shape="pill_hole_with_rect_pad" />
109
- <platedhole portHints={["5"]} pcbX="1.9mm" pcbY="2.54mm" holeShape="oval" holeWidth="1.4mm" holeHeight="0.75mm" padOutline={[{"x":-1.2,"y":0},{"x":-0.35,"y":0.8},{"x":0.7,"y":0.8},{"x":1.2,"y":0},{"x":0.7,"y":-0.8},{"x":-0.35,"y":-0.8}]} holeOffsetX="0mm" holeOffsetY="0mm" shape="hole_with_polygon_pad" />
137
+ <platedhole portHints={["1"]} pcbX="-3.81mm" pcbY="0mm" coveredWithSolderMask={true} solderMaskMargin="0.05mm" outerHeight="1.2mm" outerWidth="2.3mm" holeHeight="0.65mm" holeWidth="1.5mm" height="0.65mm" shape="pill" pcbRotation="90deg" />
138
+ <platedhole portHints={["2"]} pcbX="0mm" pcbY="0mm" coveredWithSolderMask={true} solderMaskMargin="0.06mm" outerHeight="1.4mm" outerWidth="2.4mm" holeHeight="0.8mm" holeWidth="1.5mm" height="0.8mm" shape="oval" pcbRotation="90deg" />
139
+ <platedhole portHints={["3"]} pcbX="3.81mm" pcbY="0mm" holeShape="circle" padShape="rect" coveredWithSolderMask={true} solderMaskMargin="0.07mm" holeDiameter="1mm" rectPadWidth="2.1mm" rectPadHeight="1.6mm" rectBorderRadius="0.25mm" holeOffsetX="0mm" holeOffsetY="0mm" shape="circular_hole_with_rect_pad" />
140
+ <platedhole portHints={["4"]} pcbX="-1.9mm" pcbY="2.54mm" holeShape="pill" padShape="rect" coveredWithSolderMask={true} solderMaskMargin="0.08mm" holeWidth="1.6mm" holeHeight="0.7mm" rectPadWidth="2.4mm" rectPadHeight="1.4mm" rectBorderRadius="0.25mm" holeOffsetX="0.2mm" holeOffsetY="0mm" shape="pill_hole_with_rect_pad" />
141
+ <platedhole portHints={["5"]} pcbX="1.9mm" pcbY="2.54mm" holeShape="oval" coveredWithSolderMask={true} solderMaskMargin="0.09mm" holeWidth="1.4mm" holeHeight="0.75mm" padOutline={[{"x":-1.2,"y":0},{"x":-0.35,"y":0.8},{"x":0.7,"y":0.8},{"x":1.2,"y":0},{"x":0.7,"y":-0.8},{"x":-0.35,"y":-0.8}]} holeOffsetX="0mm" holeOffsetY="0mm" shape="hole_with_polygon_pad" />
142
+ <platedhole portHints={["6"]} pcbX="0mm" pcbY="4.8mm" holeShape="pill" padShape="rect" coveredWithSolderMask={true} solderMaskMargin="0.1mm" holeWidth="1.5mm" holeHeight="0.6mm" rectPadWidth="2.3mm" rectPadHeight="1.5mm" rectBorderRadius="0.2mm" holeOffsetX="0.15mm" holeOffsetY="-0.05mm" pcbRotation="35deg" shape="pill_hole_with_rect_pad" />
110
143
  </footprint>}
111
144
  {...props}
112
145
  />
@@ -126,6 +159,67 @@ circuit.add(
126
159
  expect(Array.isArray(renderedCircuitJson)).toBe(true)
127
160
  expect(renderedCircuitJson).not.toHaveLength(0)
128
161
 
162
+ const renderedPlatedHoles = renderedCircuitJson.filter(
163
+ (elm): elm is PcbPlatedHole => elm.type === "pcb_plated_hole",
164
+ )
165
+
166
+ expect(renderedPlatedHoles).toEqual(
167
+ expect.arrayContaining([
168
+ expect.objectContaining({
169
+ port_hints: expect.arrayContaining(["1"]),
170
+ shape: "pill",
171
+ is_covered_with_solder_mask: true,
172
+ soldermask_margin: 0.05,
173
+ }),
174
+ expect.objectContaining({
175
+ port_hints: expect.arrayContaining(["3"]),
176
+ shape: "circular_hole_with_rect_pad",
177
+ rect_pad_width: 2.1,
178
+ rect_pad_height: 1.6,
179
+ rect_border_radius: 0.25,
180
+ hole_offset_x: 0,
181
+ hole_offset_y: 0,
182
+ is_covered_with_solder_mask: true,
183
+ soldermask_margin: 0.07,
184
+ }),
185
+ expect.objectContaining({
186
+ port_hints: expect.arrayContaining(["4"]),
187
+ shape: "pill_hole_with_rect_pad",
188
+ rect_pad_width: 2.4,
189
+ rect_pad_height: 1.4,
190
+ hole_offset_x: 0.2,
191
+ hole_offset_y: 0,
192
+ is_covered_with_solder_mask: true,
193
+ soldermask_margin: 0.08,
194
+ }),
195
+ expect.objectContaining({
196
+ port_hints: expect.arrayContaining(["5"]),
197
+ shape: "hole_with_polygon_pad",
198
+ hole_shape: "oval",
199
+ hole_width: 1.4,
200
+ hole_height: 0.75,
201
+ hole_offset_x: 0,
202
+ hole_offset_y: 0,
203
+ is_covered_with_solder_mask: true,
204
+ soldermask_margin: 0.09,
205
+ }),
206
+ expect.objectContaining({
207
+ port_hints: expect.arrayContaining(["6"]),
208
+ shape: "rotated_pill_hole_with_rect_pad",
209
+ hole_shape: "rotated_pill",
210
+ pad_shape: "rect",
211
+ hole_width: 1.5,
212
+ hole_height: 0.6,
213
+ rect_pad_width: 2.3,
214
+ rect_pad_height: 1.5,
215
+ hole_offset_x: 0.15,
216
+ hole_offset_y: -0.05,
217
+ is_covered_with_solder_mask: true,
218
+ soldermask_margin: 0.1,
219
+ }),
220
+ ]),
221
+ )
222
+
129
223
  const pcbSvg = convertCircuitJsonToPcbSvg(renderedCircuitJson)
130
224
  await expect(pcbSvg).toMatchSvgSnapshot(import.meta.path, "pcb")
131
225
  }, 10000)