Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
getBoundsCenter,
getBoundsFromPoints,
} from "@tscircuit/math-utils"
import { applyDirectPassiveTraceClearance } from "../../utils/offsetCollinearConnections"

const CLEARANCE_EPSILON = 1e-6
const MAX_RESOLVE_ITERATIONS = 16
Expand Down Expand Up @@ -106,11 +107,18 @@ export class ParallelAlignedPassiveSolver extends BaseSolver {
for (const [chipId, placement] of Object.entries(base.chipPlacements)) {
placements[chipId] = { ...placement }
}
for (const passiveGroup of findSameSidePassiveGroups(
this.partitionInputProblem,
)) {
const passiveGroups = findSameSidePassiveGroups(this.partitionInputProblem)
for (const passiveGroup of passiveGroups) {
this.reflowPassiveGroup(placements, passiveGroup)
}
applyDirectPassiveTraceClearance({
inputProblem: this.partitionInputProblem,
connectedPinsByPinId: this.pinIdToStronglyConnectedPins,
chipPlacements: placements,
rigidChipGroups: passiveGroups.map(
(passiveGroup) => passiveGroup.passiveChipIds,
),
})
return { chipPlacements: placements, groupPlacements: base.groupPlacements }
}

Expand Down
49 changes: 32 additions & 17 deletions lib/utils/offsetCollinearConnections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,31 +108,38 @@ const placementHasClearance = ({
return true
}

const tryOffsetChip = ({
chipId,
const tryOffsetChips = ({
chipIds,
dx,
dy,
chipPlacements,
inputProblem,
}: {
chipId: ChipId
chipIds: ChipId[]
dx: number
dy: number
chipPlacements: Record<ChipId, Placement>
inputProblem: InputProblem
}): void => {
const placement = chipPlacements[chipId]
if (!placement) return
const placements = chipIds
.map((chipId) => chipPlacements[chipId])
.filter((placement): placement is Placement => Boolean(placement))
if (placements.length !== chipIds.length) return

placement.x += dx
placement.y += dy
if (
!placementHasClearance({
for (const placement of placements) {
placement.x += dx
placement.y += dy
}
const allChipsHaveClearance = chipIds.every((chipId) =>
placementHasClearance({
chipId,
chipPlacements,
inputProblem,
})
) {
}),
)
if (allChipsHaveClearance) return

for (const placement of placements) {
placement.x -= dx
placement.y -= dy
}
Expand All @@ -142,10 +149,12 @@ export const applyDirectPassiveTraceClearance = ({
inputProblem,
connectedPinsByPinId,
chipPlacements,
rigidChipGroups = [],
}: {
inputProblem: InputProblem
connectedPinsByPinId: Record<PinId, ChipPin[]>
chipPlacements: Record<ChipId, Placement>
rigidChipGroups?: ChipId[][]
}): void => {
const pinOwnerMap = createPinOwnerMap(inputProblem)
const chipCount = Object.keys(inputProblem.chipMap).length
Expand Down Expand Up @@ -183,10 +192,16 @@ export const applyDirectPassiveTraceClearance = ({
inputProblem,
placement: connectedPlacement,
})
const rigidChipGroup = rigidChipGroups.find((chipIds) =>
chipIds.includes(connectedChip.chipId),
)
const chipIdsToOffset = rigidChipGroup ?? [connectedChip.chipId]

if (pinsShareX && pinsAreVerticallyOriented) {
tryOffsetChip({
chipId: connectedChip.chipId,
// A rigid row keeps its intentional vertical anchor trace straight.
if (rigidChipGroup) continue
tryOffsetChips({
chipIds: [connectedChip.chipId],
dx: -TRACE_CLEARANCE,
dy: 0,
chipPlacements,
Expand All @@ -205,8 +220,8 @@ export const applyDirectPassiveTraceClearance = ({
const isGroundedLoad =
otherPinId && pinConnectsToGround(inputProblem, otherPinId)
if (pinsShareY && (isSingleVerticalPassive || isGroundedLoad)) {
tryOffsetChip({
chipId: connectedChip.chipId,
tryOffsetChips({
chipIds: chipIdsToOffset,
dx: 0,
dy: -TRACE_CLEARANCE,
chipPlacements,
Expand Down Expand Up @@ -243,8 +258,8 @@ export const offsetChipAnchoredGroundedLoadConnections = ({
continue
}

tryOffsetChip({
chipId: groundedLoadPair.upperChip.chipId,
tryOffsetChips({
chipIds: [groundedLoadPair.upperChip.chipId],
dx: -TRACE_CLEARANCE,
dy: 0,
chipPlacements,
Expand Down
36 changes: 36 additions & 0 deletions tests/offsetCollinearConnections.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { rotatePinOffset } from "../lib/utils/rotatePinOffset"
import chipPortInput from "./assets/chip-port-without-portarrangement.input.json"
import repro44Input from "./assets/repro44-e2e-pack-and-schematic.input.json"
import bootResetInput from "./assets/schematic-section-rp2040-boot-reset.input.json"
import polarizedCapacitorInput from "./assets/polarized-capacitor-auto-layout.input.json"
import bq24074RightResistorsInput from "./assets/repro-bq24074-right-resistors.input.json"
import bq24074BottomResistorsInput from "./assets/repro-bq24074-bottom-resistors.input.json"

const getAbsolutePinPosition = (
inputProblem: InputProblem,
Expand Down Expand Up @@ -68,3 +71,36 @@ test("keeps a standalone rail-to-ground chain in one line", () => {

expect(resistorPin.x).toBeCloseTo(switchPin.x)
})

test("preserves direct trace clearance after reflowing a passive row", () => {
const inputProblem = polarizedCapacitorInput as InputProblem
const outputLayout = solve(inputProblem)
const mainPin = getAbsolutePinPosition(inputProblem, outputLayout, "U1.1")
const c1Pin = getAbsolutePinPosition(inputProblem, outputLayout, "C1.1")
const c2Pin = getAbsolutePinPosition(inputProblem, outputLayout, "C2.1")

expect(c1Pin.y - mainPin.y).toBeCloseTo(-0.2)
expect(c2Pin.y - mainPin.y).toBeCloseTo(-0.2)
expect(c1Pin.y).toBeCloseTo(c2Pin.y)
})

test("offsets a reflowed passive row as a rigid group", () => {
const inputProblem = bq24074RightResistorsInput as InputProblem
const outputLayout = solve(inputProblem)
const mainPin = getAbsolutePinPosition(inputProblem, outputLayout, "U1.14")
const r3Pin = getAbsolutePinPosition(inputProblem, outputLayout, "R3.1")
const rowY = outputLayout.chipPlacements.R3!.y

expect(r3Pin.y - mainPin.y).toBeCloseTo(-0.2)
expect(outputLayout.chipPlacements.R1!.y).toBeCloseTo(rowY)
expect(outputLayout.chipPlacements.R2!.y).toBeCloseTo(rowY)
})

test("preserves a straight vertical connection to a reflowed bottom row", () => {
const inputProblem = bq24074BottomResistorsInput as InputProblem
const outputLayout = solve(inputProblem)
const mainPin = getAbsolutePinPosition(inputProblem, outputLayout, "U1.12")
const r2Pin = getAbsolutePinPosition(inputProblem, outputLayout, "R2.1")

expect(r2Pin.x).toBeCloseTo(mainPin.x)
})
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading