Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ authors = ["Max Freudenberg <[email protected]> and contr
version = "0.1.1"

[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Extents = "411431e0-e8b7-467b-b5e0-f676ba4f2910"
GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"

[compat]
julia = "1.10"
AbstractTrees = "0.4.5"
Extents = "0.1.0"
GeoInterface = "1"
julia = "1.6"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
4 changes: 4 additions & 0 deletions src/SortTileRecursiveTree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module SortTileRecursiveTree

using Extents
import GeoInterface as GI
import AbstractTrees


"""
Expand Down Expand Up @@ -156,6 +157,9 @@ function query!(query_result::Vector{Int}, node::STRLeafNode, extent::Extent)
end



include("abstracttrees.jl")

export STRtree, query

end
31 changes: 31 additions & 0 deletions src/abstracttrees.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
AbstractTrees.children(tree::STRtree) = AbstractTrees.children(tree.rootnode)
AbstractTrees.parent(tree::STRtree) = nothing

AbstractTrees.nodevalue(tree::STRtree) = AbstractTrees.nodevalue(tree.rootnode)

# Implement the interface for general STRNodes

AbstractTrees.children(node::STRNode) = node.children
AbstractTrees.nodevalue(node::STRNode) = Extents.extent(node)

# Implement the interface for STRLeafNodes
AbstractTrees.children(node::STRLeafNode) = STRLeafNode[] # no children for a leaf node
AbstractTrees.nodevalue(node::STRLeafNode) = Extents.extent(node)


# Define the traits from AbstractTrees
AbstractTrees.ParentLinks(::Type{<: STRtree}) = AbstractTrees.ImplicitParents()
AbstractTrees.ParentLinks(::Type{<: STRNode}) = AbstractTrees.ImplicitParents()
AbstractTrees.ParentLinks(::Type{<: STRLeafNode}) = AbstractTrees.ImplicitParents()

AbstractTrees.SiblingLinks(::Type{<: STRtree}) = AbstractTrees.ImplicitSiblings()
AbstractTrees.SiblingLinks(::Type{<: STRNode}) = AbstractTrees.ImplicitSiblings()
AbstractTrees.SiblingLinks(::Type{<: STRLeafNode}) = AbstractTrees.ImplicitSiblings()

AbstractTrees.ChildIndexing(::Type{<: STRtree}) = AbstractTrees.IndexedChildren()
AbstractTrees.ChildIndexing(::Type{<: STRNode}) = AbstractTrees.IndexedChildren()
# We don't define this trait for STRLeafNodes, because they have no children.

# Type stability fixes

AbstractTrees.NodeType(::Type{<:Union{STRNode, STRLeafNode, STRtree}}) = AbstractTrees.NodeTypeUnknown()
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3"
Extents = "411431e0-e8b7-467b-b5e0-f676ba4f2910"
GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"
Expand Down
69 changes: 69 additions & 0 deletions test/abstracttrees.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

using Test
using AbstractTrees
using SortTileRecursiveTree
using SortTileRecursiveTree: STRtree, STRNode, STRLeafNode
using Extents
import GeoInterface as GI

@testset "AbstractTrees interface" begin
# Create a simple test tree structure
# Level 1: root with extent (0,0) -> (10,10)
# Level 2: two children with extents (0,0)->(5,5) and (5,5)->(10,10)
# Level 3: leaf nodes

geom1 = GI.MultiPoint([GI.Point((0.0, 0.0)), GI.Point((2.5, 2.5))])
geom2 = GI.MultiPoint([GI.Point((2.5, 2.5)), GI.Point((5.0, 5.0))])
geom3 = GI.MultiPoint([GI.Point((5.0, 5.0)), GI.Point((7.5, 7.5))])
geom4 = GI.MultiPoint([GI.Point((7.5, 7.5)), GI.Point((10.0, 10.0))])

tree = STRtree([geom1, geom1, geom2, geom2, geom3, geom3, geom4, geom4]; nodecapacity=2)

@testset "Basic Tree Structure" begin
# Test children access
@test length(children(tree)) == 2
@test length(children(first(children(tree)))) == 2
@test length(children(last(children(tree)))) == 2
@test all(x -> isa(x, STRLeafNode), children(first(children(tree))))
@test all(x -> isa(x, STRLeafNode), children(last(children(tree))))
end

@testset "Node Values" begin
# Test that nodevalue returns proper extents
@test nodevalue(tree) isa Extent
@test nodevalue(first(children(tree))) isa Extent
@test nodevalue(first(children(last(children(tree))))) isa Extent
end

@testset "Tree Traits" begin
# Test ParentLinks trait
@test ParentLinks(STRtree) == ImplicitParents()
@test ParentLinks(STRNode) == ImplicitParents()
@test ParentLinks(STRLeafNode) == ImplicitParents()

# Test SiblingLinks trait
@test SiblingLinks(STRtree) == ImplicitSiblings()
@test SiblingLinks(STRNode) == ImplicitSiblings()
@test SiblingLinks(STRLeafNode) == ImplicitSiblings()

# Test ChildIndexing trait
@test ChildIndexing(STRtree) == IndexedChildren()
@test ChildIndexing(STRNode) == IndexedChildren()
end

@testset "Tree Traversal Iterators" begin
# Test that we can traverse the tree
nodes = collect(PreOrderDFS(tree))
@test length(nodes) == 7 # 1 root + 2 internal nodes + 4 leaves

leaves = collect(Leaves(tree))
@test length(leaves) == 4
@test all(x -> x isa STRLeafNode, leaves)
end

@testset "Node Type Stability" begin
@test NodeType(STRtree) == NodeTypeUnknown()
@test NodeType(STRNode) == NodeTypeUnknown()
@test NodeType(STRLeafNode) == NodeTypeUnknown()
end
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ import GeoInterface as GI
@test points[query_result] == points[:,1]
@test query(tree, Extent(X=(0, 0.5), Y=(0, 0.5))) == []
end
@testset "AbstractTrees interface" begin; include("abstracttrees.jl"); end
end