Skip to content

Commit 6292bbb

Browse files
seveibarclaude
andcommitted
fix(fanout): keep the routing area consistent with the fanout boundary
fanoutBoundaryPadding moves the boundary the fanout terminates on, but simpleRouteJson.bounds was left at its earlier value, so every exit ended up outside the region copper may occupy. The routing area now widens to contain the resolved fanout bounds. Adds a descriptive error for the case where the two are still inconsistent, rather than letting the fanout silently route nothing. Two breakout snapshots shift slightly: the routable area is marginally larger, so one 45-degree bend and a pair of plane-fanout vias move a fraction. Routes are otherwise unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 8fe0d9d commit 6292bbb

5 files changed

Lines changed: 81 additions & 2 deletions

File tree

lib/components/primitive-components/Group/Group.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,18 @@ export class Group<Props extends z.ZodType<any, any, any> = typeof groupProps>
12381238
},
12391239
)
12401240
const { fanoutBounds, routingPcbGroupId } = routingPhasePlan
1241+
if (fanoutBounds) {
1242+
// The fanout terminates exactly on these bounds, so the routing area
1243+
// has to contain them. fanoutBoundaryPadding moves the boundary
1244+
// without touching simpleRouteJson.bounds, which would otherwise
1245+
// leave every exit sitting outside the area copper may occupy.
1246+
simpleRouteJson.bounds = {
1247+
minX: Math.min(simpleRouteJson.bounds.minX, fanoutBounds.minX),
1248+
maxX: Math.max(simpleRouteJson.bounds.maxX, fanoutBounds.maxX),
1249+
minY: Math.min(simpleRouteJson.bounds.minY, fanoutBounds.minY),
1250+
maxY: Math.max(simpleRouteJson.bounds.maxY, fanoutBounds.maxY),
1251+
}
1252+
}
12411253
if (fanoutBounds && routingPcbGroupId) {
12421254
db.pcb_group.update(routingPcbGroupId, {
12431255
center: {

lib/utils/autorouting/FanoutAutorouter.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,23 @@ export class FanoutAutorouter implements GenericLocalAutorouter {
415415
debugGraphics: AutorouterProgressEvent["debugGraphics"]
416416
} {
417417
const fanoutSolverOptions = this.getFanoutSolverOptions()
418+
const sharedBoundary =
419+
this.options.fanoutBounds ?? fanoutSolverOptions.sharedBoundary
420+
if (sharedBoundary) {
421+
const { bounds } = this.input
422+
const outsideBy = Math.max(
423+
bounds.minX - sharedBoundary.minX,
424+
sharedBoundary.maxX - bounds.maxX,
425+
bounds.minY - sharedBoundary.minY,
426+
sharedBoundary.maxY - bounds.maxY,
427+
)
428+
if (outsideBy > 1e-6) {
429+
throw new Error(
430+
`Fanout boundary extends ${Math.round(outsideBy * 1000) / 1000}mm outside the routable area, so its escapes would have to terminate where copper cannot go. ` +
431+
"This usually means the fanout boundary was widened without widening the routing bounds to match.",
432+
)
433+
}
434+
}
418435
const fanoutSolver = new FanoutSolver(
419436
this.input as unknown as ConstructorParameters<typeof FanoutSolver>[0],
420437
{
Lines changed: 1 addition & 1 deletion
Loading

0 commit comments

Comments
 (0)