@tscircuit/core 0.0.1915 → 0.0.1917

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6119,11 +6119,11 @@ function Trace_doInitialPcbTraceRender(trace) {
6119
6119
  const closestNetBPort = getClosest(netAPort, netBPorts);
6120
6120
  const netAPortPosition = netAPort._getGlobalPcbPositionBeforeLayout();
6121
6121
  const netBPortPosition = closestNetBPort._getGlobalPcbPositionBeforeLayout();
6122
- const distance22 = Math.sqrt(
6122
+ const distance23 = Math.sqrt(
6123
6123
  (netAPortPosition.x - netBPortPosition.x) ** 2 + (netAPortPosition.y - netBPortPosition.y) ** 2
6124
6124
  );
6125
- if (distance22 < closestDistance) {
6126
- closestDistance = distance22;
6125
+ if (distance23 < closestDistance) {
6126
+ closestDistance = distance23;
6127
6127
  closestPortPair = [netAPort, closestNetBPort];
6128
6128
  }
6129
6129
  }
@@ -7283,7 +7283,7 @@ var getMaxLengthFromConnectedComponents = (ports, { db }) => {
7283
7283
  return sourceComponent.max_decoupling_trace_length;
7284
7284
  }
7285
7285
  return null;
7286
- }).filter((length7) => typeof length7 === "number");
7286
+ }).filter((length8) => typeof length8 === "number");
7287
7287
  if (componentMaxLengths.length === 0) return void 0;
7288
7288
  return Math.min(...componentMaxLengths);
7289
7289
  };
@@ -10130,11 +10130,11 @@ import { schematicPathProps } from "@tscircuit/props";
10130
10130
  import SVGPathCommander from "svg-path-commander";
10131
10131
  function sampleCurveSegment(segmentPath, samplesPerUnit) {
10132
10132
  const commander = new SVGPathCommander(segmentPath);
10133
- const length7 = commander.getTotalLength();
10134
- const numSamples = Math.max(2, Math.ceil(length7 * samplesPerUnit));
10133
+ const length8 = commander.getTotalLength();
10134
+ const numSamples = Math.max(2, Math.ceil(length8 * samplesPerUnit));
10135
10135
  const points = [];
10136
10136
  for (let i = 1; i <= numSamples; i++) {
10137
- const t = i / numSamples * length7;
10137
+ const t = i / numSamples * length8;
10138
10138
  const point6 = commander.getPointAtLength(t);
10139
10139
  points.push({ x: point6.x, y: point6.y });
10140
10140
  }
@@ -12303,7 +12303,7 @@ var createComponentsFromCircuitJson = ({
12303
12303
  const schematicSymbolId = schematicComponent?.schematic_symbol_id;
12304
12304
  const parentSymbol = typeof schematicSymbolId === "string" ? schematicSymbolsByImportedId.get(schematicSymbolId) : void 0;
12305
12305
  if (parentSymbol && schematicComponent?.is_box_with_pins === true && elm.center && elm.side_of_component) {
12306
- const distance22 = elm.distance_from_component_edge;
12306
+ const distance23 = elm.distance_from_component_edge;
12307
12307
  const facingDirection = getFacingDirectionFromSide(
12308
12308
  elm.side_of_component
12309
12309
  );
@@ -12311,8 +12311,8 @@ var createComponentsFromCircuitJson = ({
12311
12311
  const directionVector = getUnitVectorFromDirection2(facingDirection);
12312
12312
  const stemDirection = elm.facing_direction === facingDirection ? 1 : -1;
12313
12313
  const portCenter = {
12314
- x: elm.center.x + directionVector.x * distance22 * stemDirection,
12315
- y: elm.center.y + directionVector.y * distance22 * stemDirection
12314
+ x: elm.center.x + directionVector.x * distance23 * stemDirection,
12315
+ y: elm.center.y + directionVector.y * distance23 * stemDirection
12316
12316
  };
12317
12317
  const sourcePort = sourcePortsByImportedId.get(elm.source_port_id);
12318
12318
  const aliases = Array.from(
@@ -13543,9 +13543,9 @@ var getLabelPlacementAlongRoute = (route) => {
13543
13543
  for (let pointIndex = 1; pointIndex < route.length; pointIndex++) {
13544
13544
  const from = route[pointIndex - 1];
13545
13545
  const to = route[pointIndex];
13546
- const length7 = Math.hypot(to.x - from.x, to.y - from.y);
13547
- if (length7 > longestSegment.length) {
13548
- longestSegment = { from, to, length: length7 };
13546
+ const length8 = Math.hypot(to.x - from.x, to.y - from.y);
13547
+ if (length8 > longestSegment.length) {
13548
+ longestSegment = { from, to, length: length8 };
13549
13549
  }
13550
13550
  }
13551
13551
  const deltaX = longestSegment.to.x - longestSegment.from.x;
@@ -13566,6 +13566,7 @@ var NormalComponent_addInternalConnectionFabricationNotes = (component) => {
13566
13566
  const root = component.root;
13567
13567
  if (!root || root.pcbDisabled || !component.pcb_component_id) return;
13568
13568
  if (component.componentName === "SolderJumper") return;
13569
+ if (component._getPrimaryPinCount() >= 6) return;
13569
13570
  if (hasFabricationNotes(component)) return;
13570
13571
  const { db } = root;
13571
13572
  const pcbComponent = db.pcb_component.get(component.pcb_component_id);
@@ -16770,15 +16771,15 @@ var Capacitor_addPolarityFabricationSymbols = (capacitor) => {
16770
16771
  source_port_id: negatives[0].source_port_id
16771
16772
  });
16772
16773
  if (!positive || !negative) return;
16773
- const distance22 = Math.hypot(negative.x - positive.x, negative.y - positive.y);
16774
- if (distance22 < 1e-6) return;
16774
+ const distance23 = Math.hypot(negative.x - positive.x, negative.y - positive.y);
16775
+ if (distance23 < 1e-6) return;
16775
16776
  const frame = compose6(
16776
16777
  translate4((positive.x + negative.x) / 2, (positive.y + negative.y) / 2),
16777
16778
  rotate3(Math.atan2(negative.y - positive.y, negative.x - positive.x))
16778
16779
  );
16779
16780
  const point6 = (x, y) => applyToPoint25(frame, { x, y });
16780
- const offset = distance22 / 4;
16781
- const halfSize = Math.min(distance22 * 0.12, 0.3);
16781
+ const offset = distance23 / 4;
16782
+ const halfSize = Math.min(distance23 * 0.12, 0.3);
16782
16783
  const routes = [
16783
16784
  [point6(-offset - halfSize, 0), point6(-offset + halfSize, 0)],
16784
16785
  [point6(-offset, -halfSize), point6(-offset, halfSize)],
@@ -18270,7 +18271,7 @@ import {
18270
18271
  groupProps
18271
18272
  } from "@tscircuit/props";
18272
18273
  import {
18273
- distance as distance15
18274
+ distance as distance16
18274
18275
  } from "circuit-json";
18275
18276
  import Debug15 from "debug";
18276
18277
 
@@ -18977,7 +18978,7 @@ function validateOriginalEndpointConnectivity(params) {
18977
18978
  representativeConnection.name
18978
18979
  )
18979
18980
  ).map((obstacle) => ({ type: "obstacle", obstacle }));
18980
- const routeCopper = (routedSrj.traces ?? []).filter(
18981
+ const routeCopper2 = (routedSrj.traces ?? []).filter(
18981
18982
  (trace) => traceBelongsToNet(inputSrj, trace, representativeConnection)
18982
18983
  ).flatMap((trace) => extractTraceCopper(trace, layerNames));
18983
18984
  const planeCopper = [
@@ -18994,7 +18995,7 @@ function validateOriginalEndpointConnectivity(params) {
18994
18995
  const copper = [
18995
18996
  ...endpointCopper,
18996
18997
  ...obstacleCopper,
18997
- ...routeCopper,
18998
+ ...routeCopper2,
18998
18999
  ...planeCopper
18999
19000
  ];
19000
19001
  const connectedCopper = new DisjointSet(copper.length);
@@ -19469,8 +19470,8 @@ function getTerminalDirections(params) {
19469
19470
  x: plan.targetPoint.x - plan.sourcePoint.x,
19470
19471
  y: plan.targetPoint.y - plan.sourcePoint.y
19471
19472
  };
19472
- const length7 = Math.hypot(rawOutward.x, rawOutward.y);
19473
- const outward = length7 > EPSILON4 ? { x: rawOutward.x / length7, y: rawOutward.y / length7 } : { x: 1, y: 0 };
19473
+ const length8 = Math.hypot(rawOutward.x, rawOutward.y);
19474
+ const outward = length8 > EPSILON4 ? { x: rawOutward.x / length8, y: rawOutward.y / length8 } : { x: 1, y: 0 };
19474
19475
  return {
19475
19476
  outward,
19476
19477
  perpendicular: { x: -outward.y, y: outward.x }
@@ -19759,7 +19760,7 @@ function runLocalCompletionPass(params) {
19759
19760
  };
19760
19761
  }
19761
19762
  function traceLength(trace) {
19762
- let length7 = 0;
19763
+ let length8 = 0;
19763
19764
  let previousWire;
19764
19765
  for (const point6 of trace.route) {
19765
19766
  if (point6.route_type !== "wire") {
@@ -19767,10 +19768,10 @@ function traceLength(trace) {
19767
19768
  continue;
19768
19769
  }
19769
19770
  if (previousWire?.layer === point6.layer)
19770
- length7 += distance9(previousWire, point6);
19771
+ length8 += distance9(previousWire, point6);
19771
19772
  previousWire = point6;
19772
19773
  }
19773
- return length7;
19774
+ return length8;
19774
19775
  }
19775
19776
  function trimCompletedFanoutTails(params) {
19776
19777
  const { fanoutSrj, completionTraces } = params;
@@ -20480,8 +20481,8 @@ function* getMultiSegmentTuningWindows(params) {
20480
20481
  for (const [index, segment2] of plan.segments.entries()) {
20481
20482
  if (segment2.layer !== plan.targetLayer || index < (plan.sourceEscapeSegmentCount ?? 1))
20482
20483
  continue;
20483
- const length7 = distance9(segment2.start, segment2.end);
20484
- const steps = Math.max(1, Math.ceil(length7 / (segment2.width / 2)));
20484
+ const length8 = distance9(segment2.start, segment2.end);
20485
+ const steps = Math.max(1, Math.ceil(length8 / (segment2.width / 2)));
20485
20486
  for (let step = 0; step <= steps; step++) {
20486
20487
  consumeWork();
20487
20488
  const fraction = step / steps;
@@ -26416,7 +26417,7 @@ function hasValidTurns(segments) {
26416
26417
  const segment2 = segments[i];
26417
26418
  const dx = segment2.end.x - segment2.start.x;
26418
26419
  const dy = segment2.end.y - segment2.start.y;
26419
- const length7 = Math.hypot(dx, dy);
26420
+ const length8 = Math.hypot(dx, dy);
26420
26421
  if (Math.min(
26421
26422
  Math.abs(dx),
26422
26423
  Math.abs(dy),
@@ -26425,12 +26426,12 @@ function hasValidTurns(segments) {
26425
26426
  return false;
26426
26427
  const next = segments[i + 1];
26427
26428
  if (next && distance9(segment2.end, next.start) > EPSILON8) return false;
26428
- if (!next || next.layer !== segment2.layer || length7 < EPSILON8) continue;
26429
+ if (!next || next.layer !== segment2.layer || length8 < EPSILON8) continue;
26429
26430
  const nx = next.end.x - next.start.x;
26430
26431
  const ny = next.end.y - next.start.y;
26431
26432
  const nextLength = Math.hypot(nx, ny);
26432
26433
  if (nextLength < EPSILON8) continue;
26433
- if ((dx * nx + dy * ny) / (length7 * nextLength) < Math.SQRT1_2 - EPSILON8)
26434
+ if ((dx * nx + dy * ny) / (length8 * nextLength) < Math.SQRT1_2 - EPSILON8)
26434
26435
  return false;
26435
26436
  }
26436
26437
  return true;
@@ -26751,7 +26752,7 @@ function normalizeFanoutPlanCorners(params) {
26751
26752
  0
26752
26753
  )
26753
26754
  );
26754
- if (lengths.some((length7) => !Number.isFinite(length7)) || Math.abs(lengths[0] - lengths[1]) > pair.lengthTolerance + EPSILON8)
26755
+ if (lengths.some((length8) => !Number.isFinite(length8)) || Math.abs(lengths[0] - lengths[1]) > pair.lengthTolerance + EPSILON8)
26755
26756
  return null;
26756
26757
  }
26757
26758
  if (params.inputSrj.traces?.length && plans.length) {
@@ -26990,7 +26991,7 @@ function rebuildTraceRoute(plan, segments) {
26990
26991
  function createPlanWithSegments(plan, segments, updateSourceEscapeCount = false) {
26991
26992
  const route = rebuildTraceRoute(plan, segments);
26992
26993
  if (!route) return null;
26993
- const length7 = [...segments, ...plan.planeEndpointSegments ?? []].reduce(
26994
+ const length8 = [...segments, ...plan.planeEndpointSegments ?? []].reduce(
26994
26995
  (total, segment2) => total + distance9(segment2.start, segment2.end),
26995
26996
  0
26996
26997
  );
@@ -27002,7 +27003,7 @@ function createPlanWithSegments(plan, segments, updateSourceEscapeCount = false)
27002
27003
  ...updateSourceEscapeCount && plan.sourceEscapeSegmentCount !== void 0 && sourceEscapeSegmentCount >= 0 ? { sourceEscapeSegmentCount } : {},
27003
27004
  trace: { ...plan.trace, route },
27004
27005
  segments,
27005
- length: length7
27006
+ length: length8
27006
27007
  };
27007
27008
  }
27008
27009
  function addedTuningViasAreSelfClear(plan, addedVias, clearance) {
@@ -27532,11 +27533,11 @@ function* createExtendedFoldCandidates(params) {
27532
27533
  continue;
27533
27534
  } else if (start.layer !== plan.targetLayer && (!params.allowTransitLayerMatching || !(bus.allowedLayers ?? [plan.targetLayer]).includes(start.layer) || !(bus.routableEscapeLayers ?? bus.allowedLayers ?? [plan.targetLayer]).includes(start.layer)))
27534
27535
  continue;
27535
- const length7 = distance9(start.start, start.end);
27536
- if (length7 <= EPSILON9) continue;
27536
+ const length8 = distance9(start.start, start.end);
27537
+ if (length8 <= EPSILON9) continue;
27537
27538
  const direction = {
27538
- x: (start.end.x - start.start.x) / length7,
27539
- y: (start.end.y - start.start.y) / length7
27539
+ x: (start.end.x - start.start.x) / length8,
27540
+ y: (start.end.y - start.start.y) / length8
27540
27541
  };
27541
27542
  for (let last = first + 2; last < Math.min(plan.segments.length, first + 16); last++) {
27542
27543
  const span = plan.segments.slice(first, last + 1);
@@ -27613,19 +27614,19 @@ function* createSpreadLaneCandidates(plan, clearance, workBudget) {
27613
27614
  for (const { segment: segment2, index } of plan.segments.map((segment3, index2) => ({ segment: segment3, index: index2 })).filter(({ segment: segment3 }) => segment3.layer === plan.targetLayer).toSorted(
27614
27615
  (a, b) => distance9(b.segment.start, b.segment.end) - distance9(a.segment.start, a.segment.end)
27615
27616
  )) {
27616
- const length7 = distance9(segment2.start, segment2.end);
27617
- if (length7 <= EPSILON9) continue;
27617
+ const length8 = distance9(segment2.start, segment2.end);
27618
+ if (length8 <= EPSILON9) continue;
27618
27619
  const dx = Math.abs(segment2.end.x - segment2.start.x);
27619
27620
  const dy = Math.abs(segment2.end.y - segment2.start.y);
27620
27621
  if (dx > EPSILON9 && dy > EPSILON9 && Math.abs(dx - dy) > EPSILON9) continue;
27621
27622
  const tangent = {
27622
- x: (segment2.end.x - segment2.start.x) / length7,
27623
- y: (segment2.end.y - segment2.start.y) / length7
27623
+ x: (segment2.end.x - segment2.start.x) / length8,
27624
+ y: (segment2.end.y - segment2.start.y) / length8
27624
27625
  };
27625
27626
  const pitch = segment2.width + clearance;
27626
27627
  for (const multiple of [2, 3, 4, 6]) {
27627
27628
  const offset = pitch * multiple;
27628
- if (length7 < 2 * offset + pitch) continue;
27629
+ if (length8 < 2 * offset + pitch) continue;
27629
27630
  for (const sign of [1, -1]) {
27630
27631
  consumeMatchingWork(workBudget);
27631
27632
  const normal = { x: -tangent.y * sign, y: tangent.x * sign };
@@ -28395,15 +28396,15 @@ function sourceOriginRouteIsSelfClear(params) {
28395
28396
  const radius = (viaDiameter + traceWidth) / 2 + clearance;
28396
28397
  const incident = /* @__PURE__ */ new Set();
28397
28398
  for (const direction of [-1, 1]) {
28398
- let point6 = via.center, length7 = 0;
28399
+ let point6 = via.center, length8 = 0;
28399
28400
  const z18 = direction === -1 ? via.fromZ : via.toZ;
28400
28401
  for (let edge = via.edge + direction; edge >= 0 && edge + 1 < points.length; edge += direction) {
28401
28402
  const a = points[edge], b = points[edge + 1];
28402
28403
  const near = direction === -1 ? b : a, far = direction === -1 ? a : b;
28403
- if (a.z !== z18 || b.z !== z18 || distance9(point6, near) > 1e-7 || length7 > radius + 1e-7)
28404
+ if (a.z !== z18 || b.z !== z18 || distance9(point6, near) > 1e-7 || length8 > radius + 1e-7)
28404
28405
  break;
28405
28406
  incident.add(edge);
28406
- length7 += distance9(near, far);
28407
+ length8 += distance9(near, far);
28407
28408
  point6 = far;
28408
28409
  }
28409
28410
  }
@@ -28466,10 +28467,10 @@ function shortcutSection(points, width, clear) {
28466
28467
  const lowerBound = Math.max(dx, dy) + (Math.SQRT2 - 1) * Math.min(dx, dy);
28467
28468
  if (cost[i] + lowerBound >= cost[j] - EPSILON10) continue;
28468
28469
  for (const path of connectorVariants(a, b)) {
28469
- const length7 = path.slice(1).reduce((sum, p, index) => sum + distance9(path[index], p), 0);
28470
- if (cost[i] + length7 >= cost[j] - EPSILON10 || !path.slice(1).every((p, index) => clear(path[index], p)))
28470
+ const length8 = path.slice(1).reduce((sum, p, index) => sum + distance9(path[index], p), 0);
28471
+ if (cost[i] + length8 >= cost[j] - EPSILON10 || !path.slice(1).every((p, index) => clear(path[index], p)))
28471
28472
  continue;
28472
- cost[j] = cost[i] + length7;
28473
+ cost[j] = cost[i] + length8;
28473
28474
  edges[j] = { previous: i, points: path };
28474
28475
  }
28475
28476
  }
@@ -28814,14 +28815,14 @@ var intersectsRegion = (regions, a, b = a) => regions.some(
28814
28815
  );
28815
28816
  function terminalSuffixAt(segments, point6, layer) {
28816
28817
  const positions = [];
28817
- let length7 = 0;
28818
+ let length8 = 0;
28818
28819
  for (const [index2, segment2] of segments.entries()) {
28819
28820
  if (segment2.layer === layer && distancePointToSegment(point6, segment2.start, segment2.end) < 1e-8) {
28820
- const offset = length7 + distance9(segment2.start, point6);
28821
+ const offset = length8 + distance9(segment2.start, point6);
28821
28822
  if (!positions.some((p) => Math.abs(p.offset - offset) < 1e-8))
28822
28823
  positions.push({ index: index2, offset });
28823
28824
  }
28824
- length7 += distance9(segment2.start, segment2.end);
28825
+ length8 += distance9(segment2.start, segment2.end);
28825
28826
  }
28826
28827
  if (positions.length !== 1) return null;
28827
28828
  let index = positions[0].index;
@@ -28884,12 +28885,12 @@ function boundaryTerminalPlanIsSelfClear(params) {
28884
28885
  if (Math.abs(ux * vy - uy * vx) >= 1e-10 || ux * vx + uy * vy < 0) break;
28885
28886
  runStart = previous.start;
28886
28887
  }
28887
- const length7 = distance9(runStart, cut);
28888
- if (length7 < 1e-10) return false;
28889
- const trim = Math.min(maximumJoinLength, length7 / 3);
28888
+ const length8 = distance9(runStart, cut);
28889
+ if (length8 < 1e-10) return false;
28890
+ const trim = Math.min(maximumJoinLength, length8 / 3);
28890
28891
  cut = {
28891
- x: cut.x + (runStart.x - cut.x) * trim / length7,
28892
- y: cut.y + (runStart.y - cut.y) * trim / length7
28892
+ x: cut.x + (runStart.x - cut.x) * trim / length8,
28893
+ y: cut.y + (runStart.y - cut.y) * trim / length8
28893
28894
  };
28894
28895
  }
28895
28896
  const suffix = terminalSuffixAt(plan.segments, cut, start.layer);
@@ -33562,13 +33563,13 @@ function* sourcePrefixFoldShortcuts(plan, clearance) {
33562
33563
  if (first < 0) return;
33563
33564
  const pitch = prefix[first].width + clearance;
33564
33565
  for (let start = first; start >= Math.max(0, first - 3); start--) {
33565
- let length7 = 0;
33566
+ let length8 = 0;
33566
33567
  for (let end = start; end < Math.min(prefix.length, first + 8); end++) {
33567
33568
  const segment2 = prefix[end];
33568
33569
  if (segment2.layer !== plan.sourceLayer || end > start && distance9(prefix[end - 1].end, segment2.start) > 1e-7)
33569
33570
  break;
33570
- length7 += distance9(segment2.start, segment2.end);
33571
- if (length7 > 4 * pitch + 1e-7) break;
33571
+ length8 += distance9(segment2.start, segment2.end);
33572
+ if (length8 > 4 * pitch + 1e-7) break;
33572
33573
  if (end <= first) continue;
33573
33574
  const a = prefix[start].start, b = segment2.end, dx = b.x - a.x, dy = b.y - a.y, diagonal = Math.min(Math.abs(dx), Math.abs(dy));
33574
33575
  for (const bend of [
@@ -33581,7 +33582,7 @@ function* sourcePrefixFoldShortcuts(plan, clearance) {
33581
33582
  y: b.y - Math.sign(dy) * diagonal
33582
33583
  }
33583
33584
  ]) {
33584
- if (distance9(a, bend) + distance9(bend, b) >= length7 - 1e-7) continue;
33585
+ if (distance9(a, bend) + distance9(bend, b) >= length8 - 1e-7) continue;
33585
33586
  yield [
33586
33587
  prefix[0].start,
33587
33588
  ...prefix.slice(0, start).map((s) => s.end),
@@ -33711,8 +33712,8 @@ function repairSourcePadReentries(params) {
33711
33712
  const key = JSON.stringify([anchor, points]);
33712
33713
  if (seen.has(key)) continue;
33713
33714
  seen.add(key);
33714
- const length7 = points.slice(1).reduce((sum, p, i) => sum + distance9(points[i], p), 0) + prefix.slice(anchor).reduce((sum, s) => sum + distance9(s.start, s.end), 0);
33715
- proposals.push({ anchor, points, length: length7 });
33715
+ const length8 = points.slice(1).reduce((sum, p, i) => sum + distance9(points[i], p), 0) + prefix.slice(anchor).reduce((sum, s) => sum + distance9(s.start, s.end), 0);
33716
+ proposals.push({ anchor, points, length: length8 });
33716
33717
  }
33717
33718
  }
33718
33719
  }
@@ -37514,9 +37515,9 @@ function getFreeBoundaryTracks(params) {
37514
37515
  for (const via of vias) {
37515
37516
  if (!via.spanLayers.includes(targetLayer2)) continue;
37516
37517
  const radius = via.diameter / 2 + traceWidth / 2 + clearance;
37517
- const distance22 = Math.abs(via.center[across] - edge);
37518
- if (distance22 >= radius) continue;
37519
- const extent = Math.sqrt(radius * radius - distance22 * distance22);
37518
+ const distance23 = Math.abs(via.center[across] - edge);
37519
+ if (distance23 >= radius) continue;
37520
+ const extent = Math.sqrt(radius * radius - distance23 * distance23);
37520
37521
  blocked.push([via.center[along] - extent, via.center[along] + extent]);
37521
37522
  }
37522
37523
  const gaps = [];
@@ -38731,8 +38732,8 @@ var LayerRoutingAttempts = class {
38731
38732
 
38732
38733
  // node_modules/@tscircuit/fanout-solver/lib/get-boundary-approach-reservations.ts
38733
38734
  function getBoundaryApproachReservations(params) {
38734
- const length7 = params.traceWidth + params.clearance;
38735
- if (!Number.isFinite(length7) || !(params.traceWidth > 0) || params.clearance < 0)
38735
+ const length8 = params.traceWidth + params.clearance;
38736
+ if (!Number.isFinite(length8) || !(params.traceWidth > 0) || params.clearance < 0)
38736
38737
  throw new Error("Boundary approach reservations require valid trace rules");
38737
38738
  return params.buses.filter(
38738
38739
  (bus) => bus.termination.type === "boundary" && !params.excludedBusIds.has(bus.busId)
@@ -38749,10 +38750,10 @@ function getBoundaryApproachReservations(params) {
38749
38750
  `Missing boundary approach target for ${connection.connectionIndex}`
38750
38751
  );
38751
38752
  const start = { ...end };
38752
- if (bus.exitEdge === "bottom") start.y += length7;
38753
- else if (bus.exitEdge === "top") start.y -= length7;
38754
- else if (bus.exitEdge === "left") start.x += length7;
38755
- else start.x -= length7;
38753
+ if (bus.exitEdge === "bottom") start.y += length8;
38754
+ else if (bus.exitEdge === "top") start.y -= length8;
38755
+ else if (bus.exitEdge === "left") start.x += length8;
38756
+ else start.x -= length8;
38756
38757
  return {
38757
38758
  type: "pcb_trace",
38758
38759
  pcb_trace_id: `fanout-approach-reservation:${connection.connectionIndex}`,
@@ -43010,7 +43011,7 @@ function validateDifferentialPairs(inputSrj, plansByConnection, issues) {
43010
43011
  0
43011
43012
  )
43012
43013
  );
43013
- if (lengths.some((length7) => !Number.isFinite(length7))) {
43014
+ if (lengths.some((length8) => !Number.isFinite(length8))) {
43014
43015
  addIssue2(
43015
43016
  issues,
43016
43017
  "invalid-differential-pair",
@@ -49205,6 +49206,8 @@ function getPresetAutoroutingConfig(autorouterConfig, platformConfig) {
49205
49206
  groupMode: "subcircuit",
49206
49207
  preset: "single_layer_fanout"
49207
49208
  };
49209
+ case "bus-lanes":
49210
+ return { local: true, groupMode: "subcircuit", preset: "bus_lanes" };
49208
49211
  case "fanout":
49209
49212
  return {
49210
49213
  local: true,
@@ -49267,6 +49270,1153 @@ function getPresetAutoroutingConfig(autorouterConfig, platformConfig) {
49267
49270
  }
49268
49271
  }
49269
49272
 
49273
+ // node_modules/@tscircuit/bus-lanes-solver/lib/bus-lanes-solver.ts
49274
+ import { BaseSolver as BaseSolver4 } from "@tscircuit/solver-utils";
49275
+
49276
+ // node_modules/@tscircuit/bus-lanes-solver/lib/geometry.ts
49277
+ var distance12 = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
49278
+ function pointSegmentDistance(p, edge) {
49279
+ const [a, b] = edge, dx = b.x - a.x, dy = b.y - a.y, t = Math.max(
49280
+ 0,
49281
+ Math.min(
49282
+ 1,
49283
+ ((p.x - a.x) * dx + (p.y - a.y) * dy) / (dx * dx + dy * dy || 1)
49284
+ )
49285
+ );
49286
+ return Math.hypot(p.x - a.x - t * dx, p.y - a.y - t * dy);
49287
+ }
49288
+ var cross2 = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
49289
+ function segmentDistance(ab, cd) {
49290
+ const [a, b] = ab, [c, d] = cd;
49291
+ if (Math.max(a.x, b.x) >= Math.min(c.x, d.x) && Math.max(c.x, d.x) >= Math.min(a.x, b.x) && Math.max(a.y, b.y) >= Math.min(c.y, d.y) && Math.max(c.y, d.y) >= Math.min(a.y, b.y) && cross2(a, b, c) * cross2(a, b, d) <= 0 && cross2(c, d, a) * cross2(c, d, b) <= 0)
49292
+ return 0;
49293
+ return Math.min(
49294
+ pointSegmentDistance(a, cd),
49295
+ pointSegmentDistance(b, cd),
49296
+ pointSegmentDistance(c, ab),
49297
+ pointSegmentDistance(d, ab)
49298
+ );
49299
+ }
49300
+ var length = (path) => path.slice(1).reduce((sum, p, i) => sum + distance12(path[i], p), 0);
49301
+ function simplify(path) {
49302
+ return path.filter(
49303
+ (p, i) => !i || i === path.length - 1 || Math.abs(cross2(path[i - 1], p, path[i + 1])) > 1e-9
49304
+ );
49305
+ }
49306
+
49307
+ // node_modules/@tscircuit/bus-lanes-solver/lib/vector-scene.ts
49308
+ function fixedCopper(input) {
49309
+ const result = [];
49310
+ for (const o of input.obstacles)
49311
+ for (const layer of o.layers)
49312
+ result.push({
49313
+ a: o.center,
49314
+ b: o.center,
49315
+ radius: 0,
49316
+ layer,
49317
+ owners: o.connectedTo,
49318
+ rect: {
49319
+ minX: o.center.x - o.width / 2,
49320
+ maxX: o.center.x + o.width / 2,
49321
+ minY: o.center.y - o.height / 2,
49322
+ maxY: o.center.y + o.height / 2
49323
+ }
49324
+ });
49325
+ const layers = Array.from(
49326
+ { length: input.layerCount },
49327
+ (_, i) => i === 0 ? "top" : i === input.layerCount - 1 ? "bottom" : `inner${i}`
49328
+ );
49329
+ for (const t of input.traces ?? [])
49330
+ for (let i = 0; i < t.route.length; i++) {
49331
+ const p = t.route[i], q = t.route[i + 1], owners = [t.connection_name ?? "", t.source_trace_id ?? ""];
49332
+ if (p.route_type === "via") {
49333
+ const a = layers.indexOf(p.from_layer), b = layers.indexOf(p.to_layer);
49334
+ for (const layer of p.layers ?? layers.slice(Math.min(a, b), Math.max(a, b) + 1))
49335
+ result.push({
49336
+ a: p,
49337
+ b: p,
49338
+ radius: (p.via_diameter ?? 0.3) / 2,
49339
+ layer,
49340
+ owners
49341
+ });
49342
+ } else if (q?.route_type === "wire") {
49343
+ if (p.layer !== q.layer)
49344
+ throw Error("Fixed trace changes layer without a via");
49345
+ result.push({ a: p, b: q, radius: p.width / 2, layer: p.layer, owners });
49346
+ }
49347
+ if (q && p.route_type !== q.route_type && distance12(p, q) > 1e-10) {
49348
+ const wire = p.route_type === "wire" ? p : q;
49349
+ result.push({
49350
+ a: p,
49351
+ b: q,
49352
+ radius: wire.width / 2,
49353
+ layer: wire.layer,
49354
+ owners
49355
+ });
49356
+ }
49357
+ }
49358
+ return result;
49359
+ }
49360
+ function routeCopper(t) {
49361
+ return t.route.slice(1).map((p, i) => ({
49362
+ a: t.route[i],
49363
+ b: p,
49364
+ radius: p.width / 2,
49365
+ layer: p.layer,
49366
+ owners: [t.connection_name ?? ""]
49367
+ }));
49368
+ }
49369
+ var intersectsRect = (a, b, r) => {
49370
+ let t0 = 0, t1 = 1;
49371
+ for (const [origin, delta, min, max] of [
49372
+ [a.x, b.x - a.x, r.minX, r.maxX],
49373
+ [a.y, b.y - a.y, r.minY, r.maxY]
49374
+ ]) {
49375
+ if (Math.abs(delta) < 1e-12) {
49376
+ if (origin < min || origin > max) return false;
49377
+ continue;
49378
+ }
49379
+ let lo = (min - origin) / delta, hi = (max - origin) / delta;
49380
+ if (lo > hi) [lo, hi] = [hi, lo];
49381
+ t0 = Math.max(t0, lo);
49382
+ t1 = Math.min(t1, hi);
49383
+ if (t0 > t1) return false;
49384
+ }
49385
+ return true;
49386
+ };
49387
+ function clearanceToCopper(a, b, c) {
49388
+ if (!c.rect) return segmentDistance([a, b], [c.a, c.b]) - c.radius;
49389
+ const r = c.rect;
49390
+ if (intersectsRect(a, b, r)) return 0;
49391
+ const corners = [
49392
+ { x: r.minX, y: r.minY },
49393
+ { x: r.maxX, y: r.minY },
49394
+ { x: r.maxX, y: r.maxY },
49395
+ { x: r.minX, y: r.maxY }
49396
+ ];
49397
+ return Math.min(
49398
+ ...corners.map(
49399
+ (p, i) => segmentDistance([a, b], [p, corners[(i + 1) % 4]])
49400
+ )
49401
+ );
49402
+ }
49403
+ var VectorScene = class {
49404
+ constructor(input, connection, width, all) {
49405
+ this.input = input;
49406
+ this.connection = connection;
49407
+ this.width = width;
49408
+ this.owners = new Set(
49409
+ [
49410
+ connection.name,
49411
+ connection.source_trace_id,
49412
+ ...connection.pointsToConnect.flatMap((p) => [
49413
+ p.pointId,
49414
+ p.pcb_port_id
49415
+ ])
49416
+ ].filter((s) => !!s)
49417
+ );
49418
+ this.copper = all.filter(
49419
+ (c) => c.layer === connection.pointsToConnect[0].layer && !c.owners.some((n) => this.owners.has(n))
49420
+ );
49421
+ this.margin = width / 2 + (input.minTraceToPadEdgeClearance ?? input.defaultObstacleMargin ?? 0.075);
49422
+ }
49423
+ input;
49424
+ connection;
49425
+ width;
49426
+ copper;
49427
+ owners;
49428
+ margin;
49429
+ visible(a, b) {
49430
+ const m = this.width / 2 + (this.input.minBoardEdgeClearance ?? 0), r = this.input.bounds;
49431
+ if ([a, b].some(
49432
+ (p) => p.x < r.minX + m - 1e-9 || p.x > r.maxX - m + 1e-9 || p.y < r.minY + m - 1e-9 || p.y > r.maxY - m + 1e-9
49433
+ ))
49434
+ return false;
49435
+ const minX = Math.min(a.x, b.x) - this.margin, maxX = Math.max(a.x, b.x) + this.margin, minY = Math.min(a.y, b.y) - this.margin, maxY = Math.max(a.y, b.y) + this.margin;
49436
+ for (const c of this.copper) {
49437
+ const r2 = c.rect ?? {
49438
+ minX: Math.min(c.a.x, c.b.x) - c.radius,
49439
+ maxX: Math.max(c.a.x, c.b.x) + c.radius,
49440
+ minY: Math.min(c.a.y, c.b.y) - c.radius,
49441
+ maxY: Math.max(c.a.y, c.b.y) + c.radius
49442
+ };
49443
+ if (r2.minX > maxX || r2.maxX < minX || r2.minY > maxY || r2.maxY < minY)
49444
+ continue;
49445
+ if (clearanceToCopper(a, b, c) < this.margin - 1e-8) return false;
49446
+ }
49447
+ return true;
49448
+ }
49449
+ pathVisible(path) {
49450
+ return path.slice(1).every((b, i) => this.visible(path[i], b));
49451
+ }
49452
+ /** Vertices of circumscribed octagonal Minkowski offsets. Their edges are
49453
+ * horizontal, vertical or 45 degrees, including circular vias and trace caps. */
49454
+ vertices() {
49455
+ const result = [], k = Math.SQRT2 - 1, epsilon = 1e-5;
49456
+ for (const c of this.copper) {
49457
+ if (c.rect) {
49458
+ const r = c.rect, m = this.margin + epsilon;
49459
+ result.push(
49460
+ { x: r.minX - m, y: r.minY - m },
49461
+ { x: r.minX - m, y: r.maxY + m },
49462
+ { x: r.maxX + m, y: r.minY - m },
49463
+ { x: r.maxX + m, y: r.maxY + m }
49464
+ );
49465
+ } else {
49466
+ const r = c.radius + this.margin + epsilon;
49467
+ for (const p of distance12(c.a, c.b) < 1e-9 ? [c.a] : [c.a, c.b])
49468
+ for (const [x, y] of [
49469
+ [1, k],
49470
+ [k, 1],
49471
+ [-k, 1],
49472
+ [-1, k],
49473
+ [-1, -k],
49474
+ [-k, -1],
49475
+ [k, -1],
49476
+ [1, -k]
49477
+ ])
49478
+ result.push({ x: p.x + x * r, y: p.y + y * r });
49479
+ }
49480
+ }
49481
+ const seen = /* @__PURE__ */ new Set();
49482
+ return result.filter((p) => {
49483
+ const key = `${p.x.toFixed(9)},${p.y.toFixed(9)}`;
49484
+ if (seen.has(key)) return false;
49485
+ seen.add(key);
49486
+ return this.visible(p, p);
49487
+ });
49488
+ }
49489
+ };
49490
+
49491
+ // node_modules/@tscircuit/bus-lanes-solver/lib/min-heap.ts
49492
+ var MinHeap2 = class {
49493
+ entries = [];
49494
+ sequence = 0;
49495
+ get length() {
49496
+ return this.entries.length;
49497
+ }
49498
+ values() {
49499
+ return this.entries.map((e) => e.value);
49500
+ }
49501
+ before(a, b) {
49502
+ return a.value.f < b.value.f || a.value.f === b.value.f && a.sequence < b.sequence;
49503
+ }
49504
+ push(value) {
49505
+ const entry = { value, sequence: this.sequence++ };
49506
+ let i = this.entries.length;
49507
+ this.entries.push(entry);
49508
+ while (i > 0) {
49509
+ const parent = i - 1 >> 1;
49510
+ if (!this.before(entry, this.entries[parent])) break;
49511
+ this.entries[i] = this.entries[parent];
49512
+ i = parent;
49513
+ }
49514
+ this.entries[i] = entry;
49515
+ }
49516
+ pop() {
49517
+ const first = this.entries[0], last = this.entries.pop();
49518
+ if (this.entries.length) {
49519
+ let i = 0;
49520
+ while (i * 2 + 1 < this.entries.length) {
49521
+ let child = i * 2 + 1;
49522
+ if (child + 1 < this.entries.length && this.before(this.entries[child + 1], this.entries[child]))
49523
+ child++;
49524
+ if (!this.before(this.entries[child], last)) break;
49525
+ this.entries[i] = this.entries[child];
49526
+ i = child;
49527
+ }
49528
+ this.entries[i] = last;
49529
+ }
49530
+ return first.value;
49531
+ }
49532
+ };
49533
+
49534
+ // node_modules/@tscircuit/bus-lanes-solver/lib/vector-visibility.ts
49535
+ function connectors(a, b) {
49536
+ const dx = b.x - a.x, dy = b.y - a.y, sx = Math.sign(dx), sy = Math.sign(dy), d = Math.min(Math.abs(dx), Math.abs(dy));
49537
+ if (Math.min(Math.abs(dx), Math.abs(dy)) < 1e-10 || Math.abs(Math.abs(dx) - Math.abs(dy)) < 1e-10)
49538
+ return [[a, b]];
49539
+ const lead = (Math.max(Math.abs(dx), Math.abs(dy)) - d) / 2;
49540
+ const centered = Math.abs(dx) > Math.abs(dy) ? [a, { x: a.x + sx * lead, y: a.y }, { x: b.x - sx * lead, y: b.y }, b] : [a, { x: a.x, y: a.y + sy * lead }, { x: b.x, y: b.y - sy * lead }, b];
49541
+ return [
49542
+ centered,
49543
+ [a, { x: a.x + sx * d, y: a.y + sy * d }, b],
49544
+ [a, { x: b.x - sx * d, y: b.y - sy * d }, b],
49545
+ [a, { x: a.x, y: b.y }, b],
49546
+ [a, { x: b.x, y: a.y }, b]
49547
+ ];
49548
+ }
49549
+ var VectorVisibilitySearch = class {
49550
+ constructor(scene, start, end) {
49551
+ this.scene = scene;
49552
+ this.start = start;
49553
+ this.end = end;
49554
+ this.vertices = [start, end];
49555
+ this.open.push({ id: 0, g: 0, f: distance12(start, end) });
49556
+ this.best.set(0, 0);
49557
+ }
49558
+ scene;
49559
+ start;
49560
+ end;
49561
+ vertices;
49562
+ open = new MinHeap2();
49563
+ best = /* @__PURE__ */ new Map();
49564
+ expanded = 0;
49565
+ failed = false;
49566
+ solved = false;
49567
+ result = [];
49568
+ geometryLoaded = false;
49569
+ current;
49570
+ visibleEdges = [];
49571
+ step() {
49572
+ if (!this.geometryLoaded) {
49573
+ this.geometryLoaded = true;
49574
+ const lowerBound = Math.max(
49575
+ Math.abs(this.end.x - this.start.x),
49576
+ Math.abs(this.end.y - this.start.y)
49577
+ ) + (Math.SQRT2 - 1) * Math.min(
49578
+ Math.abs(this.end.x - this.start.x),
49579
+ Math.abs(this.end.y - this.start.y)
49580
+ );
49581
+ for (const path of connectors(this.start, this.end)) {
49582
+ if (length(path) > lowerBound + 1e-9 || !this.scene.pathVisible(path))
49583
+ continue;
49584
+ this.visibleEdges = [path];
49585
+ this.result = simplify(path);
49586
+ this.solved = true;
49587
+ this.expanded = 1;
49588
+ return;
49589
+ }
49590
+ this.vertices.push(...this.scene.vertices());
49591
+ }
49592
+ if (!this.open.length) {
49593
+ this.failed = true;
49594
+ return;
49595
+ }
49596
+ const cur = this.open.pop();
49597
+ if (cur.g > (this.best.get(cur.id) ?? Infinity) + 1e-9) return;
49598
+ this.current = cur;
49599
+ this.expanded++;
49600
+ this.visibleEdges = [];
49601
+ if (cur.id === 1) {
49602
+ const edges = [];
49603
+ for (let c = cur; c?.parent; c = c.parent)
49604
+ edges.push(c.edge);
49605
+ this.result = simplify([
49606
+ this.start,
49607
+ ...edges.reverse().flatMap((p) => p.slice(1))
49608
+ ]);
49609
+ this.solved = true;
49610
+ return;
49611
+ }
49612
+ const from = this.vertices[cur.id];
49613
+ for (let id = 1; id < this.vertices.length; id++) {
49614
+ if (id === cur.id) continue;
49615
+ const to = this.vertices[id], lower = cur.g + distance12(from, to);
49616
+ if (lower >= (this.best.get(id) ?? Infinity) - 1e-9) continue;
49617
+ const candidates = connectors(from, to).sort(
49618
+ (a, b) => length(a) - length(b)
49619
+ );
49620
+ for (const path of candidates) {
49621
+ const g = cur.g + length(path);
49622
+ if (g >= (this.best.get(id) ?? Infinity) - 1e-9) continue;
49623
+ if (!this.scene.pathVisible(path)) continue;
49624
+ this.best.set(id, g);
49625
+ this.open.push({
49626
+ id,
49627
+ g,
49628
+ f: g + distance12(to, this.end),
49629
+ parent: cur,
49630
+ edge: path
49631
+ });
49632
+ if (this.visibleEdges.length < 100) this.visibleEdges.push(path);
49633
+ break;
49634
+ }
49635
+ }
49636
+ }
49637
+ currentPath() {
49638
+ const edges = [];
49639
+ for (let c = this.current; c?.parent; c = c.parent) edges.push(c.edge);
49640
+ return [this.start, ...edges.reverse().flatMap((e) => e.slice(1))];
49641
+ }
49642
+ };
49643
+
49644
+ // node_modules/@tscircuit/bus-lanes-solver/lib/winding-orders.ts
49645
+ function windingOrders(connections) {
49646
+ const orders = [];
49647
+ const seen = /* @__PURE__ */ new Set();
49648
+ const add = (order) => {
49649
+ const key = order.map((c) => c.name).join("\0");
49650
+ if (!seen.has(key)) {
49651
+ seen.add(key);
49652
+ orders.push(order);
49653
+ }
49654
+ };
49655
+ const direction = connections.reduce(
49656
+ (v, c) => ({
49657
+ x: v.x + c.pointsToConnect[1].x - c.pointsToConnect[0].x,
49658
+ y: v.y + c.pointsToConnect[1].y - c.pointsToConnect[0].y
49659
+ }),
49660
+ { x: 0, y: 0 }
49661
+ );
49662
+ const transverse = (c) => -direction.y * c.pointsToConnect[0].x + direction.x * c.pointsToConnect[0].y;
49663
+ const sweep = [...connections].sort(
49664
+ (a, b) => a.pointsToConnect[0].layer.localeCompare(b.pointsToConnect[0].layer) || transverse(a) - transverse(b) || a.name.localeCompare(b.name)
49665
+ );
49666
+ const span = (endpoint, axis) => Math.max(...connections.map((c) => c.pointsToConnect[endpoint][axis])) - Math.min(...connections.map((c) => c.pointsToConnect[endpoint][axis]));
49667
+ const transverseAxis = span(0, "x") < 1e-7 && span(1, "x") < 1e-7 ? "y" : span(0, "y") < 1e-7 && span(1, "y") < 1e-7 ? "x" : void 0;
49668
+ if (transverseAxis) {
49669
+ const drift = connections.reduce(
49670
+ (s, c) => s + c.pointsToConnect[1][transverseAxis] - c.pointsToConnect[0][transverseAxis],
49671
+ 0
49672
+ );
49673
+ if (Math.abs(drift) > 1e-7)
49674
+ add(
49675
+ [...connections].sort(
49676
+ (a, b) => a.pointsToConnect[0].layer.localeCompare(
49677
+ b.pointsToConnect[0].layer
49678
+ ) || -Math.sign(drift) * (a.pointsToConnect[0][transverseAxis] - b.pointsToConnect[0][transverseAxis]) || a.name.localeCompare(b.name)
49679
+ )
49680
+ );
49681
+ }
49682
+ add(sweep);
49683
+ add([...sweep].reverse());
49684
+ add(connections);
49685
+ for (const endpoint of [1, 0]) {
49686
+ const center = connections.reduce(
49687
+ (p, c) => ({
49688
+ x: p.x + c.pointsToConnect[endpoint].x / connections.length,
49689
+ y: p.y + c.pointsToConnect[endpoint].y / connections.length
49690
+ }),
49691
+ { x: 0, y: 0 }
49692
+ );
49693
+ const angle = (c) => Math.atan2(
49694
+ c.pointsToConnect[endpoint].y - center.y,
49695
+ c.pointsToConnect[endpoint].x - center.x
49696
+ );
49697
+ const angular = [...connections].sort(
49698
+ (a, b) => angle(a) - angle(b) || a.name.localeCompare(b.name)
49699
+ );
49700
+ add(angular);
49701
+ add([...angular].reverse());
49702
+ for (const axis of ["x", "y"]) {
49703
+ const other = axis === "x" ? "y" : "x";
49704
+ const sorted = [...connections].sort(
49705
+ (a, b) => a.pointsToConnect[endpoint][axis] - b.pointsToConnect[endpoint][axis] || a.pointsToConnect[endpoint][other] - b.pointsToConnect[endpoint][other]
49706
+ );
49707
+ add(sorted);
49708
+ add([...sorted].reverse());
49709
+ }
49710
+ for (let i = 1; i < angular.length; i++) {
49711
+ const rotated = [...angular.slice(i), ...angular.slice(0, i)];
49712
+ add(rotated);
49713
+ add([...rotated].reverse());
49714
+ }
49715
+ }
49716
+ return orders;
49717
+ }
49718
+
49719
+ // node_modules/@tscircuit/bus-lanes-solver/lib/route-lengths.ts
49720
+ function fixedRouteLength(input, name) {
49721
+ const connection = input.connections.find((c) => c.name === name);
49722
+ return (input.traces ?? []).filter(
49723
+ (t) => t.connection_name === name || t.source_trace_id === (connection?.source_trace_id ?? name)
49724
+ ).reduce((sum, t) => sum + length(t.route), 0);
49725
+ }
49726
+ function busLengthReports(input, traces) {
49727
+ return (input.buses ?? []).map((bus) => {
49728
+ const lengths = bus.connectionNames.map((name) => {
49729
+ const route = traces.find((t) => t.connection_name === name);
49730
+ return {
49731
+ name,
49732
+ carrierLengthMm: route ? length(route.route) : null,
49733
+ fixedLengthMm: fixedRouteLength(input, name),
49734
+ totalLengthMm: route ? length(route.route) + fixedRouteLength(input, name) : null
49735
+ };
49736
+ });
49737
+ const complete = lengths.every((l) => l.totalLengthMm !== null);
49738
+ const values = lengths.map((l) => l.totalLengthMm ?? 0);
49739
+ const skewMm = complete && values.length ? Math.max(...values) - Math.min(...values) : null;
49740
+ return {
49741
+ busId: bus.busId,
49742
+ toleranceMm: bus.maxLengthSkew ?? null,
49743
+ skewMm,
49744
+ matched: bus.maxLengthSkew !== void 0 && skewMm !== null && skewMm <= bus.maxLengthSkew + 1e-7,
49745
+ lengths
49746
+ };
49747
+ });
49748
+ }
49749
+ function lengthConstraints(input) {
49750
+ return [
49751
+ ...(input.buses ?? []).filter((b) => b.maxLengthSkew !== void 0).map((b) => ({
49752
+ names: b.connectionNames,
49753
+ tolerance: b.maxLengthSkew
49754
+ })),
49755
+ ...(input.differentialPairs ?? []).map((p) => ({
49756
+ names: p.connectionNames,
49757
+ tolerance: p.lengthTolerance
49758
+ }))
49759
+ ];
49760
+ }
49761
+ function minimumLengthTargets(input, traces) {
49762
+ const targets = new Map(
49763
+ traces.map((t) => [
49764
+ t.connection_name,
49765
+ length(t.route) + fixedRouteLength(input, t.connection_name)
49766
+ ])
49767
+ );
49768
+ const constraints = lengthConstraints(input);
49769
+ for (let pass = 0; pass < targets.size; pass++) {
49770
+ let changed = false;
49771
+ for (const { names, tolerance } of constraints) {
49772
+ const floor = Math.max(...names.map((n) => targets.get(n))) - tolerance;
49773
+ for (const name of names)
49774
+ if (targets.get(name) < floor - 1e-9) {
49775
+ targets.set(name, floor);
49776
+ changed = true;
49777
+ }
49778
+ }
49779
+ if (!changed) break;
49780
+ }
49781
+ return targets;
49782
+ }
49783
+ function pairLengthReports(input, traces) {
49784
+ return busLengthReports(
49785
+ {
49786
+ ...input,
49787
+ buses: (input.differentialPairs ?? []).map((p, i) => ({
49788
+ busId: `pair_${i}`,
49789
+ connectionNames: p.connectionNames,
49790
+ maxLengthSkew: p.lengthTolerance
49791
+ }))
49792
+ },
49793
+ traces
49794
+ );
49795
+ }
49796
+
49797
+ // node_modules/@tscircuit/bus-lanes-solver/lib/spread-tuning-lanes.ts
49798
+ function spreadTuningLanes(input, traces, pitch) {
49799
+ const dx = traces.reduce((s, t) => s + t.route.at(-1).x - t.route[0].x, 0);
49800
+ const dy = traces.reduce((s, t) => s + t.route.at(-1).y - t.route[0].y, 0);
49801
+ const angle = Math.round(Math.atan2(dy, dx) / (Math.PI / 4)) * Math.PI / 4, ux = Math.cos(angle), uy = Math.sin(angle);
49802
+ const uv = (p) => ({ u: p.x * ux + p.y * uy, v: -p.x * uy + p.y * ux });
49803
+ const xy = (u, v) => ({
49804
+ x: u * ux - v * uy,
49805
+ y: u * uy + v * ux
49806
+ });
49807
+ const result = [];
49808
+ for (const layer of new Set(traces.map((t) => t.route[0].layer))) {
49809
+ const group = traces.filter((t) => t.route[0].layer === layer).sort((a, b) => uv(a.route[0]).v - uv(b.route[0]).v);
49810
+ const center = group.reduce(
49811
+ (s, t) => s + (uv(t.route[0]).v + uv(t.route.at(-1)).v) / 2,
49812
+ 0
49813
+ ) / group.length;
49814
+ for (const [index, t] of group.entries()) {
49815
+ const a = uv(t.route[0]), b = uv(t.route.at(-1)), v = center + (index - (group.length - 1) / 2) * pitch;
49816
+ const da = Math.abs(v - a.v), db = Math.abs(v - b.v), space = b.u - a.u - da - db;
49817
+ if (space < 1) return null;
49818
+ const lead = space * 0.15;
49819
+ const points = simplify([
49820
+ xy(a.u, a.v),
49821
+ xy(a.u + lead, a.v),
49822
+ xy(a.u + lead + da, v),
49823
+ xy(b.u - lead - db, v),
49824
+ xy(b.u - lead, b.v),
49825
+ xy(b.u, b.v)
49826
+ ]);
49827
+ result.push({
49828
+ ...t,
49829
+ route: points.map((p) => ({
49830
+ ...p,
49831
+ route_type: "wire",
49832
+ layer,
49833
+ width: t.route[0].width
49834
+ }))
49835
+ });
49836
+ }
49837
+ }
49838
+ const copper = [...fixedCopper(input), ...result.flatMap(routeCopper)];
49839
+ for (const t of result) {
49840
+ const c = input.connections.find((c2) => c2.name === t.connection_name);
49841
+ if (!new VectorScene(
49842
+ input,
49843
+ c,
49844
+ t.route[0].width,
49845
+ copper
49846
+ ).pathVisible(t.route))
49847
+ return null;
49848
+ }
49849
+ return traces.map(
49850
+ (t) => result.find((r) => r.connection_name === t.connection_name)
49851
+ );
49852
+ }
49853
+
49854
+ // node_modules/@tscircuit/bus-lanes-solver/lib/length-tuning.ts
49855
+ function tuneLengths(input, traces, targets) {
49856
+ const fixed = fixedCopper(input);
49857
+ function* candidates(t, scene) {
49858
+ const connection = input.connections.find(
49859
+ (c) => c.name === t.connection_name
49860
+ );
49861
+ const width = t.route[0].width;
49862
+ const delta = targets.get(connection.name) - length(t.route) - fixedRouteLength(input, connection.name);
49863
+ if (delta < 1e-8) {
49864
+ yield t;
49865
+ return;
49866
+ }
49867
+ const clearance = input.minTraceToPadEdgeClearance ?? input.defaultObstacleMargin ?? 0.075;
49868
+ const returnSpacing = Math.max(width + clearance, 3 * width);
49869
+ const pitch = 2 * (returnSpacing + 2 * width);
49870
+ const segments = t.route.slice(1).map((p, i) => ({ i, span: distance12(t.route[i], p) })).sort((a, b) => b.span - a.span);
49871
+ for (const { i } of segments) {
49872
+ const a = t.route[i], b = t.route[i + 1], span = distance12(a, b);
49873
+ if (span < 0.01) continue;
49874
+ const ux = (b.x - a.x) / span, uy = (b.y - a.y) / span;
49875
+ const maximumTeeth = Math.floor(span * 0.9 / pitch);
49876
+ const preferredTeeth = Math.min(
49877
+ maximumTeeth,
49878
+ Math.max(2, Math.ceil(delta / (12 * width)))
49879
+ );
49880
+ const counts = Array.from({ length: maximumTeeth }, (_, i2) => i2 + 1).sort(
49881
+ (a2, b2) => Math.abs(a2 - preferredTeeth) - Math.abs(b2 - preferredTeeth) || b2 - a2
49882
+ );
49883
+ for (const teeth of counts) {
49884
+ for (const fraction of [0.9, 0.65, 0.4]) {
49885
+ const w = span * fraction / teeth;
49886
+ if (w < pitch) continue;
49887
+ const c = Math.min(
49888
+ delta / (2 * teeth),
49889
+ w / 10,
49890
+ (w / 2 - returnSpacing) / 2
49891
+ );
49892
+ const h = delta / (2 * teeth) + 2 * c * (2 - Math.SQRT2);
49893
+ for (const phase of [0.5, 0, 1])
49894
+ for (const side of [1, -1]) {
49895
+ const at = (x, y) => ({
49896
+ x: a.x + ux * x - uy * y * side,
49897
+ y: a.y + uy * x + ux * y * side
49898
+ });
49899
+ const bump = [at(0, 0)];
49900
+ for (let tooth = 0; tooth < teeth; tooth++) {
49901
+ const offset = span * (1 - fraction) * (0.05 + 0.9 * phase) + tooth * w, gap = w * 0.5;
49902
+ bump.push(
49903
+ ...[
49904
+ [offset, 0],
49905
+ [offset + c, c],
49906
+ [offset + c, h - c],
49907
+ [offset + 2 * c, h],
49908
+ [offset + gap - 2 * c, h],
49909
+ [offset + gap - c, h - c],
49910
+ [offset + gap - c, c],
49911
+ [offset + gap, 0]
49912
+ ].map(([x, y]) => at(x, y))
49913
+ );
49914
+ }
49915
+ bump.push(at(span, 0));
49916
+ if (!scene.pathVisible(bump)) continue;
49917
+ const next = simplify([
49918
+ ...t.route.slice(0, i),
49919
+ ...bump,
49920
+ ...t.route.slice(i + 2)
49921
+ ]);
49922
+ if (Math.abs(
49923
+ length(next) + fixedRouteLength(input, connection.name) - targets.get(connection.name)
49924
+ ) > 1e-6)
49925
+ continue;
49926
+ if (!tuningPathIsSelfClear(next, returnSpacing)) continue;
49927
+ yield {
49928
+ ...t,
49929
+ route: next.map((p) => ({
49930
+ ...p,
49931
+ route_type: "wire",
49932
+ layer: connection.pointsToConnect[0].layer,
49933
+ width
49934
+ }))
49935
+ };
49936
+ }
49937
+ }
49938
+ }
49939
+ }
49940
+ }
49941
+ const result = [...traces];
49942
+ const pending = new Set(traces.map((_, i) => i));
49943
+ let changed = true;
49944
+ while (pending.size && changed) {
49945
+ changed = false;
49946
+ for (const index of pending) {
49947
+ const connection = input.connections.find(
49948
+ (c) => c.name === traces[index].connection_name
49949
+ );
49950
+ const scene = new VectorScene(
49951
+ input,
49952
+ connection,
49953
+ traces[index].route[0].width,
49954
+ [...fixed, ...result.flatMap(routeCopper)]
49955
+ );
49956
+ const next = candidates(traces[index], scene).next().value;
49957
+ if (!next) continue;
49958
+ result[index] = next;
49959
+ pending.delete(index);
49960
+ changed = true;
49961
+ }
49962
+ }
49963
+ if (pending.size)
49964
+ throw Error(
49965
+ `Insufficient tuning clearance for ${[...pending].map((i) => traces[i].connection_name).join(", ")}`
49966
+ );
49967
+ return result;
49968
+ }
49969
+ function tuningPathIsSelfClear(path, required) {
49970
+ const cumulative = [0];
49971
+ for (let i = 1; i < path.length; i++)
49972
+ cumulative.push(cumulative[i - 1] + distance12(path[i - 1], path[i]));
49973
+ for (let i = 0; i < path.length - 1; i++)
49974
+ for (let j = i + 2; j < path.length - 1; j++) {
49975
+ if (cumulative[j] - cumulative[i + 1] <= required + 1e-8) continue;
49976
+ const a = path[i], b = path[i + 1], c = path[j], d = path[j + 1];
49977
+ if (Math.max(a.x, b.x) + required < Math.min(c.x, d.x) || Math.max(c.x, d.x) + required < Math.min(a.x, b.x) || Math.max(a.y, b.y) + required < Math.min(c.y, d.y) || Math.max(c.y, d.y) + required < Math.min(a.y, b.y))
49978
+ continue;
49979
+ if (segmentDistance([a, b], [c, d]) >= required - 1e-8) continue;
49980
+ let sx = 0, sy = 0;
49981
+ for (let k = i; k <= j; k++) {
49982
+ const dx = path[k + 1].x - path[k].x, dy = path[k + 1].y - path[k].y;
49983
+ if (Math.abs(dx) > 1e-8) {
49984
+ if (sx && sx !== Math.sign(dx)) return false;
49985
+ sx = Math.sign(dx);
49986
+ }
49987
+ if (Math.abs(dy) > 1e-8) {
49988
+ if (sy && sy !== Math.sign(dy)) return false;
49989
+ sy = Math.sign(dy);
49990
+ }
49991
+ }
49992
+ }
49993
+ return true;
49994
+ }
49995
+
49996
+ // node_modules/@tscircuit/bus-lanes-solver/lib/layer-colors.ts
49997
+ var layerColors = {
49998
+ top: "#dc2626",
49999
+ inner1: "#ca8a04",
50000
+ inner2: "#16a34a",
50001
+ inner3: "#0891b2",
50002
+ inner4: "#9333ea",
50003
+ inner5: "#ea580c",
50004
+ inner6: "#db2777",
50005
+ bottom: "#2563eb"
50006
+ };
50007
+ var layerColor = (layer) => layerColors[layer] ?? "#64748b";
50008
+
50009
+ // node_modules/@tscircuit/bus-lanes-solver/lib/bus-lanes-solver.ts
50010
+ var BusLanesSolver = class extends BaseSolver4 {
50011
+ input;
50012
+ options;
50013
+ phase = "validate";
50014
+ failureCode = null;
50015
+ traces = [];
50016
+ widths = /* @__PURE__ */ new Map();
50017
+ fixed = [];
50018
+ orders = [];
50019
+ attempt = 0;
50020
+ lane = 0;
50021
+ search;
50022
+ bestPartial = [];
50023
+ constructor(input, options = {}) {
50024
+ super();
50025
+ this.input = structuredClone(input);
50026
+ this.options = options;
50027
+ this.MAX_ITERATIONS = options.maxSearchIterations ?? 2e5;
50028
+ }
50029
+ getConstructorParams() {
50030
+ return [this.input, this.options];
50031
+ }
50032
+ getOutput() {
50033
+ if (!this.solved) throw Error(this.error ?? "Bus lanes are not solved");
50034
+ return {
50035
+ ...this.input,
50036
+ traces: [...this.input.traces ?? [], ...this.traces]
50037
+ };
50038
+ }
50039
+ fail(code, message) {
50040
+ this.failureCode = code;
50041
+ this.error = message;
50042
+ this.failed = true;
50043
+ this.phase = "failed";
50044
+ }
50045
+ tryFinalAcceptance() {
50046
+ if (!this.solved)
50047
+ this.fail(
50048
+ "search_budget_exhausted",
50049
+ "Vector visibility search budget exhausted"
50050
+ );
50051
+ }
50052
+ initialize() {
50053
+ const input = this.input;
50054
+ if (input.outline?.length) {
50055
+ this.fail("unsupported_outline", "Custom board outlines are unsupported");
50056
+ return;
50057
+ }
50058
+ if (input.differentialPairs?.some(
50059
+ (p) => p.traceGap !== void 0 || p.maxUncoupledLength !== void 0
50060
+ )) {
50061
+ this.fail(
50062
+ "unsupported_coupling",
50063
+ "Coupled differential geometry is not supported"
50064
+ );
50065
+ return;
50066
+ }
50067
+ const names = /* @__PURE__ */ new Set();
50068
+ for (const c of input.connections) {
50069
+ if (names.has(c.name)) throw Error(`Duplicate connection ${c.name}`);
50070
+ names.add(c.name);
50071
+ if (c.pointsToConnect.length !== 2) {
50072
+ this.fail(
50073
+ "invalid_terminals",
50074
+ `${c.name}: exactly two terminals required`
50075
+ );
50076
+ return;
50077
+ }
50078
+ const [a, b] = c.pointsToConnect;
50079
+ if (a.layers || b.layers || a.layer !== b.layer) {
50080
+ this.fail(
50081
+ "layer_change_required",
50082
+ `${c.name}: ${a.layer} \u2192 ${b.layer}; a common fixed layer is required; fanout handoff layers must agree`
50083
+ );
50084
+ return;
50085
+ }
50086
+ if (![a.x, a.y, b.x, b.y].every(Number.isFinite))
50087
+ throw Error("Nonfinite terminal");
50088
+ this.widths.set(
50089
+ c.name,
50090
+ c.nominalTraceWidth ?? c.width ?? input.minTraceWidth
50091
+ );
50092
+ }
50093
+ for (const b of input.buses ?? [])
50094
+ if (b.maxLengthSkew !== void 0 && (!Number.isFinite(b.maxLengthSkew) || b.maxLengthSkew < 0))
50095
+ throw Error("Invalid maximum length skew");
50096
+ for (const { names: members, tolerance } of lengthConstraints(input)) {
50097
+ if (!Number.isFinite(tolerance) || tolerance < 0)
50098
+ throw Error("Invalid maximum length skew");
50099
+ if (members.length < 1 || new Set(members).size !== members.length || members.some((n) => !names.has(n)))
50100
+ throw Error("Invalid length matching members");
50101
+ }
50102
+ const claimed = /* @__PURE__ */ new Set();
50103
+ for (const b of input.buses ?? [])
50104
+ for (const name of b.connectionNames) {
50105
+ const c = input.connections.find((c2) => c2.name === name);
50106
+ if (!c || claimed.has(name))
50107
+ throw Error(`Missing or duplicated bus member ${name}`);
50108
+ claimed.add(name);
50109
+ const layer = c.pointsToConnect[0].layer;
50110
+ if (b.allowedLayers && !b.allowedLayers.includes(layer))
50111
+ throw Error(`${b.busId}: forbidden layer ${layer}`);
50112
+ const width = b.traceWidth;
50113
+ if (width !== void 0) this.widths.set(name, width);
50114
+ }
50115
+ for (const width of this.widths.values())
50116
+ if (!Number.isFinite(width) || width <= 0 || width < input.minTraceWidth)
50117
+ throw Error("Invalid trace width");
50118
+ this.fixed = fixedCopper(input);
50119
+ for (const c of input.connections)
50120
+ for (const p of c.pointsToConnect)
50121
+ this.fixed.push({
50122
+ a: p,
50123
+ b: p,
50124
+ layer: p.layer,
50125
+ radius: this.widths.get(c.name) / 2,
50126
+ owners: [c.name]
50127
+ });
50128
+ this.orders = windingOrders(input.connections);
50129
+ if (!input.connections.length) {
50130
+ this.solved = true;
50131
+ this.phase = "solved";
50132
+ return;
50133
+ }
50134
+ this.phase = "route";
50135
+ this.startLane();
50136
+ }
50137
+ scene(c) {
50138
+ return new VectorScene(this.input, c, this.widths.get(c.name), [
50139
+ ...this.fixed,
50140
+ ...this.traces.flatMap(routeCopper)
50141
+ ]);
50142
+ }
50143
+ startLane() {
50144
+ if (this.lane === this.input.connections.length) {
50145
+ this.phase = "match";
50146
+ return;
50147
+ }
50148
+ const c = this.orders[this.attempt][this.lane], [a, b] = c.pointsToConnect;
50149
+ this.search = new VectorVisibilitySearch(this.scene(c), a, b);
50150
+ }
50151
+ retry() {
50152
+ if (this.traces.length > this.bestPartial.length)
50153
+ this.bestPartial = structuredClone(this.traces);
50154
+ this.attempt++;
50155
+ if (this.attempt >= this.orders.length) {
50156
+ this.traces = this.bestPartial;
50157
+ this.fail(
50158
+ "no_planar_route",
50159
+ "No collision-free routing found in the vector visibility graph"
50160
+ );
50161
+ return;
50162
+ }
50163
+ this.traces = [];
50164
+ this.lane = 0;
50165
+ this.startLane();
50166
+ }
50167
+ route() {
50168
+ const s = this.search;
50169
+ s.step();
50170
+ if (s.solved) {
50171
+ const c = this.orders[this.attempt][this.lane];
50172
+ this.traces.push({
50173
+ type: "pcb_trace",
50174
+ pcb_trace_id: `bus_lane_${c.name}`,
50175
+ connection_name: c.name,
50176
+ source_trace_id: c.source_trace_id ?? c.name,
50177
+ route: s.result.map((p) => ({
50178
+ route_type: "wire",
50179
+ x: p.x,
50180
+ y: p.y,
50181
+ layer: c.pointsToConnect[0].layer,
50182
+ width: this.widths.get(c.name)
50183
+ }))
50184
+ });
50185
+ this.lane++;
50186
+ this.startLane();
50187
+ } else if (s.failed || s.expanded >= (this.options.maxLaneIterations ?? 4e3))
50188
+ this.retry();
50189
+ }
50190
+ match() {
50191
+ const original = this.traces;
50192
+ const input = this.input;
50193
+ function* candidates() {
50194
+ yield original;
50195
+ const width = Math.max(...original.map((t) => t.route[0].width));
50196
+ for (const multiplier of [16, 24, 28, 32]) {
50197
+ const spread = spreadTuningLanes(input, original, width * multiplier);
50198
+ if (spread) yield spread;
50199
+ }
50200
+ }
50201
+ let error;
50202
+ for (const candidate of candidates()) {
50203
+ const targets = minimumLengthTargets(input, candidate);
50204
+ try {
50205
+ this.traces = tuneLengths(input, candidate, targets);
50206
+ this.phase = "validate_output";
50207
+ return;
50208
+ } catch (e) {
50209
+ error = e;
50210
+ }
50211
+ }
50212
+ this.fail("length_matching_failed", String(error));
50213
+ return;
50214
+ }
50215
+ validateOutput() {
50216
+ for (const c of this.input.connections) {
50217
+ const t = this.traces.find((t2) => t2.connection_name === c.name);
50218
+ if (!t) throw Error("Missing lane");
50219
+ const scene = this.scene(c);
50220
+ if (distance12(t.route[0], c.pointsToConnect[0]) > 1e-8 || distance12(t.route.at(-1), c.pointsToConnect[1]) > 1e-8)
50221
+ throw Error("Broken lane endpoints");
50222
+ for (let i = 1; i < t.route.length; i++) {
50223
+ const a = t.route[i - 1], b = t.route[i], dx = Math.abs(a.x - b.x), dy = Math.abs(a.y - b.y);
50224
+ if (a.route_type !== "wire" || b.route_type !== "wire" || a.layer !== b.layer)
50225
+ throw Error("Forbidden layer transition");
50226
+ if (Math.min(dx, dy) > 1e-8 && Math.abs(dx - dy) > 1e-8)
50227
+ throw Error("Non-octilinear segment");
50228
+ if (!scene.visible(a, b))
50229
+ throw Error("Final copper clearance violation");
50230
+ }
50231
+ }
50232
+ if ([
50233
+ ...busLengthReports(this.input, this.traces),
50234
+ ...pairLengthReports(this.input, this.traces)
50235
+ ].some((b) => b.toleranceMm !== null && !b.matched))
50236
+ throw Error("Final bus length skew violation");
50237
+ this.phase = "solved";
50238
+ this.solved = true;
50239
+ }
50240
+ _step() {
50241
+ try {
50242
+ if (this.phase === "validate") this.initialize();
50243
+ else if (this.phase === "route") this.route();
50244
+ else if (this.phase === "match") this.match();
50245
+ else if (this.phase === "validate_output") this.validateOutput();
50246
+ } catch (e) {
50247
+ this.fail("constraint_error", String(e));
50248
+ }
50249
+ this.progress = this.lane / Math.max(1, this.input.connections.length);
50250
+ this.stats = {
50251
+ busLengths: busLengthReports(this.input, this.traces),
50252
+ pairLengths: pairLengthReports(this.input, this.traces),
50253
+ phase: this.phase,
50254
+ algorithm: "octilinear_visibility",
50255
+ attempt: this.attempt,
50256
+ lane: this.lane,
50257
+ totalLanes: this.input.connections.length,
50258
+ vertices: this.search?.vertices.length ?? 0,
50259
+ expandedVertices: this.search?.expanded ?? 0,
50260
+ frontier: this.search?.open.length ?? 0,
50261
+ failureCode: this.failureCode,
50262
+ traceLengthsMm: this.traces.map((t) => ({
50263
+ name: t.connection_name,
50264
+ length: length(t.route)
50265
+ }))
50266
+ };
50267
+ }
50268
+ visualize() {
50269
+ const lines = [], points = [], rects = [], circles = [];
50270
+ for (const c of fixedCopper(this.input)) {
50271
+ if (c.rect) {
50272
+ rects.push({
50273
+ center: {
50274
+ x: (c.rect.minX + c.rect.maxX) / 2,
50275
+ y: (c.rect.minY + c.rect.maxY) / 2
50276
+ },
50277
+ width: c.rect.maxX - c.rect.minX,
50278
+ height: c.rect.maxY - c.rect.minY,
50279
+ layer: c.layer,
50280
+ fill: `${layerColor(c.layer)}30`,
50281
+ stroke: layerColor(c.layer)
50282
+ });
50283
+ continue;
50284
+ }
50285
+ if (distance12(c.a, c.b) < 1e-9)
50286
+ circles.push({
50287
+ center: c.a,
50288
+ radius: c.radius,
50289
+ layer: c.layer,
50290
+ fill: "transparent",
50291
+ stroke: layerColor(c.layer)
50292
+ });
50293
+ else
50294
+ lines.push({
50295
+ points: [
50296
+ { x: c.a.x, y: c.a.y },
50297
+ { x: c.b.x, y: c.b.y }
50298
+ ],
50299
+ strokeWidth: c.radius * 2,
50300
+ strokeColor: layerColor(c.layer),
50301
+ layer: c.layer,
50302
+ label: `Fixed fanout [${c.layer}]`
50303
+ });
50304
+ }
50305
+ for (const t of this.traces)
50306
+ lines.push({
50307
+ points: t.route.map(({ x, y }) => ({ x, y })),
50308
+ strokeWidth: t.route[0].width,
50309
+ strokeColor: layerColor(t.route[0].layer),
50310
+ layer: t.route[0].layer,
50311
+ label: t.connection_name
50312
+ });
50313
+ for (const c of this.input.connections)
50314
+ for (const [i, p] of c.pointsToConnect.entries())
50315
+ points.push({
50316
+ ...p,
50317
+ color: i ? "#d97706" : "#2563eb",
50318
+ label: `${c.name} ${i ? "target" : "source"} [${p.layer}]`
50319
+ });
50320
+ if (this.search && this.phase === "route") {
50321
+ const layer = this.orders[this.attempt][this.lane]?.pointsToConnect[0].layer;
50322
+ for (const edge of this.search.visibleEdges)
50323
+ lines.push({
50324
+ points: edge,
50325
+ strokeWidth: 0.02,
50326
+ strokeColor: "#67e8f980",
50327
+ layer
50328
+ });
50329
+ for (const n of this.search.open.values().slice(0, 80))
50330
+ points.push({ ...this.search.vertices[n.id], color: "#06b6d4", layer });
50331
+ lines.push({
50332
+ points: this.search.currentPath(),
50333
+ strokeColor: "#f43f5e",
50334
+ strokeWidth: 0.09,
50335
+ layer
50336
+ });
50337
+ }
50338
+ return {
50339
+ title: `Vector bus lanes \xB7 ${this.phase}`,
50340
+ lines,
50341
+ points,
50342
+ rects,
50343
+ circles
50344
+ };
50345
+ }
50346
+ };
50347
+
50348
+ // lib/utils/autorouting/BusLanesAutorouter.ts
50349
+ var BusLanesAutorouter = class {
50350
+ constructor(input) {
50351
+ this.input = input;
50352
+ this.solver = new BusLanesSolver(input);
50353
+ }
50354
+ input;
50355
+ isRouting = false;
50356
+ solver;
50357
+ timer;
50358
+ listeners = [];
50359
+ on(event, callback) {
50360
+ this.listeners.push({
50361
+ event,
50362
+ callback
50363
+ });
50364
+ }
50365
+ emit(event) {
50366
+ for (const listener of this.listeners)
50367
+ if (listener.event === event.type) listener.callback(event);
50368
+ }
50369
+ start() {
50370
+ if (this.isRouting) return;
50371
+ this.isRouting = true;
50372
+ const tick = () => {
50373
+ if (!this.isRouting) return;
50374
+ try {
50375
+ for (let i = 0; i < 200 && !this.solver.solved && !this.solver.failed; i++)
50376
+ this.solver.step();
50377
+ if (this.solver.failed) {
50378
+ this.isRouting = false;
50379
+ this.emit({
50380
+ type: "error",
50381
+ error: new Error(this.solver.error ?? "Bus lanes routing failed")
50382
+ });
50383
+ return;
50384
+ }
50385
+ if (this.solver.solved) {
50386
+ this.isRouting = false;
50387
+ this.emit({ type: "complete", traces: this.solver.traces });
50388
+ return;
50389
+ }
50390
+ this.emit({
50391
+ type: "progress",
50392
+ steps: this.solver.iterations,
50393
+ progress: this.solver.progress,
50394
+ phase: this.solver.phase,
50395
+ debugGraphics: this.solver.visualize()
50396
+ });
50397
+ this.timer = setTimeout(tick, 0);
50398
+ } catch (error) {
50399
+ this.isRouting = false;
50400
+ this.emit({
50401
+ type: "error",
50402
+ error: error instanceof Error ? error : new Error(String(error))
50403
+ });
50404
+ }
50405
+ };
50406
+ this.timer = setTimeout(tick, 0);
50407
+ }
50408
+ stop() {
50409
+ this.isRouting = false;
50410
+ if (this.timer) clearTimeout(this.timer);
50411
+ }
50412
+ solveSync() {
50413
+ this.solver.solve();
50414
+ if (this.solver.failed)
50415
+ throw new Error(this.solver.error ?? "Bus lanes routing failed");
50416
+ return this.solver.traces;
50417
+ }
50418
+ };
50419
+
49270
50420
  // lib/utils/autorouting/CapacityMeshAutorouter.ts
49271
50421
  import {
49272
50422
  AutoroutingPipelineSolver9_Networked as AutoroutingPipelineSolver9_Networked2
@@ -49293,7 +50443,7 @@ import { CreateFdmEnclosureSolver } from "@tscircuit/create-fdm-enclosure";
49293
50443
  // node_modules/@tscircuit/implicit-copper-pour-solver/lib/implicit-copper-pour-pipeline-solver.ts
49294
50444
  import {
49295
50445
  BasePipelineSolver,
49296
- BaseSolver as BaseSolver4,
50446
+ BaseSolver as BaseSolver5,
49297
50447
  definePipelineStep
49298
50448
  } from "@tscircuit/solver-utils";
49299
50449
 
@@ -49311,7 +50461,7 @@ import { applyToPoint as applyToPoint27, compose as compose9, scale as scale2, t
49311
50461
  // node_modules/@tscircuit/implicit-copper-pour-solver/lib/geometry.ts
49312
50462
  import {
49313
50463
  clamp,
49314
- distance as distance12,
50464
+ distance as distance13,
49315
50465
  doBoundsOverlap as doBoundsOverlap2,
49316
50466
  getBoundsFromPoints as getBoundsFromPoints3,
49317
50467
  getUnitVectorFromPointAToB as getUnitVectorFromPointAToB2,
@@ -49360,7 +50510,7 @@ var distanceToPolygon = (point6, polygon) => {
49360
50510
  var distanceToPrimitive = (primitive, px, py) => {
49361
50511
  const point6 = { x: px, y: py };
49362
50512
  if (primitive.kind === "circle") {
49363
- return Math.max(distance12(point6, primitive) - primitive.radius, 0);
50513
+ return Math.max(distance13(point6, primitive) - primitive.radius, 0);
49364
50514
  }
49365
50515
  if (primitive.kind === "segment") {
49366
50516
  return Math.max(
@@ -49411,7 +50561,7 @@ var getClosestPointOnPrimitive = (primitive, point6) => {
49411
50561
  const start = primitive.points[index];
49412
50562
  const end = primitive.points[(index + 1) % primitive.points.length];
49413
50563
  const candidate = pointToSegmentClosestPoint(point6, start, end);
49414
- const candidateDistance = distance12(point6, candidate);
50564
+ const candidateDistance = distance13(point6, candidate);
49415
50565
  if (candidateDistance < bestDistance) {
49416
50566
  bestDistance = candidateDistance;
49417
50567
  closestPoint = candidate;
@@ -50467,7 +51617,7 @@ var prepareCircuitJson = (input) => {
50467
51617
 
50468
51618
  // node_modules/@tscircuit/implicit-copper-pour-solver/lib/simplify-polygon-edges.ts
50469
51619
  import {
50470
- distance as distance13,
51620
+ distance as distance14,
50471
51621
  doSegmentsIntersect,
50472
51622
  onSegment,
50473
51623
  pointToSegmentDistance as pointToSegmentDistance2
@@ -50486,13 +51636,13 @@ var simplifyRdpPath = (points, tolerance) => {
50486
51636
  let furthestIndex = -1;
50487
51637
  let furthestDistance = tolerance;
50488
51638
  for (let index = firstIndex + 1; index < lastIndex; index++) {
50489
- const segmentDistance = pointToSegmentDistance2(
51639
+ const segmentDistance2 = pointToSegmentDistance2(
50490
51640
  points[index],
50491
51641
  first,
50492
51642
  last
50493
51643
  );
50494
- if (segmentDistance > furthestDistance) {
50495
- furthestDistance = segmentDistance;
51644
+ if (segmentDistance2 > furthestDistance) {
51645
+ furthestDistance = segmentDistance2;
50496
51646
  furthestIndex = index;
50497
51647
  }
50498
51648
  }
@@ -50530,8 +51680,8 @@ var simplifyOpenPath = (points, tolerance) => {
50530
51680
  const point6 = points[index];
50531
51681
  const next = points[index + 1];
50532
51682
  const shortestLeg = Math.min(
50533
- distance13(point6, previous),
50534
- distance13(next, point6)
51683
+ distance14(point6, previous),
51684
+ distance14(next, point6)
50535
51685
  );
50536
51686
  if (repeatsTurnDirection || shortestLeg > tolerance) {
50537
51687
  anchorIndices.push(index);
@@ -50580,8 +51730,8 @@ var normalizePolygon = (polygon) => {
50580
51730
  };
50581
51731
  var isPointStrictlyInsideSegment = (point6, start, end) => {
50582
51732
  if (pointsEqual(point6, start) || pointsEqual(point6, end)) return false;
50583
- const cross3 = crossProduct(start, end, point6);
50584
- if (Math.abs(cross3) > 1e-9) return false;
51733
+ const cross4 = crossProduct(start, end, point6);
51734
+ if (Math.abs(cross4) > 1e-9) return false;
50585
51735
  return onSegment(start, point6, end);
50586
51736
  };
50587
51737
  var splitEdgesAtVertices = (polygon, allVertices) => {
@@ -50933,7 +52083,7 @@ var mergeSolverGraphics = (source, overlay) => {
50933
52083
  };
50934
52084
 
50935
52085
  // node_modules/@tscircuit/implicit-copper-pour-solver/lib/implicit-copper-pour-pipeline-solver.ts
50936
- var PrepareCircuitJsonSolver = class extends BaseSolver4 {
52086
+ var PrepareCircuitJsonSolver = class extends BaseSolver5 {
50937
52087
  constructor(input) {
50938
52088
  super();
50939
52089
  this.input = input;
@@ -50949,7 +52099,7 @@ var PrepareCircuitJsonSolver = class extends BaseSolver4 {
50949
52099
  return this.output;
50950
52100
  }
50951
52101
  };
50952
- var AssignGridCellsSolver = class extends BaseSolver4 {
52102
+ var AssignGridCellsSolver = class extends BaseSolver5 {
50953
52103
  constructor(input) {
50954
52104
  super();
50955
52105
  this.input = input;
@@ -50972,7 +52122,7 @@ var AssignGridCellsSolver = class extends BaseSolver4 {
50972
52122
  return this.output;
50973
52123
  }
50974
52124
  };
50975
- var TracePowerPolygonsSolver = class extends BaseSolver4 {
52125
+ var TracePowerPolygonsSolver = class extends BaseSolver5 {
50976
52126
  constructor(input) {
50977
52127
  super();
50978
52128
  this.input = input;
@@ -51008,7 +52158,7 @@ var TracePowerPolygonsSolver = class extends BaseSolver4 {
51008
52158
  };
51009
52159
  }
51010
52160
  };
51011
- var SimplifyPolygonEdgesSolver = class extends BaseSolver4 {
52161
+ var SimplifyPolygonEdgesSolver = class extends BaseSolver5 {
51012
52162
  constructor(input) {
51013
52163
  super();
51014
52164
  this.input = input;
@@ -51146,13 +52296,13 @@ import { LayoutPipelineSolver } from "@tscircuit/matchpack";
51146
52296
  import { SchematicTracePipelineSolver } from "@tscircuit/schematic-trace-solver";
51147
52297
 
51148
52298
  // node_modules/@tscircuit/via-stitch-solver/lib/solvers/ViaStitchSolver.ts
51149
- import { BaseSolver as BaseSolver5 } from "@tscircuit/solver-utils";
52299
+ import { BaseSolver as BaseSolver6 } from "@tscircuit/solver-utils";
51150
52300
 
51151
52301
  // node_modules/@tscircuit/via-stitch-solver/lib/geometry/brep-point-containment.ts
51152
52302
  var POINT_EPSILON = 1e-8;
51153
52303
  var isPointOnSegment = (point6, start, end) => {
51154
- const cross3 = (point6.y - start.y) * (end.x - start.x) - (point6.x - start.x) * (end.y - start.y);
51155
- if (Math.abs(cross3) > POINT_EPSILON) return false;
52304
+ const cross4 = (point6.y - start.y) * (end.x - start.x) - (point6.x - start.x) * (end.y - start.y);
52305
+ if (Math.abs(cross4) > POINT_EPSILON) return false;
51156
52306
  const dot = (point6.x - start.x) * (end.x - start.x) + (point6.y - start.y) * (end.y - start.y);
51157
52307
  if (dot < -POINT_EPSILON) return false;
51158
52308
  const squaredLength = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;
@@ -51473,7 +52623,7 @@ var getGridCoordinates = ({
51473
52623
  }
51474
52624
  return coordinates;
51475
52625
  };
51476
- var ViaStitchSolver = class extends BaseSolver5 {
52626
+ var ViaStitchSolver = class extends BaseSolver6 {
51477
52627
  constructor(input) {
51478
52628
  super();
51479
52629
  this.input = input;
@@ -51620,6 +52770,7 @@ var ViaStitchSolver = class extends BaseSolver5 {
51620
52770
  // lib/solvers.ts
51621
52771
  import { PackSolver2 } from "calculate-packing";
51622
52772
  var SOLVERS = {
52773
+ BusLanesSolver,
51623
52774
  PackSolver2,
51624
52775
  LayoutPipelineSolver,
51625
52776
  AutoroutingPipelineSolver,
@@ -52082,6 +53233,22 @@ var localAutorouterStrategies = /* @__PURE__ */ new Map([
52082
53233
  createFanoutAutorouterStrategy("single_layer_fanout")
52083
53234
  ],
52084
53235
  ["fanout", createFanoutAutorouterStrategy("fanout")],
53236
+ [
53237
+ "bus_lanes",
53238
+ {
53239
+ name: "bus_lanes",
53240
+ cacheable: false,
53241
+ getSolverName: () => "BusLanesSolver",
53242
+ create: ({ simpleRouteJson, onSolverStarted }) => {
53243
+ onSolverStarted?.({
53244
+ solverName: "BusLanesSolver",
53245
+ solverParams: simpleRouteJson,
53246
+ solverConstructorArgs: [simpleRouteJson]
53247
+ });
53248
+ return new BusLanesAutorouter(simpleRouteJson);
53249
+ }
53250
+ }
53251
+ ],
52085
53252
  ["simplify", simplificationLocalAutorouterStrategy]
52086
53253
  ]);
52087
53254
  var getLocalAutorouterStrategy = (preset) => localAutorouterStrategies.get(preset ?? "") ?? defaultLocalAutorouterStrategy;
@@ -54640,7 +55807,7 @@ function Group_doInitialPcbComponentAnchorAlignment(group) {
54640
55807
  // lib/components/primitive-components/Group/Group_doInitialPcbLayoutFlex.ts
54641
55808
  import { getMinimumFlexContainer } from "@tscircuit/circuit-json-util";
54642
55809
  import { RootFlexBox } from "@tscircuit/miniflex";
54643
- import { length } from "circuit-json";
55810
+ import { length as length2 } from "circuit-json";
54644
55811
  var Group_doInitialPcbLayoutFlex = (group) => {
54645
55812
  const { db } = group.root;
54646
55813
  const { _parsedProps: props } = group;
@@ -54692,8 +55859,8 @@ var Group_doInitialPcbLayoutFlex = (group) => {
54692
55859
  rowGap = rawGap;
54693
55860
  columnGap = rawGap;
54694
55861
  } else if (typeof rawGap === "string") {
54695
- rowGap = length.parse(rawGap);
54696
- columnGap = length.parse(rawGap);
55862
+ rowGap = length2.parse(rawGap);
55863
+ columnGap = length2.parse(rawGap);
54697
55864
  }
54698
55865
  let minFlexContainer;
54699
55866
  let width = props.width ?? props.pcbWidth ?? void 0;
@@ -54773,7 +55940,7 @@ import {
54773
55940
  repositionPcbComponentTo as repositionPcbComponentTo2,
54774
55941
  repositionPcbGroupTo as repositionPcbGroupTo2
54775
55942
  } from "@tscircuit/circuit-json-util";
54776
- import { length as length2 } from "circuit-json";
55943
+ import { length as length3 } from "circuit-json";
54777
55944
  import { CssGrid } from "minicssgrid";
54778
55945
  var MIN_GAP = 1;
54779
55946
  function Group_doInitialPcbLayoutGrid(group) {
@@ -54835,7 +56002,7 @@ function parseGridConfiguration(props) {
54835
56002
  const templateRows = props.pcbGridTemplateRows;
54836
56003
  const parseGap = (gapValue) => {
54837
56004
  if (gapValue === void 0) return MIN_GAP;
54838
- return typeof gapValue === "number" ? gapValue : length2.parse(gapValue);
56005
+ return typeof gapValue === "number" ? gapValue : length3.parse(gapValue);
54839
56006
  };
54840
56007
  const gridGapOption = props.pcbGridGap ?? props.gridGap ?? props.pcbLayout?.gridGap;
54841
56008
  const rowGapOption = props.pcbGridRowGap ?? props.gridRowGap ?? props.pcbLayout?.gridRowGap;
@@ -54986,7 +56153,7 @@ import {
54986
56153
  convertPackOutputToPackInput,
54987
56154
  getGraphicsFromPackOutput
54988
56155
  } from "calculate-packing";
54989
- import { length as length3 } from "circuit-json";
56156
+ import { length as length4 } from "circuit-json";
54990
56157
  import Debug6 from "debug";
54991
56158
 
54992
56159
  // lib/utils/packing/solvePackSolverWithTimeout.ts
@@ -55495,16 +56662,16 @@ var Group_doInitialPcbLayoutPack = (group) => {
55495
56662
  pcbPackGap
55496
56663
  } = props;
55497
56664
  const gap = pcbPackGap ?? pcbGap ?? gapProp;
55498
- const gapMm = length3.parse(gap ?? DEFAULT_MIN_GAP);
56665
+ const gapMm = length4.parse(gap ?? DEFAULT_MIN_GAP);
55499
56666
  const chipMarginsMap = {};
55500
56667
  const staticPcbComponentIds = /* @__PURE__ */ new Set();
55501
56668
  const collectMargins = (comp) => {
55502
56669
  if (comp?.pcb_component_id && comp?._parsedProps) {
55503
56670
  const props2 = comp._parsedProps;
55504
- const left = length3.parse(props2.pcbMarginLeft ?? props2.pcbMarginX ?? 0);
55505
- const right = length3.parse(props2.pcbMarginRight ?? props2.pcbMarginX ?? 0);
55506
- const top = length3.parse(props2.pcbMarginTop ?? props2.pcbMarginY ?? 0);
55507
- const bottom = length3.parse(
56671
+ const left = length4.parse(props2.pcbMarginLeft ?? props2.pcbMarginX ?? 0);
56672
+ const right = length4.parse(props2.pcbMarginRight ?? props2.pcbMarginX ?? 0);
56673
+ const top = length4.parse(props2.pcbMarginTop ?? props2.pcbMarginY ?? 0);
56674
+ const bottom = length4.parse(
55508
56675
  props2.pcbMarginBottom ?? props2.pcbMarginY ?? 0
55509
56676
  );
55510
56677
  if (left || right || top || bottom) {
@@ -55553,8 +56720,8 @@ var Group_doInitialPcbLayoutPack = (group) => {
55553
56720
  const filteredCircuitJson = db.toArray();
55554
56721
  let bounds;
55555
56722
  if (props.width !== void 0 && props.height !== void 0) {
55556
- const widthMm = length3.parse(props.width);
55557
- const heightMm = length3.parse(props.height);
56723
+ const widthMm = length4.parse(props.width);
56724
+ const heightMm = length4.parse(props.height);
55558
56725
  bounds = {
55559
56726
  minX: -widthMm / 2,
55560
56727
  maxX: widthMm / 2,
@@ -55859,7 +57026,7 @@ import {
55859
57026
  repositionSchematicGroupTo
55860
57027
  } from "@tscircuit/circuit-json-util";
55861
57028
  import { RootFlexBox as RootFlexBox2 } from "@tscircuit/miniflex";
55862
- import { length as length4 } from "circuit-json";
57029
+ import { length as length5 } from "circuit-json";
55863
57030
  var getSizeOfTreeNodeChild = (db, child) => {
55864
57031
  const { sourceComponent, sourceGroup } = child;
55865
57032
  if (child.nodeType === "component") {
@@ -55952,8 +57119,8 @@ var Group_doInitialSchematicLayoutFlex = (group) => {
55952
57119
  rowGap = rawGap;
55953
57120
  columnGap = rawGap;
55954
57121
  } else if (typeof rawGap === "string") {
55955
- rowGap = length4.parse(rawGap);
55956
- columnGap = length4.parse(rawGap);
57122
+ rowGap = length5.parse(rawGap);
57123
+ columnGap = length5.parse(rawGap);
55957
57124
  }
55958
57125
  let minFlexContainer;
55959
57126
  let width = props.width ?? props.schWidth ?? void 0;
@@ -56047,7 +57214,7 @@ var Group_doInitialSchematicLayoutFlex = (group) => {
56047
57214
  };
56048
57215
 
56049
57216
  // lib/components/primitive-components/Group/Group_doInitialSchematicLayoutGrid.ts
56050
- import { length as length5 } from "circuit-json";
57217
+ import { length as length6 } from "circuit-json";
56051
57218
 
56052
57219
  // lib/components/primitive-components/Group/utils/updateSchematicPrimitivesForLayoutShift.ts
56053
57220
  function updateSchematicPrimitivesForLayoutShift({
@@ -56151,7 +57318,7 @@ function Group_doInitialSchematicLayoutGrid(group) {
56151
57318
  let gridGapY;
56152
57319
  const parseGap = (val) => {
56153
57320
  if (val === void 0) return void 0;
56154
- return typeof val === "number" ? val : length5.parse(val);
57321
+ return typeof val === "number" ? val : length6.parse(val);
56155
57322
  };
56156
57323
  if (gridRowGapOption !== void 0 || gridColumnGapOption !== void 0) {
56157
57324
  const fallbackX = typeof gridGapOption === "object" && gridGapOption !== null ? gridGapOption.x : gridGapOption;
@@ -56162,14 +57329,14 @@ function Group_doInitialSchematicLayoutGrid(group) {
56162
57329
  gridGapX = gridGapOption;
56163
57330
  gridGapY = gridGapOption;
56164
57331
  } else if (typeof gridGapOption === "string") {
56165
- const parsed = length5.parse(gridGapOption);
57332
+ const parsed = length6.parse(gridGapOption);
56166
57333
  gridGapX = parsed;
56167
57334
  gridGapY = parsed;
56168
57335
  } else if (typeof gridGapOption === "object" && gridGapOption !== null) {
56169
57336
  const xRaw = gridGapOption.x;
56170
57337
  const yRaw = gridGapOption.y;
56171
- gridGapX = typeof xRaw === "number" ? xRaw : length5.parse(xRaw ?? "0mm");
56172
- gridGapY = typeof yRaw === "number" ? yRaw : length5.parse(yRaw ?? "0mm");
57338
+ gridGapX = typeof xRaw === "number" ? xRaw : length6.parse(xRaw ?? "0mm");
57339
+ gridGapY = typeof yRaw === "number" ? yRaw : length6.parse(yRaw ?? "0mm");
56173
57340
  } else {
56174
57341
  gridGapX = 1;
56175
57342
  gridGapY = 1;
@@ -58402,19 +59569,19 @@ import Debug12 from "debug";
58402
59569
  import { isValidElement as isValidElement2 } from "react";
58403
59570
 
58404
59571
  // lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/segment-intersection.ts
58405
- var cross2 = (ax, ay, bx, by) => {
59572
+ var cross3 = (ax, ay, bx, by) => {
58406
59573
  return ax * by - ay * bx;
58407
59574
  };
58408
59575
  function segmentIntersection(p1, p2, q1, q2, tol) {
58409
59576
  const r = { x: p2.x - p1.x, y: p2.y - p1.y };
58410
59577
  const s = { x: q2.x - q1.x, y: q2.y - q1.y };
58411
- const rxs = cross2(r.x, r.y, s.x, s.y);
59578
+ const rxs = cross3(r.x, r.y, s.x, s.y);
58412
59579
  const q_p = { x: q1.x - p1.x, y: q1.y - p1.y };
58413
- const q_pxr = cross2(q_p.x, q_p.y, r.x, r.y);
59580
+ const q_pxr = cross3(q_p.x, q_p.y, r.x, r.y);
58414
59581
  if (Math.abs(rxs) < tol && Math.abs(q_pxr) < tol) return null;
58415
59582
  if (Math.abs(rxs) < tol && Math.abs(q_pxr) >= tol) return null;
58416
- const t = cross2(q_p.x, q_p.y, s.x, s.y) / rxs;
58417
- const u = cross2(q_p.x, q_p.y, r.x, r.y) / rxs;
59583
+ const t = cross3(q_p.x, q_p.y, s.x, s.y) / rxs;
59584
+ const u = cross3(q_p.x, q_p.y, r.x, r.y) / rxs;
58418
59585
  if (t < -tol || t > 1 + tol || u < -tol || u > 1 + tol) return null;
58419
59586
  return { x: p1.x + t * r.x, y: p1.y + t * r.y };
58420
59587
  }
@@ -58426,14 +59593,14 @@ function isHorizontalEdge(edge) {
58426
59593
  const dy = Math.abs(edge.to.y - edge.from.y);
58427
59594
  return dx >= dy;
58428
59595
  }
58429
- function length6(a, b) {
59596
+ function length7(a, b) {
58430
59597
  return Math.hypot(b.x - a.x, b.y - a.y);
58431
59598
  }
58432
59599
  function pointAt(a, b, t) {
58433
59600
  return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
58434
59601
  }
58435
59602
  function paramAlong(a, b, p) {
58436
- const L = length6(a, b);
59603
+ const L = length7(a, b);
58437
59604
  if (L < TOL) return 0;
58438
59605
  const t = ((p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y)) / ((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
58439
59606
  return Math.max(0, Math.min(1, t)) * L;
@@ -58456,7 +59623,7 @@ function mergeIntervals(intervals, tol = TOL) {
58456
59623
  return merged;
58457
59624
  }
58458
59625
  function splitEdgeByCrossings(edge, crossingDistances, crossLen) {
58459
- const L = length6(edge.from, edge.to);
59626
+ const L = length7(edge.from, edge.to);
58460
59627
  if (L < TOL || crossingDistances.length === 0) return [edge];
58461
59628
  const half = crossLen / 2;
58462
59629
  const rawIntervals = crossingDistances.map((d) => ({
@@ -58508,8 +59675,8 @@ function computeCrossings(traces, opts = {}) {
58508
59675
  }
58509
59676
  const P = segmentIntersection(eA.from, eA.to, eB.from, eB.to, tol);
58510
59677
  if (!P) continue;
58511
- const LA = length6(eA.from, eA.to);
58512
- const LB = length6(eB.from, eB.to);
59678
+ const LA = length7(eA.from, eA.to);
59679
+ const LB = length7(eB.from, eB.to);
58513
59680
  if (LA < tol || LB < tol) continue;
58514
59681
  const dA = paramAlong(eA.from, eA.to, P);
58515
59682
  const dB = paramAlong(eB.from, eB.to, P);
@@ -58607,8 +59774,8 @@ function isParallel(e1, e2, tol = TOL2) {
58607
59774
  const L1 = Math.hypot(v1.x, v1.y);
58608
59775
  const L2 = Math.hypot(v2.x, v2.y);
58609
59776
  if (L1 < tol || L2 < tol) return true;
58610
- const cross3 = v1.x * v2.y - v1.y * v2.x;
58611
- return Math.abs(cross3) <= tol * L1 * L2;
59777
+ const cross4 = v1.x * v2.y - v1.y * v2.x;
59778
+ return Math.abs(cross4) <= tol * L1 * L2;
58612
59779
  }
58613
59780
  function incidentEdgesAtPoint(trace, p, tol = TOL2) {
58614
59781
  return trace.edges.filter(
@@ -58758,7 +59925,7 @@ function isCollinear(a, b, tol = TOL3) {
58758
59925
  function splitEdgeAroundIntervals(edge, intervals) {
58759
59926
  const merged = mergeIntervals(intervals);
58760
59927
  if (merged.length === 0) return [edge];
58761
- const edgeLength = length6(edge.from, edge.to);
59928
+ const edgeLength = length7(edge.from, edge.to);
58762
59929
  if (edgeLength <= TOL3) return [edge];
58763
59930
  const result = [];
58764
59931
  let cursor = 0;
@@ -58792,7 +59959,7 @@ function removeOverlappingSameNetCrossingSegments(traces) {
58792
59959
  const crossingTrace = traces[crossingTraceIndex];
58793
59960
  if (!crossingTrace.connectivity_key) continue;
58794
59961
  for (const crossingEdge of crossingTrace.edges) {
58795
- if (!crossingEdge.is_crossing || length6(crossingEdge.from, crossingEdge.to) <= TOL3)
59962
+ if (!crossingEdge.is_crossing || length7(crossingEdge.from, crossingEdge.to) <= TOL3)
58796
59963
  continue;
58797
59964
  for (let traceIndex = 0; traceIndex < traces.length; traceIndex++) {
58798
59965
  const candidateTrace = traces[traceIndex];
@@ -58801,7 +59968,7 @@ function removeOverlappingSameNetCrossingSegments(traces) {
58801
59968
  }
58802
59969
  for (let edgeIndex = 0; edgeIndex < candidateTrace.edges.length; edgeIndex++) {
58803
59970
  const candidateEdge = candidateTrace.edges[edgeIndex];
58804
- const candidateLength = length6(candidateEdge.from, candidateEdge.to);
59971
+ const candidateLength = length7(candidateEdge.from, candidateEdge.to);
58805
59972
  if (candidateEdge.is_crossing || candidateLength <= TOL3) continue;
58806
59973
  if (!isCollinear(candidateEdge, crossingEdge)) continue;
58807
59974
  const start = Math.max(
@@ -62116,7 +63283,7 @@ function Group_getRoutingPhasePlans(group) {
62116
63283
  var package_default = {
62117
63284
  name: "@tscircuit/core",
62118
63285
  type: "module",
62119
- version: "0.0.1914",
63286
+ version: "0.0.1916",
62120
63287
  types: "dist/index.d.ts",
62121
63288
  main: "dist/index.js",
62122
63289
  module: "dist/index.js",
@@ -62150,6 +63317,7 @@ var package_default = {
62150
63317
  "@tsci/tscircuit.ti": "github:tscircuit/ti#57e314be4b2b06bc546d4def7453e619604d1157",
62151
63318
  "@tscircuit/alphabet": "0.0.25",
62152
63319
  "@tscircuit/bga-fanout-solver": "github:tscircuit/bga-fanout-solver#247c835cb8d69b65e53891dcf869731079415b39",
63320
+ "@tscircuit/bus-lanes-solver": "github:tscircuit/bus-lanes-solver#0bc8d071241b18a3e7465a878881abe4998f6384",
62153
63321
  "@tscircuit/capacity-autorouter": "^0.0.900",
62154
63322
  "@tscircuit/checks": "^0.0.192",
62155
63323
  "@tscircuit/circuit-json-util": "^0.0.113",
@@ -62848,7 +64016,7 @@ function getAccumulatedPcbTracesWithStageOutputReplacements({
62848
64016
  }
62849
64017
 
62850
64018
  // lib/components/primitive-components/Group/get-source-trace-id-for-routed-trace.ts
62851
- import { distance as distance14, pointToSegmentDistance as pointToSegmentDistance3 } from "@tscircuit/math-utils";
64019
+ import { distance as distance15, pointToSegmentDistance as pointToSegmentDistance3 } from "@tscircuit/math-utils";
62852
64020
  import { ConnectivityMap as ConnectivityMap5 } from "circuit-json-to-connectivity-map";
62853
64021
  var POINT_EPSILON2 = 1e-6;
62854
64022
  function isPointOnWireSegment({
@@ -62870,7 +64038,7 @@ function isPointInSmtPad({
62870
64038
  return Math.abs(point6.x - pad.x) <= pad.width / 2 + traceWidth / 2 && Math.abs(point6.y - pad.y) <= pad.height / 2 + traceWidth / 2;
62871
64039
  }
62872
64040
  if (pad.shape === "circle") {
62873
- return distance14(point6, pad) <= pad.radius + traceWidth / 2;
64041
+ return distance15(point6, pad) <= pad.radius + traceWidth / 2;
62874
64042
  }
62875
64043
  return false;
62876
64044
  }
@@ -62879,7 +64047,7 @@ function isPointInPlatedHole({
62879
64047
  hole,
62880
64048
  traceWidth = 0
62881
64049
  }) {
62882
- return distance14(point6, hole) <= (hole.outer_diameter ?? hole.hole_diameter ?? 0) / 2 + traceWidth / 2;
64050
+ return distance15(point6, hole) <= (hole.outer_diameter ?? hole.hole_diameter ?? 0) / 2 + traceWidth / 2;
62883
64051
  }
62884
64052
  function getEndpointSourcePortIdsFromGeometry(db, trace) {
62885
64053
  const sourcePortIds = /* @__PURE__ */ new Set();
@@ -62892,7 +64060,7 @@ function getEndpointSourcePortIdsFromGeometry(db, trace) {
62892
64060
  if (!pcbPort.source_port_id) continue;
62893
64061
  if (endpoint.layer && pcbPort.layers && !pcbPort.layers.includes(endpoint.layer))
62894
64062
  continue;
62895
- if (distance14(endpoint, pcbPort) <= 0.01) {
64063
+ if (distance15(endpoint, pcbPort) <= 0.01) {
62896
64064
  sourcePortIds.add(pcbPort.source_port_id);
62897
64065
  }
62898
64066
  }
@@ -63576,8 +64744,8 @@ var Group5 = class extends NormalComponent3 {
63576
64744
  const groupProps2 = props;
63577
64745
  const hasOutline = groupProps2.outline && groupProps2.outline.length > 0;
63578
64746
  const numericOutline = hasOutline ? groupProps2.outline.map((point6) => ({
63579
- x: distance15.parse(point6.x),
63580
- y: distance15.parse(point6.y)
64747
+ x: distance16.parse(point6.x),
64748
+ y: distance16.parse(point6.y)
63581
64749
  })) : void 0;
63582
64750
  const ctx = this.props;
63583
64751
  const anchorPosition = this._getGlobalPcbPositionBeforeLayout();
@@ -63615,8 +64783,8 @@ var Group5 = class extends NormalComponent3 {
63615
64783
  const hasExplicitPositioning = this._parsedProps.pcbX !== void 0 || this._parsedProps.pcbY !== void 0;
63616
64784
  if (hasOutline) {
63617
64785
  const numericOutline = props.outline.map((point6) => ({
63618
- x: distance15.parse(point6.x),
63619
- y: distance15.parse(point6.y)
64786
+ x: distance16.parse(point6.x),
64787
+ y: distance16.parse(point6.y)
63620
64788
  }));
63621
64789
  const outlineBounds = getBoundsFromPoints9(numericOutline);
63622
64790
  if (!outlineBounds) return;
@@ -64242,10 +65410,12 @@ var Group5 = class extends NormalComponent3 {
64242
65410
  })
64243
65411
  };
64244
65412
  }
64245
- simpleRouteJson = withFixedFanoutTraces(
64246
- simpleRouteJson,
64247
- fixedFanoutTraceIds
64248
- );
65413
+ if (phaseAutorouterConfig.preset !== "bus_lanes") {
65414
+ simpleRouteJson = withFixedFanoutTraces(
65415
+ simpleRouteJson,
65416
+ fixedFanoutTraceIds
65417
+ );
65418
+ }
64249
65419
  simpleRouteJson = Group_applyDrcTolerancesToSimpleRouteJson(
64250
65420
  simpleRouteJson,
64251
65421
  routingPhasePlan.drcTolerances
@@ -65430,8 +66600,8 @@ var Led_addPolarityFabricationSymbol = (led) => {
65430
66600
  const a = db.pcb_port.getWhere({ source_port_id: anode.source_port_id });
65431
66601
  const k = db.pcb_port.getWhere({ source_port_id: cathode.source_port_id });
65432
66602
  if (!a || !k) return;
65433
- const distance22 = Math.hypot(k.x - a.x, k.y - a.y);
65434
- if (distance22 < 1e-6) return;
66603
+ const distance23 = Math.hypot(k.x - a.x, k.y - a.y);
66604
+ if (distance23 < 1e-6) return;
65435
66605
  const angle = Math.atan2(k.y - a.y, k.x - a.x);
65436
66606
  const frame = compose14(
65437
66607
  translate14((a.x + k.x) / 2, (a.y + k.y) / 2),
@@ -65445,10 +66615,10 @@ var Led_addPolarityFabricationSymbol = (led) => {
65445
66615
  };
65446
66616
  const notes = [];
65447
66617
  generatedNotes.set(led, notes);
65448
- const halfLength = Math.min(distance22 * 0.2, 0.4);
66618
+ const halfLength = Math.min(distance23 * 0.2, 0.4);
65449
66619
  const halfHeight = halfLength * 0.75;
65450
66620
  const routes = [
65451
- [point6(-distance22 / 2, 0), point6(-halfLength, 0)],
66621
+ [point6(-distance23 / 2, 0), point6(-halfLength, 0)],
65452
66622
  [
65453
66623
  point6(-halfLength, -halfHeight),
65454
66624
  point6(halfLength, 0),
@@ -65456,7 +66626,7 @@ var Led_addPolarityFabricationSymbol = (led) => {
65456
66626
  point6(-halfLength, -halfHeight)
65457
66627
  ],
65458
66628
  [point6(halfLength, -halfHeight), point6(halfLength, halfHeight)],
65459
- [point6(halfLength, 0), point6(distance22 / 2, 0)]
66629
+ [point6(halfLength, 0), point6(distance23 / 2, 0)]
65460
66630
  ];
65461
66631
  for (const route of routes) {
65462
66632
  notes.push(
@@ -67180,8 +68350,8 @@ import {
67180
68350
  var EPSILON24 = 1e-9;
67181
68351
  var isWireRoutePoint = (routePoint) => routePoint.route_type === "wire";
67182
68352
  var isPointOnSegment2 = (p, a, b) => {
67183
- const cross3 = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
67184
- if (Math.abs(cross3) > EPSILON24) return false;
68353
+ const cross4 = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
68354
+ if (Math.abs(cross4) > EPSILON24) return false;
67185
68355
  const dot = (p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y);
67186
68356
  if (dot < -EPSILON24) return false;
67187
68357
  const squaredLength = (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
@@ -67242,8 +68412,8 @@ var isTraceConnectedToSourceNet = (trace, sourceNetId, sourceTraceById) => {
67242
68412
  var isSegmentFullyInsideCopperPour = (start, end, pour) => {
67243
68413
  const dx = end.x - start.x;
67244
68414
  const dy = end.y - start.y;
67245
- const length7 = Math.hypot(dx, dy);
67246
- if (length7 <= EPSILON24) return false;
68415
+ const length8 = Math.hypot(dx, dy);
68416
+ if (length8 <= EPSILON24) return false;
67247
68417
  const samples = [0, 0.25, 0.5, 0.75, 1];
67248
68418
  return samples.every(
67249
68419
  (t) => isPointInCopperPour(
@@ -67711,13 +68881,13 @@ var getPlatedHolePolygon = (pad, componentRotation = 0) => {
67711
68881
  );
67712
68882
  };
67713
68883
  var getTraceSegmentPolygon = (start, end, startWidth, endWidth = startWidth) => {
67714
- const length7 = Math.hypot(end.x - start.x, end.y - start.y);
68884
+ const length8 = Math.hypot(end.x - start.x, end.y - start.y);
67715
68885
  const r1 = startWidth / 2;
67716
68886
  const r2 = endWidth / 2;
67717
- if (length7 <= Math.abs(r2 - r1))
68887
+ if (length8 <= Math.abs(r2 - r1))
67718
68888
  return circlePolygon(r1 >= r2 ? start : end, Math.max(r1, r2));
67719
68889
  const angle = Math.atan2(end.y - start.y, end.x - start.x);
67720
- const tangent = Math.acos((r1 - r2) / length7);
68890
+ const tangent = Math.acos((r1 - r2) / length8);
67721
68891
  const first = new Arc(
67722
68892
  new Point(start.x, start.y),
67723
68893
  r1,
@@ -68022,7 +69192,7 @@ var Board_doInitialPcbPlacementDesignRuleChecks = (board) => {
68022
69192
 
68023
69193
  // lib/components/normal-components/board-castellated-hole.ts
68024
69194
  import {
68025
- distance as distance16
69195
+ distance as distance17
68026
69196
  } from "circuit-json";
68027
69197
  var CASTELLATED_HOLE_ENDPOINT_TOLERANCE_MM = 1e-6;
68028
69198
  var getConnectionTargets2 = (connectsTo) => {
@@ -68043,8 +69213,8 @@ var BoardCastellatedHole = class _BoardCastellatedHole extends PlatedHole {
68043
69213
  constructor(outlinePoint, outlinePointIndex) {
68044
69214
  const name = `castellated_hole_${outlinePointIndex + 1}`;
68045
69215
  const connectionTargets = getConnectionTargets2(outlinePoint.connectsTo);
68046
- const holeDiameter = distance16.parse(outlinePoint.holeDiameter);
68047
- const padDiameter = distance16.parse(outlinePoint.padDiameter);
69216
+ const holeDiameter = distance17.parse(outlinePoint.holeDiameter);
69217
+ const padDiameter = distance17.parse(outlinePoint.padDiameter);
68048
69218
  super({
68049
69219
  shape: "circle",
68050
69220
  holeDiameter,
@@ -68888,11 +70058,11 @@ var MountedBoard = class extends Subcircuit {
68888
70058
 
68889
70059
  // lib/components/normal-components/Panel.ts
68890
70060
  import { panelProps } from "@tscircuit/props";
68891
- import { distance as distance20 } from "circuit-json";
70061
+ import { distance as distance21 } from "circuit-json";
68892
70062
 
68893
70063
  // lib/components/normal-components/Subpanel.ts
68894
70064
  import { subpanelProps } from "@tscircuit/props";
68895
- import { distance as distance19 } from "circuit-json";
70065
+ import { distance as distance20 } from "circuit-json";
68896
70066
  import { compose as compose17, identity as identity8, translate as translate17 } from "transformation-matrix";
68897
70067
 
68898
70068
  // lib/utils/panels/generate-panel-tabs-and-mouse-bites.ts
@@ -69156,15 +70326,15 @@ function generatePanelOutlineRoutingCutouts(boards, options) {
69156
70326
  }
69157
70327
 
69158
70328
  // lib/utils/panels/pack-into-grid.ts
69159
- import { distance as distance18 } from "circuit-json";
70329
+ import { distance as distance19 } from "circuit-json";
69160
70330
 
69161
70331
  // lib/utils/panels/get-board-dimensions-from-props.ts
69162
70332
  import { getBoundsFromPoints as getBoundsFromPoints11 } from "@tscircuit/math-utils";
69163
- import { distance as distance17 } from "circuit-json";
70333
+ import { distance as distance18 } from "circuit-json";
69164
70334
  var getBoardDimensionsFromProps = (board) => {
69165
70335
  const props = board._parsedProps;
69166
- let width = props.width != null ? distance17.parse(props.width) : void 0;
69167
- let height = props.height != null ? distance17.parse(props.height) : void 0;
70336
+ let width = props.width != null ? distance18.parse(props.width) : void 0;
70337
+ let height = props.height != null ? distance18.parse(props.height) : void 0;
69168
70338
  if ((width === void 0 || height === void 0) && props.outline?.length) {
69169
70339
  const outlineBounds = getBoundsFromPoints11(props.outline);
69170
70340
  if (outlineBounds) {
@@ -69208,8 +70378,8 @@ function packIntoGrid({
69208
70378
  }
69209
70379
  let cols;
69210
70380
  let rows;
69211
- const minCellWidth = cellWidth ? distance18.parse(cellWidth) : 0;
69212
- const minCellHeight = cellHeight ? distance18.parse(cellHeight) : 0;
70381
+ const minCellWidth = cellWidth ? distance19.parse(cellWidth) : 0;
70382
+ const minCellHeight = cellHeight ? distance19.parse(cellHeight) : 0;
69213
70383
  if (col !== void 0) {
69214
70384
  cols = col;
69215
70385
  rows = row ?? Math.ceil(itemsWithDims.length / cols);
@@ -69308,8 +70478,8 @@ function getItemDimensions(item, db) {
69308
70478
  const props = subpanel._parsedProps;
69309
70479
  if (props.width !== void 0 && props.height !== void 0) {
69310
70480
  return {
69311
- width: distance18.parse(props.width),
69312
- height: distance18.parse(props.height)
70481
+ width: distance19.parse(props.width),
70482
+ height: distance19.parse(props.height)
69313
70483
  };
69314
70484
  }
69315
70485
  const directBoards = subpanel._getDirectBoardChildren();
@@ -69336,7 +70506,7 @@ function getItemDimensions(item, db) {
69336
70506
  return getBoardDimensionsFromProps(directBoards[0]);
69337
70507
  }
69338
70508
  if (subpanel._cachedGridWidth > 0 && subpanel._cachedGridHeight > 0) {
69339
- const edgePadding = distance18.parse(props.edgePadding ?? 5);
70509
+ const edgePadding = distance19.parse(props.edgePadding ?? 5);
69340
70510
  return {
69341
70511
  width: subpanel._cachedGridWidth + edgePadding * 2,
69342
70512
  height: subpanel._cachedGridHeight + edgePadding * 2
@@ -69494,17 +70664,17 @@ var Subpanel = class _Subpanel extends Group5 {
69494
70664
  edgePaddingTop: edgePaddingTopProp,
69495
70665
  edgePaddingBottom: edgePaddingBottomProp
69496
70666
  } = this._parsedProps;
69497
- const edgePadding = distance19.parse(edgePaddingProp ?? 5);
69498
- const edgePaddingLeft = distance19.parse(edgePaddingLeftProp ?? edgePadding);
69499
- const edgePaddingRight = distance19.parse(
70667
+ const edgePadding = distance20.parse(edgePaddingProp ?? 5);
70668
+ const edgePaddingLeft = distance20.parse(edgePaddingLeftProp ?? edgePadding);
70669
+ const edgePaddingRight = distance20.parse(
69500
70670
  edgePaddingRightProp ?? edgePadding
69501
70671
  );
69502
- const edgePaddingTop = distance19.parse(edgePaddingTopProp ?? edgePadding);
69503
- const edgePaddingBottom = distance19.parse(
70672
+ const edgePaddingTop = distance20.parse(edgePaddingTopProp ?? edgePadding);
70673
+ const edgePaddingBottom = distance20.parse(
69504
70674
  edgePaddingBottomProp ?? edgePadding
69505
70675
  );
69506
- const panelWidth = distance19.parse(this._parsedProps.width);
69507
- const panelHeight = distance19.parse(this._parsedProps.height);
70676
+ const panelWidth = distance20.parse(this._parsedProps.width);
70677
+ const panelHeight = distance20.parse(this._parsedProps.height);
69508
70678
  availablePanelWidth = panelWidth - edgePaddingLeft - edgePaddingRight;
69509
70679
  availablePanelHeight = panelHeight - edgePaddingTop - edgePaddingBottom;
69510
70680
  }
@@ -69579,8 +70749,8 @@ var Subpanel = class _Subpanel extends Group5 {
69579
70749
  if (!this.pcb_group_id) return;
69580
70750
  if (hasExplicitWidth && hasExplicitHeight) {
69581
70751
  db.pcb_group.update(this.pcb_group_id, {
69582
- width: distance19.parse(this._parsedProps.width),
69583
- height: distance19.parse(this._parsedProps.height)
70752
+ width: distance20.parse(this._parsedProps.width),
70753
+ height: distance20.parse(this._parsedProps.height)
69584
70754
  });
69585
70755
  } else if (gridWidth > 0 || gridHeight > 0) {
69586
70756
  const {
@@ -69590,18 +70760,18 @@ var Subpanel = class _Subpanel extends Group5 {
69590
70760
  edgePaddingTop: edgePaddingTopProp,
69591
70761
  edgePaddingBottom: edgePaddingBottomProp
69592
70762
  } = this._parsedProps;
69593
- const edgePadding = distance19.parse(edgePaddingProp ?? 5);
69594
- const edgePaddingLeft = distance19.parse(edgePaddingLeftProp ?? edgePadding);
69595
- const edgePaddingRight = distance19.parse(
70763
+ const edgePadding = distance20.parse(edgePaddingProp ?? 5);
70764
+ const edgePaddingLeft = distance20.parse(edgePaddingLeftProp ?? edgePadding);
70765
+ const edgePaddingRight = distance20.parse(
69596
70766
  edgePaddingRightProp ?? edgePadding
69597
70767
  );
69598
- const edgePaddingTop = distance19.parse(edgePaddingTopProp ?? edgePadding);
69599
- const edgePaddingBottom = distance19.parse(
70768
+ const edgePaddingTop = distance20.parse(edgePaddingTopProp ?? edgePadding);
70769
+ const edgePaddingBottom = distance20.parse(
69600
70770
  edgePaddingBottomProp ?? edgePadding
69601
70771
  );
69602
70772
  db.pcb_group.update(this.pcb_group_id, {
69603
- width: hasExplicitWidth ? distance19.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
69604
- height: hasExplicitHeight ? distance19.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
70773
+ width: hasExplicitWidth ? distance20.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
70774
+ height: hasExplicitHeight ? distance20.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
69605
70775
  });
69606
70776
  }
69607
70777
  }
@@ -69689,8 +70859,8 @@ var Panel = class extends Subpanel {
69689
70859
  const { db } = this.root;
69690
70860
  const props = this._parsedProps;
69691
70861
  const inserted = db.pcb_panel.insert({
69692
- width: props.width !== void 0 ? distance20.parse(props.width) : 0,
69693
- height: props.height !== void 0 ? distance20.parse(props.height) : 0,
70862
+ width: props.width !== void 0 ? distance21.parse(props.width) : 0,
70863
+ height: props.height !== void 0 ? distance21.parse(props.height) : 0,
69694
70864
  thickness: 1.6,
69695
70865
  center: this._getGlobalPcbPositionBeforeLayout(),
69696
70866
  covered_with_solder_mask: !(props.noSolderMask ?? false)
@@ -69709,8 +70879,8 @@ var Panel = class extends Subpanel {
69709
70879
  if (!this.pcb_panel_id) return;
69710
70880
  if (hasExplicitWidth && hasExplicitHeight) {
69711
70881
  db.pcb_panel.update(this.pcb_panel_id, {
69712
- width: distance20.parse(this._parsedProps.width),
69713
- height: distance20.parse(this._parsedProps.height)
70882
+ width: distance21.parse(this._parsedProps.width),
70883
+ height: distance21.parse(this._parsedProps.height)
69714
70884
  });
69715
70885
  } else if (gridWidth > 0 || gridHeight > 0) {
69716
70886
  const {
@@ -69720,18 +70890,18 @@ var Panel = class extends Subpanel {
69720
70890
  edgePaddingTop: edgePaddingTopProp,
69721
70891
  edgePaddingBottom: edgePaddingBottomProp
69722
70892
  } = this._parsedProps;
69723
- const edgePadding = distance20.parse(edgePaddingProp ?? 5);
69724
- const edgePaddingLeft = distance20.parse(edgePaddingLeftProp ?? edgePadding);
69725
- const edgePaddingRight = distance20.parse(
70893
+ const edgePadding = distance21.parse(edgePaddingProp ?? 5);
70894
+ const edgePaddingLeft = distance21.parse(edgePaddingLeftProp ?? edgePadding);
70895
+ const edgePaddingRight = distance21.parse(
69726
70896
  edgePaddingRightProp ?? edgePadding
69727
70897
  );
69728
- const edgePaddingTop = distance20.parse(edgePaddingTopProp ?? edgePadding);
69729
- const edgePaddingBottom = distance20.parse(
70898
+ const edgePaddingTop = distance21.parse(edgePaddingTopProp ?? edgePadding);
70899
+ const edgePaddingBottom = distance21.parse(
69730
70900
  edgePaddingBottomProp ?? edgePadding
69731
70901
  );
69732
70902
  db.pcb_panel.update(this.pcb_panel_id, {
69733
- width: hasExplicitWidth ? distance20.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
69734
- height: hasExplicitHeight ? distance20.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
70903
+ width: hasExplicitWidth ? distance21.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
70904
+ height: hasExplicitHeight ? distance21.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
69735
70905
  });
69736
70906
  }
69737
70907
  }
@@ -69742,8 +70912,8 @@ var Panel = class extends Subpanel {
69742
70912
  const props = this._parsedProps;
69743
70913
  const currentPanel = db.pcb_panel.get(this.pcb_panel_id);
69744
70914
  db.pcb_panel.update(this.pcb_panel_id, {
69745
- width: props.width !== void 0 ? distance20.parse(props.width) : currentPanel?.width,
69746
- height: props.height !== void 0 ? distance20.parse(props.height) : currentPanel?.height,
70915
+ width: props.width !== void 0 ? distance21.parse(props.width) : currentPanel?.width,
70916
+ height: props.height !== void 0 ? distance21.parse(props.height) : currentPanel?.height,
69747
70917
  center: this._getGlobalPcbPositionBeforeLayout(),
69748
70918
  covered_with_solder_mask: !(props.noSolderMask ?? false)
69749
70919
  });
@@ -72049,7 +73219,7 @@ var validateWindingBreakoutInput = (input) => {
72049
73219
  };
72050
73220
 
72051
73221
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/GatePlacementSolver.ts
72052
- import { BaseSolver as BaseSolver6 } from "@tscircuit/solver-utils";
73222
+ import { BaseSolver as BaseSolver7 } from "@tscircuit/solver-utils";
72053
73223
 
72054
73224
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/gate-placement/place-breakout-gates.ts
72055
73225
  var GEOMETRY_EPSILON = 1e-9;
@@ -72579,7 +73749,7 @@ var getSharedGateSlotCount = (points) => new Set(
72579
73749
  (point6) => `${point6.regionId}:${point6.x.toFixed(9)}:${point6.y.toFixed(9)}`
72580
73750
  )
72581
73751
  ).size;
72582
- var GatePlacementSolver = class extends BaseSolver6 {
73752
+ var GatePlacementSolver = class extends BaseSolver7 {
72583
73753
  constructor(params) {
72584
73754
  super();
72585
73755
  this.params = params;
@@ -72718,7 +73888,7 @@ var GatePlacementSolver = class extends BaseSolver6 {
72718
73888
  };
72719
73889
 
72720
73890
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
72721
- import { BaseSolver as BaseSolver7 } from "@tscircuit/solver-utils";
73891
+ import { BaseSolver as BaseSolver8 } from "@tscircuit/solver-utils";
72722
73892
 
72723
73893
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/ordering/get-natural-winding-order.ts
72724
73894
  var getNaturalWindingOrder = (region, connections) => connections.map((connection) => {
@@ -72785,7 +73955,7 @@ var getReferenceWindingOrder = (naturalOrder, atomicGroups, buses) => {
72785
73955
  };
72786
73956
 
72787
73957
  // node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
72788
- var ReferenceOrderingSolver = class extends BaseSolver7 {
73958
+ var ReferenceOrderingSolver = class extends BaseSolver8 {
72789
73959
  constructor(params) {
72790
73960
  super();
72791
73961
  this.params = params;
@@ -74130,7 +75300,7 @@ var SilkscreenGraphic = class extends PrimitiveComponent2 {
74130
75300
 
74131
75301
  // lib/components/primitive-components/Fiducial.ts
74132
75302
  import "zod";
74133
- import { distance as distance21 } from "circuit-json";
75303
+ import { distance as distance22 } from "circuit-json";
74134
75304
  import { fiducialProps as fiducialProps2 } from "@tscircuit/props";
74135
75305
  var Fiducial = class extends PrimitiveComponent2 {
74136
75306
  pcb_smtpad_id = null;
@@ -74155,15 +75325,15 @@ var Fiducial = class extends PrimitiveComponent2 {
74155
75325
  shape: "circle",
74156
75326
  x: position.x,
74157
75327
  y: position.y,
74158
- radius: distance21.parse(props.padDiameter) / 2,
74159
- soldermask_margin: props.soldermaskPullback ? distance21.parse(props.soldermaskPullback) : distance21.parse(props.padDiameter) / 2,
75328
+ radius: distance22.parse(props.padDiameter) / 2,
75329
+ soldermask_margin: props.soldermaskPullback ? distance22.parse(props.soldermaskPullback) : distance22.parse(props.padDiameter) / 2,
74160
75330
  is_covered_with_solder_mask: true
74161
75331
  });
74162
75332
  this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id;
74163
75333
  }
74164
75334
  getPcbSize() {
74165
75335
  const { _parsedProps: props } = this;
74166
- const d = distance21.parse(props.padDiameter);
75336
+ const d = distance22.parse(props.padDiameter);
74167
75337
  return { width: d, height: d };
74168
75338
  }
74169
75339
  _setPositionFromLayout(newCenter) {