@tscircuit/core 0.0.1297 → 0.0.1299

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 (2) hide show
  1. package/dist/index.js +269 -69
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10230,6 +10230,117 @@ var getAllDimensionsForSchematicBox = (params) => {
10230
10230
  sideLengths.right + DEFAULT_SCHEMATIC_BOX_PADDING_MM
10231
10231
  );
10232
10232
  }
10233
+ if (params.pinLabels) {
10234
+ const CHAR_WIDTH = 0.13;
10235
+ const LABEL_EDGE_OFFSET = 0.1;
10236
+ const HALF_TEXT = 0.075;
10237
+ const getLabelLen = (pinNumber) => {
10238
+ const label = params.pinLabels[`pin${pinNumber}`] ?? params.pinLabels[`${pinNumber}`];
10239
+ return label ? label.length * CHAR_WIDTH : 0;
10240
+ };
10241
+ const leftLabels = orderedTruePorts.filter((p) => p.side === "left").map((p) => ({
10242
+ y: sideLengths.left / 2 - p.distanceFromOrthogonalEdge,
10243
+ len: getLabelLen(p.pinNumber)
10244
+ })).filter((p) => p.len > 0);
10245
+ const rightLabels = orderedTruePorts.filter((p) => p.side === "right").map((p) => ({
10246
+ y: -sideLengths.right / 2 + p.distanceFromOrthogonalEdge,
10247
+ len: getLabelLen(p.pinNumber)
10248
+ })).filter((p) => p.len > 0);
10249
+ const topLabels = orderedTruePorts.filter((p) => p.side === "top").map((p) => ({
10250
+ x: sideLengths.top / 2 - p.distanceFromOrthogonalEdge,
10251
+ len: getLabelLen(p.pinNumber)
10252
+ })).filter((p) => p.len > 0);
10253
+ const bottomLabels = orderedTruePorts.filter((p) => p.side === "bottom").map((p) => ({
10254
+ x: -sideLengths.bottom / 2 + p.distanceFromOrthogonalEdge,
10255
+ len: getLabelLen(p.pinNumber)
10256
+ })).filter((p) => p.len > 0);
10257
+ const rectsOverlap = (a, b) => Math.min(a.maxX, b.maxX) > Math.max(a.minX, b.minX) && Math.min(a.maxY, b.maxY) > Math.max(a.minY, b.minY);
10258
+ const getLeftRect = (label, width) => ({
10259
+ minX: -width / 2 + LABEL_EDGE_OFFSET,
10260
+ maxX: -width / 2 + LABEL_EDGE_OFFSET + label.len,
10261
+ minY: label.y - HALF_TEXT,
10262
+ maxY: label.y + HALF_TEXT
10263
+ });
10264
+ const getRightRect = (label, width) => ({
10265
+ minX: width / 2 - LABEL_EDGE_OFFSET - label.len,
10266
+ maxX: width / 2 - LABEL_EDGE_OFFSET,
10267
+ minY: label.y - HALF_TEXT,
10268
+ maxY: label.y + HALF_TEXT
10269
+ });
10270
+ const getTopRect = (label, height) => ({
10271
+ minX: label.x - HALF_TEXT,
10272
+ maxX: label.x + HALF_TEXT,
10273
+ minY: height / 2 - LABEL_EDGE_OFFSET - label.len,
10274
+ maxY: height / 2 - LABEL_EDGE_OFFSET
10275
+ });
10276
+ const getBottomRect = (label, height) => ({
10277
+ minX: label.x - HALF_TEXT,
10278
+ maxX: label.x + HALF_TEXT,
10279
+ minY: -height / 2 + LABEL_EDGE_OFFSET,
10280
+ maxY: -height / 2 + LABEL_EDGE_OFFSET + label.len
10281
+ });
10282
+ if (!params.schHeight) {
10283
+ let hasTopBottomLabelCollision = false;
10284
+ for (const topLabel of topLabels) {
10285
+ for (const bottomLabel of bottomLabels) {
10286
+ if (rectsOverlap(
10287
+ getTopRect(topLabel, schHeight),
10288
+ getBottomRect(bottomLabel, schHeight)
10289
+ )) {
10290
+ hasTopBottomLabelCollision = true;
10291
+ schHeight = Math.max(
10292
+ schHeight,
10293
+ topLabel.len + bottomLabel.len + 2 * LABEL_EDGE_OFFSET
10294
+ );
10295
+ }
10296
+ }
10297
+ }
10298
+ if (hasTopBottomLabelCollision) {
10299
+ for (const topLabel of topLabels) {
10300
+ const topRect = getTopRect(topLabel, schHeight);
10301
+ for (const leftLabel of leftLabels) {
10302
+ const leftRect = getLeftRect(leftLabel, resolvedSchWidth);
10303
+ if (rectsOverlap(topRect, leftRect)) {
10304
+ schHeight = Math.max(
10305
+ schHeight,
10306
+ 2 * (leftRect.maxY + LABEL_EDGE_OFFSET + topLabel.len)
10307
+ );
10308
+ }
10309
+ }
10310
+ for (const rightLabel of rightLabels) {
10311
+ const rightRect = getRightRect(rightLabel, resolvedSchWidth);
10312
+ if (rectsOverlap(topRect, rightRect)) {
10313
+ schHeight = Math.max(
10314
+ schHeight,
10315
+ 2 * (rightRect.maxY + LABEL_EDGE_OFFSET + topLabel.len)
10316
+ );
10317
+ }
10318
+ }
10319
+ }
10320
+ for (const bottomLabel of bottomLabels) {
10321
+ const bottomRect = getBottomRect(bottomLabel, schHeight);
10322
+ for (const leftLabel of leftLabels) {
10323
+ const leftRect = getLeftRect(leftLabel, resolvedSchWidth);
10324
+ if (rectsOverlap(bottomRect, leftRect)) {
10325
+ schHeight = Math.max(
10326
+ schHeight,
10327
+ 2 * (LABEL_EDGE_OFFSET + bottomLabel.len - leftRect.minY)
10328
+ );
10329
+ }
10330
+ }
10331
+ for (const rightLabel of rightLabels) {
10332
+ const rightRect = getRightRect(rightLabel, resolvedSchWidth);
10333
+ if (rectsOverlap(bottomRect, rightRect)) {
10334
+ schHeight = Math.max(
10335
+ schHeight,
10336
+ 2 * (LABEL_EDGE_OFFSET + bottomLabel.len - rightRect.minY)
10337
+ );
10338
+ }
10339
+ }
10340
+ }
10341
+ }
10342
+ }
10343
+ }
10233
10344
  const trueEdgePositions = {
10234
10345
  // Top left corner
10235
10346
  left: {
@@ -13769,7 +13880,7 @@ import {
13769
13880
  groupProps
13770
13881
  } from "@tscircuit/props";
13771
13882
  import {
13772
- distance as distance10
13883
+ distance as distance11
13773
13884
  } from "circuit-json";
13774
13885
  import Debug14 from "debug";
13775
13886
 
@@ -14476,6 +14587,56 @@ var getUnbrokenCopperPourObstacles = ({
14476
14587
  return obstacles;
14477
14588
  };
14478
14589
 
14590
+ // lib/utils/autorouting/trimRouteEndsAtBreakoutPoints.ts
14591
+ import {
14592
+ distance as distance9,
14593
+ getUnitVectorFromPointAToB as getUnitVectorFromPointAToB2
14594
+ } from "@tscircuit/math-utils";
14595
+ var DEFAULT_BREAKOUT_HANDOFF_TRIM_MM = 0.6;
14596
+ var getPointXY = (routePoint) => {
14597
+ const { x, y } = routePoint;
14598
+ return typeof x === "number" && typeof y === "number" ? { x, y } : null;
14599
+ };
14600
+ var trimRouteEndsAtBreakoutPoints = ({
14601
+ route,
14602
+ breakoutPointPositions,
14603
+ trimMm = DEFAULT_BREAKOUT_HANDOFF_TRIM_MM
14604
+ }) => {
14605
+ if (breakoutPointPositions.length === 0 || route.length < 2) return route;
14606
+ const isAtBreakoutPoint = (point6) => breakoutPointPositions.some((bp) => distance9(bp, point6) < 0.05);
14607
+ const trimFront = (points) => {
14608
+ const out = [...points];
14609
+ let remaining = trimMm;
14610
+ while (out.length >= 2 && remaining > 1e-9) {
14611
+ const a = getPointXY(out[0]);
14612
+ const b = getPointXY(out[1]);
14613
+ if (!a || !b) break;
14614
+ const segmentLength = distance9(a, b);
14615
+ if (segmentLength <= remaining + 1e-9) {
14616
+ out.shift();
14617
+ remaining -= segmentLength;
14618
+ } else {
14619
+ const unit = getUnitVectorFromPointAToB2(a, b);
14620
+ out[0] = {
14621
+ ...out[0],
14622
+ x: a.x + unit.x * remaining,
14623
+ y: a.y + unit.y * remaining
14624
+ };
14625
+ remaining = 0;
14626
+ }
14627
+ }
14628
+ return out;
14629
+ };
14630
+ let trimmed = route;
14631
+ const first = getPointXY(trimmed[0]);
14632
+ if (first && isAtBreakoutPoint(first)) trimmed = trimFront(trimmed);
14633
+ const last = getPointXY(trimmed[trimmed.length - 1]);
14634
+ if (last && trimmed.length >= 2 && isAtBreakoutPoint(last)) {
14635
+ trimmed = trimFront([...trimmed].reverse()).reverse();
14636
+ }
14637
+ return trimmed;
14638
+ };
14639
+
14479
14640
  // lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts
14480
14641
  var getSimpleRouteJsonFromCircuitJson = ({
14481
14642
  db,
@@ -14514,6 +14675,7 @@ var getSimpleRouteJsonFromCircuitJson = ({
14514
14675
  (e) => !subcircuit_id || "subcircuit_id" in e && relevantSubcircuitIds.has(e.subcircuit_id)
14515
14676
  );
14516
14677
  let board = null;
14678
+ let subcircuitIsBoard = false;
14517
14679
  if (subcircuit_id) {
14518
14680
  const source_group_id = subcircuit_id.replace(/^subcircuit_/, "");
14519
14681
  const source_board = db.source_board.getWhere({ source_group_id });
@@ -14521,6 +14683,7 @@ var getSimpleRouteJsonFromCircuitJson = ({
14521
14683
  board = db.pcb_board.getWhere({
14522
14684
  source_board_id: source_board.source_board_id
14523
14685
  });
14686
+ if (board) subcircuitIsBoard = true;
14524
14687
  }
14525
14688
  }
14526
14689
  if (!board) {
@@ -14554,13 +14717,24 @@ var getSimpleRouteJsonFromCircuitJson = ({
14554
14717
  group: pcbGroup
14555
14718
  })
14556
14719
  );
14720
+ const breakoutPointPositions = breakoutPoints.map((bp) => ({
14721
+ x: bp.x,
14722
+ y: bp.y
14723
+ }));
14724
+ const breakoutHandoffTrimMm = (minViaPadDiameter ?? board?.min_via_pad_diameter ?? 0.3) + 2 * (minTraceWidth ?? board?.min_trace_width ?? 0.15) + (minTraceToPadEdgeClearance ?? board?.min_trace_to_pad_edge_clearance ?? 0.1);
14557
14725
  const descendantTraces = subcircuit_id ? db.pcb_trace.list().filter(
14558
14726
  (t) => t.subcircuit_id && t.subcircuit_id !== subcircuit_id && relevantSubcircuitIds.has(t.subcircuit_id)
14559
14727
  ).map((t) => ({
14560
14728
  type: "pcb_trace",
14561
14729
  pcb_trace_id: t.pcb_trace_id,
14562
- route: t.route
14563
- })) : [];
14730
+ source_trace_id: t.source_trace_id,
14731
+ connection_name: t.source_trace_id ?? t.connection_name ?? t.pcb_trace_id,
14732
+ route: trimRouteEndsAtBreakoutPoints({
14733
+ route: t.route,
14734
+ breakoutPointPositions,
14735
+ trimMm: breakoutHandoffTrimMm
14736
+ })
14737
+ })).filter((t) => t.route.length >= 2) : [];
14564
14738
  for (const obstacle of obstacles) {
14565
14739
  const additionalIds = obstacle.connectedTo.flatMap(
14566
14740
  (id) => connMap.getIdsConnectedToNet(id)
@@ -14624,7 +14798,15 @@ var getSimpleRouteJsonFromCircuitJson = ({
14624
14798
  }
14625
14799
  ]).concat(board?.outline ?? []);
14626
14800
  let bounds;
14627
- if (board && !board.outline) {
14801
+ const useGroupBoundsAsSrjBounds = !!(pcbGroup?.width && pcbGroup.height && subcircuit_id && !subcircuitIsBoard);
14802
+ if (useGroupBoundsAsSrjBounds) {
14803
+ bounds = {
14804
+ minX: pcbGroup.center.x - pcbGroup.width / 2,
14805
+ maxX: pcbGroup.center.x + pcbGroup.width / 2,
14806
+ minY: pcbGroup.center.y - pcbGroup.height / 2,
14807
+ maxY: pcbGroup.center.y + pcbGroup.height / 2
14808
+ };
14809
+ } else if (board && !board.outline) {
14628
14810
  bounds = {
14629
14811
  minX: board.center.x - board.width / 2,
14630
14812
  maxX: board.center.x + board.width / 2,
@@ -14639,7 +14821,7 @@ var getSimpleRouteJsonFromCircuitJson = ({
14639
14821
  maxY: Math.max(...allPoints.map((p) => p.y)) + 1
14640
14822
  };
14641
14823
  }
14642
- if (pcbGroup?.width && pcbGroup.height) {
14824
+ if (pcbGroup?.width && pcbGroup.height && !useGroupBoundsAsSrjBounds) {
14643
14825
  const groupBounds = {
14644
14826
  minX: pcbGroup.center.x - pcbGroup.width / 2,
14645
14827
  maxX: pcbGroup.center.x + pcbGroup.width / 2,
@@ -19688,7 +19870,7 @@ function addPortIdsToTracesAtJumperPads(segments, db) {
19688
19870
  }
19689
19871
 
19690
19872
  // lib/components/primitive-components/Group/get-source-trace-id-for-routed-trace.ts
19691
- import { distance as distance9, pointToSegmentDistance } from "@tscircuit/math-utils";
19873
+ import { distance as distance10, pointToSegmentDistance } from "@tscircuit/math-utils";
19692
19874
  import { ConnectivityMap as ConnectivityMap3 } from "circuit-json-to-connectivity-map";
19693
19875
  var POINT_EPSILON = 1e-6;
19694
19876
  function isPointOnWireSegment({
@@ -19710,7 +19892,7 @@ function isPointInSmtPad({
19710
19892
  return Math.abs(point6.x - pad.x) <= pad.width / 2 + traceWidth / 2 && Math.abs(point6.y - pad.y) <= pad.height / 2 + traceWidth / 2;
19711
19893
  }
19712
19894
  if (pad.shape === "circle") {
19713
- return distance9(point6, pad) <= pad.radius + traceWidth / 2;
19895
+ return distance10(point6, pad) <= pad.radius + traceWidth / 2;
19714
19896
  }
19715
19897
  return false;
19716
19898
  }
@@ -19719,7 +19901,7 @@ function isPointInPlatedHole({
19719
19901
  hole,
19720
19902
  traceWidth = 0
19721
19903
  }) {
19722
- return distance9(point6, hole) <= (hole.outer_diameter ?? hole.hole_diameter ?? 0) / 2 + traceWidth / 2;
19904
+ return distance10(point6, hole) <= (hole.outer_diameter ?? hole.hole_diameter ?? 0) / 2 + traceWidth / 2;
19723
19905
  }
19724
19906
  function getEndpointSourcePortIdsFromGeometry(db, trace) {
19725
19907
  const sourcePortIds = /* @__PURE__ */ new Set();
@@ -19730,7 +19912,7 @@ function getEndpointSourcePortIdsFromGeometry(db, trace) {
19730
19912
  for (const endpoint of endpoints) {
19731
19913
  for (const pcbPort of db.pcb_port.list()) {
19732
19914
  if (!pcbPort.source_port_id) continue;
19733
- if (distance9(endpoint, pcbPort) <= 0.01) {
19915
+ if (distance10(endpoint, pcbPort) <= 0.01) {
19734
19916
  sourcePortIds.add(pcbPort.source_port_id);
19735
19917
  }
19736
19918
  }
@@ -20356,8 +20538,8 @@ var Group5 = class extends NormalComponent3 {
20356
20538
  const groupProps2 = props;
20357
20539
  const hasOutline = groupProps2.outline && groupProps2.outline.length > 0;
20358
20540
  const numericOutline = hasOutline ? groupProps2.outline.map((point6) => ({
20359
- x: distance10.parse(point6.x),
20360
- y: distance10.parse(point6.y)
20541
+ x: distance11.parse(point6.x),
20542
+ y: distance11.parse(point6.y)
20361
20543
  })) : void 0;
20362
20544
  const ctx = this.props;
20363
20545
  const anchorPosition = this._getGlobalPcbPositionBeforeLayout();
@@ -20395,8 +20577,8 @@ var Group5 = class extends NormalComponent3 {
20395
20577
  const hasExplicitPositioning = this._parsedProps.pcbX !== void 0 || this._parsedProps.pcbY !== void 0;
20396
20578
  if (hasOutline) {
20397
20579
  const numericOutline = props.outline.map((point6) => ({
20398
- x: distance10.parse(point6.x),
20399
- y: distance10.parse(point6.y)
20580
+ x: distance11.parse(point6.x),
20581
+ y: distance11.parse(point6.y)
20400
20582
  }));
20401
20583
  const outlineBounds = getBoundsFromPoints4(numericOutline);
20402
20584
  if (!outlineBounds) return;
@@ -22430,7 +22612,7 @@ import { identity as identity5 } from "transformation-matrix";
22430
22612
  var package_default = {
22431
22613
  name: "@tscircuit/core",
22432
22614
  type: "module",
22433
- version: "0.0.1296",
22615
+ version: "0.0.1298",
22434
22616
  types: "dist/index.d.ts",
22435
22617
  main: "dist/index.js",
22436
22618
  module: "dist/index.js",
@@ -23612,11 +23794,11 @@ var MountedBoard = class extends Subcircuit {
23612
23794
 
23613
23795
  // lib/components/normal-components/Panel.ts
23614
23796
  import { panelProps } from "@tscircuit/props";
23615
- import { distance as distance14 } from "circuit-json";
23797
+ import { distance as distance15 } from "circuit-json";
23616
23798
 
23617
23799
  // lib/components/normal-components/Subpanel.ts
23618
23800
  import { subpanelProps } from "@tscircuit/props";
23619
- import { distance as distance13 } from "circuit-json";
23801
+ import { distance as distance14 } from "circuit-json";
23620
23802
  import { compose as compose7, identity as identity6, translate as translate7 } from "transformation-matrix";
23621
23803
 
23622
23804
  // lib/utils/panels/generate-panel-tabs-and-mouse-bites.ts
@@ -23829,15 +24011,15 @@ function generatePanelTabsAndMouseBites(boards, options) {
23829
24011
  }
23830
24012
 
23831
24013
  // lib/utils/panels/pack-into-grid.ts
23832
- import { distance as distance12 } from "circuit-json";
24014
+ import { distance as distance13 } from "circuit-json";
23833
24015
 
23834
24016
  // lib/utils/panels/get-board-dimensions-from-props.ts
23835
24017
  import { getBoundsFromPoints as getBoundsFromPoints6 } from "@tscircuit/math-utils";
23836
- import { distance as distance11 } from "circuit-json";
24018
+ import { distance as distance12 } from "circuit-json";
23837
24019
  var getBoardDimensionsFromProps = (board) => {
23838
24020
  const props = board._parsedProps;
23839
- let width = props.width != null ? distance11.parse(props.width) : void 0;
23840
- let height = props.height != null ? distance11.parse(props.height) : void 0;
24021
+ let width = props.width != null ? distance12.parse(props.width) : void 0;
24022
+ let height = props.height != null ? distance12.parse(props.height) : void 0;
23841
24023
  if ((width === void 0 || height === void 0) && props.outline?.length) {
23842
24024
  const outlineBounds = getBoundsFromPoints6(props.outline);
23843
24025
  if (outlineBounds) {
@@ -23881,8 +24063,8 @@ function packIntoGrid({
23881
24063
  }
23882
24064
  let cols;
23883
24065
  let rows;
23884
- const minCellWidth = cellWidth ? distance12.parse(cellWidth) : 0;
23885
- const minCellHeight = cellHeight ? distance12.parse(cellHeight) : 0;
24066
+ const minCellWidth = cellWidth ? distance13.parse(cellWidth) : 0;
24067
+ const minCellHeight = cellHeight ? distance13.parse(cellHeight) : 0;
23886
24068
  if (col !== void 0) {
23887
24069
  cols = col;
23888
24070
  rows = row ?? Math.ceil(itemsWithDims.length / cols);
@@ -23981,8 +24163,8 @@ function getItemDimensions(item, db) {
23981
24163
  const props = subpanel._parsedProps;
23982
24164
  if (props.width !== void 0 && props.height !== void 0) {
23983
24165
  return {
23984
- width: distance12.parse(props.width),
23985
- height: distance12.parse(props.height)
24166
+ width: distance13.parse(props.width),
24167
+ height: distance13.parse(props.height)
23986
24168
  };
23987
24169
  }
23988
24170
  const directBoards = subpanel._getDirectBoardChildren();
@@ -24009,7 +24191,7 @@ function getItemDimensions(item, db) {
24009
24191
  return getBoardDimensionsFromProps(directBoards[0]);
24010
24192
  }
24011
24193
  if (subpanel._cachedGridWidth > 0 && subpanel._cachedGridHeight > 0) {
24012
- const edgePadding = distance12.parse(props.edgePadding ?? 5);
24194
+ const edgePadding = distance13.parse(props.edgePadding ?? 5);
24013
24195
  return {
24014
24196
  width: subpanel._cachedGridWidth + edgePadding * 2,
24015
24197
  height: subpanel._cachedGridHeight + edgePadding * 2
@@ -24167,17 +24349,17 @@ var Subpanel = class _Subpanel extends Group5 {
24167
24349
  edgePaddingTop: edgePaddingTopProp,
24168
24350
  edgePaddingBottom: edgePaddingBottomProp
24169
24351
  } = this._parsedProps;
24170
- const edgePadding = distance13.parse(edgePaddingProp ?? 5);
24171
- const edgePaddingLeft = distance13.parse(edgePaddingLeftProp ?? edgePadding);
24172
- const edgePaddingRight = distance13.parse(
24352
+ const edgePadding = distance14.parse(edgePaddingProp ?? 5);
24353
+ const edgePaddingLeft = distance14.parse(edgePaddingLeftProp ?? edgePadding);
24354
+ const edgePaddingRight = distance14.parse(
24173
24355
  edgePaddingRightProp ?? edgePadding
24174
24356
  );
24175
- const edgePaddingTop = distance13.parse(edgePaddingTopProp ?? edgePadding);
24176
- const edgePaddingBottom = distance13.parse(
24357
+ const edgePaddingTop = distance14.parse(edgePaddingTopProp ?? edgePadding);
24358
+ const edgePaddingBottom = distance14.parse(
24177
24359
  edgePaddingBottomProp ?? edgePadding
24178
24360
  );
24179
- const panelWidth = distance13.parse(this._parsedProps.width);
24180
- const panelHeight = distance13.parse(this._parsedProps.height);
24361
+ const panelWidth = distance14.parse(this._parsedProps.width);
24362
+ const panelHeight = distance14.parse(this._parsedProps.height);
24181
24363
  availablePanelWidth = panelWidth - edgePaddingLeft - edgePaddingRight;
24182
24364
  availablePanelHeight = panelHeight - edgePaddingTop - edgePaddingBottom;
24183
24365
  }
@@ -24252,8 +24434,8 @@ var Subpanel = class _Subpanel extends Group5 {
24252
24434
  if (!this.pcb_group_id) return;
24253
24435
  if (hasExplicitWidth && hasExplicitHeight) {
24254
24436
  db.pcb_group.update(this.pcb_group_id, {
24255
- width: distance13.parse(this._parsedProps.width),
24256
- height: distance13.parse(this._parsedProps.height)
24437
+ width: distance14.parse(this._parsedProps.width),
24438
+ height: distance14.parse(this._parsedProps.height)
24257
24439
  });
24258
24440
  } else if (gridWidth > 0 || gridHeight > 0) {
24259
24441
  const {
@@ -24263,18 +24445,18 @@ var Subpanel = class _Subpanel extends Group5 {
24263
24445
  edgePaddingTop: edgePaddingTopProp,
24264
24446
  edgePaddingBottom: edgePaddingBottomProp
24265
24447
  } = this._parsedProps;
24266
- const edgePadding = distance13.parse(edgePaddingProp ?? 5);
24267
- const edgePaddingLeft = distance13.parse(edgePaddingLeftProp ?? edgePadding);
24268
- const edgePaddingRight = distance13.parse(
24448
+ const edgePadding = distance14.parse(edgePaddingProp ?? 5);
24449
+ const edgePaddingLeft = distance14.parse(edgePaddingLeftProp ?? edgePadding);
24450
+ const edgePaddingRight = distance14.parse(
24269
24451
  edgePaddingRightProp ?? edgePadding
24270
24452
  );
24271
- const edgePaddingTop = distance13.parse(edgePaddingTopProp ?? edgePadding);
24272
- const edgePaddingBottom = distance13.parse(
24453
+ const edgePaddingTop = distance14.parse(edgePaddingTopProp ?? edgePadding);
24454
+ const edgePaddingBottom = distance14.parse(
24273
24455
  edgePaddingBottomProp ?? edgePadding
24274
24456
  );
24275
24457
  db.pcb_group.update(this.pcb_group_id, {
24276
- width: hasExplicitWidth ? distance13.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
24277
- height: hasExplicitHeight ? distance13.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
24458
+ width: hasExplicitWidth ? distance14.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
24459
+ height: hasExplicitHeight ? distance14.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
24278
24460
  });
24279
24461
  }
24280
24462
  }
@@ -24348,8 +24530,8 @@ var Panel = class extends Subpanel {
24348
24530
  const { db } = this.root;
24349
24531
  const props = this._parsedProps;
24350
24532
  const inserted = db.pcb_panel.insert({
24351
- width: props.width !== void 0 ? distance14.parse(props.width) : 0,
24352
- height: props.height !== void 0 ? distance14.parse(props.height) : 0,
24533
+ width: props.width !== void 0 ? distance15.parse(props.width) : 0,
24534
+ height: props.height !== void 0 ? distance15.parse(props.height) : 0,
24353
24535
  thickness: 1.6,
24354
24536
  center: this._getGlobalPcbPositionBeforeLayout(),
24355
24537
  covered_with_solder_mask: !(props.noSolderMask ?? false)
@@ -24368,8 +24550,8 @@ var Panel = class extends Subpanel {
24368
24550
  if (!this.pcb_panel_id) return;
24369
24551
  if (hasExplicitWidth && hasExplicitHeight) {
24370
24552
  db.pcb_panel.update(this.pcb_panel_id, {
24371
- width: distance14.parse(this._parsedProps.width),
24372
- height: distance14.parse(this._parsedProps.height)
24553
+ width: distance15.parse(this._parsedProps.width),
24554
+ height: distance15.parse(this._parsedProps.height)
24373
24555
  });
24374
24556
  } else if (gridWidth > 0 || gridHeight > 0) {
24375
24557
  const {
@@ -24379,18 +24561,18 @@ var Panel = class extends Subpanel {
24379
24561
  edgePaddingTop: edgePaddingTopProp,
24380
24562
  edgePaddingBottom: edgePaddingBottomProp
24381
24563
  } = this._parsedProps;
24382
- const edgePadding = distance14.parse(edgePaddingProp ?? 5);
24383
- const edgePaddingLeft = distance14.parse(edgePaddingLeftProp ?? edgePadding);
24384
- const edgePaddingRight = distance14.parse(
24564
+ const edgePadding = distance15.parse(edgePaddingProp ?? 5);
24565
+ const edgePaddingLeft = distance15.parse(edgePaddingLeftProp ?? edgePadding);
24566
+ const edgePaddingRight = distance15.parse(
24385
24567
  edgePaddingRightProp ?? edgePadding
24386
24568
  );
24387
- const edgePaddingTop = distance14.parse(edgePaddingTopProp ?? edgePadding);
24388
- const edgePaddingBottom = distance14.parse(
24569
+ const edgePaddingTop = distance15.parse(edgePaddingTopProp ?? edgePadding);
24570
+ const edgePaddingBottom = distance15.parse(
24389
24571
  edgePaddingBottomProp ?? edgePadding
24390
24572
  );
24391
24573
  db.pcb_panel.update(this.pcb_panel_id, {
24392
- width: hasExplicitWidth ? distance14.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
24393
- height: hasExplicitHeight ? distance14.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
24574
+ width: hasExplicitWidth ? distance15.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
24575
+ height: hasExplicitHeight ? distance15.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
24394
24576
  });
24395
24577
  }
24396
24578
  }
@@ -24401,8 +24583,8 @@ var Panel = class extends Subpanel {
24401
24583
  const props = this._parsedProps;
24402
24584
  const currentPanel = db.pcb_panel.get(this.pcb_panel_id);
24403
24585
  db.pcb_panel.update(this.pcb_panel_id, {
24404
- width: props.width !== void 0 ? distance14.parse(props.width) : currentPanel?.width,
24405
- height: props.height !== void 0 ? distance14.parse(props.height) : currentPanel?.height,
24586
+ width: props.width !== void 0 ? distance15.parse(props.width) : currentPanel?.width,
24587
+ height: props.height !== void 0 ? distance15.parse(props.height) : currentPanel?.height,
24406
24588
  center: this._getGlobalPcbPositionBeforeLayout(),
24407
24589
  covered_with_solder_mask: !(props.noSolderMask ?? false)
24408
24590
  });
@@ -25495,7 +25677,7 @@ import { BaseSolver } from "@tscircuit/solver-utils";
25495
25677
 
25496
25678
  // node_modules/@tscircuit/breakout-point-solver/lib/boundary/get-breakout-boundary-intersection.ts
25497
25679
  import {
25498
- distance as distance15,
25680
+ distance as distance16,
25499
25681
  getSegmentIntersection
25500
25682
  } from "@tscircuit/math-utils";
25501
25683
  var getBreakoutBoundaryIntersection = ({
@@ -25523,12 +25705,12 @@ var getBreakoutBoundaryIntersection = ({
25523
25705
  ]
25524
25706
  ];
25525
25707
  const candidates = boundarySegments.map(([start, end]) => getSegmentIntersection(from, to, start, end)).filter((point6) => point6 !== null);
25526
- candidates.sort((a, b) => distance15(from, a) - distance15(from, b));
25708
+ candidates.sort((a, b) => distance16(from, a) - distance16(from, b));
25527
25709
  return candidates[0] ?? null;
25528
25710
  };
25529
25711
 
25530
25712
  // node_modules/@tscircuit/breakout-point-solver/lib/boundary/get-available-breakout-boundary-point.ts
25531
- import { distance as distance16 } from "@tscircuit/math-utils";
25713
+ import { distance as distance17 } from "@tscircuit/math-utils";
25532
25714
 
25533
25715
  // node_modules/@tscircuit/breakout-point-solver/lib/pad/breakout-pad-collisions.ts
25534
25716
  import {
@@ -25630,7 +25812,7 @@ var isInsideRequiredSpacing = ({
25630
25812
  candidate,
25631
25813
  usedPoint,
25632
25814
  boundaryPointSpacing
25633
- }) => distance16(usedPoint, candidate) < boundaryPointSpacing - BOUNDARY_POINT_DISTANCE_TOLERANCE;
25815
+ }) => distance17(usedPoint, candidate) < boundaryPointSpacing - BOUNDARY_POINT_DISTANCE_TOLERANCE;
25634
25816
  var getBoundsEdge = (point6, bounds) => {
25635
25817
  if (Math.abs(point6.x - bounds.minX) < BOUNDARY_POINT_DISTANCE_TOLERANCE)
25636
25818
  return "left";
@@ -25821,7 +26003,7 @@ var getAvailableBreakoutBoundaryPoint = ({
25821
26003
  step
25822
26004
  });
25823
26005
  edgeCandidates.sort(
25824
- (a, b) => distance16(a, idealPoint) - distance16(b, idealPoint)
26006
+ (a, b) => distance17(a, idealPoint) - distance17(b, idealPoint)
25825
26007
  );
25826
26008
  for (const candidate of edgeCandidates) {
25827
26009
  if (isCandidateAvailable({
@@ -25837,7 +26019,7 @@ var getAvailableBreakoutBoundaryPoint = ({
25837
26019
  }
25838
26020
  }
25839
26021
  const candidates = getAllBoundsCandidates({ bounds, step });
25840
- candidates.sort((a, b) => distance16(a, idealPoint) - distance16(b, idealPoint));
26022
+ candidates.sort((a, b) => distance17(a, idealPoint) - distance17(b, idealPoint));
25841
26023
  for (const candidate of candidates) {
25842
26024
  if (isCandidateAvailable({
25843
26025
  candidate,
@@ -25887,7 +26069,7 @@ var getAvailableBreakoutBoundaryPointForOutsidePorts = ({
25887
26069
  if (!edge) continue;
25888
26070
  const edgeCandidates = getBoundsEdgeCandidates({ edge, bounds, step });
25889
26071
  edgeCandidates.sort(
25890
- (a, b) => distance16(a, idealPoint) - distance16(b, idealPoint)
26072
+ (a, b) => distance17(a, idealPoint) - distance17(b, idealPoint)
25891
26073
  );
25892
26074
  for (const candidate of edgeCandidates) {
25893
26075
  if (isCandidateAvailableForOutsidePorts({
@@ -25907,7 +26089,7 @@ var getAvailableBreakoutBoundaryPointForOutsidePorts = ({
25907
26089
  }
25908
26090
  for (const idealPoint of idealPoints) {
25909
26091
  const candidates = getAllBoundsCandidates({ bounds, step });
25910
- candidates.sort((a, b) => distance16(a, idealPoint) - distance16(b, idealPoint));
26092
+ candidates.sort((a, b) => distance17(a, idealPoint) - distance17(b, idealPoint));
25911
26093
  for (const candidate of candidates) {
25912
26094
  if (isCandidateAvailableForOutsidePorts({
25913
26095
  candidate,
@@ -26427,6 +26609,11 @@ var createBreakoutPointSolverInput = (breakout) => {
26427
26609
  label: component.pcb_component_id
26428
26610
  }));
26429
26611
  const usedBoundaryPoints = db.pcb_breakout_point.list().filter((point6) => point6.pcb_group_id === breakout.pcb_group_id).map((point6) => ({ x: point6.x, y: point6.y }));
26612
+ const board = db.pcb_board.list()[0];
26613
+ const traceWidth = board?.min_trace_width ?? 0.15;
26614
+ const clearance = board?.min_trace_to_pad_edge_clearance ?? 0.2;
26615
+ const viaPadDiameter = board?.min_via_pad_diameter ?? 0.3;
26616
+ const boundaryPointSpacing = viaPadDiameter + 2 * (traceWidth + clearance);
26430
26617
  return {
26431
26618
  bounds: {
26432
26619
  minX: boundsMinX,
@@ -26434,7 +26621,7 @@ var createBreakoutPointSolverInput = (breakout) => {
26434
26621
  minY: boundsMinY,
26435
26622
  maxY: boundsMaxY
26436
26623
  },
26437
- boundaryPointSpacing: 0.5,
26624
+ boundaryPointSpacing,
26438
26625
  traces,
26439
26626
  pads,
26440
26627
  components,
@@ -26502,15 +26689,28 @@ var Breakout = class extends Group5 {
26502
26689
  const autoBreakoutPoints = this.children.filter(
26503
26690
  (c) => c instanceof AutoplacedBreakoutPoint
26504
26691
  );
26692
+ const BOUNDARY_INSET_MM = 1e-4;
26693
+ const { bounds } = solverInput;
26694
+ const insetWithinBounds = (x, y) => ({
26695
+ x: Math.max(
26696
+ bounds.minX + BOUNDARY_INSET_MM,
26697
+ Math.min(bounds.maxX - BOUNDARY_INSET_MM, x)
26698
+ ),
26699
+ y: Math.max(
26700
+ bounds.minY + BOUNDARY_INSET_MM,
26701
+ Math.min(bounds.maxY - BOUNDARY_INSET_MM, y)
26702
+ )
26703
+ });
26505
26704
  for (const solvedPoint of output.breakoutPoints) {
26506
26705
  const matchingBreakoutPoint = autoBreakoutPoints.find(
26507
26706
  (child) => child.matchedPort?.source_port_id === solvedPoint.sourcePortId
26508
26707
  );
26509
26708
  if (matchingBreakoutPoint) {
26510
26709
  matchingBreakoutPoint.matchedSourceTraceId = solvedPoint.sourceTraceId;
26710
+ const insetPoint = insetWithinBounds(solvedPoint.x, solvedPoint.y);
26511
26711
  matchingBreakoutPoint._setPositionFromLayout({
26512
- x: solvedPoint.x,
26513
- y: solvedPoint.y
26712
+ x: insetPoint.x,
26713
+ y: insetPoint.y
26514
26714
  });
26515
26715
  }
26516
26716
  }
@@ -26736,7 +26936,7 @@ var NetLabel = class extends PrimitiveComponent2 {
26736
26936
 
26737
26937
  // lib/components/primitive-components/Fiducial.ts
26738
26938
  import "zod";
26739
- import { distance as distance17 } from "circuit-json";
26939
+ import { distance as distance18 } from "circuit-json";
26740
26940
  import { fiducialProps } from "@tscircuit/props";
26741
26941
  var Fiducial = class extends PrimitiveComponent2 {
26742
26942
  pcb_smtpad_id = null;
@@ -26761,15 +26961,15 @@ var Fiducial = class extends PrimitiveComponent2 {
26761
26961
  shape: "circle",
26762
26962
  x: position.x,
26763
26963
  y: position.y,
26764
- radius: distance17.parse(props.padDiameter) / 2,
26765
- soldermask_margin: props.soldermaskPullback ? distance17.parse(props.soldermaskPullback) : distance17.parse(props.padDiameter) / 2,
26964
+ radius: distance18.parse(props.padDiameter) / 2,
26965
+ soldermask_margin: props.soldermaskPullback ? distance18.parse(props.soldermaskPullback) : distance18.parse(props.padDiameter) / 2,
26766
26966
  is_covered_with_solder_mask: true
26767
26967
  });
26768
26968
  this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id;
26769
26969
  }
26770
26970
  getPcbSize() {
26771
26971
  const { _parsedProps: props } = this;
26772
- const d = distance17.parse(props.padDiameter);
26972
+ const d = distance18.parse(props.padDiameter);
26773
26973
  return { width: d, height: d };
26774
26974
  }
26775
26975
  _setPositionFromLayout(newCenter) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.1297",
4
+ "version": "0.0.1299",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",