Skip to content
Closed
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 @@ -171,38 +171,39 @@ export class SingleTransitionCrossingRouteSolver extends BaseSolver {
const C = flatRoute.B

const turnDirection = computeTurnDirection(A, B, C, this.bounds)
// const turnDirection = computeTurnDirection(A, B, C, this.bounds)
console.debug("turnDirection", turnDirection)
const sideTraversal = calculateTraversalPercentages(
A,
B,
C,
this.bounds,
turnDirection,
)
console.debug("sideTraversal", sideTraversal)

// console.log({ sideTraversal, turnDirection })

const viaBounds = {
minX:
this.bounds.minX +
(sideTraversal.left > 0.5
? marginFromBorderWithTrace
: marginFromBorderWithoutTrace),
(sideTraversal.left > 0.75
? marginFromBorderWithoutTrace
: marginFromBorderWithTrace),
minY:
this.bounds.minY +
(sideTraversal.bottom > 0.5
? marginFromBorderWithTrace
: marginFromBorderWithoutTrace),
(sideTraversal.bottom > 0.75
? marginFromBorderWithoutTrace
: marginFromBorderWithTrace),
maxX:
this.bounds.maxX -
(sideTraversal.right > 0.5
? marginFromBorderWithTrace
: marginFromBorderWithoutTrace),
(sideTraversal.right > 0.75
? marginFromBorderWithoutTrace
: marginFromBorderWithTrace),
maxY:
this.bounds.maxY -
(sideTraversal.top > 0.5
? marginFromBorderWithTrace
: marginFromBorderWithoutTrace),
(sideTraversal.top > 0.75
? marginFromBorderWithoutTrace
: marginFromBorderWithTrace),
}

if (viaBounds.maxY < viaBounds.minY) {
Expand All @@ -215,13 +216,15 @@ export class SingleTransitionCrossingRouteSolver extends BaseSolver {
viaBounds.maxX = viaBounds.minX
}

return findClosestPointToABCWithinBounds(
let via = findClosestPointToABCWithinBounds(
A,
B,
C,
marginFromBorderWithTrace,
viaBounds,
)
via = { x: viaBounds.minX, y: viaBounds.maxY }
return via
}
/**
* Create a single transition route with properly placed via
Expand Down Expand Up @@ -302,12 +305,10 @@ export class SingleTransitionCrossingRouteSolver extends BaseSolver {

const minDistFromViaToTrace =
this.viaDiameter / 2 + this.traceThickness / 2 + this.obstacleMargin
const p2 = middleWithMargin(
via,
this.viaDiameter,
otherRouteStart.z !== flatStart.z ? otherRouteStart : otherRouteEnd,
this.traceThickness,
)
const p2 = {
x: via.x - minDistFromViaToTrace * 1.2,
y: via.y,
}
const viaCircle = {
center: { x: via.x, y: via.y },
radius: minDistFromViaToTrace,
Expand Down Expand Up @@ -363,6 +364,7 @@ export class SingleTransitionCrossingRouteSolver extends BaseSolver {
const flatRoute = routeAHasTransition ? routeB : routeA

const viaPosition = this.calculateViaPosition(transitionRoute, flatRoute)
console.debug("viaPosition", viaPosition)
if (viaPosition) {
this.debugViaPositions.push({ via: viaPosition })
} else {
Expand Down
83 changes: 50 additions & 33 deletions lib/testing/utils/convertToCircuitJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,41 +215,46 @@ function extractViasFromRoutes(
})
})
} else {
// Extract vias from HighDensityRoutes by looking for layer changes
;(routes as HighDensityRoute[]).forEach((route) => {
for (let i = 1; i < route.route.length; i++) {
const prevPoint = route.route[i - 1]
const currPoint = route.route[i]
// HighDensityRoutes will be processed later when converting each trace
// This function intentionally does nothing for that case
}
}

// If z-coordinate changes, we have a via
if (
prevPoint.z !== currPoint.z &&
Math.abs(prevPoint.x - currPoint.x) < 0.01 &&
Math.abs(prevPoint.y - currPoint.y) < 0.01
) {
const fromLayer = mapZToLayerName(prevPoint.z, 2)
const toLayer = mapZToLayerName(currPoint.z, 2)
const locationKey = `${currPoint.x},${currPoint.y},${fromLayer},${toLayer}`
return vias
}

if (!viaLocations.has(locationKey)) {
vias.push({
type: "pcb_via",
pcb_via_id: `via_${vias.length}`,
x: currPoint.x,
y: currPoint.y,
outer_diameter: minViaDiameter,
hole_diameter: minViaDiameter * 0.5,
layers: [fromLayer, toLayer] as LayerName[],
})
viaLocations.add(locationKey)
}
}
}
function extractViasFromHdRoute(
route: HighDensityRoute,
pcbTraceId: string,
viaIdStart: number,
minViaDiameter = 0.6,
): { vias: PcbVia[]; nextViaId: number } {
const vias: PcbVia[] = []
let counter = viaIdStart
for (let i = 1; i < route.route.length; i++) {
const prevPoint = route.route[i - 1]
const currPoint = route.route[i]

if (
prevPoint.z !== currPoint.z &&
Math.abs(prevPoint.x - currPoint.x) < 0.01 &&
Math.abs(prevPoint.y - currPoint.y) < 0.01
) {
const fromLayer = mapZToLayerName(prevPoint.z, 2)
const toLayer = mapZToLayerName(currPoint.z, 2)
vias.push({
type: "pcb_via",
pcb_via_id: `via_${counter++}`,
pcb_trace_id: pcbTraceId,
x: currPoint.x,
y: currPoint.y,
outer_diameter: minViaDiameter,
hole_diameter: minViaDiameter * 0.5,
layers: [fromLayer, toLayer] as LayerName[],
})
}
}

return vias
return { vias, nextViaId: counter }
}

/**
Expand All @@ -267,15 +272,18 @@ export function convertToCircuitJson(
): AnyCircuitElement[] {
// Start with empty circuit JSON
const circuitJson: AnyCircuitElement[] = []
let viaCounter = 0

// Add source traces from connection information
circuitJson.push(...createSourceTraces(srjWithPointPairs, routes))

// Add PCB ports for connection points
circuitJson.push(...createPcbPorts(srjWithPointPairs))

// Extract and add vias as independent pcb_via elements
circuitJson.push(...extractViasFromRoutes(routes, minViaDiameter))
// Extract and add vias as independent pcb_via elements for simple traces
const preExtractedVias = extractViasFromRoutes(routes, minViaDiameter)
viaCounter += preExtractedVias.length
circuitJson.push(...preExtractedVias)

// Build a map of connection names to simplify lookups
const connectionMap = new Map<string, string>()
Expand All @@ -301,14 +309,23 @@ export function convertToCircuitJson(
// Handle HighDensityRoutes
;(routes as HighDensityRoute[]).forEach((route, index) => {
const connectionName = route.connectionName
const traceId = `trace_${index}`
circuitJson.push(
convertHdRouteToCircuitJson(
route,
`trace_${index}`,
traceId,
connectionMap.get(connectionName) || connectionName,
minTraceWidth,
) as AnyCircuitElement,
)
const { vias, nextViaId } = extractViasFromHdRoute(
route,
traceId,
viaCounter,
minViaDiameter,
)
viaCounter = nextViaId
circuitJson.push(...vias)
})
}
}
Expand Down
52 changes: 26 additions & 26 deletions tests/bugs/__snapshots__/repro01-highdensity-drc-failure.snap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 8 additions & 7 deletions tests/bugs/repro01-highdensity-drc-failure.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect } from "bun:test"
import { HyperSingleIntraNodeSolver } from "lib/solvers/HyperHighDensitySolver/HyperSingleIntraNodeSolver"
import { SingleTransitionCrossingRouteSolver } from "lib/solvers/HighDensitySolver/TwoRouteHighDensitySolver/SingleTransitionCrossingRouteSolver"
import { convertToCircuitJson } from "lib/testing/utils/convertToCircuitJson"
import { checkEachPcbTraceNonOverlapping } from "@tscircuit/checks"
import "graphics-debug/matcher"
Expand Down Expand Up @@ -40,16 +40,15 @@ function createSrjFromNode(node: any) {
}
}

test("cn11081 high density routing fails DRC", () => {
test("cn11081 single transition solver routes without DRC errors", () => {
const srj = createSrjFromNode(node)
const solver = new HyperSingleIntraNodeSolver({ nodeWithPortPoints })
const solver = new SingleTransitionCrossingRouteSolver({ nodeWithPortPoints })

solver.solve()

expect(solver.solved).toBe(true)

const winning = solver.supervisedSolvers?.find((s) => s.solver.solved)
const solverName = winning?.solver.constructor.name
const solverName = solver.constructor.name

// Convert routes to circuit json and run DRC
const circuitJson = convertToCircuitJson(
Expand All @@ -59,7 +58,9 @@ test("cn11081 high density routing fails DRC", () => {
)
const errors = checkEachPcbTraceNonOverlapping(circuitJson)

expect(errors.length).toBeGreaterThan(0)
expect(errors.length).toBe(0)
expect(solver.visualize()).toMatchGraphicsSvg(import.meta.path)
expect(solverName).toMatchInlineSnapshot(`"SingleTransitionCrossingRouteSolver"`)
expect(solverName).toMatchInlineSnapshot(
`"SingleTransitionCrossingRouteSolver"`,
)
})
Loading