|
| 1 | +import * as dataset01 from "@tscircuit/autorouting-dataset-01" |
| 2 | +import { AutoroutingPipelineSolver3_HgPortPointPathing } from "../lib/autorouter-pipelines/AutoroutingPipeline2_PortPointPathing/AutoroutingPipelineSolver3_HgPortPointPathing" |
| 3 | + |
| 4 | +type Point2D = { x: number; y: number } |
| 5 | + |
| 6 | +type RoutePoint = Point2D & { z?: number; layer?: string; route_type?: string } |
| 7 | + |
| 8 | +const EPS = 1e-6 |
| 9 | + |
| 10 | +const distance = (a: Point2D, b: Point2D) => Math.hypot(a.x - b.x, a.y - b.y) |
| 11 | + |
| 12 | +const triangleArea2 = (a: Point2D, b: Point2D, c: Point2D) => |
| 13 | + Math.abs((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) |
| 14 | + |
| 15 | +const describePoint = (p: RoutePoint) => |
| 16 | + `(${p.x.toFixed(6)}, ${p.y.toFixed(6)}${typeof p.z === "number" ? `, z=${p.z}` : ""}${p.layer ? `, layer=${p.layer}` : ""})` |
| 17 | + |
| 18 | +const srj = dataset01.circuit011 |
| 19 | +const solver = new AutoroutingPipelineSolver3_HgPortPointPathing(srj) |
| 20 | +solver.solve() |
| 21 | + |
| 22 | +console.log("=== dataset01 / circuit011 / Solver3 debug ===") |
| 23 | +console.log("trace count:", solver.getOutputSimpleRouteJson().traces.length) |
| 24 | + |
| 25 | +const node25 = solver.capacityNodes?.find((n) => n.capacityMeshNodeId === "cmn_25") |
| 26 | +if (!node25) { |
| 27 | + console.log("cmn_25 not found in capacity nodes") |
| 28 | + process.exit(0) |
| 29 | +} |
| 30 | + |
| 31 | +const node25Bounds = { |
| 32 | + minX: node25.center.x - node25.width / 2, |
| 33 | + maxX: node25.center.x + node25.width / 2, |
| 34 | + minY: node25.center.y - node25.height / 2, |
| 35 | + maxY: node25.center.y + node25.height / 2, |
| 36 | +} |
| 37 | + |
| 38 | +console.log("cmn_25 bounds:", node25Bounds) |
| 39 | + |
| 40 | +const solvedRoutes = solver.portPointPathingSolver?.solvedRoutes ?? [] |
| 41 | +const routesThrough25 = solvedRoutes.filter((route) => |
| 42 | + route.path.some((step) => step.nextRegion?.regionId === "cmn_25"), |
| 43 | +) |
| 44 | + |
| 45 | +console.log("connections whose hypergraph path traverses cmn_25:") |
| 46 | +for (const route of routesThrough25) { |
| 47 | + const name = route.connection.simpleRouteConnection.name |
| 48 | + const regionPath = route.path |
| 49 | + .map((step) => step.nextRegion?.regionId) |
| 50 | + .filter(Boolean) |
| 51 | + .join(" -> ") |
| 52 | + console.log(`- ${name}: ${regionPath}`) |
| 53 | +} |
| 54 | + |
| 55 | +const traces = solver.getOutputSimpleRouteJson().traces |
| 56 | + |
| 57 | +const tinyTriangleCandidates: Array<{ |
| 58 | + traceId: string |
| 59 | + index: number |
| 60 | + points: [RoutePoint, RoutePoint, RoutePoint] |
| 61 | + chordLength: number |
| 62 | + area2: number |
| 63 | +}> = [] |
| 64 | + |
| 65 | +for (const trace of traces) { |
| 66 | + const wirePoints = trace.route.filter((p) => p.route_type === "wire") as RoutePoint[] |
| 67 | + |
| 68 | + for (let i = 0; i < wirePoints.length - 2; i++) { |
| 69 | + const a = wirePoints[i] |
| 70 | + const b = wirePoints[i + 1] |
| 71 | + const c = wirePoints[i + 2] |
| 72 | + |
| 73 | + const chordLength = distance(a, c) |
| 74 | + const area2 = triangleArea2(a, b, c) |
| 75 | + |
| 76 | + const hasSmallDetour = chordLength < 0.08 && area2 > EPS |
| 77 | + if (hasSmallDetour) { |
| 78 | + tinyTriangleCandidates.push({ |
| 79 | + traceId: trace.pcb_trace_id, |
| 80 | + index: i, |
| 81 | + points: [a, b, c], |
| 82 | + chordLength, |
| 83 | + area2, |
| 84 | + }) |
| 85 | + } |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +console.log("tiny triangle candidates in final simplified traces:", tinyTriangleCandidates.length) |
| 90 | +for (const candidate of tinyTriangleCandidates) { |
| 91 | + const [a, b, c] = candidate.points |
| 92 | + console.log( |
| 93 | + `- ${candidate.traceId} at i=${candidate.index}, chord=${candidate.chordLength.toFixed(6)}, area2=${candidate.area2.toExponential(2)}`, |
| 94 | + ) |
| 95 | + console.log(` a=${describePoint(a)}`) |
| 96 | + console.log(` b=${describePoint(b)}`) |
| 97 | + console.log(` c=${describePoint(c)}`) |
| 98 | +} |
| 99 | + |
| 100 | +// Determine at which stage the most obvious kink appears. |
| 101 | +const target = { x: 0.75, y: -4.205 } |
| 102 | +const stageRoutes: Array<[string, Array<{ connectionName: string; route: RoutePoint[] }>]> = [ |
| 103 | + ["highDensityRouteSolver", solver.highDensityRouteSolver?.routes ?? []], |
| 104 | + ["highDensityStitchSolver", solver.highDensityStitchSolver?.mergedHdRoutes ?? []], |
| 105 | + ["traceSimplificationSolver", solver.traceSimplificationSolver?.simplifiedHdRoutes ?? []], |
| 106 | + ["traceWidthSolver", solver.traceWidthSolver?.getHdRoutesWithWidths() ?? []], |
| 107 | +] |
| 108 | + |
| 109 | +console.log("stage presence of kink point (0.75, -4.205):") |
| 110 | +for (const [stageName, routes] of stageRoutes) { |
| 111 | + const hits = routes.filter((route) => |
| 112 | + route.route.some( |
| 113 | + (point) => Math.abs(point.x - target.x) < EPS && Math.abs(point.y - target.y) < EPS, |
| 114 | + ), |
| 115 | + ) |
| 116 | + console.log(`- ${stageName}: ${hits.length} route(s)`) |
| 117 | + for (const hit of hits) { |
| 118 | + console.log(` -> ${hit.connectionName}`) |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +console.log("Conclusion: the detour is already present in raw intra-node output from highDensityRouteSolver, not introduced by later stitching/simplification.") |
0 commit comments