diff --git a/bun.lock b/bun.lock index 0dab289f..cd2c69df 100644 --- a/bun.lock +++ b/bun.lock @@ -24,7 +24,7 @@ "@types/react-dom": "^19.0.3", "@vercel/node": "^5.1.7", "@vitejs/plugin-react": "^4.3.4", - "bun-match-svg": "^0.0.9", + "bun-match-svg": "^0.0.12", "circuit-json-to-connectivity-map": "^0.0.19", "circuit-to-svg": "^0.0.110", "clsx": "^2.1.1", @@ -487,7 +487,7 @@ "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - "bun-match-svg": ["bun-match-svg@0.0.9", "", { "dependencies": { "looks-same": "^9.0.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "bin": { "bun-match-svg": "cli.ts" } }, "sha512-WISE8cUd3ztIEbYRymuxs+l4qwRviHIhyRQHmDz26vnhKON9g+Ur+2L3pfJrffpGiYWGF/jtWoWmYRQiaimTxg=="], + "bun-match-svg": ["bun-match-svg@0.0.12", "", { "dependencies": { "looks-same": "^9.0.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "bin": { "bun-match-svg": "cli.ts" } }, "sha512-qjQtTwRvuqGDe8xza1OEm3OMA4bUEuFDl4i4y1vH9GwdEegqB9x1/H5+AjoRwQUcMmt5kP9bfPdplkBWxmlfWg=="], "bun-types": ["bun-types@1.2.16", "", { "dependencies": { "@types/node": "*" } }, "sha512-ciXLrHV4PXax9vHvUrkvun9VPVGOVwbbbBF/Ev1cXz12lyEZMoJpIJABOfPcN9gDJRaiKF9MVbSygLg4NXu3/A=="], diff --git a/lib/solvers/HighDensitySolver/IntraNodeSolver.ts b/lib/solvers/HighDensitySolver/IntraNodeSolver.ts index 5b3012ea..2b8ae54e 100644 --- a/lib/solvers/HighDensitySolver/IntraNodeSolver.ts +++ b/lib/solvers/HighDensitySolver/IntraNodeSolver.ts @@ -192,7 +192,7 @@ export class IntraNodeRouteSolver extends BaseSolver { ) : this.solvedRoutes, futureConnections: this.unsolvedConnections, - layerCount: 2, + layerCount: this.nodeWithPortPoints.availableZ?.length ?? 2, hyperParameters: this.hyperParameters, connMap: this.connMap, }) diff --git a/lib/solvers/HighDensitySolver/SingleHighDensityRouteSolver.ts b/lib/solvers/HighDensitySolver/SingleHighDensityRouteSolver.ts index 4593549e..0269557a 100644 --- a/lib/solvers/HighDensitySolver/SingleHighDensityRouteSolver.ts +++ b/lib/solvers/HighDensitySolver/SingleHighDensityRouteSolver.ts @@ -282,7 +282,7 @@ export class SingleHighDensityRouteSolver extends BaseSolver { computeG(node: Node) { return ( (node.parent?.g ?? 0) + - (node.z === 0 ? 0 : this.viaPenaltyDistance) + + (node.parent && node.z !== node.parent.z ? this.viaPenaltyDistance : 0) + distance(node, node.parent!) ) } @@ -342,26 +342,23 @@ export class SingleHighDensityRouteSolver extends BaseSolver { } } - const viaNeighbor = { - ...node, - parent: node, - z: node.z === 0 ? this.layerCount - 1 : 0, - } - - if ( - !this.exploredNodes.has(this.getNodeKey(viaNeighbor)) && - !this.isNodeTooCloseToObstacle( - viaNeighbor, - this.viaDiameter / 2 + this.obstacleMargin / 2, - true, - ) && - !this.isNodeTooCloseToEdge(viaNeighbor, true) - ) { - viaNeighbor.g = this.computeG(viaNeighbor) - viaNeighbor.h = this.computeH(viaNeighbor) - viaNeighbor.f = this.computeF(viaNeighbor.g, viaNeighbor.h) - - neighbors.push(viaNeighbor) + for (let z = 0; z < this.layerCount; z++) { + if (z === node.z) continue + const viaNeighbor = { ...node, parent: node, z } + if ( + !this.exploredNodes.has(this.getNodeKey(viaNeighbor)) && + !this.isNodeTooCloseToObstacle( + viaNeighbor, + this.viaDiameter / 2 + this.obstacleMargin / 2, + true, + ) && + !this.isNodeTooCloseToEdge(viaNeighbor, true) + ) { + viaNeighbor.g = this.computeG(viaNeighbor) + viaNeighbor.h = this.computeH(viaNeighbor) + viaNeighbor.f = this.computeF(viaNeighbor.g, viaNeighbor.h) + neighbors.push(viaNeighbor) + } } return neighbors diff --git a/package.json b/package.json index df6b8909..ac6f0664 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@types/react-dom": "^19.0.3", "@vercel/node": "^5.1.7", "@vitejs/plugin-react": "^4.3.4", - "bun-match-svg": "^0.0.9", + "bun-match-svg": "^0.0.12", "circuit-json-to-connectivity-map": "^0.0.19", "circuit-to-svg": "^0.0.110", "clsx": "^2.1.1", diff --git a/tests/__snapshots__/e2e-4layer.snap.svg b/tests/__snapshots__/e2e-4layer.snap.svg new file mode 100644 index 00000000..83aa978e --- /dev/null +++ b/tests/__snapshots__/e2e-4layer.snap.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/e2e-4layer.test.ts b/tests/e2e-4layer.test.ts new file mode 100644 index 00000000..91b6f869 --- /dev/null +++ b/tests/e2e-4layer.test.ts @@ -0,0 +1,14 @@ +import { expect, test } from "bun:test" +import { CapacityMeshSolver } from "../lib" +import type { SimpleRouteJson } from "../lib/types" +import srj from "./fixtures/simple-4layer.json" +import { convertSrjToGraphicsObject } from "./fixtures/convertSrjToGraphicsObject" + +test("should solve 4 layer board", async () => { + const solver = new CapacityMeshSolver(srj as SimpleRouteJson) + await solver.solve() + const result = solver.getOutputSimpleRouteJson() + expect(convertSrjToGraphicsObject(result)).toMatchGraphicsSvg( + import.meta.path, + ) +}) diff --git a/tests/fixtures/convertSrjToGraphicsObject.ts b/tests/fixtures/convertSrjToGraphicsObject.ts index eb27b16b..8df0ff45 100644 --- a/tests/fixtures/convertSrjToGraphicsObject.ts +++ b/tests/fixtures/convertSrjToGraphicsObject.ts @@ -10,7 +10,7 @@ export const convertSrjToGraphicsObject = (srj: SimpleRouteJson) => { const points: Point[] = [] const colorMap: Record = getColorMap(srj) - const layerCount = 2 + const layerCount = srj.layerCount ?? 2 // Add points for each connection's pointsToConnect if (srj.connections) { @@ -45,7 +45,7 @@ export const convertSrjToGraphicsObject = (srj: SimpleRouteJson) => { radius: 0.3, // 0.6 via diameter fill: "blue", stroke: "none", - layer: "z0,1", + layer: `z${mapLayerNameToZ(routePoint.from_layer!, layerCount)},${mapLayerNameToZ(routePoint.to_layer!, layerCount)}`, }) } else if ( routePoint.route_type === "wire" && diff --git a/tests/fixtures/simple-4layer.json b/tests/fixtures/simple-4layer.json new file mode 100644 index 00000000..a42afd38 --- /dev/null +++ b/tests/fixtures/simple-4layer.json @@ -0,0 +1,31 @@ +{ + "layerCount": 4, + "minTraceWidth": 0.15, + "obstacles": [ + { + "type": "rect", + "layers": ["top"], + "center": { "x": 5, "y": 5 }, + "width": 1, + "height": 1, + "connectedTo": [] + } + ], + "connections": [ + { + "name": "conn1", + "pointsToConnect": [ + { "x": 2, "y": 2, "layer": "top" }, + { "x": 8, "y": 2, "layer": "inner1" } + ] + }, + { + "name": "conn2", + "pointsToConnect": [ + { "x": 2, "y": 8, "layer": "top" }, + { "x": 8, "y": 8, "layer": "bottom" } + ] + } + ], + "bounds": { "minX": 0, "maxX": 10, "minY": 0, "maxY": 10 } +}