@tscircuit/core 0.0.1335 → 0.0.1336

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 +245 -24
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -18045,6 +18045,141 @@ import { getCircuitJsonTree as getCircuitJsonTree2 } from "@tscircuit/circuit-js
18045
18045
  import "@tscircuit/circuit-json-util";
18046
18046
  import { LayoutPipelineSolver } from "@tscircuit/matchpack";
18047
18047
  import Debug8 from "debug";
18048
+
18049
+ // lib/utils/schematic/getSchematicComponentWithTextBounds.ts
18050
+ import { getBoundFromCenteredRect } from "@tscircuit/math-utils";
18051
+ import { symbols as symbols3 } from "schematic-symbols";
18052
+ var SYMBOL_TEXT_FONT_SIZE = 0.18;
18053
+ var TEXT_BOX_ENABLED_FTYPES = /* @__PURE__ */ new Set(["simple_resistor"]);
18054
+ function getTextBounds({
18055
+ text,
18056
+ position,
18057
+ anchor,
18058
+ fontSize
18059
+ }) {
18060
+ const width = getSchematicNetLabelTextWidth({ text, font_size: fontSize });
18061
+ const height = fontSize;
18062
+ let relMinX;
18063
+ let relMaxX;
18064
+ if (anchor.includes("left")) {
18065
+ relMinX = 0;
18066
+ relMaxX = width;
18067
+ } else if (anchor.includes("right")) {
18068
+ relMinX = -width;
18069
+ relMaxX = 0;
18070
+ } else {
18071
+ relMinX = -width / 2;
18072
+ relMaxX = width / 2;
18073
+ }
18074
+ let relMinY;
18075
+ let relMaxY;
18076
+ if (anchor.includes("top")) {
18077
+ relMinY = -height;
18078
+ relMaxY = 0;
18079
+ } else if (anchor.includes("bottom")) {
18080
+ relMinY = 0;
18081
+ relMaxY = height;
18082
+ } else {
18083
+ relMinY = -height / 2;
18084
+ relMaxY = height / 2;
18085
+ }
18086
+ return {
18087
+ minX: position.x + relMinX,
18088
+ maxX: position.x + relMaxX,
18089
+ minY: position.y + relMinY,
18090
+ maxY: position.y + relMaxY
18091
+ };
18092
+ }
18093
+ function getSymbolTextBounds({
18094
+ schematicComponent,
18095
+ sourceComponent
18096
+ }) {
18097
+ if (!schematicComponent.symbol_name) return [];
18098
+ const symbol = symbols3[schematicComponent.symbol_name];
18099
+ if (!symbol?.primitives || !symbol.center) return [];
18100
+ const textBounds = [];
18101
+ for (const primitive of symbol.primitives) {
18102
+ if (primitive.type !== "text") continue;
18103
+ let value;
18104
+ if (primitive.text === "{REF}") {
18105
+ value = sourceComponent?.display_name ?? sourceComponent?.name ?? "";
18106
+ } else if (primitive.text === "{VAL}") {
18107
+ value = schematicComponent.symbol_display_value ?? "";
18108
+ } else {
18109
+ value = primitive.text ?? "";
18110
+ }
18111
+ if (!value) continue;
18112
+ textBounds.push(
18113
+ getTextBounds({
18114
+ text: value,
18115
+ position: {
18116
+ x: primitive.x - symbol.center.x + schematicComponent.center.x,
18117
+ y: primitive.y - symbol.center.y + schematicComponent.center.y
18118
+ },
18119
+ anchor: primitive.anchor ?? "center",
18120
+ fontSize: SYMBOL_TEXT_FONT_SIZE
18121
+ })
18122
+ );
18123
+ }
18124
+ return textBounds;
18125
+ }
18126
+ function getSymbolBoxBounds(schematicComponent) {
18127
+ return getBoundFromCenteredRect({
18128
+ center: schematicComponent.center,
18129
+ width: schematicComponent.size.width,
18130
+ height: schematicComponent.size.height
18131
+ });
18132
+ }
18133
+ function getSchematicComponentTextInclusiveBounds(db, schematicComponent) {
18134
+ if (!schematicComponent.center || !schematicComponent.size) return null;
18135
+ const sourceComponent = schematicComponent.source_component_id ? db.source_component.get(schematicComponent.source_component_id) : void 0;
18136
+ if (!sourceComponent || !TEXT_BOX_ENABLED_FTYPES.has(sourceComponent.ftype)) {
18137
+ return null;
18138
+ }
18139
+ const textBounds = getSymbolTextBounds({
18140
+ schematicComponent,
18141
+ sourceComponent
18142
+ });
18143
+ if (textBounds.length === 0) return null;
18144
+ const boxBounds = getSymbolBoxBounds(schematicComponent);
18145
+ const bounds = { ...boxBounds };
18146
+ for (const textBound of textBounds) {
18147
+ bounds.minX = Math.min(bounds.minX, textBound.minX);
18148
+ bounds.maxX = Math.max(bounds.maxX, textBound.maxX);
18149
+ bounds.minY = Math.min(bounds.minY, textBound.minY);
18150
+ bounds.maxY = Math.max(bounds.maxY, textBound.maxY);
18151
+ }
18152
+ if (bounds.minX === boxBounds.minX && bounds.maxX === boxBounds.maxX && bounds.minY === boxBounds.minY && bounds.maxY === boxBounds.maxY) {
18153
+ return null;
18154
+ }
18155
+ return bounds;
18156
+ }
18157
+ function getSchematicComponentWithTextBounds(db, schematicComponent) {
18158
+ const textBounds = getSchematicComponentTextInclusiveBounds(
18159
+ db,
18160
+ schematicComponent
18161
+ );
18162
+ if (!textBounds) return null;
18163
+ const boxBounds = getSymbolBoxBounds(schematicComponent);
18164
+ const isVertical = schematicComponent.size.height > schematicComponent.size.width;
18165
+ if (isVertical) return textBounds;
18166
+ const padX = Math.max(
18167
+ boxBounds.minX - textBounds.minX,
18168
+ textBounds.maxX - boxBounds.maxX
18169
+ );
18170
+ const padY = Math.max(
18171
+ textBounds.maxY - boxBounds.maxY,
18172
+ boxBounds.minY - textBounds.minY
18173
+ );
18174
+ return getBoundFromCenteredRect({
18175
+ center: schematicComponent.center,
18176
+ width: schematicComponent.size.width + 2 * padX,
18177
+ height: schematicComponent.size.height + 2 * padY
18178
+ });
18179
+ }
18180
+
18181
+ // lib/components/primitive-components/Group/applySchematicMatchPackLayoutToTree.ts
18182
+ import { getBoundFromCenteredRect as getBoundFromCenteredRect2 } from "@tscircuit/math-utils";
18048
18183
  var debug6 = Debug8("Group_doInitialSchematicLayoutMatchpack");
18049
18184
  var DEFAULT_AVAILABLE_ROTATIONS = [0, 90, 180, 270];
18050
18185
  var ROTATION_TO_PLACE_SIDE_ON_TOP = {
@@ -18184,10 +18319,26 @@ function convertTreeToMatchPackInputProblem(tree, db, group) {
18184
18319
  if (component?.componentName === "Chip") {
18185
18320
  availableRotations = [0];
18186
18321
  }
18187
- const marginLeft = component?._parsedProps?.schMarginLeft ?? component?._parsedProps?.schMarginX ?? 0;
18188
- const marginRight = component?._parsedProps?.schMarginRight ?? component?._parsedProps?.schMarginX ?? 0;
18189
- let marginTop = component?._parsedProps?.schMarginTop ?? component?._parsedProps?.schMarginY ?? 0;
18190
- let marginBottom = component?._parsedProps?.schMarginBottom ?? component?._parsedProps?.schMarginY ?? 0;
18322
+ const componentWithTextBounds = getSchematicComponentWithTextBounds(
18323
+ db,
18324
+ schematicComponent
18325
+ );
18326
+ let textPadLeft = 0;
18327
+ let textPadRight = 0;
18328
+ let textPadTop = 0;
18329
+ let textPadBottom = 0;
18330
+ if (componentWithTextBounds && schematicComponent.center) {
18331
+ const halfWidth = (schematicComponent.size?.width ?? 0) / 2;
18332
+ const halfHeight = (schematicComponent.size?.height ?? 0) / 2;
18333
+ textPadLeft = schematicComponent.center.x - halfWidth - componentWithTextBounds.minX;
18334
+ textPadRight = componentWithTextBounds.maxX - (schematicComponent.center.x + halfWidth);
18335
+ textPadTop = componentWithTextBounds.maxY - (schematicComponent.center.y + halfHeight);
18336
+ textPadBottom = schematicComponent.center.y - halfHeight - componentWithTextBounds.minY;
18337
+ }
18338
+ const marginLeft = (component?._parsedProps?.schMarginLeft ?? component?._parsedProps?.schMarginX ?? 0) + textPadLeft;
18339
+ const marginRight = (component?._parsedProps?.schMarginRight ?? component?._parsedProps?.schMarginX ?? 0) + textPadRight;
18340
+ let marginTop = (component?._parsedProps?.schMarginTop ?? component?._parsedProps?.schMarginY ?? 0) + textPadTop;
18341
+ let marginBottom = (component?._parsedProps?.schMarginBottom ?? component?._parsedProps?.schMarginY ?? 0) + textPadBottom;
18191
18342
  if (component?.config.shouldRenderAsSchematicBox) {
18192
18343
  marginTop += 0.4;
18193
18344
  marginBottom += 0.4;
@@ -18257,12 +18408,15 @@ function convertTreeToMatchPackInputProblem(tree, db, group) {
18257
18408
  for (const comp of groupComponents) {
18258
18409
  if (comp.center && comp.size) {
18259
18410
  hasValidBounds = true;
18260
- const halfWidth = comp.size.width / 2;
18261
- const halfHeight = comp.size.height / 2;
18262
- minX = Math.min(minX, comp.center.x - halfWidth);
18263
- maxX = Math.max(maxX, comp.center.x + halfWidth);
18264
- minY = Math.min(minY, comp.center.y - halfHeight);
18265
- maxY = Math.max(maxY, comp.center.y + halfHeight);
18411
+ const compBounds = getSchematicComponentWithTextBounds(db, comp) ?? getBoundFromCenteredRect2({
18412
+ center: comp.center,
18413
+ width: comp.size.width,
18414
+ height: comp.size.height
18415
+ });
18416
+ minX = Math.min(minX, compBounds.minX);
18417
+ maxX = Math.max(maxX, compBounds.maxX);
18418
+ minY = Math.min(minY, compBounds.minY);
18419
+ maxY = Math.max(maxY, compBounds.maxY);
18266
18420
  }
18267
18421
  }
18268
18422
  const marginLeft = groupInstance?._parsedProps?.schMarginLeft ?? groupInstance?._parsedProps?.schMarginX ?? 0;
@@ -19026,6 +19180,10 @@ import Debug12 from "debug";
19026
19180
 
19027
19181
  // lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/createSchematicTraceSolverInputProblem.ts
19028
19182
  import "@tscircuit/schematic-trace-solver";
19183
+ import {
19184
+ getBoundFromCenteredRect as getBoundFromCenteredRect3,
19185
+ getBoundsCenter
19186
+ } from "@tscircuit/math-utils";
19029
19187
  var DEFAULT_MAX_MSP_PAIR_DISTANCE = 2.4;
19030
19188
  function createSchematicTraceSolverInputProblem(group) {
19031
19189
  const { db } = group.root;
@@ -19075,11 +19233,16 @@ function createSchematicTraceSolverInputProblem(group) {
19075
19233
  if (sourceComponent?.name) {
19076
19234
  sectionId = componentNameToSectionId.get(sourceComponent.name);
19077
19235
  }
19078
- chips.push({
19079
- chipId,
19236
+ const layoutBounds = getSchematicComponentWithTextBounds(db, schematicComponent) ?? getBoundFromCenteredRect3({
19080
19237
  center: schematicComponent.center,
19081
19238
  width: schematicComponent.size.width,
19082
- height: schematicComponent.size.height,
19239
+ height: schematicComponent.size.height
19240
+ });
19241
+ chips.push({
19242
+ chipId,
19243
+ center: getBoundsCenter(layoutBounds),
19244
+ width: layoutBounds.maxX - layoutBounds.minX,
19245
+ height: layoutBounds.maxY - layoutBounds.minY,
19083
19246
  pins,
19084
19247
  sectionId
19085
19248
  });
@@ -19590,6 +19753,45 @@ function computeJunctions(traces, opts = {}) {
19590
19753
  // lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/applyTracesFromSolverOutput.ts
19591
19754
  import Debug10 from "debug";
19592
19755
  var debug8 = Debug10("Group_doInitialSchematicTraceRender");
19756
+ var MAX_PIN_SNAP_GAP = 1.5;
19757
+ function extendTraceEndpointsToReachPinsInsideExpandedBoundingBox(params, db) {
19758
+ const { points, schematicPortIds, eligiblePortIds } = params;
19759
+ const centers = schematicPortIds.filter((id) => eligiblePortIds.has(id)).map((id) => db.schematic_port.get(id)?.center).filter((c) => Boolean(c));
19760
+ if (centers.length === 0) return points;
19761
+ const result = points.map((p) => ({ x: p.x, y: p.y }));
19762
+ const d2 = (a, b) => (a.x - b.x) ** 2 + (a.y - b.y) ** 2;
19763
+ const usedCenters = /* @__PURE__ */ new Set();
19764
+ const snap = (endpoint) => {
19765
+ const pt = endpoint === "start" ? result[0] : result[result.length - 1];
19766
+ let bestIndex = -1;
19767
+ let bestDist = Number.POSITIVE_INFINITY;
19768
+ for (let i = 0; i < centers.length; i++) {
19769
+ if (usedCenters.has(i)) continue;
19770
+ const dist = d2(centers[i], pt);
19771
+ if (dist < bestDist) {
19772
+ bestDist = dist;
19773
+ bestIndex = i;
19774
+ }
19775
+ }
19776
+ if (bestIndex < 0) return;
19777
+ if (bestDist <= 1e-12) {
19778
+ usedCenters.add(bestIndex);
19779
+ return;
19780
+ }
19781
+ if (bestDist > MAX_PIN_SNAP_GAP ** 2) return;
19782
+ const c = centers[bestIndex];
19783
+ const ALIGN_EPS = 1e-3;
19784
+ if (Math.abs(c.x - pt.x) > ALIGN_EPS && Math.abs(c.y - pt.y) > ALIGN_EPS) {
19785
+ return;
19786
+ }
19787
+ usedCenters.add(bestIndex);
19788
+ if (endpoint === "start") result.unshift({ x: c.x, y: c.y });
19789
+ else result.push({ x: c.x, y: c.y });
19790
+ };
19791
+ snap("start");
19792
+ snap("end");
19793
+ return result;
19794
+ }
19593
19795
  function applyTracesFromSolverOutput(args) {
19594
19796
  const {
19595
19797
  group,
@@ -19599,6 +19801,17 @@ function applyTracesFromSolverOutput(args) {
19599
19801
  schematicPortIdsWithPreExistingNetLabels
19600
19802
  } = args;
19601
19803
  const { db } = group.root;
19804
+ const eligiblePortIds = /* @__PURE__ */ new Set();
19805
+ for (const schematicComponent of db.schematic_component.list()) {
19806
+ if (!getSchematicComponentWithTextBounds(db, schematicComponent)) {
19807
+ continue;
19808
+ }
19809
+ for (const port of db.schematic_port.list({
19810
+ schematic_component_id: schematicComponent.schematic_component_id
19811
+ })) {
19812
+ eligiblePortIds.add(port.schematic_port_id);
19813
+ }
19814
+ }
19602
19815
  const traces = solver.netLabelTraceCollisionSolver?.getOutput().traces ?? solver.traceCleanupSolver?.getOutput().traces ?? solver.traceLabelOverlapAvoidanceSolver?.getOutput().traces ?? solver.schematicTraceLinesSolver?.solvedTracePaths;
19603
19816
  const pendingTraces = [];
19604
19817
  debug8(`Traces inside SchematicTraceSolver output: ${(traces ?? []).length}`);
@@ -19621,11 +19834,19 @@ function applyTracesFromSolverOutput(args) {
19621
19834
  );
19622
19835
  continue;
19623
19836
  }
19837
+ const snappedPoints = extendTraceEndpointsToReachPinsInsideExpandedBoundingBox(
19838
+ {
19839
+ points,
19840
+ schematicPortIds: solvedTraceSchematicPortIds,
19841
+ eligiblePortIds
19842
+ },
19843
+ db
19844
+ );
19624
19845
  const edges = [];
19625
- for (let i = 0; i < points.length - 1; i++) {
19846
+ for (let i = 0; i < snappedPoints.length - 1; i++) {
19626
19847
  edges.push({
19627
- from: { x: points[i].x, y: points[i].y },
19628
- to: { x: points[i + 1].x, y: points[i + 1].y }
19848
+ from: { x: snappedPoints[i].x, y: snappedPoints[i].y },
19849
+ to: { x: snappedPoints[i + 1].x, y: snappedPoints[i + 1].y }
19629
19850
  });
19630
19851
  }
19631
19852
  const source_trace_id = String(solvedTracePath?.mspPairId);
@@ -22978,7 +23199,7 @@ function inflateSourcePort(sourcePort, inflatorContext) {
22978
23199
 
22979
23200
  // lib/components/normal-components/PushButton.ts
22980
23201
  import { pushButtonProps } from "@tscircuit/props";
22981
- import { symbols as symbols3 } from "schematic-symbols";
23202
+ import { symbols as symbols4 } from "schematic-symbols";
22982
23203
  var PushButton = class extends NormalComponent3 {
22983
23204
  get config() {
22984
23205
  return {
@@ -22996,7 +23217,7 @@ var PushButton = class extends NormalComponent3 {
22996
23217
  pinCount: 2,
22997
23218
  ignoreSymbolPorts: true
22998
23219
  });
22999
- const symbol = symbols3[this._getSchematicSymbolNameOrThrow()];
23220
+ const symbol = symbols4[this._getSchematicSymbolNameOrThrow()];
23000
23221
  const symPort1 = symbol.ports.find((p) => p.labels.includes("1"));
23001
23222
  const symPort2 = symbol.ports.find((p) => p.labels.includes("2"));
23002
23223
  const ports = this.selectAll("port");
@@ -23785,7 +24006,7 @@ import { identity as identity5 } from "transformation-matrix";
23785
24006
  var package_default = {
23786
24007
  name: "@tscircuit/core",
23787
24008
  type: "module",
23788
- version: "0.0.1334",
24009
+ version: "0.0.1335",
23789
24010
  types: "dist/index.d.ts",
23790
24011
  main: "dist/index.js",
23791
24012
  module: "dist/index.js",
@@ -23836,8 +24057,8 @@ var package_default = {
23836
24057
  "@tscircuit/props": "^0.0.549",
23837
24058
  "@tscircuit/ngspice-spice-engine": "^0.0.16",
23838
24059
  "@tscircuit/schematic-match-adapt": "^0.0.18",
23839
- "@tscircuit/schematic-trace-solver": "^0.0.69",
23840
24060
  "@tscircuit/solver-utils": "^0.0.16",
24061
+ "@tscircuit/schematic-trace-solver": "^0.0.70",
23841
24062
  "@tscircuit/soup-util": "^0.0.41",
23842
24063
  "@types/bun": "^1.2.16",
23843
24064
  "@types/debug": "^4.1.12",
@@ -26844,7 +27065,7 @@ import { distance as distance17 } from "@tscircuit/math-utils";
26844
27065
  // node_modules/@tscircuit/breakout-point-solver/lib/pad/breakout-pad-collisions.ts
26845
27066
  import {
26846
27067
  doesSegmentIntersectRect,
26847
- getBoundFromCenteredRect
27068
+ getBoundFromCenteredRect as getBoundFromCenteredRect4
26848
27069
  } from "@tscircuit/math-utils";
26849
27070
  var degreesToRadians = (degrees) => degrees * Math.PI / 180;
26850
27071
  var rotatePoint = (point6, radians) => {
@@ -26867,7 +27088,7 @@ var getLocalPadPoint = (point6, pad) => {
26867
27088
  };
26868
27089
  var getInflatedPadRect = (pad) => {
26869
27090
  const clearance = pad.clearance ?? 0;
26870
- return getBoundFromCenteredRect({
27091
+ return getBoundFromCenteredRect4({
26871
27092
  center: { x: 0, y: 0 },
26872
27093
  width: pad.width + clearance * 2,
26873
27094
  height: pad.height + clearance * 2
@@ -28766,7 +28987,7 @@ var convertCircuitJsonToUsbCStandardCircuitJson = (partCircuitJson) => {
28766
28987
  };
28767
28988
 
28768
28989
  // lib/components/normal-components/Connector.ts
28769
- import { symbols as symbols4 } from "schematic-symbols";
28990
+ import { symbols as symbols5 } from "schematic-symbols";
28770
28991
 
28771
28992
  // lib/components/normal-components/Connector_insertInnerSymbolInSchematicBox.ts
28772
28993
  var INNER_SYMBOL_SCALE_FACTOR = 0.5;
@@ -29148,7 +29369,7 @@ var Connector = class extends Chip {
29148
29369
  doInitialSchematicComponentRender() {
29149
29370
  super.doInitialSchematicComponentRender();
29150
29371
  if (!this.root?.schematicDisabled && this.schematic_component_id && this._getConnectorProps().standard === "usb_c") {
29151
- const usbcSymbol = symbols4.usbc;
29372
+ const usbcSymbol = symbols5.usbc;
29152
29373
  if (usbcSymbol) {
29153
29374
  insertInnerSymbolInSchematicBox(this, usbcSymbol);
29154
29375
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.1335",
4
+ "version": "0.0.1336",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -52,8 +52,8 @@
52
52
  "@tscircuit/props": "^0.0.549",
53
53
  "@tscircuit/ngspice-spice-engine": "^0.0.16",
54
54
  "@tscircuit/schematic-match-adapt": "^0.0.18",
55
- "@tscircuit/schematic-trace-solver": "^0.0.69",
56
55
  "@tscircuit/solver-utils": "^0.0.16",
56
+ "@tscircuit/schematic-trace-solver": "^0.0.70",
57
57
  "@tscircuit/soup-util": "^0.0.41",
58
58
  "@types/bun": "^1.2.16",
59
59
  "@types/debug": "^4.1.12",