11import { BaseSolver } from "@tscircuit/solver-utils"
22import type { GraphicsObject } from "graphics-debug"
3- import type { CapacityMeshNode } from "../.. /types/capacity-mesh-types"
3+ import type { CapacityMeshNode , RTreeRect } from "lib /types/capacity-mesh-types"
44import { expandRectFromSeed } from "../../utils/expandRectFromSeed"
55import { finalizeRects } from "../../utils/finalizeRects"
66import { allLayerNode } from "../../utils/buildHardPlacedByLayer"
77import { resizeSoftOverlaps } from "../../utils/resizeSoftOverlaps"
88import { rectsToMeshNodes } from "./rectsToMeshNodes"
99import type { XYRect , Candidate3D , Placed3D } from "../../rectdiff-types"
10- import type { SimpleRouteJson } from "../../types/srj-types"
10+ import type { SimpleRouteJson } from "lib/types/srj-types"
11+ import {
12+ buildZIndexMap ,
13+ obstacleToXYRect ,
14+ obstacleZs ,
15+ } from "../RectDiffSeedingSolver/layers"
16+ import RBush from "rbush"
17+ import { rectToTree } from "../../utils/rectToTree"
18+ import { sameTreeRect } from "../../utils/sameTreeRect"
1119
1220export type RectDiffExpansionSolverSnapshot = {
1321 srj : SimpleRouteJson
@@ -19,12 +27,10 @@ export type RectDiffExpansionSolverSnapshot = {
1927 // the engine only uses gridSizes here, other options are ignored
2028 [ key : string ] : any
2129 }
22- obstaclesByLayer : XYRect [ ] [ ]
2330 boardVoidRects : XYRect [ ]
2431 gridIndex : number
2532 candidates : Candidate3D [ ]
2633 placed : Placed3D [ ]
27- placedByLayer : XYRect [ ] [ ]
2834 expansionIndex : number
2935 edgeAnalysisDone : boolean
3036 totalSeedsThisGrid : number
@@ -33,6 +39,7 @@ export type RectDiffExpansionSolverSnapshot = {
3339
3440export type RectDiffExpansionSolverInput = {
3541 initialSnapshot : RectDiffExpansionSolverSnapshot
42+ obstacleIndexByLayer : Array < RBush < RTreeRect > >
3643}
3744
3845/**
@@ -52,12 +59,11 @@ export class RectDiffExpansionSolver extends BaseSolver {
5259 // the engine only uses gridSizes here, other options are ignored
5360 [ key : string ] : any
5461 }
55- private obstaclesByLayer ! : XYRect [ ] [ ]
5662 private boardVoidRects ! : XYRect [ ]
5763 private gridIndex ! : number
5864 private candidates ! : Candidate3D [ ]
5965 private placed ! : Placed3D [ ]
60- private placedByLayer ! : XYRect [ ] [ ]
66+ private placedIndexByLayer ! : Array < RBush < RTreeRect > >
6167 private expansionIndex ! : number
6268 private edgeAnalysisDone ! : boolean
6369 private totalSeedsThisGrid ! : number
@@ -75,6 +81,44 @@ export class RectDiffExpansionSolver extends BaseSolver {
7581 this . stats = {
7682 gridIndex : this . gridIndex ,
7783 }
84+
85+ if ( this . input . obstacleIndexByLayer ) {
86+ } else {
87+ const { zIndexByName } = buildZIndexMap ( this . srj )
88+ this . input . obstacleIndexByLayer = Array . from (
89+ { length : this . layerCount } ,
90+ ( ) => new RBush < RTreeRect > ( ) ,
91+ )
92+ const insertObstacle = ( rect : XYRect , z : number ) => {
93+ const tree = this . input . obstacleIndexByLayer [ z ]
94+ if ( tree ) tree . insert ( rectToTree ( rect ) )
95+ }
96+ for ( const voidRect of this . boardVoidRects ?? [ ] ) {
97+ for ( let z = 0 ; z < this . layerCount ; z ++ ) insertObstacle ( voidRect , z )
98+ }
99+ for ( const obstacle of this . srj . obstacles ?? [ ] ) {
100+ const rect = obstacleToXYRect ( obstacle as any )
101+ if ( ! rect ) continue
102+ const zLayers =
103+ obstacle . zLayers ?. length && obstacle . zLayers . length > 0
104+ ? obstacle . zLayers
105+ : obstacleZs ( obstacle as any , zIndexByName )
106+ zLayers . forEach ( ( z ) => {
107+ if ( z >= 0 && z < this . layerCount ) insertObstacle ( rect , z )
108+ } )
109+ }
110+ }
111+
112+ this . placedIndexByLayer = Array . from (
113+ { length : this . layerCount } ,
114+ ( ) => new RBush < RTreeRect > ( ) ,
115+ )
116+ for ( const placement of this . placed ?? [ ] ) {
117+ for ( const z of placement . zLayers ) {
118+ const tree = this . placedIndexByLayer [ z ]
119+ if ( tree ) tree . insert ( rectToTree ( placement . rect ) )
120+ }
121+ }
78122 }
79123
80124 override _step ( ) {
@@ -107,7 +151,8 @@ export class RectDiffExpansionSolver extends BaseSolver {
107151 // HARD blockers only: obstacles on p.zLayers + full-stack nodes
108152 const hardBlockers : XYRect [ ] = [ ]
109153 for ( const z of p . zLayers ) {
110- hardBlockers . push ( ...( this . obstaclesByLayer [ z ] ?? [ ] ) )
154+ const obstacleTree = this . input . obstacleIndexByLayer [ z ]
155+ if ( obstacleTree ) hardBlockers . push ( ...obstacleTree . all ( ) )
111156 hardBlockers . push ( ...( hardPlacedByLayer [ z ] ?? [ ] ) )
112157 }
113158
@@ -127,18 +172,20 @@ export class RectDiffExpansionSolver extends BaseSolver {
127172 // Update placement + per-layer index (replace old rect object)
128173 this . placed [ idx ] = { rect : expanded , zLayers : p . zLayers }
129174 for ( const z of p . zLayers ) {
130- const arr = this . placedByLayer [ z ] !
131- const j = arr . findIndex ( ( r ) => r === oldRect )
132- if ( j >= 0 ) arr [ j ] = expanded
175+ const tree = this . placedIndexByLayer [ z ]
176+ if ( tree ) {
177+ tree . remove ( rectToTree ( oldRect ) , sameTreeRect )
178+ tree . insert ( rectToTree ( expanded ) )
179+ }
133180 }
134181
135182 // Carve overlapped soft neighbors (respect full-stack nodes)
136183 resizeSoftOverlaps (
137184 {
138185 layerCount : this . layerCount ,
139186 placed : this . placed ,
140- placedByLayer : this . placedByLayer ,
141187 options : this . options ,
188+ placedIndexByLayer : this . placedIndexByLayer ,
142189 } ,
143190 idx ,
144191 )
@@ -152,7 +199,7 @@ export class RectDiffExpansionSolver extends BaseSolver {
152199
153200 const rects = finalizeRects ( {
154201 placed : this . placed ,
155- obstaclesByLayer : this . obstaclesByLayer ,
202+ srj : this . srj ,
156203 boardVoidRects : this . boardVoidRects ,
157204 } )
158205 this . _meshNodes = rectsToMeshNodes ( rects )
0 commit comments