You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is only really workable for (assumed static) trees...but very powerful abstraction. Assumes a certain structure to all spatial trees which may not be desirable. We may also want to combine trees with geometry representations in preparations - which this allows us to do but requires some acrobatics.
Notably this interface does NOT help us get the actual geometries, trees are assumed to store indices to geometries. Maybe that's a bad idea? But considering featurecollections etc it seems to be the most prudent thing.
- Leaf nodes contain references to the geometries they represent as indices (or so we assume here)
10
+
11
+
## Why is this useful?
12
+
13
+
- It allows us to write algorithms that can work with any spatial tree type, without having to know the details of the tree type.
14
+
- for example, dual tree traversal / queries
15
+
- It allows us to flexibly and easily swap out and use different tree types, depending on the problem at hand.
16
+
17
+
This is also a zero cost interface if implemented correctly! Verified implementations exist for "flat" trees like the "Natural Index" from `tg`, and "hierarchical" trees like the `STRtree` from `SortTileRecursiveTree.jl`.
18
+
19
+
## Interface
20
+
21
+
-`isspatialtree(tree)::Bool`
22
+
-`isleaf(node)::Bool` - is the node a leaf node? In this context, a leaf node is a node that does not have other nodes as its children, but stores a list of indices and extents (even if implicit).
23
+
-`getchild(node)` - get the children of a node. This may be materialized if necessary or available, but can also be lazy (like a generator).
24
+
-`getchild(node, i)` - get the `i`-th child of a node.
25
+
-`nchild(node)::Int` - the number of children of a node.
26
+
-`child_indices_extents(node)` - an iterator over the indices and extents of the children of a node.
27
+
28
+
These are the only methods that are required to be implemented. They enable the generic query functions described below:
29
+
30
+
## Query functions
31
+
32
+
-`do_query(f, predicate, node)` - call `f(i)` for each index `i` in `node` that satisfies `predicate(extent(i))`.
33
+
-`do_dual_query(f, predicate, tree1, tree2)` - call `f(i1, i2)` for each index `i1` in `tree1` and `i2` in `tree2` that satisfies `predicate(extent(i1), extent(i2))`.
34
+
35
+
These are both completely non-allocating, and will only call `f` for indices that satisfy the predicate.
36
+
You can of course build a standard query interface on top of `do_query` if you want - that's simply:
37
+
```julia
38
+
a = Int[]
39
+
do_query(Base.Fix1(push!, a), predicate, node)
40
+
```
41
+
where `predicate` might be `Base.Fix1(Extents.intersects, extent_to_query)`.
0 commit comments