@tscircuit/core 0.0.549 → 0.0.551

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 (3) hide show
  1. package/dist/index.d.ts +3 -3
  2. package/dist/index.js +1241 -1209
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -54,7 +54,7 @@ __export(components_exports, {
54
54
  Subcircuit: () => Subcircuit,
55
55
  Switch: () => Switch,
56
56
  TestPoint: () => TestPoint,
57
- Trace: () => Trace2,
57
+ Trace: () => Trace3,
58
58
  TraceHint: () => TraceHint,
59
59
  Transistor: () => Transistor,
60
60
  Via: () => Via
@@ -3602,10 +3602,10 @@ var getNumericSchPinStyle = (pinStyles, pinLabels) => {
3602
3602
  };
3603
3603
 
3604
3604
  // lib/components/primitive-components/Trace/Trace.ts
3605
- import { MultilayerIjump } from "@tscircuit/infgrid-ijump-astar";
3605
+ import "@tscircuit/infgrid-ijump-astar";
3606
3606
  import { traceProps } from "@tscircuit/props";
3607
3607
  import "circuit-json";
3608
- import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map";
3608
+ import "circuit-json-to-connectivity-map";
3609
3609
 
3610
3610
  // lib/utils/autorouting/DirectLineRouter.ts
3611
3611
  var DirectLineRouter = class {
@@ -3890,198 +3890,7 @@ function tryNow(fn) {
3890
3890
  // lib/components/primitive-components/Trace/Trace.ts
3891
3891
  import "zod";
3892
3892
 
3893
- // lib/components/primitive-components/Trace/compute-trace-length.ts
3894
- function getTraceLength(route) {
3895
- let totalLength = 0;
3896
- for (let i = 0; i < route.length; i++) {
3897
- const point = route[i];
3898
- if (point.route_type === "wire") {
3899
- const nextPoint = route[i + 1];
3900
- if (nextPoint) {
3901
- const dx = nextPoint.x - point.x;
3902
- const dy = nextPoint.y - point.y;
3903
- totalLength += Math.sqrt(dx * dx + dy * dy);
3904
- }
3905
- } else if (point.route_type === "via") {
3906
- totalLength += 1.6;
3907
- }
3908
- }
3909
- return totalLength;
3910
- }
3911
-
3912
- // lib/components/primitive-components/Trace/create-schematic-trace-crossing-segments.ts
3913
- import { distance as distance2, doesLineIntersectLine } from "@tscircuit/math-utils";
3914
-
3915
- // lib/components/primitive-components/Trace/get-other-schematic-traces.ts
3916
- var getOtherSchematicTraces = ({
3917
- db,
3918
- source_trace_id,
3919
- sameNetOnly,
3920
- differentNetOnly
3921
- }) => {
3922
- if (!sameNetOnly && !differentNetOnly) {
3923
- differentNetOnly = true;
3924
- }
3925
- const mySourceTrace = db.source_trace.get(source_trace_id);
3926
- const traces = [];
3927
- for (const otherSchematicTrace of db.schematic_trace.list()) {
3928
- if (otherSchematicTrace.source_trace_id === source_trace_id) continue;
3929
- const otherSourceTrace = db.source_trace.get(
3930
- otherSchematicTrace.source_trace_id
3931
- );
3932
- const isSameNet = otherSourceTrace?.subcircuit_connectivity_map_key === mySourceTrace.subcircuit_connectivity_map_key;
3933
- if (differentNetOnly && isSameNet) {
3934
- continue;
3935
- }
3936
- if (sameNetOnly && !isSameNet) {
3937
- continue;
3938
- }
3939
- traces.push(otherSchematicTrace);
3940
- }
3941
- return traces;
3942
- };
3943
-
3944
- // lib/components/primitive-components/Trace/create-schematic-trace-crossing-segments.ts
3945
- import { getUnitVectorFromPointAToB } from "@tscircuit/math-utils";
3946
- var createSchematicTraceCrossingSegments = ({
3947
- edges: inputEdges,
3948
- otherEdges
3949
- }) => {
3950
- const edges = [...inputEdges];
3951
- for (let i = 0; i < edges.length; i++) {
3952
- if (i > 2e3) {
3953
- throw new Error(
3954
- "Over 2000 iterations spent inside createSchematicTraceCrossingSegments, you have triggered an infinite loop, please report this!"
3955
- );
3956
- }
3957
- const edge = edges[i];
3958
- const edgeOrientation = Math.abs(edge.from.x - edge.to.x) < 0.01 ? "vertical" : edge.from.y === edge.to.y ? "horizontal" : "not-orthogonal";
3959
- if (edgeOrientation === "not-orthogonal") {
3960
- continue;
3961
- }
3962
- const otherEdgesIntersections = [];
3963
- for (const otherEdge of otherEdges) {
3964
- const otherOrientation = otherEdge.from.x === otherEdge.to.x ? "vertical" : otherEdge.from.y === otherEdge.to.y ? "horizontal" : "not-orthogonal";
3965
- if (otherOrientation === "not-orthogonal") continue;
3966
- if (edgeOrientation === otherOrientation)
3967
- continue;
3968
- const hasIntersection = doesLineIntersectLine(
3969
- [edge.from, edge.to],
3970
- [otherEdge.from, otherEdge.to],
3971
- { lineThickness: 0.01 }
3972
- );
3973
- if (hasIntersection) {
3974
- const intersectX = edgeOrientation === "vertical" ? edge.from.x : otherEdge.from.x;
3975
- const intersectY = edgeOrientation === "vertical" ? otherEdge.from.y : edge.from.y;
3976
- const crossingPoint2 = { x: intersectX, y: intersectY };
3977
- otherEdgesIntersections.push({
3978
- otherEdge,
3979
- crossingPoint: crossingPoint2,
3980
- distanceFromEdgeFrom: distance2(edge.from, crossingPoint2)
3981
- });
3982
- }
3983
- }
3984
- if (otherEdgesIntersections.length === 0) continue;
3985
- let closestIntersection = otherEdgesIntersections[0];
3986
- for (const intersection of otherEdgesIntersections) {
3987
- if (intersection.distanceFromEdgeFrom < closestIntersection.distanceFromEdgeFrom) {
3988
- closestIntersection = intersection;
3989
- }
3990
- }
3991
- const crossingPoint = closestIntersection.crossingPoint;
3992
- const crossingSegmentLength = 0.075;
3993
- if (crossingPoint.x === edge.from.x && crossingPoint.y === edge.from.y) {
3994
- continue;
3995
- }
3996
- const crossingUnitVec = getUnitVectorFromPointAToB(edge.from, crossingPoint);
3997
- const beforeCrossing = {
3998
- x: crossingPoint.x - crossingUnitVec.x * crossingSegmentLength / 2,
3999
- y: crossingPoint.y - crossingUnitVec.y * crossingSegmentLength / 2
4000
- };
4001
- const afterCrossing = {
4002
- x: crossingPoint.x + crossingUnitVec.x * crossingSegmentLength / 2,
4003
- y: crossingPoint.y + crossingUnitVec.y * crossingSegmentLength / 2
4004
- };
4005
- const overshot = distance2(afterCrossing, edge.to) < crossingSegmentLength;
4006
- const newEdges = [
4007
- { from: edge.from, to: beforeCrossing },
4008
- { from: beforeCrossing, to: afterCrossing, is_crossing: true },
4009
- { from: afterCrossing, to: edge.to }
4010
- ];
4011
- edges.splice(i, 1, ...newEdges);
4012
- i += newEdges.length - 2;
4013
- if (overshot) {
4014
- i++;
4015
- }
4016
- }
4017
- return edges;
4018
- };
4019
-
4020
- // lib/components/primitive-components/Trace/create-schematic-trace-junctions.ts
4021
- var getIntersectionPoint = (edge1, edge2) => {
4022
- if (edge1.from.x === edge1.to.x && edge2.from.x === edge2.to.x) {
4023
- return null;
4024
- }
4025
- if (edge1.from.x === edge1.to.x) {
4026
- const x2 = edge1.from.x;
4027
- const m22 = (edge2.to.y - edge2.from.y) / (edge2.to.x - edge2.from.x);
4028
- const b22 = edge2.from.y - m22 * edge2.from.x;
4029
- const y2 = m22 * x2 + b22;
4030
- if (x2 >= Math.min(edge2.from.x, edge2.to.x) && x2 <= Math.max(edge2.from.x, edge2.to.x) && y2 >= Math.min(edge2.from.y, edge2.to.y) && y2 <= Math.max(edge2.from.y, edge2.to.y)) {
4031
- return { x: x2, y: y2 };
4032
- }
4033
- return null;
4034
- }
4035
- if (edge2.from.x === edge2.to.x) {
4036
- const x2 = edge2.from.x;
4037
- const m12 = (edge1.to.y - edge1.from.y) / (edge1.to.x - edge1.from.x);
4038
- const b12 = edge1.from.y - m12 * edge1.from.x;
4039
- const y2 = m12 * x2 + b12;
4040
- if (x2 >= Math.min(edge1.from.x, edge1.to.x) && x2 <= Math.max(edge1.from.x, edge1.to.x) && y2 >= Math.min(edge1.from.y, edge1.to.y) && y2 <= Math.max(edge1.from.y, edge1.to.y)) {
4041
- return { x: x2, y: y2 };
4042
- }
4043
- return null;
4044
- }
4045
- const m1 = (edge1.to.y - edge1.from.y) / (edge1.to.x - edge1.from.x);
4046
- const b1 = edge1.from.y - m1 * edge1.from.x;
4047
- const m2 = (edge2.to.y - edge2.from.y) / (edge2.to.x - edge2.from.x);
4048
- const b2 = edge2.from.y - m2 * edge2.from.x;
4049
- if (m1 === m2) {
4050
- return null;
4051
- }
4052
- const x = (b2 - b1) / (m1 - m2);
4053
- const y = m1 * x + b1;
4054
- const isWithinEdge1 = x >= Math.min(edge1.from.x, edge1.to.x) && x <= Math.max(edge1.from.x, edge1.to.x) && y >= Math.min(edge1.from.y, edge1.to.y) && y <= Math.max(edge1.from.y, edge1.to.y);
4055
- const isWithinEdge2 = x >= Math.min(edge2.from.x, edge2.to.x) && x <= Math.max(edge2.from.x, edge2.to.x) && y >= Math.min(edge2.from.y, edge2.to.y) && y <= Math.max(edge2.from.y, edge2.to.y);
4056
- if (isWithinEdge1 && isWithinEdge2) {
4057
- return { x, y };
4058
- }
4059
- return null;
4060
- };
4061
- var createSchematicTraceJunctions = ({
4062
- edges: myEdges,
4063
- db,
4064
- source_trace_id
4065
- }) => {
4066
- const otherEdges = getOtherSchematicTraces({
4067
- db,
4068
- source_trace_id,
4069
- sameNetOnly: true
4070
- }).flatMap((t) => t.edges);
4071
- const junctions = /* @__PURE__ */ new Set();
4072
- for (const myEdge of myEdges) {
4073
- for (const otherEdge of otherEdges) {
4074
- const intersection = getIntersectionPoint(myEdge, otherEdge);
4075
- if (intersection) {
4076
- const pointKey = `${intersection.x},${intersection.y}`;
4077
- return [{ x: intersection.x, y: intersection.y }];
4078
- }
4079
- }
4080
- }
4081
- return [];
4082
- };
4083
-
4084
- // lib/components/primitive-components/Trace/get-max-length-from-connected-capacitors.ts
3893
+ // lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-capacitors.ts
4085
3894
  var getMaxLengthFromConnectedCapacitors = (ports, { db }) => {
4086
3895
  const capacitorMaxLengths = ports.map((port) => {
4087
3896
  const sourcePort = db.source_port.get(port.source_port_id);
@@ -4098,219 +3907,20 @@ var getMaxLengthFromConnectedCapacitors = (ports, { db }) => {
4098
3907
  return Math.min(...capacitorMaxLengths);
4099
3908
  };
4100
3909
 
4101
- // lib/components/primitive-components/Trace/get-obstacles-for-trace.ts
4102
- import { getUnitVectorFromDirection } from "@tscircuit/math-utils";
4103
-
4104
- // lib/utils/autorouting/getBoundsForSchematic.ts
4105
- function getBoundsForSchematic(db) {
4106
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
4107
- for (const elm of db) {
4108
- let cx, cy, w, h;
4109
- if (elm.type === "schematic_component") {
4110
- cx = elm.center?.x;
4111
- cy = elm.center?.y;
4112
- w = elm.size?.width;
4113
- h = elm.size?.height;
4114
- } else if (elm.type === "schematic_box") {
4115
- cx = elm.x;
4116
- cy = elm.y;
4117
- w = elm.width;
4118
- h = elm.height;
4119
- } else if (elm.type === "schematic_port") {
4120
- cx = elm.center?.x;
4121
- cy = elm.center?.y;
4122
- w = 0.2;
4123
- h = 0.2;
4124
- } else if (elm.type === "schematic_text") {
4125
- cx = elm.position?.x;
4126
- cy = elm.position?.y;
4127
- w = (elm.text?.length ?? 0) * 0.1;
4128
- h = 0.2;
4129
- }
4130
- if (typeof cx === "number" && typeof cy === "number" && typeof w === "number" && typeof h === "number") {
4131
- minX = Math.min(minX, cx - w / 2);
4132
- maxX = Math.max(maxX, cx + w / 2);
4133
- minY = Math.min(minY, cy - h / 2);
4134
- maxY = Math.max(maxY, cy + h / 2);
4135
- }
3910
+ // lib/components/primitive-components/Trace/trace-utils/get-trace-display-name.ts
3911
+ function getTraceDisplayName({
3912
+ ports,
3913
+ nets
3914
+ }) {
3915
+ if (ports.length >= 2) {
3916
+ return `${ports[0]?.selector} to ${ports[1]?.selector}`;
4136
3917
  }
4137
- return { minX, maxX, minY, maxY };
3918
+ if (ports.length === 1 && nets.length === 1) {
3919
+ return `${ports[0]?.selector} to net.${nets[0]._parsedProps.name}`;
3920
+ }
3921
+ return void 0;
4138
3922
  }
4139
3923
 
4140
- // lib/utils/autorouting/getObstaclesFromBounds.ts
4141
- function getObstaclesFromBounds(bounds, opts = {}) {
4142
- const { minX, maxX, minY, maxY } = bounds;
4143
- const PADDING = opts.padding ?? 1;
4144
- if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY))
4145
- return [];
4146
- const left = minX - PADDING;
4147
- const right = maxX + PADDING;
4148
- const top = maxY + PADDING;
4149
- const bottom = minY - PADDING;
4150
- const thickness = 0.01;
4151
- return [
4152
- // Top border (horizontal)
4153
- {
4154
- type: "rect",
4155
- layers: ["top"],
4156
- center: { x: (left + right) / 2, y: top },
4157
- width: right - left,
4158
- height: thickness,
4159
- connectedTo: []
4160
- },
4161
- // Bottom border (horizontal)
4162
- {
4163
- type: "rect",
4164
- layers: ["top"],
4165
- center: { x: (left + right) / 2, y: bottom },
4166
- width: right - left,
4167
- height: thickness,
4168
- connectedTo: []
4169
- },
4170
- // Left border (vertical)
4171
- {
4172
- type: "rect",
4173
- layers: ["top"],
4174
- center: { x: left, y: (top + bottom) / 2 },
4175
- width: thickness,
4176
- height: top - bottom,
4177
- connectedTo: []
4178
- },
4179
- // Right border (vertical)
4180
- {
4181
- type: "rect",
4182
- layers: ["top"],
4183
- center: { x: right, y: (top + bottom) / 2 },
4184
- width: thickness,
4185
- height: top - bottom,
4186
- connectedTo: []
4187
- }
4188
- ];
4189
- }
4190
-
4191
- // lib/components/primitive-components/Trace/get-obstacles-for-trace.ts
4192
- var getSchematicObstaclesForTrace = (trace) => {
4193
- const db = trace.root.db;
4194
- const connectedPorts = trace._findConnectedPorts().ports ?? [];
4195
- const connectedPortIds = new Set(
4196
- connectedPorts.map((p) => p.schematic_port_id)
4197
- );
4198
- const obstacles = [];
4199
- for (const elm of db.toArray()) {
4200
- if (elm.type === "schematic_component") {
4201
- const isSymbol = Boolean(elm.symbol_name);
4202
- const dominateAxis = elm.size.width > elm.size.height ? "horz" : "vert";
4203
- obstacles.push({
4204
- type: "rect",
4205
- layers: ["top"],
4206
- center: elm.center,
4207
- width: elm.size.width + (isSymbol && dominateAxis === "horz" ? -0.5 : 0),
4208
- height: elm.size.height + (isSymbol && dominateAxis === "vert" ? -0.5 : 0),
4209
- connectedTo: []
4210
- });
4211
- }
4212
- if (elm.type === "schematic_port") {
4213
- if (connectedPortIds.has(elm.schematic_port_id)) {
4214
- continue;
4215
- }
4216
- const dirVec = elm.facing_direction ? getUnitVectorFromDirection(elm.facing_direction) : {
4217
- x: 0,
4218
- y: 0
4219
- };
4220
- obstacles.push({
4221
- type: "rect",
4222
- layers: ["top"],
4223
- center: {
4224
- x: elm.center.x - dirVec.x * 0.1,
4225
- y: elm.center.y - dirVec.y * 0.1
4226
- },
4227
- width: 0.1 + Math.abs(dirVec.x) * 0.3,
4228
- height: 0.1 + Math.abs(dirVec.y) * 0.3,
4229
- connectedTo: []
4230
- });
4231
- }
4232
- if (elm.type === "schematic_text") {
4233
- obstacles.push({
4234
- type: "rect",
4235
- layers: ["top"],
4236
- center: elm.position,
4237
- width: (elm.text?.length ?? 0) * 0.1,
4238
- height: 0.2,
4239
- connectedTo: []
4240
- });
4241
- }
4242
- if (elm.type === "schematic_box") {
4243
- obstacles.push({
4244
- type: "rect",
4245
- layers: ["top"],
4246
- center: { x: elm.x, y: elm.y },
4247
- width: elm.width,
4248
- height: elm.height,
4249
- connectedTo: []
4250
- });
4251
- }
4252
- }
4253
- const bounds = getBoundsForSchematic(db.toArray());
4254
- obstacles.push(...getObstaclesFromBounds(bounds, { padding: 1 }));
4255
- return obstacles;
4256
- };
4257
-
4258
- // lib/components/primitive-components/Trace/get-trace-display-name.ts
4259
- function getTraceDisplayName({
4260
- ports,
4261
- nets
4262
- }) {
4263
- if (ports.length >= 2) {
4264
- return `${ports[0]?.selector} to ${ports[1]?.selector}`;
4265
- }
4266
- if (ports.length === 1 && nets.length === 1) {
4267
- return `${ports[0]?.selector} to net.${nets[0]._parsedProps.name}`;
4268
- }
4269
- return void 0;
4270
- }
4271
-
4272
- // lib/components/primitive-components/Trace/push-edges-of-schematic-trace-to-prevent-overlap.ts
4273
- import { doesLineIntersectLine as doesLineIntersectLine2 } from "@tscircuit/math-utils";
4274
- var pushEdgesOfSchematicTraceToPreventOverlap = ({
4275
- edges,
4276
- db,
4277
- source_trace_id
4278
- }) => {
4279
- const mySourceTrace = db.source_trace.get(source_trace_id);
4280
- const otherEdges = getOtherSchematicTraces({
4281
- db,
4282
- source_trace_id,
4283
- differentNetOnly: true
4284
- }).flatMap((t) => t.edges);
4285
- const edgeOrientation = (edge) => {
4286
- const { from, to } = edge;
4287
- return from.x === to.x ? "vertical" : "horizontal";
4288
- };
4289
- for (const mySegment of edges) {
4290
- const mySegmentOrientation = edgeOrientation(mySegment);
4291
- const findOverlappingParallelSegment = () => otherEdges.find(
4292
- (otherEdge) => edgeOrientation(otherEdge) === mySegmentOrientation && doesLineIntersectLine2(
4293
- [mySegment.from, mySegment.to],
4294
- [otherEdge.from, otherEdge.to],
4295
- {
4296
- lineThickness: 0.05
4297
- }
4298
- )
4299
- );
4300
- let overlappingParallelSegmentFromOtherTrace = findOverlappingParallelSegment();
4301
- while (overlappingParallelSegmentFromOtherTrace) {
4302
- if (mySegmentOrientation === "horizontal") {
4303
- mySegment.from.y += 0.1;
4304
- mySegment.to.y += 0.1;
4305
- } else {
4306
- mySegment.from.x += 0.1;
4307
- mySegment.to.x += 0.1;
4308
- }
4309
- overlappingParallelSegmentFromOtherTrace = findOverlappingParallelSegment();
4310
- }
4311
- }
4312
- };
4313
-
4314
3924
  // lib/utils/is-route-outside-board.ts
4315
3925
  var isRouteOutsideBoard = (mergedRoute, { db }) => {
4316
3926
  const pcbBoard = db.pcb_board.list()[0];
@@ -4760,135 +4370,1129 @@ var computeSchematicNetLabelCenter = ({
4760
4370
  return center;
4761
4371
  };
4762
4372
 
4763
- // lib/components/primitive-components/Trace/Trace.ts
4764
- var portToObjective = (port) => {
4765
- const portPosition = port._getGlobalPcbPositionAfterLayout();
4766
- return {
4767
- ...portPosition,
4768
- layers: port.getAvailablePcbLayers()
4769
- };
4770
- };
4771
- var SHOULD_USE_SINGLE_LAYER_ROUTING = false;
4772
- var Trace2 = class extends PrimitiveComponent2 {
4773
- source_trace_id = null;
4774
- pcb_trace_id = null;
4775
- schematic_trace_id = null;
4776
- _portsRoutedOnPcb;
4777
- subcircuit_connectivity_map_key = null;
4778
- _traceConnectionHash = null;
4779
- constructor(props) {
4780
- super(props);
4781
- this._portsRoutedOnPcb = [];
4782
- }
4783
- get config() {
4784
- return {
4785
- zodProps: traceProps,
4786
- componentName: "Trace"
4787
- };
4788
- }
4789
- _getTracePortOrNetSelectorListFromProps() {
4790
- if ("from" in this.props && "to" in this.props) {
4791
- return [
4792
- typeof this.props.from === "string" ? this.props.from : this.props.from.getPortSelector(),
4793
- typeof this.props.to === "string" ? this.props.to : this.props.to.getPortSelector()
4794
- ];
4795
- }
4796
- if ("path" in this.props) {
4797
- return this.props.path.map(
4798
- (p) => typeof p === "string" ? p : p.getPortSelector()
4799
- );
4800
- }
4801
- return [];
4802
- }
4803
- getTracePortPathSelectors() {
4804
- return this._getTracePortOrNetSelectorListFromProps().filter(
4805
- (selector) => !selector.includes("net.")
4806
- );
4373
+ // lib/components/primitive-components/Trace/Trace_doInitialSchematicTraceRender.ts
4374
+ import { MultilayerIjump } from "@tscircuit/infgrid-ijump-astar";
4375
+ import "circuit-json";
4376
+
4377
+ // lib/components/primitive-components/Trace/trace-utils/create-schematic-trace-crossing-segments.ts
4378
+ import { distance as distance2, doesLineIntersectLine } from "@tscircuit/math-utils";
4379
+
4380
+ // lib/components/primitive-components/Trace/trace-utils/get-other-schematic-traces.ts
4381
+ var getOtherSchematicTraces = ({
4382
+ db,
4383
+ source_trace_id,
4384
+ sameNetOnly,
4385
+ differentNetOnly
4386
+ }) => {
4387
+ if (!sameNetOnly && !differentNetOnly) {
4388
+ differentNetOnly = true;
4807
4389
  }
4808
- getTracePathNetSelectors() {
4809
- return this._getTracePortOrNetSelectorListFromProps().filter(
4810
- (selector) => selector.includes("net.")
4390
+ const mySourceTrace = db.source_trace.get(source_trace_id);
4391
+ const traces = [];
4392
+ for (const otherSchematicTrace of db.schematic_trace.list()) {
4393
+ if (otherSchematicTrace.source_trace_id === source_trace_id) continue;
4394
+ const otherSourceTrace = db.source_trace.get(
4395
+ otherSchematicTrace.source_trace_id
4811
4396
  );
4812
- }
4813
- _findConnectedPorts() {
4814
- const { db } = this.root;
4815
- const { _parsedProps: props, parent } = this;
4816
- if (!parent) throw new Error("Trace has no parent");
4817
- const portSelectors = this.getTracePortPathSelectors();
4818
- const portsWithSelectors = portSelectors.map((selector) => ({
4819
- selector,
4820
- port: this.getSubcircuit().selectOne(selector, { type: "port" }) ?? null
4821
- }));
4822
- for (const { selector, port } of portsWithSelectors) {
4823
- if (!port) {
4824
- let parentSelector;
4825
- let portToken;
4826
- const dotIndex = selector.lastIndexOf(".");
4827
- if (dotIndex !== -1 && dotIndex > selector.lastIndexOf(" ")) {
4828
- parentSelector = selector.slice(0, dotIndex);
4829
- portToken = selector.slice(dotIndex + 1);
4830
- } else {
4831
- const match = selector.match(/^(.*[ >])?([^ >]+)$/);
4832
- parentSelector = match?.[1]?.trim() ?? "";
4833
- portToken = match?.[2] ?? selector;
4834
- }
4835
- let targetComponent = parentSelector ? this.getSubcircuit().selectOne(parentSelector) : null;
4836
- if (!targetComponent && parentSelector && !/[.#\[]/.test(parentSelector)) {
4837
- targetComponent = this.getSubcircuit().selectOne(`.${parentSelector}`);
4838
- }
4839
- if (!targetComponent) {
4840
- if (parentSelector) {
4841
- this.renderError(
4842
- `Could not find port for selector "${selector}". Component "${parentSelector}" not found`
4843
- );
4844
- } else {
4845
- this.renderError(`Could not find port for selector "${selector}"`);
4846
- }
4847
- } else {
4848
- const ports = targetComponent.children.filter(
4849
- (c) => c.componentName === "Port"
4850
- );
4851
- const portLabel = portToken.includes(".") ? portToken.split(".").pop() ?? "" : portToken;
4852
- const portNames = ports.map((c) => c.getNameAndAliases()).flat();
4853
- const hasCustomLabels = portNames.some(
4854
- (n) => !/^(pin\d+|\d+)$/.test(n)
4855
- );
4856
- const labelList = Array.from(new Set(portNames)).join(", ");
4857
- let detail;
4858
- if (ports.length === 0) {
4859
- detail = "It has no ports";
4860
- } else if (!hasCustomLabels) {
4861
- detail = `It has ${ports.length} pins and no pinLabels (consider adding pinLabels)`;
4862
- } else {
4863
- detail = `It has [${labelList}]`;
4864
- }
4865
- this.renderError(
4866
- `Could not find port for selector "${selector}". Component "${targetComponent.props.name ?? parentSelector}" found, but does not have pin "${portLabel}". ${detail}`
4867
- );
4868
- }
4869
- }
4397
+ const isSameNet = otherSourceTrace?.subcircuit_connectivity_map_key === mySourceTrace.subcircuit_connectivity_map_key;
4398
+ if (differentNetOnly && isSameNet) {
4399
+ continue;
4870
4400
  }
4871
- if (portsWithSelectors.some((p) => !p.port)) {
4872
- return { allPortsFound: false };
4401
+ if (sameNetOnly && !isSameNet) {
4402
+ continue;
4873
4403
  }
4874
- return {
4875
- allPortsFound: true,
4876
- portsWithSelectors,
4877
- ports: portsWithSelectors.map(({ port }) => port)
4878
- };
4879
- }
4880
- _resolveNet(selector) {
4881
- const direct = this.getSubcircuit().selectOne(selector, {
4882
- type: "net"
4883
- });
4884
- if (direct) return direct;
4885
- const match = selector.match(/^net\.(.+)$/);
4886
- const netName = match ? match[1] : null;
4887
- if (!netName) return null;
4888
- const allDescendants = this.root._getBoard().getDescendants();
4889
- return allDescendants.find(
4890
- (d) => d.componentName === "Net" && d._parsedProps.name === netName
4891
- ) || null;
4404
+ traces.push(otherSchematicTrace);
4405
+ }
4406
+ return traces;
4407
+ };
4408
+
4409
+ // lib/components/primitive-components/Trace/trace-utils/create-schematic-trace-crossing-segments.ts
4410
+ import { getUnitVectorFromPointAToB } from "@tscircuit/math-utils";
4411
+ var createSchematicTraceCrossingSegments = ({
4412
+ edges: inputEdges,
4413
+ otherEdges
4414
+ }) => {
4415
+ const edges = [...inputEdges];
4416
+ for (let i = 0; i < edges.length; i++) {
4417
+ if (i > 2e3) {
4418
+ throw new Error(
4419
+ "Over 2000 iterations spent inside createSchematicTraceCrossingSegments, you have triggered an infinite loop, please report this!"
4420
+ );
4421
+ }
4422
+ const edge = edges[i];
4423
+ const edgeOrientation = Math.abs(edge.from.x - edge.to.x) < 0.01 ? "vertical" : edge.from.y === edge.to.y ? "horizontal" : "not-orthogonal";
4424
+ if (edgeOrientation === "not-orthogonal") {
4425
+ continue;
4426
+ }
4427
+ const otherEdgesIntersections = [];
4428
+ for (const otherEdge of otherEdges) {
4429
+ const otherOrientation = otherEdge.from.x === otherEdge.to.x ? "vertical" : otherEdge.from.y === otherEdge.to.y ? "horizontal" : "not-orthogonal";
4430
+ if (otherOrientation === "not-orthogonal") continue;
4431
+ if (edgeOrientation === otherOrientation)
4432
+ continue;
4433
+ const hasIntersection = doesLineIntersectLine(
4434
+ [edge.from, edge.to],
4435
+ [otherEdge.from, otherEdge.to],
4436
+ { lineThickness: 0.01 }
4437
+ );
4438
+ if (hasIntersection) {
4439
+ const intersectX = edgeOrientation === "vertical" ? edge.from.x : otherEdge.from.x;
4440
+ const intersectY = edgeOrientation === "vertical" ? otherEdge.from.y : edge.from.y;
4441
+ const crossingPoint2 = { x: intersectX, y: intersectY };
4442
+ otherEdgesIntersections.push({
4443
+ otherEdge,
4444
+ crossingPoint: crossingPoint2,
4445
+ distanceFromEdgeFrom: distance2(edge.from, crossingPoint2)
4446
+ });
4447
+ }
4448
+ }
4449
+ if (otherEdgesIntersections.length === 0) continue;
4450
+ let closestIntersection = otherEdgesIntersections[0];
4451
+ for (const intersection of otherEdgesIntersections) {
4452
+ if (intersection.distanceFromEdgeFrom < closestIntersection.distanceFromEdgeFrom) {
4453
+ closestIntersection = intersection;
4454
+ }
4455
+ }
4456
+ const crossingPoint = closestIntersection.crossingPoint;
4457
+ const crossingSegmentLength = 0.075;
4458
+ if (crossingPoint.x === edge.from.x && crossingPoint.y === edge.from.y) {
4459
+ continue;
4460
+ }
4461
+ const crossingUnitVec = getUnitVectorFromPointAToB(edge.from, crossingPoint);
4462
+ const beforeCrossing = {
4463
+ x: crossingPoint.x - crossingUnitVec.x * crossingSegmentLength / 2,
4464
+ y: crossingPoint.y - crossingUnitVec.y * crossingSegmentLength / 2
4465
+ };
4466
+ const afterCrossing = {
4467
+ x: crossingPoint.x + crossingUnitVec.x * crossingSegmentLength / 2,
4468
+ y: crossingPoint.y + crossingUnitVec.y * crossingSegmentLength / 2
4469
+ };
4470
+ const overshot = distance2(afterCrossing, edge.to) < crossingSegmentLength;
4471
+ const newEdges = [
4472
+ { from: edge.from, to: beforeCrossing },
4473
+ { from: beforeCrossing, to: afterCrossing, is_crossing: true },
4474
+ { from: afterCrossing, to: edge.to }
4475
+ ];
4476
+ edges.splice(i, 1, ...newEdges);
4477
+ i += newEdges.length - 2;
4478
+ if (overshot) {
4479
+ i++;
4480
+ }
4481
+ }
4482
+ return edges;
4483
+ };
4484
+
4485
+ // lib/components/primitive-components/Trace/trace-utils/create-schematic-trace-junctions.ts
4486
+ var getIntersectionPoint = (edge1, edge2) => {
4487
+ if (edge1.from.x === edge1.to.x && edge2.from.x === edge2.to.x) {
4488
+ return null;
4489
+ }
4490
+ if (edge1.from.x === edge1.to.x) {
4491
+ const x2 = edge1.from.x;
4492
+ const m22 = (edge2.to.y - edge2.from.y) / (edge2.to.x - edge2.from.x);
4493
+ const b22 = edge2.from.y - m22 * edge2.from.x;
4494
+ const y2 = m22 * x2 + b22;
4495
+ if (x2 >= Math.min(edge2.from.x, edge2.to.x) && x2 <= Math.max(edge2.from.x, edge2.to.x) && y2 >= Math.min(edge2.from.y, edge2.to.y) && y2 <= Math.max(edge2.from.y, edge2.to.y)) {
4496
+ return { x: x2, y: y2 };
4497
+ }
4498
+ return null;
4499
+ }
4500
+ if (edge2.from.x === edge2.to.x) {
4501
+ const x2 = edge2.from.x;
4502
+ const m12 = (edge1.to.y - edge1.from.y) / (edge1.to.x - edge1.from.x);
4503
+ const b12 = edge1.from.y - m12 * edge1.from.x;
4504
+ const y2 = m12 * x2 + b12;
4505
+ if (x2 >= Math.min(edge1.from.x, edge1.to.x) && x2 <= Math.max(edge1.from.x, edge1.to.x) && y2 >= Math.min(edge1.from.y, edge1.to.y) && y2 <= Math.max(edge1.from.y, edge1.to.y)) {
4506
+ return { x: x2, y: y2 };
4507
+ }
4508
+ return null;
4509
+ }
4510
+ const m1 = (edge1.to.y - edge1.from.y) / (edge1.to.x - edge1.from.x);
4511
+ const b1 = edge1.from.y - m1 * edge1.from.x;
4512
+ const m2 = (edge2.to.y - edge2.from.y) / (edge2.to.x - edge2.from.x);
4513
+ const b2 = edge2.from.y - m2 * edge2.from.x;
4514
+ if (m1 === m2) {
4515
+ return null;
4516
+ }
4517
+ const x = (b2 - b1) / (m1 - m2);
4518
+ const y = m1 * x + b1;
4519
+ const isWithinEdge1 = x >= Math.min(edge1.from.x, edge1.to.x) && x <= Math.max(edge1.from.x, edge1.to.x) && y >= Math.min(edge1.from.y, edge1.to.y) && y <= Math.max(edge1.from.y, edge1.to.y);
4520
+ const isWithinEdge2 = x >= Math.min(edge2.from.x, edge2.to.x) && x <= Math.max(edge2.from.x, edge2.to.x) && y >= Math.min(edge2.from.y, edge2.to.y) && y <= Math.max(edge2.from.y, edge2.to.y);
4521
+ if (isWithinEdge1 && isWithinEdge2) {
4522
+ return { x, y };
4523
+ }
4524
+ return null;
4525
+ };
4526
+ var createSchematicTraceJunctions = ({
4527
+ edges: myEdges,
4528
+ db,
4529
+ source_trace_id
4530
+ }) => {
4531
+ const otherEdges = getOtherSchematicTraces({
4532
+ db,
4533
+ source_trace_id,
4534
+ sameNetOnly: true
4535
+ }).flatMap((t) => t.edges);
4536
+ const junctions = /* @__PURE__ */ new Set();
4537
+ for (const myEdge of myEdges) {
4538
+ for (const otherEdge of otherEdges) {
4539
+ const intersection = getIntersectionPoint(myEdge, otherEdge);
4540
+ if (intersection) {
4541
+ const pointKey = `${intersection.x},${intersection.y}`;
4542
+ return [{ x: intersection.x, y: intersection.y }];
4543
+ }
4544
+ }
4545
+ }
4546
+ return [];
4547
+ };
4548
+
4549
+ // lib/components/primitive-components/Trace/trace-utils/get-obstacles-for-trace.ts
4550
+ import { getUnitVectorFromDirection } from "@tscircuit/math-utils";
4551
+
4552
+ // lib/utils/autorouting/getBoundsForSchematic.ts
4553
+ function getBoundsForSchematic(db) {
4554
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
4555
+ for (const elm of db) {
4556
+ let cx, cy, w, h;
4557
+ if (elm.type === "schematic_component") {
4558
+ cx = elm.center?.x;
4559
+ cy = elm.center?.y;
4560
+ w = elm.size?.width;
4561
+ h = elm.size?.height;
4562
+ } else if (elm.type === "schematic_box") {
4563
+ cx = elm.x;
4564
+ cy = elm.y;
4565
+ w = elm.width;
4566
+ h = elm.height;
4567
+ } else if (elm.type === "schematic_port") {
4568
+ cx = elm.center?.x;
4569
+ cy = elm.center?.y;
4570
+ w = 0.2;
4571
+ h = 0.2;
4572
+ } else if (elm.type === "schematic_text") {
4573
+ cx = elm.position?.x;
4574
+ cy = elm.position?.y;
4575
+ w = (elm.text?.length ?? 0) * 0.1;
4576
+ h = 0.2;
4577
+ }
4578
+ if (typeof cx === "number" && typeof cy === "number" && typeof w === "number" && typeof h === "number") {
4579
+ minX = Math.min(minX, cx - w / 2);
4580
+ maxX = Math.max(maxX, cx + w / 2);
4581
+ minY = Math.min(minY, cy - h / 2);
4582
+ maxY = Math.max(maxY, cy + h / 2);
4583
+ }
4584
+ }
4585
+ return { minX, maxX, minY, maxY };
4586
+ }
4587
+
4588
+ // lib/utils/autorouting/getObstaclesFromBounds.ts
4589
+ function getObstaclesFromBounds(bounds, opts = {}) {
4590
+ const { minX, maxX, minY, maxY } = bounds;
4591
+ const PADDING = opts.padding ?? 1;
4592
+ if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY))
4593
+ return [];
4594
+ const left = minX - PADDING;
4595
+ const right = maxX + PADDING;
4596
+ const top = maxY + PADDING;
4597
+ const bottom = minY - PADDING;
4598
+ const thickness = 0.01;
4599
+ return [
4600
+ // Top border (horizontal)
4601
+ {
4602
+ type: "rect",
4603
+ layers: ["top"],
4604
+ center: { x: (left + right) / 2, y: top },
4605
+ width: right - left,
4606
+ height: thickness,
4607
+ connectedTo: []
4608
+ },
4609
+ // Bottom border (horizontal)
4610
+ {
4611
+ type: "rect",
4612
+ layers: ["top"],
4613
+ center: { x: (left + right) / 2, y: bottom },
4614
+ width: right - left,
4615
+ height: thickness,
4616
+ connectedTo: []
4617
+ },
4618
+ // Left border (vertical)
4619
+ {
4620
+ type: "rect",
4621
+ layers: ["top"],
4622
+ center: { x: left, y: (top + bottom) / 2 },
4623
+ width: thickness,
4624
+ height: top - bottom,
4625
+ connectedTo: []
4626
+ },
4627
+ // Right border (vertical)
4628
+ {
4629
+ type: "rect",
4630
+ layers: ["top"],
4631
+ center: { x: right, y: (top + bottom) / 2 },
4632
+ width: thickness,
4633
+ height: top - bottom,
4634
+ connectedTo: []
4635
+ }
4636
+ ];
4637
+ }
4638
+
4639
+ // lib/components/primitive-components/Trace/trace-utils/get-obstacles-for-trace.ts
4640
+ var getSchematicObstaclesForTrace = (trace) => {
4641
+ const db = trace.root.db;
4642
+ const connectedPorts = trace._findConnectedPorts().ports ?? [];
4643
+ const connectedPortIds = new Set(
4644
+ connectedPorts.map((p) => p.schematic_port_id)
4645
+ );
4646
+ const obstacles = [];
4647
+ for (const elm of db.toArray()) {
4648
+ if (elm.type === "schematic_component") {
4649
+ const isSymbol = Boolean(elm.symbol_name);
4650
+ const dominateAxis = elm.size.width > elm.size.height ? "horz" : "vert";
4651
+ obstacles.push({
4652
+ type: "rect",
4653
+ layers: ["top"],
4654
+ center: elm.center,
4655
+ width: elm.size.width + (isSymbol && dominateAxis === "horz" ? -0.5 : 0),
4656
+ height: elm.size.height + (isSymbol && dominateAxis === "vert" ? -0.5 : 0),
4657
+ connectedTo: []
4658
+ });
4659
+ }
4660
+ if (elm.type === "schematic_port") {
4661
+ if (connectedPortIds.has(elm.schematic_port_id)) {
4662
+ continue;
4663
+ }
4664
+ const dirVec = elm.facing_direction ? getUnitVectorFromDirection(elm.facing_direction) : {
4665
+ x: 0,
4666
+ y: 0
4667
+ };
4668
+ obstacles.push({
4669
+ type: "rect",
4670
+ layers: ["top"],
4671
+ center: {
4672
+ x: elm.center.x - dirVec.x * 0.1,
4673
+ y: elm.center.y - dirVec.y * 0.1
4674
+ },
4675
+ width: 0.1 + Math.abs(dirVec.x) * 0.3,
4676
+ height: 0.1 + Math.abs(dirVec.y) * 0.3,
4677
+ connectedTo: []
4678
+ });
4679
+ }
4680
+ if (elm.type === "schematic_text") {
4681
+ obstacles.push({
4682
+ type: "rect",
4683
+ layers: ["top"],
4684
+ center: elm.position,
4685
+ width: (elm.text?.length ?? 0) * 0.1,
4686
+ height: 0.2,
4687
+ connectedTo: []
4688
+ });
4689
+ }
4690
+ if (elm.type === "schematic_box") {
4691
+ obstacles.push({
4692
+ type: "rect",
4693
+ layers: ["top"],
4694
+ center: { x: elm.x, y: elm.y },
4695
+ width: elm.width,
4696
+ height: elm.height,
4697
+ connectedTo: []
4698
+ });
4699
+ }
4700
+ }
4701
+ const bounds = getBoundsForSchematic(db.toArray());
4702
+ obstacles.push(...getObstaclesFromBounds(bounds, { padding: 1 }));
4703
+ return obstacles;
4704
+ };
4705
+
4706
+ // lib/components/primitive-components/Trace/trace-utils/push-edges-of-schematic-trace-to-prevent-overlap.ts
4707
+ import { doesLineIntersectLine as doesLineIntersectLine2 } from "@tscircuit/math-utils";
4708
+ var pushEdgesOfSchematicTraceToPreventOverlap = ({
4709
+ edges,
4710
+ db,
4711
+ source_trace_id
4712
+ }) => {
4713
+ const mySourceTrace = db.source_trace.get(source_trace_id);
4714
+ const otherEdges = getOtherSchematicTraces({
4715
+ db,
4716
+ source_trace_id,
4717
+ differentNetOnly: true
4718
+ }).flatMap((t) => t.edges);
4719
+ const edgeOrientation = (edge) => {
4720
+ const { from, to } = edge;
4721
+ return from.x === to.x ? "vertical" : "horizontal";
4722
+ };
4723
+ for (const mySegment of edges) {
4724
+ const mySegmentOrientation = edgeOrientation(mySegment);
4725
+ const findOverlappingParallelSegment = () => otherEdges.find(
4726
+ (otherEdge) => edgeOrientation(otherEdge) === mySegmentOrientation && doesLineIntersectLine2(
4727
+ [mySegment.from, mySegment.to],
4728
+ [otherEdge.from, otherEdge.to],
4729
+ {
4730
+ lineThickness: 0.05
4731
+ }
4732
+ )
4733
+ );
4734
+ let overlappingParallelSegmentFromOtherTrace = findOverlappingParallelSegment();
4735
+ while (overlappingParallelSegmentFromOtherTrace) {
4736
+ if (mySegmentOrientation === "horizontal") {
4737
+ mySegment.from.y += 0.1;
4738
+ mySegment.to.y += 0.1;
4739
+ } else {
4740
+ mySegment.from.x += 0.1;
4741
+ mySegment.to.x += 0.1;
4742
+ }
4743
+ overlappingParallelSegmentFromOtherTrace = findOverlappingParallelSegment();
4744
+ }
4745
+ }
4746
+ };
4747
+
4748
+ // lib/components/primitive-components/Trace/Trace_doInitialSchematicTraceRender.ts
4749
+ var Trace_doInitialSchematicTraceRender = (trace) => {
4750
+ if (trace.root?.schematicDisabled) return;
4751
+ const { db } = trace.root;
4752
+ const { _parsedProps: props, parent } = trace;
4753
+ if (!parent) throw new Error("Trace has no parent");
4754
+ const { allPortsFound, portsWithSelectors: connectedPorts } = trace._findConnectedPorts();
4755
+ const { netsWithSelectors } = trace._findConnectedNets();
4756
+ if (!allPortsFound) return;
4757
+ const portIds = connectedPorts.map((p) => p.port.schematic_port_id).sort();
4758
+ const portPairKey = portIds.join(",");
4759
+ const board = trace.root?._getBoard();
4760
+ if (board?._connectedSchematicPortPairs) {
4761
+ if (board._connectedSchematicPortPairs.has(portPairKey)) {
4762
+ return;
4763
+ }
4764
+ }
4765
+ const connection = {
4766
+ name: trace.source_trace_id,
4767
+ pointsToConnect: []
4768
+ };
4769
+ const obstacles = getSchematicObstaclesForTrace(trace);
4770
+ const portsWithPosition = connectedPorts.map(({ port }) => ({
4771
+ port,
4772
+ position: port._getGlobalSchematicPositionAfterLayout(),
4773
+ schematic_port_id: port.schematic_port_id ?? void 0,
4774
+ facingDirection: port.facingDirection
4775
+ }));
4776
+ const isPortAndNetConnection = portsWithPosition.length === 1 && netsWithSelectors.length === 1;
4777
+ if (isPortAndNetConnection) {
4778
+ const net = netsWithSelectors[0].net;
4779
+ const { port, position: anchorPos } = portsWithPosition[0];
4780
+ let connectedNetLabel = trace.getSubcircuit().selectAll("netlabel").find((nl) => {
4781
+ const conn = nl._parsedProps.connection ?? nl._parsedProps.connectsTo;
4782
+ if (!conn) return false;
4783
+ if (Array.isArray(conn)) {
4784
+ return conn.some((selector) => {
4785
+ const targetPort2 = trace.getSubcircuit().selectOne(selector, {
4786
+ port: true
4787
+ });
4788
+ return targetPort2 === port;
4789
+ });
4790
+ }
4791
+ const targetPort = trace.getSubcircuit().selectOne(conn, {
4792
+ port: true
4793
+ });
4794
+ return targetPort === port;
4795
+ });
4796
+ if (!connectedNetLabel) {
4797
+ const dbNetLabel = db.schematic_net_label.getWhere({
4798
+ source_trace_id: trace.source_trace_id
4799
+ });
4800
+ if (dbNetLabel) {
4801
+ connectedNetLabel = dbNetLabel;
4802
+ }
4803
+ }
4804
+ if (connectedNetLabel) {
4805
+ const labelPos = "_getGlobalSchematicPositionBeforeLayout" in connectedNetLabel ? connectedNetLabel._getGlobalSchematicPositionBeforeLayout() : connectedNetLabel.anchor_position;
4806
+ const edges2 = [];
4807
+ if (anchorPos.x === labelPos.x || anchorPos.y === labelPos.y) {
4808
+ edges2.push({ from: anchorPos, to: labelPos });
4809
+ } else {
4810
+ edges2.push({ from: anchorPos, to: { x: labelPos.x, y: anchorPos.y } });
4811
+ edges2.push({ from: { x: labelPos.x, y: anchorPos.y }, to: labelPos });
4812
+ }
4813
+ const dbTrace2 = db.schematic_trace.insert({
4814
+ source_trace_id: trace.source_trace_id,
4815
+ edges: edges2,
4816
+ junctions: []
4817
+ });
4818
+ trace.schematic_trace_id = dbTrace2.schematic_trace_id;
4819
+ return;
4820
+ }
4821
+ if (trace.props.schDisplayLabel) {
4822
+ const side2 = getEnteringEdgeFromDirection(port.facingDirection) ?? "bottom";
4823
+ db.schematic_net_label.insert({
4824
+ text: trace.props.schDisplayLabel,
4825
+ source_net_id: net.source_net_id,
4826
+ anchor_position: anchorPos,
4827
+ center: computeSchematicNetLabelCenter({
4828
+ anchor_position: anchorPos,
4829
+ anchor_side: side2,
4830
+ text: trace.props.schDisplayLabel
4831
+ }),
4832
+ anchor_side: side2
4833
+ });
4834
+ return;
4835
+ }
4836
+ const side = getEnteringEdgeFromDirection(port.facingDirection) ?? "bottom";
4837
+ const netLabel = db.schematic_net_label.insert({
4838
+ text: net._parsedProps.name,
4839
+ source_net_id: net.source_net_id,
4840
+ anchor_position: anchorPos,
4841
+ center: computeSchematicNetLabelCenter({
4842
+ anchor_position: anchorPos,
4843
+ anchor_side: side,
4844
+ text: net._parsedProps.name
4845
+ }),
4846
+ anchor_side: side
4847
+ });
4848
+ return;
4849
+ }
4850
+ if (trace.props.schDisplayLabel) {
4851
+ if ("from" in trace.props && "to" in trace.props || "path" in trace.props) {
4852
+ trace._doInitialSchematicTraceRenderWithDisplayLabel();
4853
+ return;
4854
+ }
4855
+ }
4856
+ if (portsWithPosition.length < 2) {
4857
+ return;
4858
+ }
4859
+ connection.pointsToConnect = portsWithPosition.map(({ position }) => ({
4860
+ ...position,
4861
+ layer: "top"
4862
+ }));
4863
+ const bounds = computeObstacleBounds(obstacles);
4864
+ const BOUNDS_MARGIN = 2;
4865
+ const simpleRouteJsonInput = {
4866
+ minTraceWidth: 0.1,
4867
+ obstacles,
4868
+ connections: [connection],
4869
+ bounds: {
4870
+ minX: bounds.minX - BOUNDS_MARGIN,
4871
+ maxX: bounds.maxX + BOUNDS_MARGIN,
4872
+ minY: bounds.minY - BOUNDS_MARGIN,
4873
+ maxY: bounds.maxY + BOUNDS_MARGIN
4874
+ },
4875
+ layerCount: 1
4876
+ };
4877
+ let Autorouter = MultilayerIjump;
4878
+ let skipOtherTraceInteraction = false;
4879
+ if (trace.getSubcircuit().props._schDirectLineRoutingEnabled) {
4880
+ Autorouter = DirectLineRouter;
4881
+ skipOtherTraceInteraction = true;
4882
+ }
4883
+ const autorouter = new Autorouter({
4884
+ input: simpleRouteJsonInput,
4885
+ MAX_ITERATIONS: 100,
4886
+ OBSTACLE_MARGIN: 0.1,
4887
+ isRemovePathLoopsEnabled: true,
4888
+ isShortenPathWithShortcutsEnabled: true,
4889
+ marginsWithCosts: [
4890
+ {
4891
+ margin: 1,
4892
+ enterCost: 0,
4893
+ travelCostFactor: 1
4894
+ },
4895
+ {
4896
+ margin: 0.3,
4897
+ enterCost: 0,
4898
+ travelCostFactor: 1
4899
+ },
4900
+ {
4901
+ margin: 0.2,
4902
+ enterCost: 0,
4903
+ travelCostFactor: 2
4904
+ },
4905
+ {
4906
+ margin: 0.1,
4907
+ enterCost: 0,
4908
+ travelCostFactor: 3
4909
+ }
4910
+ ]
4911
+ });
4912
+ let results = autorouter.solveAndMapToTraces();
4913
+ if (results.length === 0) {
4914
+ if (trace._isSymbolToChipConnection() || trace._isSymbolToSymbolConnection() || trace._isChipToChipConnection()) {
4915
+ trace._doInitialSchematicTraceRenderWithDisplayLabel();
4916
+ return;
4917
+ }
4918
+ const directLineRouter = new DirectLineRouter({
4919
+ input: simpleRouteJsonInput
4920
+ });
4921
+ results = directLineRouter.solveAndMapToTraces();
4922
+ skipOtherTraceInteraction = true;
4923
+ }
4924
+ const [{ route }] = results;
4925
+ let edges = [];
4926
+ for (let i = 0; i < route.length - 1; i++) {
4927
+ edges.push({
4928
+ from: route[i],
4929
+ to: route[i + 1]
4930
+ });
4931
+ }
4932
+ const source_trace_id = trace.source_trace_id;
4933
+ let junctions = [];
4934
+ if (!skipOtherTraceInteraction) {
4935
+ pushEdgesOfSchematicTraceToPreventOverlap({ edges, db, source_trace_id });
4936
+ const otherEdges = getOtherSchematicTraces({
4937
+ db,
4938
+ source_trace_id,
4939
+ differentNetOnly: true
4940
+ }).flatMap((t) => t.edges);
4941
+ edges = createSchematicTraceCrossingSegments({ edges, otherEdges });
4942
+ junctions = createSchematicTraceJunctions({
4943
+ edges,
4944
+ db,
4945
+ source_trace_id: trace.source_trace_id
4946
+ });
4947
+ }
4948
+ const lastEdge = edges[edges.length - 1];
4949
+ const lastEdgePort = portsWithPosition[portsWithPosition.length - 1];
4950
+ const lastDominantDirection = getDominantDirection(lastEdge);
4951
+ edges.push(...getStubEdges({ lastEdge, lastEdgePort, lastDominantDirection }));
4952
+ const firstEdge = edges[0];
4953
+ const firstEdgePort = portsWithPosition[0];
4954
+ const firstDominantDirection = getDominantDirection(firstEdge);
4955
+ edges.unshift(
4956
+ ...getStubEdges({
4957
+ firstEdge,
4958
+ firstEdgePort,
4959
+ firstDominantDirection
4960
+ })
4961
+ );
4962
+ if (!trace.source_trace_id) {
4963
+ throw new Error("Missing source_trace_id for schematic trace insertion.");
4964
+ }
4965
+ if (trace.getSubcircuit()._parsedProps.schTraceAutoLabelEnabled && countComplexElements(junctions, edges) >= 5 && (trace._isSymbolToChipConnection() || trace._isSymbolToSymbolConnection() || trace._isChipToChipConnection())) {
4966
+ trace._doInitialSchematicTraceRenderWithDisplayLabel();
4967
+ return;
4968
+ }
4969
+ const dbTrace = db.schematic_trace.insert({
4970
+ source_trace_id: trace.source_trace_id,
4971
+ edges,
4972
+ junctions
4973
+ });
4974
+ trace.schematic_trace_id = dbTrace.schematic_trace_id;
4975
+ if (board?._connectedSchematicPortPairs)
4976
+ board._connectedSchematicPortPairs.add(portPairKey);
4977
+ };
4978
+
4979
+ // lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts
4980
+ import { MultilayerIjump as MultilayerIjump2 } from "@tscircuit/infgrid-ijump-astar";
4981
+ import "circuit-json";
4982
+ import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map";
4983
+
4984
+ // lib/components/primitive-components/Trace/trace-utils/compute-trace-length.ts
4985
+ function getTraceLength(route) {
4986
+ let totalLength = 0;
4987
+ for (let i = 0; i < route.length; i++) {
4988
+ const point = route[i];
4989
+ if (point.route_type === "wire") {
4990
+ const nextPoint = route[i + 1];
4991
+ if (nextPoint) {
4992
+ const dx = nextPoint.x - point.x;
4993
+ const dy = nextPoint.y - point.y;
4994
+ totalLength += Math.sqrt(dx * dx + dy * dy);
4995
+ }
4996
+ } else if (point.route_type === "via") {
4997
+ totalLength += 1.6;
4998
+ }
4999
+ }
5000
+ return totalLength;
5001
+ }
5002
+
5003
+ // lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts
5004
+ var portToObjective = (port) => {
5005
+ const portPosition = port._getGlobalPcbPositionAfterLayout();
5006
+ return {
5007
+ ...portPosition,
5008
+ layers: port.getAvailablePcbLayers()
5009
+ };
5010
+ };
5011
+ var SHOULD_USE_SINGLE_LAYER_ROUTING = false;
5012
+ function Trace_doInitialPcbTraceRender(trace) {
5013
+ if (trace.root?.pcbDisabled) return;
5014
+ const { db } = trace.root;
5015
+ const { _parsedProps: props, parent } = trace;
5016
+ const subcircuit = trace.getSubcircuit();
5017
+ if (!parent) throw new Error("Trace has no parent");
5018
+ if (subcircuit._parsedProps.routingDisabled) {
5019
+ return;
5020
+ }
5021
+ const cachedRoute = subcircuit._parsedProps.pcbRouteCache?.pcbTraces;
5022
+ if (cachedRoute) {
5023
+ const pcb_trace2 = db.pcb_trace.insert({
5024
+ route: cachedRoute.flatMap((trace2) => trace2.route),
5025
+ source_trace_id: trace.source_trace_id,
5026
+ subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
5027
+ pcb_group_id: trace.getGroup()?.pcb_group_id ?? void 0
5028
+ });
5029
+ trace.pcb_trace_id = pcb_trace2.pcb_trace_id;
5030
+ return;
5031
+ }
5032
+ if (!subcircuit._shouldUseTraceByTraceRouting()) {
5033
+ return;
5034
+ }
5035
+ const { allPortsFound, ports } = trace._findConnectedPorts();
5036
+ const portsConnectedOnPcbViaNet = [];
5037
+ if (!allPortsFound) return;
5038
+ const portsWithoutMatchedPcbPrimitive = [];
5039
+ for (const port of ports) {
5040
+ if (!port._hasMatchedPcbPrimitive()) {
5041
+ portsWithoutMatchedPcbPrimitive.push(port);
5042
+ }
5043
+ }
5044
+ if (portsWithoutMatchedPcbPrimitive.length > 0) {
5045
+ db.pcb_trace_error.insert({
5046
+ error_type: "pcb_trace_error",
5047
+ source_trace_id: trace.source_trace_id,
5048
+ message: `Some ports did not have a matching PCB primitive (e.g. a pad or plated hole), this can happen if a footprint is missing. As a result, ${trace} wasn't routed. Missing ports: ${portsWithoutMatchedPcbPrimitive.map((p) => p.getString()).join(", ")}`,
5049
+ pcb_trace_id: trace.pcb_trace_id,
5050
+ pcb_component_ids: [],
5051
+ pcb_port_ids: portsWithoutMatchedPcbPrimitive.map((p) => p.pcb_port_id).filter(Boolean)
5052
+ });
5053
+ return;
5054
+ }
5055
+ const nets = trace._findConnectedNets().netsWithSelectors;
5056
+ if (ports.length === 0 && nets.length === 2) {
5057
+ trace.renderError(
5058
+ `Trace connects two nets, we haven't implemented a way to route this yet`
5059
+ );
5060
+ return;
5061
+ } else if (ports.length === 1 && nets.length === 1) {
5062
+ const port = ports[0];
5063
+ const portsInNet = nets[0].net.getAllConnectedPorts();
5064
+ const otherPortsInNet = portsInNet.filter((p) => p !== port);
5065
+ if (otherPortsInNet.length === 0) {
5066
+ console.log(
5067
+ "Nothing to connect this port to, the net is empty. TODO should emit a warning!"
5068
+ );
5069
+ return;
5070
+ }
5071
+ const closestPortInNet = getClosest(port, otherPortsInNet);
5072
+ portsConnectedOnPcbViaNet.push(closestPortInNet);
5073
+ ports.push(closestPortInNet);
5074
+ } else if (ports.length > 1 && nets.length >= 1) {
5075
+ trace.renderError(
5076
+ `Trace has more than one port and one or more nets, we don't currently support this type of complex trace routing`
5077
+ );
5078
+ return;
5079
+ }
5080
+ const hints = ports.flatMap(
5081
+ (port) => port.matchedComponents.filter((c) => c.componentName === "TraceHint")
5082
+ );
5083
+ const pcbRouteHints = (trace._parsedProps.pcbRouteHints ?? []).concat(
5084
+ hints.flatMap((h) => h.getPcbRouteHints())
5085
+ );
5086
+ if (ports.length > 2) {
5087
+ trace.renderError(
5088
+ `Trace has more than two ports (${ports.map((p) => p.getString()).join(
5089
+ ", "
5090
+ )}), routing between more than two ports for a single trace is not implemented`
5091
+ );
5092
+ return;
5093
+ }
5094
+ const alreadyRoutedTraces = trace.getSubcircuit().selectAll("trace").filter(
5095
+ (trace2) => trace2.renderPhaseStates.PcbTraceRender.initialized
5096
+ );
5097
+ const isAlreadyRouted = alreadyRoutedTraces.some(
5098
+ (trace2) => trace2._portsRoutedOnPcb.length === ports.length && trace2._portsRoutedOnPcb.every(
5099
+ (portRoutedByOtherTrace) => ports.includes(portRoutedByOtherTrace)
5100
+ )
5101
+ );
5102
+ if (isAlreadyRouted) {
5103
+ return;
5104
+ }
5105
+ let orderedRouteObjectives = [];
5106
+ if (pcbRouteHints.length === 0) {
5107
+ orderedRouteObjectives = [
5108
+ portToObjective(ports[0]),
5109
+ portToObjective(ports[1])
5110
+ ];
5111
+ } else {
5112
+ orderedRouteObjectives = [
5113
+ portToObjective(ports[0]),
5114
+ ...pcbRouteHints,
5115
+ portToObjective(ports[1])
5116
+ ];
5117
+ }
5118
+ const candidateLayerCombinations = findPossibleTraceLayerCombinations(
5119
+ orderedRouteObjectives
5120
+ );
5121
+ if (SHOULD_USE_SINGLE_LAYER_ROUTING && candidateLayerCombinations.length === 0) {
5122
+ trace.renderError(
5123
+ `Could not find a common layer (using hints) for trace ${trace.getString()}`
5124
+ );
5125
+ return;
5126
+ }
5127
+ const connMap = getFullConnectivityMapFromCircuitJson(
5128
+ trace.root.db.toArray()
5129
+ );
5130
+ const [obstacles, errGettingObstacles] = tryNow(
5131
+ () => getObstaclesFromCircuitJson(trace.root.db.toArray())
5132
+ // Remove as any when autorouting-dataset gets updated
5133
+ );
5134
+ if (errGettingObstacles) {
5135
+ trace.renderError({
5136
+ type: "pcb_trace_error",
5137
+ error_type: "pcb_trace_error",
5138
+ pcb_trace_error_id: trace.pcb_trace_id,
5139
+ message: `Error getting obstacles for autorouting: ${errGettingObstacles.message}`,
5140
+ source_trace_id: trace.source_trace_id,
5141
+ center: { x: 0, y: 0 },
5142
+ pcb_port_ids: ports.map((p) => p.pcb_port_id),
5143
+ pcb_trace_id: trace.pcb_trace_id,
5144
+ pcb_component_ids: []
5145
+ });
5146
+ return;
5147
+ }
5148
+ for (const obstacle of obstacles) {
5149
+ const connectedTo = obstacle.connectedTo;
5150
+ if (connectedTo.length > 0) {
5151
+ const netId = connMap.getNetConnectedToId(obstacle.connectedTo[0]);
5152
+ if (netId) {
5153
+ obstacle.connectedTo.push(netId);
5154
+ }
5155
+ }
5156
+ }
5157
+ let orderedRoutePoints = [];
5158
+ if (candidateLayerCombinations.length === 0) {
5159
+ orderedRoutePoints = orderedRouteObjectives;
5160
+ } else {
5161
+ const candidateLayerSelections = candidateLayerCombinations[0].layer_path;
5162
+ orderedRoutePoints = orderedRouteObjectives.map((t, idx) => {
5163
+ if (t.via) {
5164
+ return {
5165
+ ...t,
5166
+ via_to_layer: candidateLayerSelections[idx]
5167
+ };
5168
+ }
5169
+ return { ...t, layers: [candidateLayerSelections[idx]] };
5170
+ });
5171
+ }
5172
+ ;
5173
+ orderedRoutePoints[0].pcb_port_id = ports[0].pcb_port_id;
5174
+ orderedRoutePoints[orderedRoutePoints.length - 1].pcb_port_id = ports[1].pcb_port_id;
5175
+ const routes = [];
5176
+ for (const [a, b] of pairs(orderedRoutePoints)) {
5177
+ const dominantLayer = "via_to_layer" in a ? a.via_to_layer : null;
5178
+ const BOUNDS_MARGIN = 2;
5179
+ const aLayer = "layers" in a && a.layers.length === 1 ? a.layers[0] : dominantLayer ?? "top";
5180
+ const bLayer = "layers" in b && b.layers.length === 1 ? b.layers[0] : dominantLayer ?? "top";
5181
+ const pcbPortA = "pcb_port_id" in a ? a.pcb_port_id : null;
5182
+ const pcbPortB = "pcb_port_id" in b ? b.pcb_port_id : null;
5183
+ const minTraceWidth = trace.getSubcircuit()._parsedProps.minTraceWidth ?? 0.16;
5184
+ const ijump = new MultilayerIjump2({
5185
+ OBSTACLE_MARGIN: minTraceWidth * 2,
5186
+ isRemovePathLoopsEnabled: true,
5187
+ optimizeWithGoalBoxes: Boolean(pcbPortA && pcbPortB),
5188
+ connMap,
5189
+ input: {
5190
+ obstacles,
5191
+ minTraceWidth,
5192
+ connections: [
5193
+ {
5194
+ name: trace.source_trace_id,
5195
+ pointsToConnect: [
5196
+ { ...a, layer: aLayer, pcb_port_id: pcbPortA },
5197
+ { ...b, layer: bLayer, pcb_port_id: pcbPortB }
5198
+ ]
5199
+ }
5200
+ ],
5201
+ layerCount: 2,
5202
+ bounds: {
5203
+ minX: Math.min(a.x, b.x) - BOUNDS_MARGIN,
5204
+ maxX: Math.max(a.x, b.x) + BOUNDS_MARGIN,
5205
+ minY: Math.min(a.y, b.y) - BOUNDS_MARGIN,
5206
+ maxY: Math.max(a.y, b.y) + BOUNDS_MARGIN
5207
+ }
5208
+ }
5209
+ });
5210
+ let traces = null;
5211
+ try {
5212
+ traces = ijump.solveAndMapToTraces();
5213
+ } catch (e) {
5214
+ trace.renderError({
5215
+ type: "pcb_trace_error",
5216
+ pcb_trace_error_id: trace.source_trace_id,
5217
+ error_type: "pcb_trace_error",
5218
+ message: `error solving route: ${e.message}`,
5219
+ source_trace_id: trace.pcb_trace_id,
5220
+ center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
5221
+ pcb_port_ids: ports.map((p) => p.pcb_port_id),
5222
+ pcb_trace_id: trace.pcb_trace_id,
5223
+ pcb_component_ids: ports.map((p) => p.pcb_component_id)
5224
+ });
5225
+ }
5226
+ if (!traces) return;
5227
+ if (traces.length === 0) {
5228
+ trace.renderError({
5229
+ type: "pcb_trace_error",
5230
+ error_type: "pcb_trace_error",
5231
+ pcb_trace_error_id: trace.pcb_trace_id,
5232
+ message: `Could not find a route for ${trace}`,
5233
+ source_trace_id: trace.source_trace_id,
5234
+ center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
5235
+ pcb_port_ids: ports.map((p) => p.pcb_port_id),
5236
+ pcb_trace_id: trace.pcb_trace_id,
5237
+ pcb_component_ids: ports.map((p) => p.pcb_component_id)
5238
+ });
5239
+ return;
5240
+ }
5241
+ const [autoroutedTrace] = traces;
5242
+ if (dominantLayer) {
5243
+ autoroutedTrace.route = autoroutedTrace.route.map((p) => {
5244
+ if (p.route_type === "wire" && !p.layer) {
5245
+ p.layer = dominantLayer;
5246
+ }
5247
+ return p;
5248
+ });
5249
+ }
5250
+ if (pcbPortA && autoroutedTrace.route[0].route_type === "wire") {
5251
+ autoroutedTrace.route[0].start_pcb_port_id = pcbPortA;
5252
+ }
5253
+ const lastRoutePoint = autoroutedTrace.route[autoroutedTrace.route.length - 1];
5254
+ if (pcbPortB && lastRoutePoint.route_type === "wire") {
5255
+ lastRoutePoint.end_pcb_port_id = pcbPortB;
5256
+ }
5257
+ routes.push(autoroutedTrace.route);
5258
+ }
5259
+ const mergedRoute = mergeRoutes(routes);
5260
+ const traceLength = getTraceLength(mergedRoute);
5261
+ const pcb_trace = db.pcb_trace.insert({
5262
+ route: mergedRoute,
5263
+ source_trace_id: trace.source_trace_id,
5264
+ subcircuit_id: trace.getSubcircuit()?.subcircuit_id,
5265
+ trace_length: traceLength
5266
+ });
5267
+ trace._portsRoutedOnPcb = ports;
5268
+ trace.pcb_trace_id = pcb_trace.pcb_trace_id;
5269
+ for (const point of mergedRoute) {
5270
+ if (point.route_type === "via") {
5271
+ db.pcb_via.insert({
5272
+ pcb_trace_id: pcb_trace.pcb_trace_id,
5273
+ x: point.x,
5274
+ y: point.y,
5275
+ hole_diameter: 0.3,
5276
+ outer_diameter: 0.6,
5277
+ layers: [point.from_layer, point.to_layer],
5278
+ from_layer: point.from_layer,
5279
+ to_layer: point.to_layer
5280
+ });
5281
+ }
5282
+ }
5283
+ trace._insertErrorIfTraceIsOutsideBoard(mergedRoute, ports);
5284
+ }
5285
+
5286
+ // lib/components/primitive-components/Trace/Trace__doInitialSchematicTraceRenderWithDisplayLabel.ts
5287
+ function Trace__doInitialSchematicTraceRenderWithDisplayLabel(trace) {
5288
+ if (trace.root?.schematicDisabled) return;
5289
+ const { db } = trace.root;
5290
+ const { _parsedProps: props, parent } = trace;
5291
+ if (!parent) throw new Error("Trace has no parent");
5292
+ const { allPortsFound, portsWithSelectors: connectedPorts } = trace._findConnectedPorts();
5293
+ if (!allPortsFound) return;
5294
+ const portsWithPosition = connectedPorts.map(({ port }) => ({
5295
+ port,
5296
+ position: port._getGlobalSchematicPositionAfterLayout(),
5297
+ schematic_port_id: port.schematic_port_id,
5298
+ facingDirection: port.facingDirection
5299
+ }));
5300
+ if (portsWithPosition.length < 2) {
5301
+ throw new Error("Expected at least two ports in portsWithPosition.");
5302
+ }
5303
+ let fromPortName;
5304
+ let toPortName;
5305
+ const fromAnchorPos = portsWithPosition[0].position;
5306
+ const fromPort = portsWithPosition[0].port;
5307
+ if ("path" in trace.props) {
5308
+ if (trace.props.path.length !== 2) {
5309
+ throw new Error("Invalid 'path': Must contain exactly two elements.");
5310
+ }
5311
+ ;
5312
+ [fromPortName, toPortName] = trace.props.path;
5313
+ } else {
5314
+ if (!("from" in trace.props && "to" in trace.props)) {
5315
+ throw new Error("Missing 'from' or 'to' properties in props.");
5316
+ }
5317
+ fromPortName = trace.props.from;
5318
+ toPortName = trace.props.to;
5319
+ }
5320
+ if (!fromPort.source_port_id) {
5321
+ throw new Error(
5322
+ `Missing source_port_id for the 'from' port (${fromPortName}).`
5323
+ );
5324
+ }
5325
+ const toAnchorPos = portsWithPosition[1].position;
5326
+ const toPort = portsWithPosition[1].port;
5327
+ if (!toPort.source_port_id) {
5328
+ throw new Error(`Missing source_port_id for the 'to' port (${toPortName}).`);
5329
+ }
5330
+ const existingFromNetLabel = db.schematic_net_label.list().find((label) => label.source_net_id === fromPort.source_port_id);
5331
+ const existingToNetLabel = db.schematic_net_label.list().find((label) => label.source_net_id === toPort.source_port_id);
5332
+ const [firstPort, secondPort] = connectedPorts.map(({ port }) => port);
5333
+ const isFirstPortSchematicBox = firstPort.parent?.config.shouldRenderAsSchematicBox;
5334
+ const pinFullName = isFirstPortSchematicBox ? `${firstPort?.parent?.props.name}_${firstPort?.props.name}` : `${secondPort?.parent?.props.name}_${secondPort?.props.name}`;
5335
+ const netLabelText = trace.props.schDisplayLabel ?? pinFullName;
5336
+ if (existingFromNetLabel && existingFromNetLabel.text !== netLabelText) {
5337
+ existingFromNetLabel.text = `${netLabelText} / ${existingFromNetLabel.text}`;
5338
+ }
5339
+ if (existingToNetLabel && existingToNetLabel?.text !== netLabelText) {
5340
+ existingToNetLabel.text = `${netLabelText} / ${existingToNetLabel.text}`;
5341
+ }
5342
+ if (!existingToNetLabel) {
5343
+ const toSide = getEnteringEdgeFromDirection(toPort.facingDirection) ?? "bottom";
5344
+ db.schematic_net_label.insert({
5345
+ text: trace.props.schDisplayLabel ?? pinFullName,
5346
+ source_net_id: toPort.source_port_id,
5347
+ anchor_position: toAnchorPos,
5348
+ center: computeSchematicNetLabelCenter({
5349
+ anchor_position: toAnchorPos,
5350
+ anchor_side: toSide,
5351
+ text: trace.props.schDisplayLabel ?? pinFullName
5352
+ }),
5353
+ anchor_side: toSide
5354
+ });
5355
+ }
5356
+ if (!existingFromNetLabel) {
5357
+ const fromSide = getEnteringEdgeFromDirection(fromPort.facingDirection) ?? "bottom";
5358
+ db.schematic_net_label.insert({
5359
+ text: trace.props.schDisplayLabel ?? pinFullName,
5360
+ source_net_id: fromPort.source_port_id,
5361
+ anchor_position: fromAnchorPos,
5362
+ center: computeSchematicNetLabelCenter({
5363
+ anchor_position: fromAnchorPos,
5364
+ anchor_side: fromSide,
5365
+ text: trace.props.schDisplayLabel ?? pinFullName
5366
+ }),
5367
+ anchor_side: fromSide
5368
+ });
5369
+ }
5370
+ }
5371
+
5372
+ // lib/components/primitive-components/Trace/Trace__findConnectedPorts.ts
5373
+ function Trace__findConnectedPorts(trace) {
5374
+ const { db } = trace.root;
5375
+ const { _parsedProps: props, parent } = trace;
5376
+ if (!parent) throw new Error("Trace has no parent");
5377
+ const portSelectors = trace.getTracePortPathSelectors();
5378
+ const portsWithSelectors = portSelectors.map((selector) => ({
5379
+ selector,
5380
+ port: trace.getSubcircuit().selectOne(selector, { type: "port" }) ?? null
5381
+ }));
5382
+ for (const { selector, port } of portsWithSelectors) {
5383
+ if (!port) {
5384
+ let parentSelector;
5385
+ let portToken;
5386
+ const dotIndex = selector.lastIndexOf(".");
5387
+ if (dotIndex !== -1 && dotIndex > selector.lastIndexOf(" ")) {
5388
+ parentSelector = selector.slice(0, dotIndex);
5389
+ portToken = selector.slice(dotIndex + 1);
5390
+ } else {
5391
+ const match = selector.match(/^(.*[ >])?([^ >]+)$/);
5392
+ parentSelector = match?.[1]?.trim() ?? "";
5393
+ portToken = match?.[2] ?? selector;
5394
+ }
5395
+ let targetComponent = parentSelector ? trace.getSubcircuit().selectOne(parentSelector) : null;
5396
+ if (!targetComponent && parentSelector && !/[.#\[]/.test(parentSelector)) {
5397
+ targetComponent = trace.getSubcircuit().selectOne(`.${parentSelector}`);
5398
+ }
5399
+ if (!targetComponent) {
5400
+ if (parentSelector) {
5401
+ trace.renderError(
5402
+ `Could not find port for selector "${selector}". Component "${parentSelector}" not found`
5403
+ );
5404
+ } else {
5405
+ trace.renderError(`Could not find port for selector "${selector}"`);
5406
+ }
5407
+ } else {
5408
+ const ports = targetComponent.children.filter(
5409
+ (c) => c.componentName === "Port"
5410
+ );
5411
+ const portLabel = portToken.includes(".") ? portToken.split(".").pop() ?? "" : portToken;
5412
+ const portNames = ports.flatMap((c) => c.getNameAndAliases());
5413
+ const hasCustomLabels = portNames.some((n) => !/^(pin\d+|\d+)$/.test(n));
5414
+ const labelList = Array.from(new Set(portNames)).join(", ");
5415
+ let detail;
5416
+ if (ports.length === 0) {
5417
+ detail = "It has no ports";
5418
+ } else if (!hasCustomLabels) {
5419
+ detail = `It has ${ports.length} pins and no pinLabels (consider adding pinLabels)`;
5420
+ } else {
5421
+ detail = `It has [${labelList}]`;
5422
+ }
5423
+ trace.renderError(
5424
+ `Could not find port for selector "${selector}". Component "${targetComponent.props.name ?? parentSelector}" found, but does not have pin "${portLabel}". ${detail}`
5425
+ );
5426
+ }
5427
+ }
5428
+ }
5429
+ if (portsWithSelectors.some((p) => !p.port)) {
5430
+ return { allPortsFound: false };
5431
+ }
5432
+ return {
5433
+ allPortsFound: true,
5434
+ portsWithSelectors,
5435
+ ports: portsWithSelectors.map(({ port }) => port)
5436
+ };
5437
+ }
5438
+
5439
+ // lib/components/primitive-components/Trace/Trace.ts
5440
+ var Trace3 = class extends PrimitiveComponent2 {
5441
+ source_trace_id = null;
5442
+ pcb_trace_id = null;
5443
+ schematic_trace_id = null;
5444
+ _portsRoutedOnPcb;
5445
+ subcircuit_connectivity_map_key = null;
5446
+ _traceConnectionHash = null;
5447
+ constructor(props) {
5448
+ super(props);
5449
+ this._portsRoutedOnPcb = [];
5450
+ }
5451
+ get config() {
5452
+ return {
5453
+ zodProps: traceProps,
5454
+ componentName: "Trace"
5455
+ };
5456
+ }
5457
+ _getTracePortOrNetSelectorListFromProps() {
5458
+ if ("from" in this.props && "to" in this.props) {
5459
+ return [
5460
+ typeof this.props.from === "string" ? this.props.from : this.props.from.getPortSelector(),
5461
+ typeof this.props.to === "string" ? this.props.to : this.props.to.getPortSelector()
5462
+ ];
5463
+ }
5464
+ if ("path" in this.props) {
5465
+ return this.props.path.map(
5466
+ (p) => typeof p === "string" ? p : p.getPortSelector()
5467
+ );
5468
+ }
5469
+ return [];
5470
+ }
5471
+ getTracePortPathSelectors() {
5472
+ return this._getTracePortOrNetSelectorListFromProps().filter(
5473
+ (selector) => !selector.includes("net.")
5474
+ );
5475
+ }
5476
+ getTracePathNetSelectors() {
5477
+ return this._getTracePortOrNetSelectorListFromProps().filter(
5478
+ (selector) => selector.includes("net.")
5479
+ );
5480
+ }
5481
+ _findConnectedPorts() {
5482
+ return Trace__findConnectedPorts(this);
5483
+ }
5484
+ _resolveNet(selector) {
5485
+ const direct = this.getSubcircuit().selectOne(selector, {
5486
+ type: "net"
5487
+ });
5488
+ if (direct) return direct;
5489
+ const match = selector.match(/^net\.(.+)$/);
5490
+ const netName = match ? match[1] : null;
5491
+ if (!netName) return null;
5492
+ const allDescendants = this.root._getBoard().getDescendants();
5493
+ return allDescendants.find(
5494
+ (d) => d.componentName === "Net" && d._parsedProps.name === netName
5495
+ ) || null;
4892
5496
  }
4893
5497
  _findConnectedNets() {
4894
5498
  const netsWithSelectors = this.getTracePathNetSelectors().map(
@@ -4944,416 +5548,63 @@ var Trace2 = class extends PrimitiveComponent2 {
4944
5548
  const { allPortsFound, ports } = this._findConnectedPorts();
4945
5549
  if (!allPortsFound || !ports) return null;
4946
5550
  const sortedPorts = [...ports].sort(
4947
- (a, b) => (a.pcb_port_id || "").localeCompare(b.pcb_port_id || "")
4948
- );
4949
- const allIds = sortedPorts.map((p) => p.pcb_port_id);
4950
- return allIds.join(",");
4951
- }
4952
- doInitialSourceTraceRender() {
4953
- const { db } = this.root;
4954
- const { _parsedProps: props, parent } = this;
4955
- if (!parent) {
4956
- this.renderError("Trace has no parent");
4957
- return;
4958
- }
4959
- const { allPortsFound, portsWithSelectors: ports } = this._findConnectedPorts();
4960
- if (!allPortsFound) return;
4961
- this._traceConnectionHash = this._computeTraceConnectionHash();
4962
- const existingTraces = db.source_trace.list();
4963
- const existingTrace = existingTraces.find(
4964
- (t) => t.subcircuit_connectivity_map_key === this.subcircuit_connectivity_map_key && t.connected_source_port_ids.sort().join(",") === this._traceConnectionHash
4965
- );
4966
- if (existingTrace) {
4967
- this.source_trace_id = existingTrace.source_trace_id;
4968
- return;
4969
- }
4970
- const nets = this._findConnectedNets().nets;
4971
- const displayName = getTraceDisplayName({ ports, nets });
4972
- const trace = db.source_trace.insert({
4973
- connected_source_port_ids: ports.map((p) => p.port.source_port_id),
4974
- connected_source_net_ids: nets.map((n) => n.source_net_id),
4975
- subcircuit_id: this.getSubcircuit()?.subcircuit_id,
4976
- max_length: getMaxLengthFromConnectedCapacitors(
4977
- ports.map((p) => p.port),
4978
- { db }
4979
- ) ?? props.maxLength,
4980
- display_name: displayName,
4981
- min_trace_thickness: props.thickness
4982
- });
4983
- this.source_trace_id = trace.source_trace_id;
4984
- }
4985
- _insertErrorIfTraceIsOutsideBoard(mergedRoute, ports) {
4986
- const { db } = this.root;
4987
- const isOutsideBoard = isRouteOutsideBoard(mergedRoute, { db });
4988
- if (isOutsideBoard) {
4989
- db.pcb_trace_error.insert({
4990
- error_type: "pcb_trace_error",
4991
- source_trace_id: this.source_trace_id,
4992
- message: `Trace ${this.getString()} routed outside the board boundaries.`,
4993
- pcb_trace_id: this.pcb_trace_id,
4994
- pcb_component_ids: [],
4995
- pcb_port_ids: ports.map((p) => p.pcb_port_id)
4996
- });
4997
- }
4998
- }
4999
- doInitialPcbTraceRender() {
5000
- if (this.root?.pcbDisabled) return;
5001
- const { db } = this.root;
5002
- const { _parsedProps: props, parent } = this;
5003
- const subcircuit = this.getSubcircuit();
5004
- if (!parent) throw new Error("Trace has no parent");
5005
- if (subcircuit._parsedProps.routingDisabled) {
5006
- return;
5007
- }
5008
- const cachedRoute = subcircuit._parsedProps.pcbRouteCache?.pcbTraces;
5009
- if (cachedRoute) {
5010
- const pcb_trace2 = db.pcb_trace.insert({
5011
- route: cachedRoute.flatMap((trace) => trace.route),
5012
- source_trace_id: this.source_trace_id,
5013
- subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
5014
- pcb_group_id: this.getGroup()?.pcb_group_id ?? void 0
5015
- });
5016
- this.pcb_trace_id = pcb_trace2.pcb_trace_id;
5017
- return;
5018
- }
5019
- if (!subcircuit._shouldUseTraceByTraceRouting()) {
5020
- return;
5021
- }
5022
- const { allPortsFound, ports } = this._findConnectedPorts();
5023
- const portsConnectedOnPcbViaNet = [];
5024
- if (!allPortsFound) return;
5025
- const portsWithoutMatchedPcbPrimitive = [];
5026
- for (const port of ports) {
5027
- if (!port._hasMatchedPcbPrimitive()) {
5028
- portsWithoutMatchedPcbPrimitive.push(port);
5029
- }
5030
- }
5031
- if (portsWithoutMatchedPcbPrimitive.length > 0) {
5032
- db.pcb_trace_error.insert({
5033
- error_type: "pcb_trace_error",
5034
- source_trace_id: this.source_trace_id,
5035
- message: `Some ports did not have a matching PCB primitive (e.g. a pad or plated hole), this can happen if a footprint is missing. As a result, ${this} wasn't routed. Missing ports: ${portsWithoutMatchedPcbPrimitive.map((p) => p.getString()).join(", ")}`,
5036
- pcb_trace_id: this.pcb_trace_id,
5037
- pcb_component_ids: [],
5038
- pcb_port_ids: portsWithoutMatchedPcbPrimitive.map((p) => p.pcb_port_id).filter(Boolean)
5039
- });
5040
- return;
5041
- }
5042
- const nets = this._findConnectedNets().netsWithSelectors;
5043
- if (ports.length === 0 && nets.length === 2) {
5044
- this.renderError(
5045
- `Trace connects two nets, we haven't implemented a way to route this yet`
5046
- );
5047
- return;
5048
- } else if (ports.length === 1 && nets.length === 1) {
5049
- const port = ports[0];
5050
- const portsInNet = nets[0].net.getAllConnectedPorts();
5051
- const otherPortsInNet = portsInNet.filter((p) => p !== port);
5052
- if (otherPortsInNet.length === 0) {
5053
- console.log(
5054
- "Nothing to connect this port to, the net is empty. TODO should emit a warning!"
5055
- );
5056
- return;
5057
- }
5058
- const closestPortInNet = getClosest(port, otherPortsInNet);
5059
- portsConnectedOnPcbViaNet.push(closestPortInNet);
5060
- ports.push(closestPortInNet);
5061
- } else if (ports.length > 1 && nets.length >= 1) {
5062
- this.renderError(
5063
- `Trace has more than one port and one or more nets, we don't currently support this type of complex trace routing`
5064
- );
5065
- return;
5066
- }
5067
- const hints = ports.flatMap(
5068
- (port) => port.matchedComponents.filter((c) => c.componentName === "TraceHint")
5069
- );
5070
- const pcbRouteHints = (this._parsedProps.pcbRouteHints ?? []).concat(
5071
- hints.flatMap((h) => h.getPcbRouteHints())
5072
- );
5073
- if (ports.length > 2) {
5074
- this.renderError(
5075
- `Trace has more than two ports (${ports.map((p) => p.getString()).join(
5076
- ", "
5077
- )}), routing between more than two ports for a single trace is not implemented`
5078
- );
5079
- return;
5080
- }
5081
- const alreadyRoutedTraces = this.getSubcircuit().selectAll("trace").filter(
5082
- (trace) => trace.renderPhaseStates.PcbTraceRender.initialized
5083
- );
5084
- const isAlreadyRouted = alreadyRoutedTraces.some(
5085
- (trace) => trace._portsRoutedOnPcb.length === ports.length && trace._portsRoutedOnPcb.every(
5086
- (portRoutedByOtherTrace) => ports.includes(portRoutedByOtherTrace)
5087
- )
5551
+ (a, b) => (a.pcb_port_id || "").localeCompare(b.pcb_port_id || "")
5088
5552
  );
5089
- if (isAlreadyRouted) {
5553
+ const allIds = sortedPorts.map((p) => p.pcb_port_id);
5554
+ return allIds.join(",");
5555
+ }
5556
+ doInitialSourceTraceRender() {
5557
+ const { db } = this.root;
5558
+ const { _parsedProps: props, parent } = this;
5559
+ if (!parent) {
5560
+ this.renderError("Trace has no parent");
5090
5561
  return;
5091
5562
  }
5092
- let orderedRouteObjectives = [];
5093
- if (pcbRouteHints.length === 0) {
5094
- orderedRouteObjectives = [
5095
- portToObjective(ports[0]),
5096
- portToObjective(ports[1])
5097
- ];
5098
- } else {
5099
- orderedRouteObjectives = [
5100
- portToObjective(ports[0]),
5101
- ...pcbRouteHints,
5102
- portToObjective(ports[1])
5103
- ];
5104
- }
5105
- const candidateLayerCombinations = findPossibleTraceLayerCombinations(
5106
- orderedRouteObjectives
5563
+ const { allPortsFound, portsWithSelectors: ports } = this._findConnectedPorts();
5564
+ if (!allPortsFound) return;
5565
+ this._traceConnectionHash = this._computeTraceConnectionHash();
5566
+ const existingTraces = db.source_trace.list();
5567
+ const existingTrace = existingTraces.find(
5568
+ (t) => t.subcircuit_connectivity_map_key === this.subcircuit_connectivity_map_key && t.connected_source_port_ids.sort().join(",") === this._traceConnectionHash
5107
5569
  );
5108
- if (SHOULD_USE_SINGLE_LAYER_ROUTING && candidateLayerCombinations.length === 0) {
5109
- this.renderError(
5110
- `Could not find a common layer (using hints) for trace ${this.getString()}`
5111
- );
5570
+ if (existingTrace) {
5571
+ this.source_trace_id = existingTrace.source_trace_id;
5112
5572
  return;
5113
5573
  }
5114
- const connMap = getFullConnectivityMapFromCircuitJson(
5115
- this.root.db.toArray()
5116
- );
5117
- const [obstacles, errGettingObstacles] = tryNow(
5118
- () => getObstaclesFromCircuitJson(this.root.db.toArray())
5119
- // Remove as any when autorouting-dataset gets updated
5120
- );
5121
- if (errGettingObstacles) {
5122
- this.renderError({
5123
- type: "pcb_trace_error",
5574
+ const nets = this._findConnectedNets().nets;
5575
+ const displayName = getTraceDisplayName({ ports, nets });
5576
+ const trace = db.source_trace.insert({
5577
+ connected_source_port_ids: ports.map((p) => p.port.source_port_id),
5578
+ connected_source_net_ids: nets.map((n) => n.source_net_id),
5579
+ subcircuit_id: this.getSubcircuit()?.subcircuit_id,
5580
+ max_length: getMaxLengthFromConnectedCapacitors(
5581
+ ports.map((p) => p.port),
5582
+ { db }
5583
+ ) ?? props.maxLength,
5584
+ display_name: displayName,
5585
+ min_trace_thickness: props.thickness
5586
+ });
5587
+ this.source_trace_id = trace.source_trace_id;
5588
+ }
5589
+ _insertErrorIfTraceIsOutsideBoard(mergedRoute, ports) {
5590
+ const { db } = this.root;
5591
+ const isOutsideBoard = isRouteOutsideBoard(mergedRoute, { db });
5592
+ if (isOutsideBoard) {
5593
+ db.pcb_trace_error.insert({
5124
5594
  error_type: "pcb_trace_error",
5125
- pcb_trace_error_id: this.pcb_trace_id,
5126
- message: `Error getting obstacles for autorouting: ${errGettingObstacles.message}`,
5127
5595
  source_trace_id: this.source_trace_id,
5128
- center: { x: 0, y: 0 },
5129
- pcb_port_ids: ports.map((p) => p.pcb_port_id),
5596
+ message: `Trace ${this.getString()} routed outside the board boundaries.`,
5130
5597
  pcb_trace_id: this.pcb_trace_id,
5131
- pcb_component_ids: []
5132
- });
5133
- return;
5134
- }
5135
- for (const obstacle of obstacles) {
5136
- const connectedTo = obstacle.connectedTo;
5137
- if (connectedTo.length > 0) {
5138
- const netId = connMap.getNetConnectedToId(obstacle.connectedTo[0]);
5139
- if (netId) {
5140
- obstacle.connectedTo.push(netId);
5141
- }
5142
- }
5143
- }
5144
- let orderedRoutePoints = [];
5145
- if (candidateLayerCombinations.length === 0) {
5146
- orderedRoutePoints = orderedRouteObjectives;
5147
- } else {
5148
- const candidateLayerSelections = candidateLayerCombinations[0].layer_path;
5149
- orderedRoutePoints = orderedRouteObjectives.map((t, idx) => {
5150
- if (t.via) {
5151
- return {
5152
- ...t,
5153
- via_to_layer: candidateLayerSelections[idx]
5154
- };
5155
- }
5156
- return { ...t, layers: [candidateLayerSelections[idx]] };
5157
- });
5158
- }
5159
- ;
5160
- orderedRoutePoints[0].pcb_port_id = ports[0].pcb_port_id;
5161
- orderedRoutePoints[orderedRoutePoints.length - 1].pcb_port_id = ports[1].pcb_port_id;
5162
- const routes = [];
5163
- for (const [a, b] of pairs(orderedRoutePoints)) {
5164
- const dominantLayer = "via_to_layer" in a ? a.via_to_layer : null;
5165
- const BOUNDS_MARGIN = 2;
5166
- const aLayer = "layers" in a && a.layers.length === 1 ? a.layers[0] : dominantLayer ?? "top";
5167
- const bLayer = "layers" in b && b.layers.length === 1 ? b.layers[0] : dominantLayer ?? "top";
5168
- const pcbPortA = "pcb_port_id" in a ? a.pcb_port_id : null;
5169
- const pcbPortB = "pcb_port_id" in b ? b.pcb_port_id : null;
5170
- const minTraceWidth = this.getSubcircuit()._parsedProps.minTraceWidth ?? 0.16;
5171
- const ijump = new MultilayerIjump({
5172
- OBSTACLE_MARGIN: minTraceWidth * 2,
5173
- isRemovePathLoopsEnabled: true,
5174
- optimizeWithGoalBoxes: Boolean(pcbPortA && pcbPortB),
5175
- connMap,
5176
- input: {
5177
- obstacles,
5178
- minTraceWidth,
5179
- connections: [
5180
- {
5181
- name: this.source_trace_id,
5182
- pointsToConnect: [
5183
- { ...a, layer: aLayer, pcb_port_id: pcbPortA },
5184
- { ...b, layer: bLayer, pcb_port_id: pcbPortB }
5185
- ]
5186
- }
5187
- ],
5188
- layerCount: 2,
5189
- bounds: {
5190
- minX: Math.min(a.x, b.x) - BOUNDS_MARGIN,
5191
- maxX: Math.max(a.x, b.x) + BOUNDS_MARGIN,
5192
- minY: Math.min(a.y, b.y) - BOUNDS_MARGIN,
5193
- maxY: Math.max(a.y, b.y) + BOUNDS_MARGIN
5194
- }
5195
- }
5598
+ pcb_component_ids: [],
5599
+ pcb_port_ids: ports.map((p) => p.pcb_port_id)
5196
5600
  });
5197
- let traces = null;
5198
- try {
5199
- traces = ijump.solveAndMapToTraces();
5200
- } catch (e) {
5201
- this.renderError({
5202
- type: "pcb_trace_error",
5203
- pcb_trace_error_id: this.source_trace_id,
5204
- error_type: "pcb_trace_error",
5205
- message: `error solving route: ${e.message}`,
5206
- source_trace_id: this.pcb_trace_id,
5207
- center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
5208
- pcb_port_ids: ports.map((p) => p.pcb_port_id),
5209
- pcb_trace_id: this.pcb_trace_id,
5210
- pcb_component_ids: ports.map((p) => p.pcb_component_id)
5211
- });
5212
- }
5213
- if (!traces) return;
5214
- if (traces.length === 0) {
5215
- this.renderError({
5216
- type: "pcb_trace_error",
5217
- error_type: "pcb_trace_error",
5218
- pcb_trace_error_id: this.pcb_trace_id,
5219
- message: `Could not find a route for ${this}`,
5220
- source_trace_id: this.source_trace_id,
5221
- center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
5222
- pcb_port_ids: ports.map((p) => p.pcb_port_id),
5223
- pcb_trace_id: this.pcb_trace_id,
5224
- pcb_component_ids: ports.map((p) => p.pcb_component_id)
5225
- });
5226
- return;
5227
- }
5228
- const [trace] = traces;
5229
- if (dominantLayer) {
5230
- trace.route = trace.route.map((p) => {
5231
- if (p.route_type === "wire" && !p.layer) {
5232
- p.layer = dominantLayer;
5233
- }
5234
- return p;
5235
- });
5236
- }
5237
- if (pcbPortA && trace.route[0].route_type === "wire") {
5238
- trace.route[0].start_pcb_port_id = pcbPortA;
5239
- }
5240
- const lastRoutePoint = trace.route[trace.route.length - 1];
5241
- if (pcbPortB && lastRoutePoint.route_type === "wire") {
5242
- lastRoutePoint.end_pcb_port_id = pcbPortB;
5243
- }
5244
- routes.push(trace.route);
5245
- }
5246
- const mergedRoute = mergeRoutes(routes);
5247
- const traceLength = getTraceLength(mergedRoute);
5248
- const pcb_trace = db.pcb_trace.insert({
5249
- route: mergedRoute,
5250
- source_trace_id: this.source_trace_id,
5251
- subcircuit_id: this.getSubcircuit()?.subcircuit_id,
5252
- trace_length: traceLength
5253
- });
5254
- this._portsRoutedOnPcb = ports;
5255
- this.pcb_trace_id = pcb_trace.pcb_trace_id;
5256
- for (const point of mergedRoute) {
5257
- if (point.route_type === "via") {
5258
- db.pcb_via.insert({
5259
- pcb_trace_id: pcb_trace.pcb_trace_id,
5260
- x: point.x,
5261
- y: point.y,
5262
- hole_diameter: 0.3,
5263
- outer_diameter: 0.6,
5264
- layers: [point.from_layer, point.to_layer],
5265
- from_layer: point.from_layer,
5266
- to_layer: point.to_layer
5267
- });
5268
- }
5269
5601
  }
5270
- this._insertErrorIfTraceIsOutsideBoard(mergedRoute, ports);
5602
+ }
5603
+ doInitialPcbTraceRender() {
5604
+ Trace_doInitialPcbTraceRender(this);
5271
5605
  }
5272
5606
  _doInitialSchematicTraceRenderWithDisplayLabel() {
5273
- if (this.root?.schematicDisabled) return;
5274
- const { db } = this.root;
5275
- const { _parsedProps: props, parent } = this;
5276
- if (!parent) throw new Error("Trace has no parent");
5277
- const { allPortsFound, portsWithSelectors: connectedPorts } = this._findConnectedPorts();
5278
- if (!allPortsFound) return;
5279
- const portsWithPosition = connectedPorts.map(({ port }) => ({
5280
- port,
5281
- position: port._getGlobalSchematicPositionAfterLayout(),
5282
- schematic_port_id: port.schematic_port_id,
5283
- facingDirection: port.facingDirection
5284
- }));
5285
- if (portsWithPosition.length < 2) {
5286
- throw new Error("Expected at least two ports in portsWithPosition.");
5287
- }
5288
- let fromPortName;
5289
- let toPortName;
5290
- const fromAnchorPos = portsWithPosition[0].position;
5291
- const fromPort = portsWithPosition[0].port;
5292
- if ("path" in this.props) {
5293
- if (this.props.path.length !== 2) {
5294
- throw new Error("Invalid 'path': Must contain exactly two elements.");
5295
- }
5296
- ;
5297
- [fromPortName, toPortName] = this.props.path;
5298
- } else {
5299
- if (!("from" in this.props && "to" in this.props)) {
5300
- throw new Error("Missing 'from' or 'to' properties in props.");
5301
- }
5302
- fromPortName = this.props.from;
5303
- toPortName = this.props.to;
5304
- }
5305
- if (!fromPort.source_port_id) {
5306
- throw new Error(
5307
- `Missing source_port_id for the 'from' port (${fromPortName}).`
5308
- );
5309
- }
5310
- const toAnchorPos = portsWithPosition[1].position;
5311
- const toPort = portsWithPosition[1].port;
5312
- if (!toPort.source_port_id) {
5313
- throw new Error(
5314
- `Missing source_port_id for the 'to' port (${toPortName}).`
5315
- );
5316
- }
5317
- const existingFromNetLabel = db.schematic_net_label.list().find((label) => label.source_net_id === fromPort.source_port_id);
5318
- const existingToNetLabel = db.schematic_net_label.list().find((label) => label.source_net_id === toPort.source_port_id);
5319
- const [firstPort, secondPort] = connectedPorts.map(({ port }) => port);
5320
- const isFirstPortSchematicBox = firstPort.parent?.config.shouldRenderAsSchematicBox;
5321
- const pinFullName = isFirstPortSchematicBox ? `${firstPort?.parent?.props.name}_${firstPort?.props.name}` : `${secondPort?.parent?.props.name}_${secondPort?.props.name}`;
5322
- const netLabelText = this.props.schDisplayLabel ?? pinFullName;
5323
- if (existingFromNetLabel && existingFromNetLabel.text !== netLabelText) {
5324
- existingFromNetLabel.text = `${netLabelText} / ${existingFromNetLabel.text}`;
5325
- }
5326
- if (existingToNetLabel && existingToNetLabel?.text !== netLabelText) {
5327
- existingToNetLabel.text = `${netLabelText} / ${existingToNetLabel.text}`;
5328
- }
5329
- if (!existingToNetLabel) {
5330
- const toSide = getEnteringEdgeFromDirection(toPort.facingDirection) ?? "bottom";
5331
- db.schematic_net_label.insert({
5332
- text: this.props.schDisplayLabel ?? pinFullName,
5333
- source_net_id: toPort.source_port_id,
5334
- anchor_position: toAnchorPos,
5335
- center: computeSchematicNetLabelCenter({
5336
- anchor_position: toAnchorPos,
5337
- anchor_side: toSide,
5338
- text: this.props.schDisplayLabel ?? pinFullName
5339
- }),
5340
- anchor_side: toSide
5341
- });
5342
- }
5343
- if (!existingFromNetLabel) {
5344
- const fromSide = getEnteringEdgeFromDirection(fromPort.facingDirection) ?? "bottom";
5345
- db.schematic_net_label.insert({
5346
- text: this.props.schDisplayLabel ?? pinFullName,
5347
- source_net_id: fromPort.source_port_id,
5348
- anchor_position: fromAnchorPos,
5349
- center: computeSchematicNetLabelCenter({
5350
- anchor_position: fromAnchorPos,
5351
- anchor_side: fromSide,
5352
- text: this.props.schDisplayLabel ?? pinFullName
5353
- }),
5354
- anchor_side: fromSide
5355
- });
5356
- }
5607
+ Trace__doInitialSchematicTraceRenderWithDisplayLabel(this);
5357
5608
  }
5358
5609
  _isSymbolToChipConnection() {
5359
5610
  const { allPortsFound, ports } = this._findConnectedPorts();
@@ -5383,235 +5634,7 @@ var Trace2 = class extends PrimitiveComponent2 {
5383
5634
  return isPort1Chip && isPort2Chip;
5384
5635
  }
5385
5636
  doInitialSchematicTraceRender() {
5386
- if (this.root?.schematicDisabled) return;
5387
- const { db } = this.root;
5388
- const { _parsedProps: props, parent } = this;
5389
- if (!parent) throw new Error("Trace has no parent");
5390
- const { allPortsFound, portsWithSelectors: connectedPorts } = this._findConnectedPorts();
5391
- const { netsWithSelectors } = this._findConnectedNets();
5392
- if (!allPortsFound) return;
5393
- const portIds = connectedPorts.map((p) => p.port.schematic_port_id).sort();
5394
- const portPairKey = portIds.join(",");
5395
- const board = this.root?._getBoard();
5396
- if (board?._connectedSchematicPortPairs) {
5397
- if (board._connectedSchematicPortPairs.has(portPairKey)) {
5398
- return;
5399
- }
5400
- }
5401
- const connection = {
5402
- name: this.source_trace_id,
5403
- pointsToConnect: []
5404
- };
5405
- const obstacles = getSchematicObstaclesForTrace(this);
5406
- const portsWithPosition = connectedPorts.map(({ port }) => ({
5407
- port,
5408
- position: port._getGlobalSchematicPositionAfterLayout(),
5409
- schematic_port_id: port.schematic_port_id ?? void 0,
5410
- facingDirection: port.facingDirection
5411
- }));
5412
- const isPortAndNetConnection = portsWithPosition.length === 1 && netsWithSelectors.length === 1;
5413
- if (isPortAndNetConnection) {
5414
- const net = netsWithSelectors[0].net;
5415
- const { port, position: anchorPos } = portsWithPosition[0];
5416
- let connectedNetLabel = this.getSubcircuit().selectAll("netlabel").find((nl) => {
5417
- const conn = nl._parsedProps.connection ?? nl._parsedProps.connectsTo;
5418
- if (!conn) return false;
5419
- if (Array.isArray(conn)) {
5420
- return conn.some((selector) => {
5421
- const targetPort2 = this.getSubcircuit().selectOne(selector, {
5422
- port: true
5423
- });
5424
- return targetPort2 === port;
5425
- });
5426
- }
5427
- const targetPort = this.getSubcircuit().selectOne(conn, {
5428
- port: true
5429
- });
5430
- return targetPort === port;
5431
- });
5432
- if (!connectedNetLabel) {
5433
- const dbNetLabel = db.schematic_net_label.getWhere({
5434
- source_trace_id: this.source_trace_id
5435
- });
5436
- if (dbNetLabel) {
5437
- connectedNetLabel = dbNetLabel;
5438
- }
5439
- }
5440
- if (connectedNetLabel) {
5441
- const labelPos = "_getGlobalSchematicPositionBeforeLayout" in connectedNetLabel ? connectedNetLabel._getGlobalSchematicPositionBeforeLayout() : connectedNetLabel.anchor_position;
5442
- const edges2 = [];
5443
- if (anchorPos.x === labelPos.x || anchorPos.y === labelPos.y) {
5444
- edges2.push({ from: anchorPos, to: labelPos });
5445
- } else {
5446
- edges2.push({ from: anchorPos, to: { x: labelPos.x, y: anchorPos.y } });
5447
- edges2.push({ from: { x: labelPos.x, y: anchorPos.y }, to: labelPos });
5448
- }
5449
- const trace2 = db.schematic_trace.insert({
5450
- source_trace_id: this.source_trace_id,
5451
- edges: edges2,
5452
- junctions: []
5453
- });
5454
- this.schematic_trace_id = trace2.schematic_trace_id;
5455
- return;
5456
- }
5457
- if (this.props.schDisplayLabel) {
5458
- const side2 = getEnteringEdgeFromDirection(port.facingDirection) ?? "bottom";
5459
- db.schematic_net_label.insert({
5460
- text: this.props.schDisplayLabel,
5461
- source_net_id: net.source_net_id,
5462
- anchor_position: anchorPos,
5463
- center: computeSchematicNetLabelCenter({
5464
- anchor_position: anchorPos,
5465
- anchor_side: side2,
5466
- text: this.props.schDisplayLabel
5467
- }),
5468
- anchor_side: side2
5469
- });
5470
- return;
5471
- }
5472
- const side = getEnteringEdgeFromDirection(port.facingDirection) ?? "bottom";
5473
- const netLabel = db.schematic_net_label.insert({
5474
- text: net._parsedProps.name,
5475
- source_net_id: net.source_net_id,
5476
- anchor_position: anchorPos,
5477
- center: computeSchematicNetLabelCenter({
5478
- anchor_position: anchorPos,
5479
- anchor_side: side,
5480
- text: net._parsedProps.name
5481
- }),
5482
- anchor_side: side
5483
- });
5484
- return;
5485
- }
5486
- if (this.props.schDisplayLabel) {
5487
- if ("from" in this.props && "to" in this.props || "path" in this.props) {
5488
- this._doInitialSchematicTraceRenderWithDisplayLabel();
5489
- return;
5490
- }
5491
- }
5492
- if (portsWithPosition.length < 2) {
5493
- return;
5494
- }
5495
- connection.pointsToConnect = portsWithPosition.map(({ position }) => ({
5496
- ...position,
5497
- layer: "top"
5498
- }));
5499
- const bounds = computeObstacleBounds(obstacles);
5500
- const BOUNDS_MARGIN = 2;
5501
- const simpleRouteJsonInput = {
5502
- minTraceWidth: 0.1,
5503
- obstacles,
5504
- connections: [connection],
5505
- bounds: {
5506
- minX: bounds.minX - BOUNDS_MARGIN,
5507
- maxX: bounds.maxX + BOUNDS_MARGIN,
5508
- minY: bounds.minY - BOUNDS_MARGIN,
5509
- maxY: bounds.maxY + BOUNDS_MARGIN
5510
- },
5511
- layerCount: 1
5512
- };
5513
- let Autorouter = MultilayerIjump;
5514
- let skipOtherTraceInteraction = false;
5515
- if (this.getSubcircuit().props._schDirectLineRoutingEnabled) {
5516
- Autorouter = DirectLineRouter;
5517
- skipOtherTraceInteraction = true;
5518
- }
5519
- const autorouter = new Autorouter({
5520
- input: simpleRouteJsonInput,
5521
- MAX_ITERATIONS: 100,
5522
- OBSTACLE_MARGIN: 0.1,
5523
- isRemovePathLoopsEnabled: true,
5524
- isShortenPathWithShortcutsEnabled: true,
5525
- marginsWithCosts: [
5526
- {
5527
- margin: 1,
5528
- enterCost: 0,
5529
- travelCostFactor: 1
5530
- },
5531
- {
5532
- margin: 0.3,
5533
- enterCost: 0,
5534
- travelCostFactor: 1
5535
- },
5536
- {
5537
- margin: 0.2,
5538
- enterCost: 0,
5539
- travelCostFactor: 2
5540
- },
5541
- {
5542
- margin: 0.1,
5543
- enterCost: 0,
5544
- travelCostFactor: 3
5545
- }
5546
- ]
5547
- });
5548
- let results = autorouter.solveAndMapToTraces();
5549
- if (results.length === 0) {
5550
- if (this._isSymbolToChipConnection() || this._isSymbolToSymbolConnection() || this._isChipToChipConnection()) {
5551
- this._doInitialSchematicTraceRenderWithDisplayLabel();
5552
- return;
5553
- }
5554
- const directLineRouter = new DirectLineRouter({
5555
- input: simpleRouteJsonInput
5556
- });
5557
- results = directLineRouter.solveAndMapToTraces();
5558
- skipOtherTraceInteraction = true;
5559
- }
5560
- const [{ route }] = results;
5561
- let edges = [];
5562
- for (let i = 0; i < route.length - 1; i++) {
5563
- edges.push({
5564
- from: route[i],
5565
- to: route[i + 1]
5566
- });
5567
- }
5568
- const source_trace_id = this.source_trace_id;
5569
- let junctions = [];
5570
- if (!skipOtherTraceInteraction) {
5571
- pushEdgesOfSchematicTraceToPreventOverlap({ edges, db, source_trace_id });
5572
- const otherEdges = getOtherSchematicTraces({
5573
- db,
5574
- source_trace_id,
5575
- differentNetOnly: true
5576
- }).flatMap((t) => t.edges);
5577
- edges = createSchematicTraceCrossingSegments({ edges, otherEdges });
5578
- junctions = createSchematicTraceJunctions({
5579
- edges,
5580
- db,
5581
- source_trace_id: this.source_trace_id
5582
- });
5583
- }
5584
- const lastEdge = edges[edges.length - 1];
5585
- const lastEdgePort = portsWithPosition[portsWithPosition.length - 1];
5586
- const lastDominantDirection = getDominantDirection(lastEdge);
5587
- edges.push(
5588
- ...getStubEdges({ lastEdge, lastEdgePort, lastDominantDirection })
5589
- );
5590
- const firstEdge = edges[0];
5591
- const firstEdgePort = portsWithPosition[0];
5592
- const firstDominantDirection = getDominantDirection(firstEdge);
5593
- edges.unshift(
5594
- ...getStubEdges({
5595
- firstEdge,
5596
- firstEdgePort,
5597
- firstDominantDirection
5598
- })
5599
- );
5600
- if (!this.source_trace_id) {
5601
- throw new Error("Missing source_trace_id for schematic trace insertion.");
5602
- }
5603
- if (this.getSubcircuit()._parsedProps.schTraceAutoLabelEnabled && countComplexElements(junctions, edges) >= 5 && (this._isSymbolToChipConnection() || this._isSymbolToSymbolConnection() || this._isChipToChipConnection())) {
5604
- this._doInitialSchematicTraceRenderWithDisplayLabel();
5605
- return;
5606
- }
5607
- const trace = db.schematic_trace.insert({
5608
- source_trace_id: this.source_trace_id,
5609
- edges,
5610
- junctions
5611
- });
5612
- this.schematic_trace_id = trace.schematic_trace_id;
5613
- if (board?._connectedSchematicPortPairs)
5614
- board._connectedSchematicPortPairs.add(portPairKey);
5637
+ Trace_doInitialSchematicTraceRender(this);
5615
5638
  }
5616
5639
  };
5617
5640
 
@@ -6456,7 +6479,7 @@ var NormalComponent = class extends PrimitiveComponent2 {
6456
6479
  const targets = Array.isArray(target) ? target : [target];
6457
6480
  for (const targetPath of targets) {
6458
6481
  this.add(
6459
- new Trace2({
6482
+ new Trace3({
6460
6483
  from: `${this.getSubcircuitSelector()} > port.${pinName}`,
6461
6484
  to: targetPath
6462
6485
  })
@@ -6887,7 +6910,7 @@ var applyEditEvents = ({
6887
6910
  // lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts
6888
6911
  import { su as su4 } from "@tscircuit/circuit-json-util";
6889
6912
  import {
6890
- getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson2
6913
+ getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson3
6891
6914
  } from "circuit-json-to-connectivity-map";
6892
6915
 
6893
6916
  // lib/utils/autorouting/getAncestorSubcircuitIds.ts
@@ -6938,7 +6961,7 @@ var getSimpleRouteJsonFromCircuitJson = ({
6938
6961
  );
6939
6962
  const board = db.pcb_board.list()[0];
6940
6963
  db = su4(subcircuitElements);
6941
- const connMap = getFullConnectivityMapFromCircuitJson2(subcircuitElements);
6964
+ const connMap = getFullConnectivityMapFromCircuitJson3(subcircuitElements);
6942
6965
  const obstacles = getObstaclesFromCircuitJson(
6943
6966
  [
6944
6967
  ...db.pcb_component.list(),
@@ -7725,6 +7748,53 @@ function Group_doInitialPcbLayoutGrid(group) {
7725
7748
  }
7726
7749
  }
7727
7750
 
7751
+ // lib/utils/autorouting/getPresetAutoroutingConfig.ts
7752
+ function getPresetAutoroutingConfig(autorouterConfig) {
7753
+ const defaults = {
7754
+ serverUrl: "https://registry-api.tscircuit.com",
7755
+ serverMode: "job",
7756
+ serverCacheEnabled: true
7757
+ };
7758
+ if (typeof autorouterConfig === "object" && !autorouterConfig.preset) {
7759
+ return {
7760
+ local: !(autorouterConfig.serverUrl || autorouterConfig.serverMode || autorouterConfig.serverCacheEnabled),
7761
+ ...defaults,
7762
+ ...autorouterConfig
7763
+ };
7764
+ }
7765
+ const preset = typeof autorouterConfig === "object" ? autorouterConfig.preset : autorouterConfig;
7766
+ switch (preset) {
7767
+ case "auto-local":
7768
+ return {
7769
+ local: true,
7770
+ groupMode: "subcircuit"
7771
+ };
7772
+ case "sequential-trace":
7773
+ return {
7774
+ local: true,
7775
+ groupMode: "sequential-trace"
7776
+ };
7777
+ case "subcircuit":
7778
+ return {
7779
+ local: true,
7780
+ groupMode: "subcircuit"
7781
+ };
7782
+ case "auto-cloud":
7783
+ return {
7784
+ local: false,
7785
+ groupMode: "subcircuit",
7786
+ serverUrl: defaults.serverUrl,
7787
+ serverMode: defaults.serverMode,
7788
+ serverCacheEnabled: true
7789
+ };
7790
+ default:
7791
+ return {
7792
+ local: true,
7793
+ groupMode: "subcircuit"
7794
+ };
7795
+ }
7796
+ }
7797
+
7728
7798
  // lib/components/primitive-components/Group/Group.ts
7729
7799
  var Group = class extends NormalComponent {
7730
7800
  pcb_group_id = null;
@@ -8327,46 +8397,8 @@ var Group = class extends NormalComponent {
8327
8397
  };
8328
8398
  }
8329
8399
  _getAutorouterConfig() {
8330
- const defaults = {
8331
- serverUrl: "https://registry-api.tscircuit.com",
8332
- serverMode: "job",
8333
- serverCacheEnabled: true
8334
- };
8335
- const autorouter = this._parsedProps.autorouter || this._parsedProps.autorouter?.preset || this.getInheritedProperty("autorouter");
8336
- if (typeof autorouter === "object") {
8337
- return {
8338
- local: !(autorouter.serverUrl || autorouter.serverMode || autorouter.serverCacheEnabled),
8339
- ...defaults,
8340
- ...autorouter
8341
- };
8342
- }
8343
- if (autorouter === "auto-local")
8344
- return {
8345
- local: true,
8346
- groupMode: "subcircuit"
8347
- };
8348
- if (autorouter === "sequential-trace")
8349
- return {
8350
- local: true,
8351
- groupMode: "sequential-trace"
8352
- };
8353
- if (autorouter === "subcircuit")
8354
- return {
8355
- local: true,
8356
- groupMode: "subcircuit"
8357
- };
8358
- if (autorouter === "auto-cloud")
8359
- return {
8360
- local: false,
8361
- groupMode: "subcircuit",
8362
- serverUrl: defaults.serverUrl,
8363
- serverMode: defaults.serverMode,
8364
- serverCacheEnabled: true
8365
- };
8366
- return {
8367
- local: true,
8368
- groupMode: "subcircuit"
8369
- };
8400
+ const autorouter = this._parsedProps.autorouter || this.getInheritedProperty("autorouter");
8401
+ return getPresetAutoroutingConfig(autorouter);
8370
8402
  }
8371
8403
  /**
8372
8404
  * Trace-by-trace autorouting is where each trace routes itself in a well-known
@@ -8644,13 +8676,13 @@ var Capacitor = class extends NormalComponent {
8644
8676
  doInitialCreateTracesFromProps() {
8645
8677
  if (this.props.decouplingFor && this.props.decouplingTo) {
8646
8678
  this.add(
8647
- new Trace2({
8679
+ new Trace3({
8648
8680
  from: `${this.getSubcircuitSelector()} > port.1`,
8649
8681
  to: this.props.decouplingFor
8650
8682
  })
8651
8683
  );
8652
8684
  this.add(
8653
- new Trace2({
8685
+ new Trace3({
8654
8686
  from: `${this.getSubcircuitSelector()} > port.2`,
8655
8687
  to: this.props.decouplingTo
8656
8688
  })
@@ -8726,7 +8758,7 @@ var Chip = class extends NormalComponent {
8726
8758
  if (props.externallyConnectedPins) {
8727
8759
  for (const [pin1, pin2] of props.externallyConnectedPins) {
8728
8760
  this.add(
8729
- new Trace2({
8761
+ new Trace3({
8730
8762
  from: `${this.getSubcircuitSelector()} > port.${pin1}`,
8731
8763
  to: `${this.getSubcircuitSelector()} > port.${pin2}`
8732
8764
  })
@@ -9183,13 +9215,13 @@ var Resistor = class extends NormalComponent {
9183
9215
  doInitialCreateTracesFromProps() {
9184
9216
  if (this.props.pullupFor && this.props.pullupTo) {
9185
9217
  this.add(
9186
- new Trace2({
9218
+ new Trace3({
9187
9219
  from: `${this.getSubcircuitSelector()} > port.1`,
9188
9220
  to: this.props.pullupFor
9189
9221
  })
9190
9222
  );
9191
9223
  this.add(
9192
- new Trace2({
9224
+ new Trace3({
9193
9225
  from: `${this.getSubcircuitSelector()} > port.2`,
9194
9226
  to: this.props.pullupTo
9195
9227
  })
@@ -9197,13 +9229,13 @@ var Resistor = class extends NormalComponent {
9197
9229
  }
9198
9230
  if (this.props.pulldownFor && this.props.pulldownTo) {
9199
9231
  this.add(
9200
- new Trace2({
9232
+ new Trace3({
9201
9233
  from: `${this.getSubcircuitSelector()} > port.1`,
9202
9234
  to: this.props.pulldownFor
9203
9235
  })
9204
9236
  );
9205
9237
  this.add(
9206
- new Trace2({
9238
+ new Trace3({
9207
9239
  from: `${this.getSubcircuitSelector()} > port.2`,
9208
9240
  to: this.props.pulldownTo
9209
9241
  })
@@ -9602,7 +9634,7 @@ var NetLabel = class extends PrimitiveComponent2 {
9602
9634
  if (!connectsTo) return;
9603
9635
  for (const connection of connectsTo) {
9604
9636
  this.add(
9605
- new Trace2({
9637
+ new Trace3({
9606
9638
  from: connection,
9607
9639
  to: `net.${this._getNetName()}`
9608
9640
  })
@@ -10716,7 +10748,7 @@ import { identity as identity5 } from "transformation-matrix";
10716
10748
  var package_default = {
10717
10749
  name: "@tscircuit/core",
10718
10750
  type: "module",
10719
- version: "0.0.547",
10751
+ version: "0.0.550",
10720
10752
  types: "dist/index.d.ts",
10721
10753
  main: "dist/index.js",
10722
10754
  module: "dist/index.js",
@@ -11249,7 +11281,7 @@ export {
11249
11281
  Subcircuit,
11250
11282
  Switch,
11251
11283
  TestPoint,
11252
- Trace2 as Trace,
11284
+ Trace3 as Trace,
11253
11285
  TraceHint,
11254
11286
  Transistor,
11255
11287
  Via,