@@ -19,6 +19,7 @@ import {
1919 findUncoveredPoints ,
2020 calculateCoverage ,
2121} from "./rectdiff/gapfill/engine"
22+ import { EdgeExpansionGapFillSubSolver } from "./rectdiff/subsolvers/EdgeExpansionGapFillSubSolver"
2223
2324/**
2425 * A streaming, one-step-per-iteration solver for capacity mesh generation.
@@ -28,6 +29,7 @@ export class RectDiffSolver extends BaseSolver {
2829 private gridOptions : Partial < GridFill3DOptions >
2930 private state ! : RectDiffState
3031 private _meshNodes : CapacityMeshNode [ ] = [ ]
32+ private gapFillSubSolver ?: EdgeExpansionGapFillSubSolver
3133
3234 constructor ( opts : {
3335 simpleRouteJson : SimpleRouteJson
@@ -53,7 +55,44 @@ export class RectDiffSolver extends BaseSolver {
5355 } else if ( this . state . phase === "EXPANSION" ) {
5456 stepExpansion ( this . state )
5557 } else if ( this . state . phase === "GAP_FILL" ) {
56- this . state . phase = "DONE"
58+ // Initialize gap fill subsolver on first entry
59+ if ( ! this . gapFillSubSolver ) {
60+ this . gapFillSubSolver = new EdgeExpansionGapFillSubSolver ( {
61+ bounds : this . state . bounds ,
62+ layerCount : this . state . layerCount ,
63+ obstacles : this . state . obstaclesByLayer ,
64+ existingPlaced : this . state . placed ,
65+ existingPlacedByLayer : this . state . placedByLayer ,
66+ options : {
67+ minSingle : this . state . options . minSingle ,
68+ minMulti : this . state . options . minMulti ,
69+ maxAspectRatio : this . state . options . maxAspectRatio ,
70+ maxMultiLayerSpan : this . state . options . maxMultiLayerSpan ,
71+ } ,
72+ } )
73+ this . gapFillSubSolver . setup ( )
74+ }
75+
76+ // Step the subsolver
77+ if ( ! this . gapFillSubSolver . solved ) {
78+ this . gapFillSubSolver . step ( )
79+ } else {
80+ // Merge gap-fill results into main state
81+ const gapFillOutput = this . gapFillSubSolver . getOutput ( )
82+ this . state . placed . push ( ...gapFillOutput . newPlaced )
83+
84+ // Update placedByLayer
85+ for ( const placed of gapFillOutput . newPlaced ) {
86+ for ( const z of placed . zLayers ) {
87+ if ( ! this . state . placedByLayer [ z ] ) {
88+ this . state . placedByLayer [ z ] = [ ]
89+ }
90+ this . state . placedByLayer [ z ] ! . push ( placed . rect )
91+ }
92+ }
93+
94+ this . state . phase = "DONE"
95+ }
5796 } else if ( this . state . phase === "DONE" ) {
5897 // Finalize once
5998 if ( ! this . solved ) {
@@ -75,7 +114,18 @@ export class RectDiffSolver extends BaseSolver {
75114 if ( this . solved || this . state . phase === "DONE" ) {
76115 return 1
77116 }
78- return computeProgress ( this . state )
117+
118+ const baseProgress = computeProgress ( this . state )
119+
120+ // If in GAP_FILL phase, factor in subsolver progress
121+ if ( this . state . phase === "GAP_FILL" && this . gapFillSubSolver ) {
122+ const gapFillProgress = this . gapFillSubSolver . computeProgress ( )
123+ // GAP_FILL is the last phase before DONE, so weight it appropriately
124+ // Assume GRID+EXPANSION is 90%, GAP_FILL is remaining 10%
125+ return 0.9 + gapFillProgress * 0.1
126+ }
127+
128+ return baseProgress * 0.9 // Scale down to leave room for GAP_FILL
79129 }
80130
81131 override getOutput ( ) : { meshNodes : CapacityMeshNode [ ] } {
@@ -129,6 +179,11 @@ export class RectDiffSolver extends BaseSolver {
129179
130180 /** Streaming visualization: board + obstacles + current placements. */
131181 override visualize ( ) : GraphicsObject {
182+ // If in GAP_FILL phase, delegate to subsolver visualization
183+ if ( this . state ?. phase === "GAP_FILL" && this . gapFillSubSolver ) {
184+ return this . gapFillSubSolver . visualize ( )
185+ }
186+
132187 const rects : NonNullable < GraphicsObject [ "rects" ] > = [ ]
133188 const points : NonNullable < GraphicsObject [ "points" ] > = [ ]
134189 const lines : NonNullable < GraphicsObject [ "lines" ] > = [ ] // Initialize lines array
@@ -163,17 +218,23 @@ export class RectDiffSolver extends BaseSolver {
163218 } )
164219 }
165220
166- // obstacles (rect & oval as bounding boxes)
221+ // obstacles (rect & oval as bounding boxes) with layer information
167222 for ( const obstacle of this . srj . obstacles ?? [ ] ) {
168223 if ( obstacle . type === "rect" || obstacle . type === "oval" ) {
224+ // Get layer information if available
225+ const layerInfo =
226+ obstacle . layers && obstacle . layers . length > 0
227+ ? `\nz:${ obstacle . layers . join ( "," ) } `
228+ : ""
229+
169230 rects . push ( {
170231 center : { x : obstacle . center . x , y : obstacle . center . y } ,
171232 width : obstacle . width ,
172233 height : obstacle . height ,
173234 fill : "#fee2e2" ,
174235 stroke : "#ef4444" ,
175236 layer : "obstacle" ,
176- label : " obstacle" ,
237+ label : ` obstacle ${ layerInfo } ` ,
177238 } )
178239 }
179240 }
0 commit comments