@@ -54,9 +54,7 @@ function _isempty(node::Node, region::Region{T,N}) where {T,N}
5454 return true
5555end
5656
57- # the RTreeIterator/RTreeRegionQueryIterator state
58- # FIXME can mark whether the MBR of the node satisfies the query, so all
59- # its subnodes and data elements need not to be checked
57+ # the RTreeIterator state
6058struct RTreeIteratorState{T,N,V}
6159 leaf:: Leaf{T,N,V} # current leaf node
6260 indices:: Vector{Int} # indices of the nodes (in their parents) in the current subtree
@@ -112,22 +110,32 @@ struct RTreeRegionQueryIterator{T,N,V,Q,TT,R} <: SpatialQueryIterator{T,N,V,Q}
112110 end
113111end
114112
113+ # the RTreeRegionQueryIterator state
114+ struct RTreeQueryIteratorState{T,N,V}
115+ leaf:: Leaf{T,N,V} # current leaf node
116+ indices:: Vector{Int} # indices of the nodes (in their parents) in the current subtree
117+ needtests:: BitVector # whether children MBRs should be tested or not (because they automatically satisfy query)
118+ end
119+
120+ # get the current data element pointed by `RTreeIteratorState`
121+ Base. get (state:: RTreeQueryIteratorState ) = @inbounds (state. leaf[state. indices[1 ]])
122+
115123function Base. iterate (iter:: RTreeRegionQueryIterator )
124+ isempty (iter. tree) && return nothing
116125 # no data or doesn't intersect at all
117- if (isempty (iter. tree) || ! should_visit (iter. tree. root, iter))
118- # @debug "iterate(): empty iter=$iter root_visit=$(should_visit(iter.tree.root, iter))"
119- return nothing
120- end
121- return _iterate (iter, iter. tree. root, fill (1 , height (iter. tree)))
126+ root_match = should_visit (iter. tree. root, iter)
127+ root_match == QueryNoMatch && return nothing
128+ return _iterate (iter, iter. tree. root, fill (1 , height (iter. tree)),
129+ root_match == QueryMatchComplete ? falses (height (iter. tree)) : trues (height (iter. tree)))
122130end
123131
124132function Base. iterate (iter:: RTreeRegionQueryIterator ,
125- state:: RTreeIteratorState )
126- @inbounds ix = state. indices[1 ] = _nextchild (state. leaf, state. indices[1 ] + 1 , iter)
133+ state:: RTreeQueryIteratorState )
134+ @inbounds ix = state. indices[1 ] = _nextchild (state. leaf, state. indices[1 ] + 1 , state . needtests[ 1 ], iter)[ 1 ]
127135 if ix <= length (state. leaf) # fast branch: next data element in the same leaf
128136 return get (state), state
129137 else
130- return _iterate (iter, state. leaf, state. indices)
138+ return _iterate (iter, state. leaf, state. indices, state . needtests )
131139 end
132140end
133141
@@ -149,40 +157,45 @@ intersects_with(tree::RTree{T,N}, region::Region{T,N}) where {T,N} =
149157
150158# whether the R-tree node/data element should be visited (i.e. its children examined)
151159# by the region iterator
152- should_visit (node:: Node , iter:: RTreeRegionQueryIterator ) =
153- intersects (iter. region, mbr (node)) # FIXME update for NotContainedIn etc
160+ function should_visit (node:: Node , iter:: RTreeRegionQueryIterator )
161+ kind = querykind (iter)
162+ if kind == QueryContainedIn || kind == QueryIntersectsWith
163+ contains (iter. region, mbr (node)) && return QueryMatchComplete # node (and all its children) fully contained in query region
164+ intersects (iter. region, mbr (node)) && return QueryMatchPartial # node (and maybe its children) intersects query region
165+ return QueryNoMatch
166+ else
167+ throw (ArgumentError (" Unknown spatial query kind: $kind " ))
168+ end
169+ end
154170
155171should_visit (el:: Any , iter:: RTreeRegionQueryIterator ) =
156172 ((querykind (iter) == QueryContainedIn) && contains (iter. region, mbr (el))) ||
157- ((querykind (iter) == QueryIntersectsWith) && intersects (iter. region, mbr (el)))
173+ ((querykind (iter) == QueryIntersectsWith) && intersects (iter. region, mbr (el))) ?
174+ QueryMatchComplete : QueryNoMatch
158175 # FIXME update for NotContainedIn etc
159176
160177# get the index of the first child of `node` starting from `pos` (including)
161178# that satifies `iter` query (or length(node) + 1 if not found)
162- @inline function _nextchild (node:: Node , pos:: Integer , iter:: RTreeRegionQueryIterator )
163- if level (node) == 0 && length (iter. tree) > 100 && pos <= length (node)
164- # @debug "_nextchild(): lev=$(level(node)) len=$(length(node)) pos=$pos should_visit=$(should_visit(@inbounds(node[pos]), iter)) rect=$(mbr(node[pos]))"
165- end
166- while pos <= length (node) && ! should_visit (@inbounds (node[pos]), iter)
179+ @inline function _nextchild (node:: Node , pos:: Integer , needtests:: Bool , iter:: RTreeRegionQueryIterator )
180+ res = needtests ? QueryNoMatch : QueryMatchComplete # if tests not needed, all node subtrees are considered fully matching
181+ while pos <= length (node) && needtests &&
182+ ((res = should_visit (@inbounds (node[pos]), iter)) == QueryNoMatch)
167183 pos += 1
168- if level (node) == 0 && length (iter. tree) > 100 && pos <= length (node)
169- # @debug "_nextchild(): lev=$(level(node)) len=$(length(node)) pos=$pos should_visit=$(should_visit(@inbounds(node[pos]), iter)) rect=$(mbr(node[pos]))"
170- end
171184 end
172- return pos
185+ return pos, res
173186end
174187
175188# do depth-first search starting from the `node` subtree and return the
176189# `RTreeIteratorState` for the first leaf that satisfies `iter` query or
177190# `nothing` if no such leaf in the R-tree.
178191# The method modifies `indicies` array and uses it for the returned iteration state
179- function _iterate (iter:: RTreeRegionQueryIterator , nod :: Node , indices :: AbstractVector{Int} )
180- node = nod
192+ function _iterate (iter:: RTreeRegionQueryIterator , node :: Node ,
193+ indices :: AbstractVector{Int} , needtests :: AbstractVector{Bool} )
181194 # @debug"_iterate(): enter lev=$(level(node)) indices=$indices"
182195 @assert length (indices) == height (iter. tree)
183196 ix = @inbounds (indices[level (node) + 1 ])
184197 while true
185- ix_new = _nextchild (node, ix, iter)
198+ ix_new, queryres = _nextchild (node, ix, needtests[ level (node) + 1 ] , iter)
186199 # @debug "node=$(Int(Base.pointer_from_objref(node))) lev=$(level(node)) ix_new=$ix_new"
187200 if ix_new > length (node) # all node subtrees visited, go up one level
188201 while ix_new > length (node)
@@ -201,11 +214,12 @@ function _iterate(iter::RTreeRegionQueryIterator, nod::Node, indices::AbstractVe
201214 if node isa Branch
202215 # go down into the first child
203216 indices[level (node)] = ix = 1
217+ needtests[level (node)] = queryres != QueryMatchComplete
204218 node = node[ix_new]
205219 # @debug "_iterate(): down lev=$(level(node)) indices=$indices"
206220 else # Leaf
207221 # @debug "_iterate(): return lev=$(level(node)) indices=$indices"
208- state = RTreeIteratorState (node, indices)
222+ state = RTreeQueryIteratorState (node, indices, needtests )
209223 return get (state), state
210224 end
211225 end
0 commit comments