diff --git a/Project.toml b/Project.toml index 477a770..28d9553 100644 --- a/Project.toml +++ b/Project.toml @@ -4,13 +4,15 @@ authors = ["Max Freudenberg 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" diff --git a/src/SortTileRecursiveTree.jl b/src/SortTileRecursiveTree.jl index 8c8ede9..8112f75 100644 --- a/src/SortTileRecursiveTree.jl +++ b/src/SortTileRecursiveTree.jl @@ -2,6 +2,7 @@ module SortTileRecursiveTree using Extents import GeoInterface as GI +import AbstractTrees """ @@ -156,6 +157,9 @@ function query!(query_result::Vector{Int}, node::STRLeafNode, extent::Extent) end + +include("abstracttrees.jl") + export STRtree, query end diff --git a/src/abstracttrees.jl b/src/abstracttrees.jl new file mode 100644 index 0000000..68fa8f4 --- /dev/null +++ b/src/abstracttrees.jl @@ -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() diff --git a/test/Project.toml b/test/Project.toml index 062349f..8c80403 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -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" diff --git a/test/abstracttrees.jl b/test/abstracttrees.jl new file mode 100644 index 0000000..e5bcedb --- /dev/null +++ b/test/abstracttrees.jl @@ -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 \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 9443def..cdad0bb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -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