@@ -54,9 +54,7 @@ function _isempty(node::Node, region::Region{T,N}) where {T,N}
54
54
return true
55
55
end
56
56
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
60
58
struct RTreeIteratorState{T,N,V}
61
59
leaf:: Leaf{T,N,V} # current leaf node
62
60
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}
112
110
end
113
111
end
114
112
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
+
115
123
function Base. iterate (iter:: RTreeRegionQueryIterator )
124
+ isempty (iter. tree) && return nothing
116
125
# 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)))
122
130
end
123
131
124
132
function 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 ]
127
135
if ix <= length (state. leaf) # fast branch: next data element in the same leaf
128
136
return get (state), state
129
137
else
130
- return _iterate (iter, state. leaf, state. indices)
138
+ return _iterate (iter, state. leaf, state. indices, state . needtests )
131
139
end
132
140
end
133
141
@@ -149,40 +157,45 @@ intersects_with(tree::RTree{T,N}, region::Region{T,N}) where {T,N} =
149
157
150
158
# whether the R-tree node/data element should be visited (i.e. its children examined)
151
159
# 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
154
170
155
171
should_visit (el:: Any , iter:: RTreeRegionQueryIterator ) =
156
172
((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
158
175
# FIXME update for NotContainedIn etc
159
176
160
177
# get the index of the first child of `node` starting from `pos` (including)
161
178
# 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)
167
183
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
171
184
end
172
- return pos
185
+ return pos, res
173
186
end
174
187
175
188
# do depth-first search starting from the `node` subtree and return the
176
189
# `RTreeIteratorState` for the first leaf that satisfies `iter` query or
177
190
# `nothing` if no such leaf in the R-tree.
178
191
# 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} )
181
194
# @debug"_iterate(): enter lev=$(level(node)) indices=$indices"
182
195
@assert length (indices) == height (iter. tree)
183
196
ix = @inbounds (indices[level (node) + 1 ])
184
197
while true
185
- ix_new = _nextchild (node, ix, iter)
198
+ ix_new, queryres = _nextchild (node, ix, needtests[ level (node) + 1 ] , iter)
186
199
# @debug "node=$(Int(Base.pointer_from_objref(node))) lev=$(level(node)) ix_new=$ix_new"
187
200
if ix_new > length (node) # all node subtrees visited, go up one level
188
201
while ix_new > length (node)
@@ -201,11 +214,12 @@ function _iterate(iter::RTreeRegionQueryIterator, nod::Node, indices::AbstractVe
201
214
if node isa Branch
202
215
# go down into the first child
203
216
indices[level (node)] = ix = 1
217
+ needtests[level (node)] = queryres != QueryMatchComplete
204
218
node = node[ix_new]
205
219
# @debug "_iterate(): down lev=$(level(node)) indices=$indices"
206
220
else # Leaf
207
221
# @debug "_iterate(): return lev=$(level(node)) indices=$indices"
208
- state = RTreeIteratorState (node, indices)
222
+ state = RTreeQueryIteratorState (node, indices, needtests )
209
223
return get (state), state
210
224
end
211
225
end
0 commit comments