@@ -121,26 +121,83 @@ impl QuadTree {
121121 self . children = Some ( Box :: new ( kids) ) ;
122122 }
123123
124- pub fn query ( & self , range : Rect ) -> Vec < Item > {
125- let mut out = Vec :: new ( ) ;
126- let mut stack: SmallVec < [ & QuadTree ; 16 ] > = SmallVec :: new ( ) ;
127- stack. push ( self ) ;
128-
129- while let Some ( node) = stack. pop ( ) {
130- for it in & node. items {
131- if range. contains ( & it. point ) {
132- out. push ( * it) ;
124+ #[ inline( always) ]
125+ fn rect_contains_rect ( a : & Rect , b : & Rect ) -> bool {
126+ a. min_x <= b. min_x && a. min_y <= b. min_y &&
127+ a. max_x >= b. max_x && a. max_y >= b. max_y
128+ }
129+
130+ pub fn query ( & self , range : Rect ) -> Vec < ( u64 , f32 , f32 ) > {
131+ #[ derive( Copy , Clone ) ]
132+ enum Mode { Filter , ReportAll }
133+
134+ // Hoist bounds for tight leaf checks
135+ let rx0 = range. min_x ;
136+ let ry0 = range. min_y ;
137+ let rx1 = range. max_x ;
138+ let ry1 = range. max_y ;
139+
140+ let mut out: Vec < ( u64 , f32 , f32 ) > = Vec :: with_capacity ( 128 ) ;
141+ let mut stack: SmallVec < [ ( & QuadTree , Mode ) ; 64 ] > = SmallVec :: new ( ) ;
142+ stack. push ( ( self , Mode :: Filter ) ) ;
143+
144+ while let Some ( ( node, mode) ) = stack. pop ( ) {
145+ match mode {
146+ Mode :: ReportAll => {
147+ if let Some ( children) = node. children . as_ref ( ) {
148+ // Entire subtree is inside the query.
149+ // No filtering, just recurse in ReportAll.
150+ stack. push ( ( & children[ 0 ] , Mode :: ReportAll ) ) ;
151+ stack. push ( ( & children[ 1 ] , Mode :: ReportAll ) ) ;
152+ stack. push ( ( & children[ 2 ] , Mode :: ReportAll ) ) ;
153+ stack. push ( ( & children[ 3 ] , Mode :: ReportAll ) ) ;
154+ } else {
155+ // Leaf: append all items, no per-point test
156+ let items = & node. items ;
157+ out. reserve ( items. len ( ) ) ;
158+ out. extend ( items. iter ( ) . map ( |it| ( it. id , it. point . x , it. point . y ) ) ) ;
159+ }
133160 }
134- }
135- if let Some ( children) = node. children . as_ref ( ) {
136- // Push children that intersect the query range
137- for child in children. iter ( ) {
138- if range. intersects ( & child. boundary ) {
139- stack. push ( child) ;
161+
162+ Mode :: Filter => {
163+ // Node cull
164+ if !range. intersects ( & node. boundary ) {
165+ continue ;
166+ }
167+
168+ // Full cover: switch to ReportAll
169+ if Self :: rect_contains_rect ( & range, & node. boundary ) {
170+ stack. push ( ( node, Mode :: ReportAll ) ) ;
171+ continue ;
172+ }
173+
174+ // Partial overlap
175+ if let Some ( children) = node. children . as_ref ( ) {
176+ // Only push intersecting children
177+ let c0 = & children[ 0 ] ;
178+ if range. intersects ( & c0. boundary ) { stack. push ( ( c0, Mode :: Filter ) ) ; }
179+ let c1 = & children[ 1 ] ;
180+ if range. intersects ( & c1. boundary ) { stack. push ( ( c1, Mode :: Filter ) ) ; }
181+ let c2 = & children[ 2 ] ;
182+ if range. intersects ( & c2. boundary ) { stack. push ( ( c2, Mode :: Filter ) ) ; }
183+ let c3 = & children[ 3 ] ;
184+ if range. intersects ( & c3. boundary ) { stack. push ( ( c3, Mode :: Filter ) ) ; }
185+ } else {
186+ // Leaf scan with tight predicate
187+ let items = & node. items ;
188+ // Reserve a little to reduce reallocs if many will pass
189+ out. reserve ( items. len ( ) . min ( 64 ) ) ;
190+ for it in items {
191+ let p = & it. point ;
192+ if p. x >= rx0 && p. x < rx1 && p. y >= ry0 && p. y < ry1 {
193+ out. push ( ( it. id , p. x , p. y ) ) ;
194+ }
195+ }
140196 }
141197 }
142198 }
143199 }
200+
144201 out
145202 }
146203
0 commit comments