@tscircuit/footprinter 0.0.338 → 0.0.340

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.
package/dist/index.js CHANGED
@@ -1223,6 +1223,101 @@ var pillpad = (pn, x, y, w, h) => {
1223
1223
  };
1224
1224
  };
1225
1225
 
1226
+ // src/helpers/rect-union-outline.ts
1227
+ var createRectUnionOutline = (rectBoundsFromOuterToInner) => {
1228
+ if (rectBoundsFromOuterToInner.length < 2) {
1229
+ throw new Error("Rect union outline requires at least two bounds");
1230
+ }
1231
+ for (const bounds of rectBoundsFromOuterToInner) {
1232
+ if (bounds.minX >= bounds.maxX || bounds.minY >= bounds.maxY) {
1233
+ throw new Error("Each rectangle bound must have min < max on both axes");
1234
+ }
1235
+ }
1236
+ for (let i = 1; i < rectBoundsFromOuterToInner.length; i++) {
1237
+ const previous = rectBoundsFromOuterToInner[i - 1];
1238
+ const current = rectBoundsFromOuterToInner[i];
1239
+ if (current.minX < previous.minX || current.maxX > previous.maxX || current.minY > previous.minY || current.maxY < previous.maxY) {
1240
+ throw new Error(
1241
+ "Bounds must be ordered outer-to-inner with tighter X and larger Y span"
1242
+ );
1243
+ }
1244
+ }
1245
+ const buildTopLeftRouteFromInnerToOuter = () => {
1246
+ const route = [];
1247
+ let index = rectBoundsFromOuterToInner.length - 1;
1248
+ route.push({
1249
+ x: rectBoundsFromOuterToInner[index].minX,
1250
+ y: rectBoundsFromOuterToInner[index].maxY
1251
+ });
1252
+ while (index > 0) {
1253
+ const current = rectBoundsFromOuterToInner[index];
1254
+ const previous = rectBoundsFromOuterToInner[index - 1];
1255
+ route.push({ x: current.minX, y: previous.maxY });
1256
+ route.push({ x: previous.minX, y: previous.maxY });
1257
+ index -= 1;
1258
+ }
1259
+ return route;
1260
+ };
1261
+ const buildTopRightRouteFromInnerToOuter = () => {
1262
+ const route = [];
1263
+ let index = rectBoundsFromOuterToInner.length - 1;
1264
+ route.push({
1265
+ x: rectBoundsFromOuterToInner[index].maxX,
1266
+ y: rectBoundsFromOuterToInner[index].maxY
1267
+ });
1268
+ while (index > 0) {
1269
+ const current = rectBoundsFromOuterToInner[index];
1270
+ const previous = rectBoundsFromOuterToInner[index - 1];
1271
+ route.push({ x: current.maxX, y: previous.maxY });
1272
+ route.push({ x: previous.maxX, y: previous.maxY });
1273
+ index -= 1;
1274
+ }
1275
+ return route;
1276
+ };
1277
+ const buildBottomRightRouteFromInnerToOuter = () => {
1278
+ const route = [];
1279
+ let index = rectBoundsFromOuterToInner.length - 1;
1280
+ route.push({
1281
+ x: rectBoundsFromOuterToInner[index].maxX,
1282
+ y: rectBoundsFromOuterToInner[index].minY
1283
+ });
1284
+ while (index > 0) {
1285
+ const current = rectBoundsFromOuterToInner[index];
1286
+ const previous = rectBoundsFromOuterToInner[index - 1];
1287
+ route.push({ x: current.maxX, y: previous.minY });
1288
+ route.push({ x: previous.maxX, y: previous.minY });
1289
+ index -= 1;
1290
+ }
1291
+ return route;
1292
+ };
1293
+ const buildBottomLeftRouteFromInnerToOuter = () => {
1294
+ const route = [];
1295
+ let index = rectBoundsFromOuterToInner.length - 1;
1296
+ route.push({
1297
+ x: rectBoundsFromOuterToInner[index].minX,
1298
+ y: rectBoundsFromOuterToInner[index].minY
1299
+ });
1300
+ while (index > 0) {
1301
+ const current = rectBoundsFromOuterToInner[index];
1302
+ const previous = rectBoundsFromOuterToInner[index - 1];
1303
+ route.push({ x: current.minX, y: previous.minY });
1304
+ route.push({ x: previous.minX, y: previous.minY });
1305
+ index -= 1;
1306
+ }
1307
+ return route;
1308
+ };
1309
+ const topLeftInnerToOuter = buildTopLeftRouteFromInnerToOuter();
1310
+ const topRightInnerToOuter = buildTopRightRouteFromInnerToOuter();
1311
+ const bottomRightInnerToOuter = buildBottomRightRouteFromInnerToOuter();
1312
+ const bottomLeftInnerToOuter = buildBottomLeftRouteFromInnerToOuter();
1313
+ return [
1314
+ ...topLeftInnerToOuter.reverse(),
1315
+ ...topRightInnerToOuter,
1316
+ ...bottomRightInnerToOuter.reverse(),
1317
+ ...bottomLeftInnerToOuter
1318
+ ];
1319
+ };
1320
+
1226
1321
  // src/fn/soic.ts
1227
1322
  var extendSoicDef = (newDefaults) => base_def.extend({
1228
1323
  fn: z13.string(),
@@ -1313,22 +1408,33 @@ var soicWithoutParsing = (parameters) => {
1313
1408
  { x: -sw / 2, y: -sh / 2 }
1314
1409
  ]
1315
1410
  };
1316
- const courtyardPadding = 0.25;
1317
- const silkXs = silkscreenBorder.route.map((pt) => pt.x);
1318
- const silkYs = silkscreenBorder.route.map((pt) => pt.y);
1319
- const padXExtent = parameters.legsoutside ? parameters.w / 2 + parameters.pl : parameters.w / 2;
1320
- const crtMinX = Math.min(-padXExtent, ...silkXs) - courtyardPadding;
1321
- const crtMaxX = Math.max(padXExtent, ...silkXs) + courtyardPadding;
1322
- const crtMinY = Math.min(...silkYs) - courtyardPadding;
1323
- const crtMaxY = Math.max(...silkYs) + courtyardPadding;
1411
+ const roundToCourtyardGrid = (value) => Math.round(value / 0.01) * 0.01;
1412
+ const pinRowSpanY = (parameters.num_pins / 2 - 1) * parameters.p + parameters.pw;
1413
+ const courtyardStepInnerHalfX = roundToCourtyardGrid(parameters.w / 2 + 0.25);
1414
+ const courtyardStepOuterHalfX = roundToCourtyardGrid(
1415
+ courtyardStepInnerHalfX + 1.93
1416
+ );
1417
+ const courtyardStepInnerHalfY = roundToCourtyardGrid(pinRowSpanY / 2 + 0.27);
1418
+ const courtyardStepOuterHalfY = roundToCourtyardGrid(pinRowSpanY / 2 + 0.63);
1324
1419
  const courtyard = {
1325
- type: "pcb_courtyard_rect",
1326
- pcb_courtyard_rect_id: "",
1420
+ type: "pcb_courtyard_outline",
1421
+ pcb_courtyard_outline_id: "",
1327
1422
  pcb_component_id: "",
1328
- center: { x: (crtMinX + crtMaxX) / 2, y: (crtMinY + crtMaxY) / 2 },
1329
- width: crtMaxX - crtMinX,
1330
- height: crtMaxY - crtMinY,
1331
- layer: "top"
1423
+ layer: "top",
1424
+ outline: createRectUnionOutline([
1425
+ {
1426
+ minX: -courtyardStepOuterHalfX,
1427
+ maxX: courtyardStepOuterHalfX,
1428
+ minY: -courtyardStepInnerHalfY,
1429
+ maxY: courtyardStepInnerHalfY
1430
+ },
1431
+ {
1432
+ minX: -courtyardStepInnerHalfX,
1433
+ maxX: courtyardStepInnerHalfX,
1434
+ minY: -courtyardStepOuterHalfY,
1435
+ maxY: courtyardStepOuterHalfY
1436
+ }
1437
+ ])
1332
1438
  };
1333
1439
  return [
1334
1440
  ...pads,
@@ -1487,6 +1593,8 @@ var getQuadCoords = (params) => {
1487
1593
  var quad = (raw_params) => {
1488
1594
  const parameters = quad_def.parse(raw_params);
1489
1595
  const pads = [];
1596
+ let padOuterHalfX = 0;
1597
+ let padOuterHalfY = 0;
1490
1598
  const pin_map = getQuadPinMap(parameters);
1491
1599
  const spc = parameters.num_pins / 4;
1492
1600
  for (let i = 0; i < parameters.num_pins; i++) {
@@ -1503,21 +1611,27 @@ var quad = (raw_params) => {
1503
1611
  pl: parameters.pl,
1504
1612
  legsoutside: parameters.legsoutside
1505
1613
  });
1506
- let pw = parameters.pw;
1507
- let pl = parameters.pl;
1614
+ let padWidth = parameters.pw;
1615
+ let padHeight = parameters.pl;
1508
1616
  if (orientation === "vert") {
1509
1617
  ;
1510
- [pw, pl] = [pl, pw];
1618
+ [padWidth, padHeight] = [padHeight, padWidth];
1511
1619
  }
1512
1620
  const pn = pin_map[i + 1];
1513
- pads.push(rectpad(pn, x, y, pw, pl));
1621
+ padOuterHalfX = Math.max(padOuterHalfX, Math.abs(x) + padWidth / 2);
1622
+ padOuterHalfY = Math.max(padOuterHalfY, Math.abs(y) + padHeight / 2);
1623
+ pads.push(rectpad(pn, x, y, padWidth, padHeight));
1514
1624
  }
1515
1625
  if (parameters.thermalpad) {
1516
1626
  if (typeof parameters.thermalpad === "boolean") {
1517
1627
  const ibw = parameters.p * (spc - 1) + parameters.pw;
1518
1628
  const ibh = parameters.p * (spc - 1) + parameters.pw;
1629
+ padOuterHalfX = Math.max(padOuterHalfX, ibw / 2);
1630
+ padOuterHalfY = Math.max(padOuterHalfY, ibh / 2);
1519
1631
  pads.push(rectpad(["thermalpad"], 0, 0, ibw, ibh));
1520
1632
  } else {
1633
+ padOuterHalfX = Math.max(padOuterHalfX, parameters.thermalpad.x / 2);
1634
+ padOuterHalfY = Math.max(padOuterHalfY, parameters.thermalpad.y / 2);
1521
1635
  pads.push(
1522
1636
  rectpad(
1523
1637
  ["thermalpad"],
@@ -1660,21 +1774,47 @@ var quad = (raw_params) => {
1660
1774
  parameters.h / 2 + (parameters.legsoutside ? parameters.pl * 1.2 : 0.5),
1661
1775
  0.3
1662
1776
  );
1663
- const courtyardPadding = 0.25;
1664
- const padExtentX = parameters.legsoutside ? parameters.w / 2 + parameters.pl : parameters.w / 2;
1665
- const padExtentY = parameters.legsoutside ? parameters.h / 2 + parameters.pl : parameters.h / 2;
1666
- const crtMinX = -padExtentX - courtyardPadding;
1667
- const crtMaxX = padExtentX + courtyardPadding;
1668
- const crtMinY = -padExtentY - courtyardPadding;
1669
- const crtMaxY = padExtentY + courtyardPadding;
1777
+ const roundToCourtyardGrid = (value) => Math.round(value / 0.01) * 0.01;
1778
+ const roundUpToCourtyardOuterGrid = (value) => Math.ceil(value / 0.05) * 0.05;
1779
+ const pinRowSpanX = (spc - 1) * parameters.p + parameters.pw;
1780
+ const pinRowSpanY = (spc - 1) * parameters.p + parameters.pw;
1781
+ const courtyardStepInnerHalfX = roundToCourtyardGrid(pinRowSpanX / 2 + 0.25);
1782
+ const courtyardStepInnerHalfY = roundToCourtyardGrid(pinRowSpanY / 2 + 0.25);
1783
+ const courtyardStepOuterHalfX = roundToCourtyardGrid(parameters.w / 2 + 0.25);
1784
+ const courtyardStepOuterHalfY = roundToCourtyardGrid(parameters.h / 2 + 0.25);
1785
+ const courtyardOuterHalfX = Math.max(
1786
+ courtyardStepOuterHalfX,
1787
+ roundUpToCourtyardOuterGrid(padOuterHalfX + 0.25)
1788
+ );
1789
+ const courtyardOuterHalfY = Math.max(
1790
+ courtyardStepOuterHalfY,
1791
+ roundUpToCourtyardOuterGrid(padOuterHalfY + 0.25)
1792
+ );
1670
1793
  const courtyard = {
1671
- type: "pcb_courtyard_rect",
1672
- pcb_courtyard_rect_id: "",
1794
+ type: "pcb_courtyard_outline",
1795
+ pcb_courtyard_outline_id: "",
1673
1796
  pcb_component_id: "",
1674
- center: { x: (crtMinX + crtMaxX) / 2, y: (crtMinY + crtMaxY) / 2 },
1675
- width: crtMaxX - crtMinX,
1676
- height: crtMaxY - crtMinY,
1677
- layer: "top"
1797
+ layer: "top",
1798
+ outline: createRectUnionOutline([
1799
+ {
1800
+ minX: -courtyardOuterHalfX,
1801
+ maxX: courtyardOuterHalfX,
1802
+ minY: -courtyardStepInnerHalfY,
1803
+ maxY: courtyardStepInnerHalfY
1804
+ },
1805
+ {
1806
+ minX: -courtyardStepOuterHalfX,
1807
+ maxX: courtyardStepOuterHalfX,
1808
+ minY: -courtyardStepOuterHalfY,
1809
+ maxY: courtyardStepOuterHalfY
1810
+ },
1811
+ {
1812
+ minX: -courtyardStepInnerHalfX,
1813
+ maxX: courtyardStepInnerHalfX,
1814
+ minY: -courtyardOuterHalfY,
1815
+ maxY: courtyardOuterHalfY
1816
+ }
1817
+ ])
1678
1818
  };
1679
1819
  return {
1680
1820
  circuitJson: [
@@ -2553,18 +2693,17 @@ var dfn = (raw_params) => {
2553
2693
  sh / 2 + 0.4,
2554
2694
  sh / 12
2555
2695
  );
2556
- const courtyardPadding = 0.25;
2557
- const crtMinX = -sw / 2 - courtyardPadding;
2558
- const crtMaxX = sw / 2 + courtyardPadding;
2559
- const crtMinY = -sh / 2 - courtyardPadding;
2560
- const crtMaxY = sh / 2 + courtyardPadding;
2696
+ const roundUpToCourtyardGrid = (value) => Math.ceil(value / 0.05) * 0.05;
2697
+ const pinRowSpanY = (parameters.num_pins / 2 - 1) * parameters.p + parameters.pw;
2698
+ const courtyardHalfWidthMm = roundUpToCourtyardGrid(parameters.w / 2 + 0.25);
2699
+ const courtyardHalfHeightMm = roundUpToCourtyardGrid(pinRowSpanY / 2 + 0.45);
2561
2700
  const courtyard = {
2562
2701
  type: "pcb_courtyard_rect",
2563
2702
  pcb_courtyard_rect_id: "",
2564
2703
  pcb_component_id: "",
2565
- center: { x: (crtMinX + crtMaxX) / 2, y: (crtMinY + crtMaxY) / 2 },
2566
- width: crtMaxX - crtMinX,
2567
- height: crtMaxY - crtMinY,
2704
+ center: { x: 0, y: 0 },
2705
+ width: courtyardHalfWidthMm * 2,
2706
+ height: courtyardHalfHeightMm * 2,
2568
2707
  layer: "top"
2569
2708
  };
2570
2709
  return {
@@ -7958,20 +8097,33 @@ var msop = (raw_params) => {
7958
8097
  silkscreenBoxHeight / 2 + 0.5,
7959
8098
  0.3
7960
8099
  );
7961
- const courtyardPadding = 0.25;
7962
- const padCenterX = length51.parse("2mm");
7963
- const crtMinX = -(padCenterX + pl / 2) - courtyardPadding;
7964
- const crtMaxX = padCenterX + pl / 2 + courtyardPadding;
7965
- const crtMinY = -silkscreenBoxHeight / 2 - courtyardPadding;
7966
- const crtMaxY = silkscreenBoxHeight / 2 + courtyardPadding;
8100
+ const roundToCourtyardGrid = (value) => Math.round(value / 0.01) * 0.01;
8101
+ const pinRowSpanY = (parameters.num_pins / 2 - 1) * p + pw;
8102
+ const courtyardStepInnerHalfX = roundToCourtyardGrid(w / 2 + 0.25);
8103
+ const courtyardStepOuterHalfX = roundToCourtyardGrid(
8104
+ courtyardStepInnerHalfX + 1.43
8105
+ );
8106
+ const courtyardStepInnerHalfY = roundToCourtyardGrid(pinRowSpanY / 2 + 0.255);
8107
+ const courtyardStepOuterHalfY = roundToCourtyardGrid(h / 2 + 0.25);
7967
8108
  const courtyard = {
7968
- type: "pcb_courtyard_rect",
7969
- pcb_courtyard_rect_id: "",
8109
+ type: "pcb_courtyard_outline",
8110
+ pcb_courtyard_outline_id: "",
7970
8111
  pcb_component_id: "",
7971
- center: { x: (crtMinX + crtMaxX) / 2, y: (crtMinY + crtMaxY) / 2 },
7972
- width: crtMaxX - crtMinX,
7973
- height: crtMaxY - crtMinY,
7974
- layer: "top"
8112
+ layer: "top",
8113
+ outline: createRectUnionOutline([
8114
+ {
8115
+ minX: -courtyardStepOuterHalfX,
8116
+ maxX: courtyardStepOuterHalfX,
8117
+ minY: -courtyardStepInnerHalfY,
8118
+ maxY: courtyardStepInnerHalfY
8119
+ },
8120
+ {
8121
+ minX: -courtyardStepInnerHalfX,
8122
+ maxX: courtyardStepInnerHalfX,
8123
+ minY: -courtyardStepOuterHalfY,
8124
+ maxY: courtyardStepOuterHalfY
8125
+ }
8126
+ ])
7975
8127
  };
7976
8128
  return {
7977
8129
  circuitJson: [