From fbe8e618d1c7bf2eaa82980832015e9ef1ee9224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?0hm=E2=98=98=EF=B8=8F?= Date: Sat, 27 Dec 2025 00:49:27 +0530 Subject: [PATCH] fix regression soft nodes were treated as blockers they should not be --- .../RectDiffExpansionSolver.ts | 9 ++++--- .../buildObstacleIndexes.ts | 3 ++- .../RectDiffSeedingSolver.ts | 9 ++----- lib/types/capacity-mesh-types.ts | 1 + lib/utils/expandRectFromSeed.ts | 3 +++ lib/utils/rectToTree.ts | 6 ++++- lib/utils/resizeSoftOverlaps.ts | 24 +++++++------------ .../rectDiffGridSolverPipeline.snap.svg | 6 ++--- 8 files changed, 30 insertions(+), 31 deletions(-) diff --git a/lib/solvers/RectDiffExpansionSolver/RectDiffExpansionSolver.ts b/lib/solvers/RectDiffExpansionSolver/RectDiffExpansionSolver.ts index 61543aa..115b151 100644 --- a/lib/solvers/RectDiffExpansionSolver/RectDiffExpansionSolver.ts +++ b/lib/solvers/RectDiffExpansionSolver/RectDiffExpansionSolver.ts @@ -56,7 +56,10 @@ export class RectDiffExpansionSolver extends BaseSolver { for (const placement of this.input.placed) { for (const z of placement.zLayers) { const placedIndex = this.placedIndexByLayer[z] - if (placedIndex) placedIndex.insert(rectToTree(placement.rect)) + if (placedIndex) + placedIndex.insert( + rectToTree(placement.rect, { zLayers: placement.zLayers }), + ) } } } @@ -104,8 +107,8 @@ export class RectDiffExpansionSolver extends BaseSolver { for (const z of p.zLayers) { const tree = this.placedIndexByLayer[z] if (tree) { - tree.remove(rectToTree(oldRect), sameTreeRect) - tree.insert(rectToTree(expanded)) + tree.remove(rectToTree(oldRect, { zLayers: p.zLayers }), sameTreeRect) + tree.insert(rectToTree(expanded, { zLayers: p.zLayers })) } } diff --git a/lib/solvers/RectDiffGridSolverPipeline/buildObstacleIndexes.ts b/lib/solvers/RectDiffGridSolverPipeline/buildObstacleIndexes.ts index 170bdd9..1191057 100644 --- a/lib/solvers/RectDiffGridSolverPipeline/buildObstacleIndexes.ts +++ b/lib/solvers/RectDiffGridSolverPipeline/buildObstacleIndexes.ts @@ -30,12 +30,13 @@ export const buildObstacleIndexesByLayer = (params: { ) const insertObstacle = (rect: XYRect, z: number) => { - const treeRect = { + const treeRect: RTreeRect = { ...rect, minX: rect.x, minY: rect.y, maxX: rect.x + rect.width, maxY: rect.y + rect.height, + zLayers: [z], } obstacleIndexByLayer[z]?.insert(treeRect) } diff --git a/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts b/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts index 585e01a..2c79ef7 100644 --- a/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts +++ b/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts @@ -21,6 +21,7 @@ import { resizeSoftOverlaps } from "../../utils/resizeSoftOverlaps" import { getColorForZLayer } from "lib/utils/getColorForZLayer" import RBush from "rbush" import type { RTreeRect } from "lib/types/capacity-mesh-types" +import { rectToTree } from "lib/utils/rectToTree" export type RectDiffSeedingSolverInput = { simpleRouteJson: SimpleRouteJson @@ -258,13 +259,7 @@ export class RectDiffSeedingSolver extends BaseSolver { for (const z of attempt.layers) { const idx = this.placedIndexByLayer[z] if (idx) { - idx.insert({ - ...rect, - minX: rect.x, - minY: rect.y, - maxX: rect.x + rect.width, - maxY: rect.y + rect.height, - }) + idx.insert(rectToTree(rect, { zLayers: placed.zLayers })) } } diff --git a/lib/types/capacity-mesh-types.ts b/lib/types/capacity-mesh-types.ts index 02073b4..2beae8b 100644 --- a/lib/types/capacity-mesh-types.ts +++ b/lib/types/capacity-mesh-types.ts @@ -39,4 +39,5 @@ export type RTreeRect = XYRect & { minY: number maxX: number maxY: number + zLayers: number[] } diff --git a/lib/utils/expandRectFromSeed.ts b/lib/utils/expandRectFromSeed.ts index 25aa3c1..c8ecfb7 100644 --- a/lib/utils/expandRectFromSeed.ts +++ b/lib/utils/expandRectFromSeed.ts @@ -216,6 +216,7 @@ export function expandRectFromSeed(params: { const initialH = Math.max(minSide, minReq.height) const blockers: XYRect[] = [] const seen = new Set() + const totalLayers = placedIndexByLayer.length // Ignore the existing placement we are expanding so it doesn't self-block. @@ -232,6 +233,8 @@ export function expandRectFromSeed(params: { const placedLayer = placedIndexByLayer[z] if (placedLayer) { for (const entry of placedLayer.search(query)) { + const isFullStack = entry.zLayers.length >= totalLayers + if (!isFullStack) continue const rect = toRect(entry) if ( isSelfRect({ diff --git a/lib/utils/rectToTree.ts b/lib/utils/rectToTree.ts index 959ded4..e191a6c 100644 --- a/lib/utils/rectToTree.ts +++ b/lib/utils/rectToTree.ts @@ -1,10 +1,14 @@ import type { XYRect } from "lib/rectdiff-types" import type { RTreeRect } from "lib/types/capacity-mesh-types" -export const rectToTree = (rect: XYRect): RTreeRect => ({ +export const rectToTree = ( + rect: XYRect, + opts: { zLayers: number[] }, +): RTreeRect => ({ ...rect, minX: rect.x, minY: rect.y, maxX: rect.x + rect.width, maxY: rect.y + rect.height, + zLayers: opts.zLayers, }) diff --git a/lib/utils/resizeSoftOverlaps.ts b/lib/utils/resizeSoftOverlaps.ts index adcdf26..ce52ad5 100644 --- a/lib/utils/resizeSoftOverlaps.ts +++ b/lib/utils/resizeSoftOverlaps.ts @@ -1,7 +1,8 @@ import type { RTreeRect } from "lib/types/capacity-mesh-types" -import type { Placed3D, XYRect } from "../rectdiff-types" +import type { Placed3D } from "../rectdiff-types" import { overlaps, subtractRect2D, EPS } from "./rectdiff-geometry" import type RBush from "rbush" +import { rectToTree } from "./rectToTree" export function resizeSoftOverlaps( params: { @@ -57,13 +58,6 @@ export function resizeSoftOverlaps( } // Remove fully overlapped nodes and keep indexes in sync - const rectToTree = (rect: XYRect): RTreeRect => ({ - ...rect, - minX: rect.x, - minY: rect.y, - maxX: rect.x + rect.width, - maxY: rect.y + rect.height, - }) const sameRect = (a: RTreeRect, b: RTreeRect) => a.minX === b.minX && a.minY === b.minY && @@ -77,7 +71,11 @@ export function resizeSoftOverlaps( if (params.placedIndexByLayer) { for (const z of rem.zLayers) { const tree = params.placedIndexByLayer[z] - if (tree) tree.remove(rectToTree(rem.rect), sameRect) + if (tree) + tree.remove( + rectToTree(rem.rect, { zLayers: rem.zLayers }), + sameRect, + ) } } }) @@ -89,13 +87,7 @@ export function resizeSoftOverlaps( if (params.placedIndexByLayer) { const idx = params.placedIndexByLayer[z] if (idx) { - idx.insert({ - ...p.rect, - minX: p.rect.x, - minY: p.rect.y, - maxX: p.rect.x + p.rect.width, - maxY: p.rect.y + p.rect.height, - }) + idx.insert(rectToTree(p.rect, { zLayers: p.zLayers.slice() })) } } } diff --git a/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg b/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg index a74ec2b..5fa1f1f 100644 --- a/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg +++ b/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg @@ -1,4 +1,4 @@ -Layer z=0Layer z=1Layer z=2Layer z=3