Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import type { ConnectivityMap } from "connectivity-map"
import { getConnectivityMapsFromInputProblem } from "lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem"
import type { MspConnectionPair } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
import type {
InputProblem,
InputChip,
InputPin,
InputProblem,
PinId,
InputChip,
} from "lib/types/InputProblem"
import { doesTraceOverlapWithExistingTraces } from "lib/utils/does-trace-overlap-with-existing-traces"
import { createLabeledRailNetHelpers } from "lib/utils/labeledRailNets"
import { arePinsInDifferentSchematicSections } from "../../utils/arePinsInDifferentSchematicSections"
import { BaseSolver } from "../BaseSolver/BaseSolver"
import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
import { SchematicTraceSingleLineSolver2 } from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2"
import { doesTraceOverlapWithExistingTraces } from "lib/utils/does-trace-overlap-with-existing-traces"
import { visualizeInputProblem } from "../SchematicTracePipelineSolver/visualizeInputProblem"
import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
import type { ConnectivityMap } from "connectivity-map"
import { arePinsInDifferentSchematicSections } from "../../utils/arePinsInDifferentSchematicSections"

const NEAREST_NEIGHBOR_COUNT = 3

const distance = (p1: InputPin, p2: InputPin) => {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2))
return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2)
}

export class LongDistancePairSolver extends BaseSolver {
Expand Down Expand Up @@ -73,6 +74,11 @@ export class LongDistancePairSolver extends BaseSolver {
> = []
const addedPairKeys = new Set<string>()

// Distant pairs on labeled rails stay label-connected; wiring them
// duplicates the net labels with a long bus trace (#670).
const { isLabeledRailNet, exceedsDirectWiringDistance } =
createLabeledRailNetHelpers(inputProblem)

for (const netId of Object.keys(netConnMap.netMap)) {
const allPinIdsInNet = netConnMap.getIdsConnectedToNet(netId)
if (allPinIdsInNet.length < 2) continue
Expand All @@ -97,6 +103,11 @@ export class LongDistancePairSolver extends BaseSolver {
},
]
})
.filter(
(neighbor) =>
!isLabeledRailNet(unconnectedPinId) ||
!exceedsDirectWiringDistance(neighbor.distance),
)
.sort((a, b) => a.distance - b.distance)
.slice(0, NEAREST_NEIGHBOR_COUNT)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
import type { InputProblem, PinId } from "lib/types/InputProblem"
import type { FacingDirection } from "lib/utils/dir"
import { createLabeledRailNetHelpers } from "lib/utils/labeledRailNets"

const ROUTE_CLEARANCE = 0.2
const COORDINATE_TOLERANCE = 1e-9
Expand Down Expand Up @@ -469,6 +470,7 @@ export class UnroutedTraceRecoverySolver extends BaseSolver {
private queuedConnectionPairs: MspConnectionPair[]
private maxConnectionDistance: number
private groundGlobalConnNetId?: string
private labeledRailNets: ReturnType<typeof createLabeledRailNetHelpers>
public solvedUnroutedTraces: SolvedTracePath[] = []

constructor(
Expand All @@ -490,6 +492,7 @@ export class UnroutedTraceRecoverySolver extends BaseSolver {
)
this.groundGlobalConnNetId =
netConnMap.getNetConnectedToId(GROUND_NET_ID) ?? undefined
this.labeledRailNets = createLabeledRailNetHelpers(this.inputProblem)
}

override getConstructorParams() {
Expand Down Expand Up @@ -536,7 +539,25 @@ export class UnroutedTraceRecoverySolver extends BaseSolver {
failedConnectionPairs: this.failedConnectionPairs,
})

// Pins on a labeled rail already carry a net label each. A recovery route
// that has to detour far around obstacles duplicates those labels with a
// long bus trace, which is exactly what #670 asks us to avoid. The pins can
// sit within `maxConnectionDistance` of each other and still only be
// reachable by a much longer path, so the routed length — not the
// straight-line pin distance — decides this.
const isLabeledRailPair = this.labeledRailNets.isLabeledRailNet(
connectionPair.pins[0].pinId,
)

for (const tracePath of candidates) {
if (
isLabeledRailPair &&
this.labeledRailNets.exceedsDirectWiringDistance(
getPathLength(tracePath),
)
) {
continue
}
if (
pathCollidesWithObstacles({
path: tracePath,
Expand Down
60 changes: 60 additions & 0 deletions lib/utils/labeledRailNets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { getConnectivityMapsFromInputProblem } from "lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem"
import { DEFAULT_MAX_MSP_PAIR_DISTANCE } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
import type { InputProblem, PinId } from "lib/types/InputProblem"

/**
* Nets that declare net-label orientations (power/ground rails and named buses
* like V3_3, GND, SDA) get a net label drawn at every pin once the net has more
* than two pins. Wiring a distant pair on such a net duplicates information
* that the labels already carry, and the resulting bus trace snakes across the
* schematic (#670).
*
* `isLabeledRailNet` reports whether a pin sits on such a net: it declares
* available net-label orientations and has more than two pins, so every pin
* really does get a label. A two-pin labeled net is excluded because one trace
* is cleaner than a floating label pair (see rotated-components-rail-label).
*
* `exceedsDirectWiringDistance` compares a length against `maxMspPairDistance`,
* the same threshold `MspConnectionPairSolver` uses to decide a pair is too far
* apart to wire directly. Callers pass whichever length is meaningful for them:
* the straight-line pin distance when choosing candidate pairs, or the routed
* path length when a detour around obstacles is what makes a trace long.
*/
export const createLabeledRailNetHelpers = (inputProblem: InputProblem) => {
const labeledNetIds = new Set(
Object.keys(inputProblem.availableNetLabelOrientations ?? {}),
)
const maxPairDistance =
inputProblem.maxMspPairDistance ?? DEFAULT_MAX_MSP_PAIR_DISTANCE

const { netConnMap } = getConnectivityMapsFromInputProblem(inputProblem)

const pinIds = new Set<PinId>()
for (const chip of inputProblem.chips) {
for (const pin of chip.pins) pinIds.add(pin.pinId)
}

const labeledNetCache = new Map<string, boolean>()

const netIsLabeled = (pinId: PinId): boolean => {
const netId = netConnMap.getNetConnectedToId(pinId)
if (!netId) return false

const cached = labeledNetCache.get(netId)
if (cached !== undefined) return cached

const idsInNet = netConnMap.getIdsConnectedToNet(netId)
const pinCount = idsInNet.filter((id) => pinIds.has(id)).length
const declaresLabels = idsInNet.some((id) => labeledNetIds.has(id))

const isLabeled = pinCount > 2 && declaresLabels
labeledNetCache.set(netId, isLabeled)
return isLabeled
}

return {
isLabeledRailNet: (pinId: PinId): boolean => netIsLabeled(pinId),
exceedsDirectWiringDistance: (length: number): boolean =>
length > maxPairDistance,
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading