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
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,27 @@
import type { GraphicsObject } from "graphics-debug"
import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
import type { InputProblem } from "lib/types/InputProblem"
import { AvailableNetOrientationSolver } from "../AvailableNetOrientationSolver/AvailableNetOrientationSolver"
import { Example28Solver } from "../Example28Solver/Example28Solver"
import { LongDistancePairSolver } from "../LongDistancePairSolver/LongDistancePairSolver"
import { MspConnectionPairSolver } from "../MspConnectionPairSolver/MspConnectionPairSolver"
import { NetLabelPlacementSolver } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
import { NetLabelTraceCollisionSolver } from "../NetLabelTraceCollisionSolver/NetLabelTraceCollisionSolver"
import {
SchematicTraceLinesSolver,
type SolvedTracePath,
} from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
import { TraceAnchoredNetLabelOverlapSolver } from "../TraceAnchoredNetLabelOverlapSolver/TraceAnchoredNetLabelOverlapSolver"
import { TraceCleanupSolver } from "../TraceCleanupSolver/TraceCleanupSolver"
import type { MergedNetLabelObstacleSolver } from "../TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver"
import { TraceLabelOverlapAvoidanceSolver } from "../TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver"
import { TraceOverlapShiftSolver } from "../TraceOverlapShiftSolver/TraceOverlapShiftSolver"
import { NetLabelPlacementSolver } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
import { TraceSegmentCombinerSolver } from "../TraceSegmentCombinerSolver/TraceSegmentCombinerSolver"
import { VccNetLabelCornerPlacementSolver } from "../VccNetLabelCornerPlacementSolver/VccNetLabelCornerPlacementSolver"
import { colorAvailableNetOrientationLabels } from "./colorAvailableNetOrientationLabels"
import { visualizeInputProblem } from "./visualizeInputProblem"
import { TraceLabelOverlapAvoidanceSolver } from "../TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver"
import { correctPinsInsideChips } from "./correctPinsInsideChip"
import { expandChipsToFitPins } from "./expandChipsToFitPins"
import { LongDistancePairSolver } from "../LongDistancePairSolver/LongDistancePairSolver"
import { MergedNetLabelObstacleSolver } from "../TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver"
import { TraceCleanupSolver } from "../TraceCleanupSolver/TraceCleanupSolver"
import { Example28Solver } from "../Example28Solver/Example28Solver"
import { AvailableNetOrientationSolver } from "../AvailableNetOrientationSolver/AvailableNetOrientationSolver"
import { VccNetLabelCornerPlacementSolver } from "../VccNetLabelCornerPlacementSolver/VccNetLabelCornerPlacementSolver"
import { TraceAnchoredNetLabelOverlapSolver } from "../TraceAnchoredNetLabelOverlapSolver/TraceAnchoredNetLabelOverlapSolver"
import { NetLabelTraceCollisionSolver } from "../NetLabelTraceCollisionSolver/NetLabelTraceCollisionSolver"
import { visualizeInputProblem } from "./visualizeInputProblem"

type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
solverName: string
Expand Down Expand Up @@ -70,6 +71,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
// guidelinesSolver?: GuidelinesSolver
schematicTraceLinesSolver?: SchematicTraceLinesSolver
longDistancePairSolver?: LongDistancePairSolver
traceSegmentCombinerSolver?: TraceSegmentCombinerSolver
traceOverlapShiftSolver?: TraceOverlapShiftSolver
netLabelPlacementSolver?: NetLabelPlacementSolver
labelMergingSolver?: MergedNetLabelObstacleSolver
Expand All @@ -94,7 +96,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
MspConnectionPairSolver,
() => [{ inputProblem: this.inputProblem }],
{
onSolved: (mspSolver) => {},
onSolved: (_mspSolver) => {},
},
),
// definePipelineStep(
Expand Down Expand Up @@ -136,17 +138,27 @@ export class SchematicTracePipelineSolver extends BaseSolver {
},
],
{
onSolved: (schematicTraceLinesSolver) => {},
onSolved: (_schematicTraceLinesSolver) => {},
},
),
definePipelineStep(
"traceSegmentCombinerSolver",
TraceSegmentCombinerSolver,
(instance) => [
{
inputProblem: instance.inputProblem,
allTraces:
instance.longDistancePairSolver!.getOutput().allTracesMerged,
},
],
),
definePipelineStep(
"traceOverlapShiftSolver",
TraceOverlapShiftSolver,
() => [
{
inputProblem: this.inputProblem,
inputTracePaths:
this.longDistancePairSolver?.getOutput().allTracesMerged!,
inputTracePaths: this.traceSegmentCombinerSolver!.getOutput().traces!,
globalConnMap: this.mspConnectionPairSolver!.globalConnMap,
},
],
Expand All @@ -163,9 +175,10 @@ export class SchematicTracePipelineSolver extends BaseSolver {
inputTraceMap:
this.traceOverlapShiftSolver?.correctedTraceMap ??
Object.fromEntries(
this.longDistancePairSolver!.getOutput().allTracesMerged.map(
(p) => [p.mspPairId, p],
),
this.traceSegmentCombinerSolver!.getOutput().traces.map((p) => [
p.mspPairId,
p,
]),
),
},
],
Expand All @@ -183,8 +196,8 @@ export class SchematicTracePipelineSolver extends BaseSolver {
instance.traceOverlapShiftSolver?.correctedTraceMap ??
Object.fromEntries(
instance
.longDistancePairSolver!.getOutput()
.allTracesMerged.map((p) => [p.mspPairId, p]),
.traceSegmentCombinerSolver!.getOutput()
.traces.map((p: SolvedTracePath) => [p.mspPairId, p]),
)
const traces = Object.values(traceMap)
const netLabelPlacements =
Expand Down Expand Up @@ -360,7 +373,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
}

const constructorParams = pipelineStepDef.getConstructorParams(this)
// @ts-ignore
// @ts-expect-error
this.activeSubSolver = new pipelineStepDef.solverClass(...constructorParams)
;(this as any)[pipelineStepDef.solverName] = this.activeSubSolver
this.timeSpentOnPhase[pipelineStepDef.solverName] = 0
Expand Down
151 changes: 151 additions & 0 deletions lib/solvers/TraceSegmentCombinerSolver/TraceSegmentCombinerSolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
import type { InputProblem } from "lib/types/InputProblem"
import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
import { visualizeInputProblem } from "../SchematicTracePipelineSolver/visualizeInputProblem"
import { simplifyPath } from "../TraceCleanupSolver/simplifyPath"

export interface TraceSegmentCombinerSolverParams {
inputProblem: InputProblem
allTraces: SolvedTracePath[]
}

export class TraceSegmentCombinerSolver extends BaseSolver {
inputProblem: InputProblem
allTraces: SolvedTracePath[]
outputTraces: SolvedTracePath[]

constructor(params: TraceSegmentCombinerSolverParams) {
super()
this.inputProblem = params.inputProblem
this.allTraces = params.allTraces
this.outputTraces = JSON.parse(JSON.stringify(params.allTraces))
}

override _step() {
this.combineSameNetTraces()
this.solved = true
}

private combineSameNetTraces() {
const EPS = 0.1001 // Distance threshold for "close together"
const netGroups: Record<string, SolvedTracePath[]> = {}

for (const trace of this.outputTraces) {
const netId = trace.globalConnNetId
if (!netGroups[netId]) netGroups[netId] = []
netGroups[netId].push(trace)
}

for (const netId in netGroups) {
const paths = netGroups[netId]!
if (paths.length < 2) continue

let changed = true
while (changed) {
changed = false
for (let i = 0; i < paths.length; i++) {
for (let j = 0; j < paths.length; j++) {
if (i === j) continue
if (this.tryCombinePaths(paths[i]!, paths[j]!, EPS)) {
changed = true
}
}
}
}
}

// Final simplification pass
for (const trace of this.outputTraces) {
trace.tracePath = simplifyPath(trace.tracePath)
}
}

private tryCombinePaths(
pathA: SolvedTracePath,
pathB: SolvedTracePath,
eps: number,
): boolean {
let changed = false
const ptsA = pathA.tracePath
const ptsB = pathB.tracePath

for (let i = 0; i < ptsA.length - 1; i++) {
const a1 = ptsA[i]!
const a2 = ptsA[i + 1]!
const aVert = Math.abs(a1.x - a2.x) < 1e-6
const aHorz = Math.abs(a1.y - a2.y) < 1e-6
if (!aVert && !aHorz) continue

for (let j = 0; j < ptsB.length - 1; j++) {
const b1 = ptsB[j]!
const b2 = ptsB[j + 1]!
const bVert = Math.abs(b1.x - b2.x) < 1e-6
const bHorz = Math.abs(b1.y - b2.y) < 1e-6
if (!bVert && !bHorz) continue

if (aVert && bVert) {
// Both vertical, check if they are close in X and overlap in Y
const dx = Math.abs(a1.x - b1.x)
if (dx > 0 && dx < eps) {
if (this.segmentsOverlap1D(a1.y, a2.y, b1.y, b2.y)) {
// Snap B's segments to A's X
this.snapSegmentX(pathB, j, a1.x)
changed = true
}
}
} else if (aHorz && bHorz) {
// Both horizontal, check if they are close in Y and overlap in X
const dy = Math.abs(a1.y - b1.y)
if (dy > 0 && dy < eps) {
if (this.segmentsOverlap1D(a1.x, a2.x, b1.x, b2.x)) {
// Snap B's segments to A's Y
this.snapSegmentY(pathB, j, a1.y)
changed = true
}
}
}
}
}
return changed
}

private segmentsOverlap1D(
a1: number,
a2: number,
b1: number,
b2: number,
): boolean {
const minA = Math.min(a1, a2)
const maxA = Math.max(a1, a2)
const minB = Math.min(b1, b2)
const maxB = Math.max(b1, b2)
return Math.max(minA, minB) < Math.min(maxA, maxB) - 1e-6
}

private snapSegmentX(path: SolvedTracePath, segIdx: number, newX: number) {
path.tracePath[segIdx]!.x = newX
path.tracePath[segIdx + 1]!.x = newX
}

private snapSegmentY(path: SolvedTracePath, segIdx: number, newY: number) {
path.tracePath[segIdx]!.y = newY
path.tracePath[segIdx + 1]!.y = newY
}

getOutput() {
return {
traces: this.outputTraces,
}
}

override visualize() {
const graphics = visualizeInputProblem(this.inputProblem)
for (const trace of this.outputTraces) {
graphics.lines!.push({
points: trace.tracePath,
strokeColor: "blue",
})
}
return graphics
}
}
Loading
Loading