1
+ module NaturalIndexing
2
+
3
+ import GeoInterface as GI
4
+ import Extents
5
+
6
+ using .. SpatialTreeInterface
7
+
8
+ """
9
+ NaturalLevel{E <: Extents.Extent}
10
+
11
+ A level in the natural tree. Stored in a vector in [`NaturalIndex`](@ref).
12
+
13
+ - `extents` is a vector of extents of the children of the node
14
+ """
15
+ struct NaturalLevel{E <: Extents.Extent }
16
+ extents:: Vector{E} # child extents
17
+ end
18
+
19
+ Base. show (io:: IO , level:: NaturalLevel ) = print (io, " NaturalLevel($(length (level. extents)) extents)" )
20
+ Base. show (io:: IO , :: MIME"text/plain" , level:: NaturalLevel ) = Base. show (io, level)
21
+
22
+ """
23
+ NaturalIndex{E <: Extents.Extent}
24
+
25
+ A natural tree index. Stored in a vector in [`NaturalIndex`](@ref).
26
+
27
+ - `nodecapacity` is the "spread", number of children per node
28
+ - `extent` is the extent of the tree
29
+ - `levels` is a vector of [`NaturalLevel`](@ref)s
30
+ """
31
+ struct NaturalIndex{E <: Extents.Extent }
32
+ nodecapacity:: Int # "spread", number of children per node
33
+ extent:: E
34
+ levels:: Vector{NaturalLevel{E}}
35
+ end
36
+
37
+ GI. extent (idx:: NaturalIndex ) = idx. extent
38
+ Extents. extent (idx:: NaturalIndex ) = idx. extent
39
+
40
+ function Base. show (io:: IO , :: MIME"text/plain" , idx:: NaturalIndex )
41
+ println (io, " NaturalIndex with $(length (idx. levels)) levels and $(idx. nodecapacity) children per node" )
42
+ println (io, " extent: $(idx. extent) " )
43
+ end
44
+
45
+ function Base. show (io:: IO , idx:: NaturalIndex )
46
+ println (io, " NaturalIndex($(length (idx. levels)) levels, $(idx. extent) )" )
47
+ end
48
+
49
+ function NaturalIndex (geoms; nodecapacity = 32 )
50
+ e1 = GI. extent (first (geoms))
51
+ E = typeof (e1)
52
+ return NaturalIndex {E} (geoms; nodecapacity = nodecapacity)
53
+ end
54
+
55
+ function NaturalIndex {E} (geoms; nodecapacity = 32 ) where E <: Extents.Extent
56
+ last_level_extents = GI. extent .(geoms)
57
+ return NaturalIndex {E} (last_level_extents; nodecapacity = nodecapacity)
58
+ end
59
+
60
+ function NaturalIndex (last_level_extents:: Vector{E} ; nodecapacity = 32 ) where E <: Extents.Extent
61
+ return NaturalIndex {E} (last_level_extents; nodecapacity = nodecapacity)
62
+ end
63
+
64
+ function NaturalIndex {E} (last_level_extents:: Vector{E} ; nodecapacity = 32 ) where E <: Extents.Extent
65
+ ngeoms = length (last_level_extents)
66
+ last_level = NaturalLevel (last_level_extents)
67
+
68
+ nlevels = _number_of_levels (nodecapacity, ngeoms)
69
+
70
+ levels = Vector {NaturalLevel{E}} (undef, nlevels)
71
+ levels[end ] = last_level
72
+
73
+ for level_index in (nlevels- 1 ): (- 1 ): 1
74
+ prev_level = levels[level_index+ 1 ] # this is always instantiated
75
+ nrects = _number_of_keys (nodecapacity, nlevels - (level_index), ngeoms)
76
+ # @show level_index nrects
77
+ extents = [
78
+ begin
79
+ start = (rect_index - 1 ) * nodecapacity + 1
80
+ stop = min (start + nodecapacity - 1 , length (prev_level. extents))
81
+ reduce (Extents. union, view (prev_level. extents, start: stop))
82
+ end
83
+ for rect_index in 1 : nrects
84
+ ]
85
+ levels[level_index] = NaturalLevel (extents)
86
+ end
87
+
88
+ return NaturalIndex (nodecapacity, reduce (Extents. union, levels[1 ]. extents), levels)
89
+
90
+ end
91
+
92
+ function _number_of_keys (nodecapacity:: Int , level:: Int , ngeoms:: Int )
93
+ return ceil (Int, ngeoms / (nodecapacity ^ (level)))
94
+ end
95
+
96
+ """
97
+ _number_of_levels(nodecapacity::Int, ngeoms::Int)
98
+
99
+ Calculate the number of levels in a natural tree for a given number of geometries and node capacity.
100
+
101
+ ## How this works
102
+
103
+ The number of keys in a level is given by `ngeoms / nodecapacity ^ level`.
104
+
105
+ The number of levels is the smallest integer such that the number of keys in the last level is 1.
106
+ So it goes - if that makes sense.
107
+ """
108
+ function _number_of_levels (nodecapacity:: Int , ngeoms:: Int )
109
+ level = 1
110
+ while _number_of_keys (nodecapacity, level, ngeoms) > 1
111
+ level += 1
112
+ end
113
+ return level
114
+ end
115
+
116
+
117
+ # This is like a pointer to a node in the tree.
118
+ """
119
+ NaturalTreeNode{E <: Extents.Extent}
120
+
121
+ A reference to a node in the natural tree. Kind of like a tree cursor.
122
+
123
+ - `parent_index` is a pointer to the parent index
124
+ - `level` is the level of the node in the tree
125
+ - `index` is the index of the node in the level
126
+ - `extent` is the extent of the node
127
+ """
128
+ struct NaturalTreeNode{E <: Extents.Extent }
129
+ parent_index:: NaturalIndex{E}
130
+ level:: Int
131
+ index:: Int
132
+ extent:: E
133
+ end
134
+
135
+ Extents. extent (node:: NaturalTreeNode ) = node. extent
136
+
137
+ # What does SpatialTreeInterface require of trees?
138
+ # - Parents completely cover their children
139
+ # - `GI.extent(node)` returns `Extent`
140
+ # - can mean that `Extents.extent(node)` returns the extent of the node
141
+ # - `nchild(node)` returns the number of children of the node
142
+ # - `getchild(node)` returns an iterator over all children of the node
143
+ # - `getchild(node, i)` returns the i-th child of the node
144
+ # - `isleaf(node)` returns a boolean indicating whether the node is a leaf
145
+ # - `child_indices_extents(node)` returns an iterator over the indices and extents of the children of the node
146
+
147
+ function SpatialTreeInterface. nchild (node:: NaturalTreeNode )
148
+ start_idx = (node. index - 1 ) * node. parent_index. nodecapacity + 1
149
+ stop_idx = min (start_idx + node. parent_index. nodecapacity - 1 , length (node. parent_index. levels[node. level+ 1 ]. extents))
150
+ return stop_idx - start_idx + 1
151
+ end
152
+
153
+ function SpatialTreeInterface. getchild (node:: NaturalTreeNode , i:: Int )
154
+ child_index = (node. index - 1 ) * node. parent_index. nodecapacity + i
155
+ return NaturalTreeNode (
156
+ node. parent_index,
157
+ node. level + 1 , # increment level by 1
158
+ child_index, # index of this particular child
159
+ node. parent_index. levels[node. level+ 1 ]. extents[child_index] # the extent of this child
160
+ )
161
+ end
162
+
163
+ # Get all children of a node
164
+ function SpatialTreeInterface. getchild (node:: NaturalTreeNode )
165
+ return (SpatialTreeInterface. getchild (node, i) for i in 1 : SpatialTreeInterface. nchild (node))
166
+ end
167
+
168
+ SpatialTreeInterface. isleaf (node:: NaturalTreeNode ) = node. level == length (node. parent_index. levels) - 1
169
+
170
+ function SpatialTreeInterface. child_indices_extents (node:: NaturalTreeNode )
171
+ start_idx = (node. index - 1 ) * node. parent_index. nodecapacity + 1
172
+ stop_idx = min (start_idx + node. parent_index. nodecapacity - 1 , length (node. parent_index. levels[node. level+ 1 ]. extents))
173
+ return ((i, node. parent_index. levels[node. level+ 1 ]. extents[i]) for i in start_idx: stop_idx)
174
+ end
175
+
176
+ # implementation for "root node" / top level tree
177
+
178
+ SpatialTreeInterface. isleaf (node:: NaturalIndex ) = length (node. levels) == 1
179
+
180
+ SpatialTreeInterface. nchild (node:: NaturalIndex ) = length (node. levels[1 ]. extents)
181
+
182
+ SpatialTreeInterface. getchild (node:: NaturalIndex ) = SpatialTreeInterface. getchild (NaturalTreeNode (node, 0 , 1 , node. extent))
183
+ SpatialTreeInterface. getchild (node:: NaturalIndex , i) = SpatialTreeInterface. getchild (NaturalTreeNode (node, 0 , 1 , node. extent), i)
184
+
185
+ SpatialTreeInterface. child_indices_extents (node:: NaturalIndex ) = (i_ext for i_ext in enumerate (node. levels[1 ]. extents))
186
+
187
+ struct NaturallyIndexedRing
188
+ points:: Vector{Tuple{Float64, Float64}}
189
+ index:: NaturalIndex {Extents. Extent{(:X , :Y ), NTuple{2 , NTuple{2 , Float64}}}}
190
+ end
191
+
192
+ function NaturallyIndexedRing (points:: Vector{Tuple{Float64, Float64}} ; nodecapacity = 32 )
193
+ index = NaturalIndex (GO. edge_extents (GI. LinearRing (points)); nodecapacity)
194
+ return NaturallyIndexedRing (points, index)
195
+ end
196
+
197
+ NaturallyIndexedRing (ring:: NaturallyIndexedRing ) = ring
198
+
199
+ function GI. convert (:: Type{NaturallyIndexedRing} , :: GI.LinearRingTrait , geom)
200
+ points = GO. tuples (geom). geom
201
+ return NaturallyIndexedRing (points)
202
+ end
203
+
204
+ Base. show (io:: IO , :: MIME"text/plain" , ring:: NaturallyIndexedRing ) = Base. show (io, ring)
205
+
206
+ Base. show (io:: IO , ring:: NaturallyIndexedRing ) = print (io, " NaturallyIndexedRing($(length (ring. points)) points) with index $(sprint (show, ring. index)) " )
207
+
208
+ GI. ncoord (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing ) = 2
209
+ GI. is3d (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing ) = false
210
+ GI. ismeasured (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing ) = false
211
+
212
+ GI. npoint (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing ) = length (ring. points)
213
+ GI. getpoint (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing ) = ring. points[i]
214
+ GI. getpoint (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing , i:: Int ) = ring. points[i]
215
+
216
+ GI. ngeom (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing ) = length (ring. points)
217
+ GI. getgeom (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing ) = ring. points
218
+ GI. getgeom (:: GI.LinearRingTrait , ring:: NaturallyIndexedRing , i:: Int ) = ring. points[i]
219
+
220
+ Extents. extent (ring:: NaturallyIndexedRing ) = ring. index. extent
221
+
222
+ GI. isgeometry (:: NaturallyIndexedRing ) = true
223
+ GI. geomtrait (:: NaturallyIndexedRing ) = GI. LinearRingTrait ()
224
+
225
+ function prepare_naturally (geom)
226
+ return GO. apply (GI. PolygonTrait (), geom) do poly
227
+ return GI. Polygon ([GI. convert (NaturallyIndexedRing, GI. LinearRingTrait (), ring) for ring in GI. getring (poly)])
228
+ end
229
+ end
230
+
231
+ export NaturalTree, NaturallyIndexedRing, prepare_naturally
232
+
233
+ end # module NaturalIndexing
234
+
235
+ using . NaturalIndexing
0 commit comments