@tscircuit/fanout-solver 0.0.10 → 0.0.12

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.
@@ -8,7 +8,10 @@ import { buildOutputSimpleRouteJson } from "./build-output"
8
8
  import { distanceSegmentToObstacle } from "./geometry"
9
9
  import { getCopperLayerColor } from "./layer-colors"
10
10
  import { generateLayerAssignments, getCopperLayerNames } from "./layer-names"
11
- import { prepareFanoutBuses } from "./prepare-buses"
11
+ import {
12
+ prepareFanoutBuses,
13
+ resolveAvailableBoundaryRegions,
14
+ } from "./prepare-buses"
12
15
  import { routeBus } from "./route-bus"
13
16
  import { routeSingleLayerWithAdaptiveExits } from "./route-single-layer-adaptive-exits"
14
17
  import { routeSingleLayerWithPushAndShove } from "./route-single-layer-push-shove"
@@ -404,9 +407,13 @@ export class FanoutSolver extends BaseSolver {
404
407
  }
405
408
  const singleLayerPlans =
406
409
  routeSingleLayerWithPushAndShove(singleLayerParams) ??
407
- (this.config.singleLayerAdaptiveExits &&
408
- this.options.availableCornersAndSides === undefined
409
- ? routeSingleLayerWithAdaptiveExits(singleLayerParams)
410
+ (this.config.singleLayerAdaptiveExits
411
+ ? routeSingleLayerWithAdaptiveExits({
412
+ ...singleLayerParams,
413
+ availableBoundaryRegions: resolveAvailableBoundaryRegions(
414
+ this.options.availableCornersAndSides,
415
+ ),
416
+ })
410
417
  : null)
411
418
  if (singleLayerPlans) {
412
419
  plans.push(...singleLayerPlans)
@@ -17,7 +17,7 @@ import type {
17
17
  PreparedConnection,
18
18
  } from "./types"
19
19
 
20
- interface AvailableBoundaryRegion {
20
+ export interface AvailableBoundaryRegion {
21
21
  direction: FanoutDirection
22
22
  preferredExit: FanoutBorderTarget
23
23
  }
@@ -407,7 +407,7 @@ function resolvePreferredExit(
407
407
  return value
408
408
  }
409
409
 
410
- function resolveAvailableBoundaryRegions(
410
+ export function resolveAvailableBoundaryRegions(
411
411
  value: readonly FanoutAvailableCornerAndSideInput[] | undefined,
412
412
  ): AvailableBoundaryRegion[] | undefined {
413
413
  if (value === undefined) return undefined
@@ -768,7 +768,7 @@ function getDistanceToBoundary(
768
768
  }
769
769
  }
770
770
 
771
- function getRegionAnchor(
771
+ export function getRegionAnchor(
772
772
  region: AvailableBoundaryRegion,
773
773
  boundary: Bounds,
774
774
  ): number {
@@ -9,6 +9,7 @@ import {
9
9
  distanceSegmentToObstacle,
10
10
  distanceSegmentToSegment,
11
11
  } from "./geometry"
12
+ import { type AvailableBoundaryRegion, getRegionAnchor } from "./prepare-buses"
12
13
  import type {
13
14
  FanoutDirection,
14
15
  FanoutRoutePlan,
@@ -23,6 +24,7 @@ interface FlowRoutingParams {
23
24
  buses: PreparedBus[]
24
25
  traceWidth: number
25
26
  clearance: number
27
+ availableBoundaryRegions?: AvailableBoundaryRegion[]
26
28
  }
27
29
 
28
30
  interface FlowItem {
@@ -449,6 +451,7 @@ function createFlowGrid(params: {
449
451
 
450
452
  function routeDirectionGroup(params: {
451
453
  direction: FanoutDirection | "any"
454
+ availableDirections?: ReadonlySet<FanoutDirection>
452
455
  items: FlowItem[]
453
456
  grid: FlowGrid
454
457
  obstacles: Obstacle[]
@@ -460,6 +463,7 @@ function routeDirectionGroup(params: {
460
463
  }): DirectionGroupResult | null {
461
464
  const {
462
465
  direction,
466
+ availableDirections,
463
467
  items,
464
468
  grid,
465
469
  obstacles,
@@ -695,10 +699,14 @@ function routeDirectionGroup(params: {
695
699
  }
696
700
  const isTarget =
697
701
  (direction === "any" &&
698
- (column === 0 ||
699
- column === columnCount - 1 ||
700
- row === 0 ||
701
- row === rowCount - 1)) ||
702
+ (((!availableDirections || availableDirections.has("left")) &&
703
+ column === 0) ||
704
+ ((!availableDirections || availableDirections.has("right")) &&
705
+ column === columnCount - 1) ||
706
+ ((!availableDirections || availableDirections.has("down")) &&
707
+ row === 0) ||
708
+ ((!availableDirections || availableDirections.has("up")) &&
709
+ row === rowCount - 1))) ||
702
710
  (direction === "left" && column === 0) ||
703
711
  (direction === "right" && column === columnCount - 1) ||
704
712
  (direction === "down" && row === 0) ||
@@ -965,8 +973,19 @@ function routeWithAdaptiveExits(params: {
965
973
  obstacles: Obstacle[]
966
974
  traceWidth: number
967
975
  clearance: number
976
+ availableBoundaryRegions?: AvailableBoundaryRegion[]
968
977
  }): FanoutRoutePlan[] | null {
969
- const { items, grid, obstacles, traceWidth, clearance } = params
978
+ const {
979
+ items,
980
+ grid,
981
+ obstacles,
982
+ traceWidth,
983
+ clearance,
984
+ availableBoundaryRegions,
985
+ } = params
986
+ const availableDirections = availableBoundaryRegions
987
+ ? new Set(availableBoundaryRegions.map((region) => region.direction))
988
+ : undefined
970
989
  const mergeItems = new Set(
971
990
  items.filter(
972
991
  (item) =>
@@ -985,6 +1004,7 @@ function routeWithAdaptiveExits(params: {
985
1004
  ) {
986
1005
  const result = routeDirectionGroup({
987
1006
  direction: "any",
1007
+ availableDirections,
988
1008
  items: directlyRoutedItems,
989
1009
  grid,
990
1010
  obstacles,
@@ -1115,14 +1135,31 @@ function routeWithAdaptiveExits(params: {
1115
1135
  plan.exitPoint,
1116
1136
  grid.boundary,
1117
1137
  )
1118
- if (!direction) return null
1138
+ if (
1139
+ !direction ||
1140
+ (availableDirections && !availableDirections.has(direction))
1141
+ ) {
1142
+ return null
1143
+ }
1119
1144
  const item = items.find(
1120
1145
  (candidate) =>
1121
1146
  candidate.connection.connection.name === plan.connectionName,
1122
1147
  )!
1123
1148
  item.bus.direction = direction
1149
+ const compatibleRegions = availableBoundaryRegions?.filter(
1150
+ (region) => region.direction === direction,
1151
+ )
1152
+ const exitCoordinate =
1153
+ direction === "up" || direction === "down"
1154
+ ? plan.exitPoint.x
1155
+ : plan.exitPoint.y
1124
1156
  item.bus.preferredExit =
1125
- direction === "up" ? "top" : direction === "down" ? "bottom" : direction
1157
+ compatibleRegions?.toSorted(
1158
+ (first, second) =>
1159
+ Math.abs(exitCoordinate - getRegionAnchor(first, grid.boundary)) -
1160
+ Math.abs(exitCoordinate - getRegionAnchor(second, grid.boundary)),
1161
+ )[0]?.preferredExit ??
1162
+ (direction === "up" ? "top" : direction === "down" ? "bottom" : direction)
1126
1163
  plan.direction = direction
1127
1164
  }
1128
1165
  const planByConnectionName = new Map(
@@ -1136,7 +1173,7 @@ function routeWithAdaptiveExits(params: {
1136
1173
  export function routeSingleLayerWithAdaptiveExits(
1137
1174
  params: FlowRoutingParams,
1138
1175
  ): FanoutRoutePlan[] | null {
1139
- const { srj, buses, traceWidth, clearance } = params
1176
+ const { srj, buses, traceWidth, clearance, availableBoundaryRegions } = params
1140
1177
  if (buses.some((bus) => bus.connections.length !== 1)) return null
1141
1178
  const items = buses.flatMap((bus) =>
1142
1179
  bus.connections.map(
@@ -1173,6 +1210,7 @@ export function routeSingleLayerWithAdaptiveExits(
1173
1210
  obstacles: topObstacles,
1174
1211
  traceWidth,
1175
1212
  clearance,
1213
+ availableBoundaryRegions,
1176
1214
  })
1177
1215
  if (adaptivePlans) return adaptivePlans
1178
1216
  return null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/fanout-solver",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "BGA fanout solver with coordinated bus-layer escapes for SimpleRouteJson",
5
5
  "module": "lib/index.ts",
6
6
  "type": "module",