Skip to content
Open
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
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"
LibSpatialIndex_jll = "00e98e2a-4326-5239-88cb-15dcbe1c18d0"

[compat]
Aqua = "0.7"
Aqua = "0.8"
GeoInterface = "1"
LibSpatialIndex_jll = "1.9"
julia = "1.6"
Test = "1.6"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Expand Down
14 changes: 11 additions & 3 deletions src/LibSpatialIndex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,10 @@ module LibSpatialIndex
minvalues::Vector{Float64},
maxvalues::Vector{Float64}
)
length(minvalues) == rtree.ndim || throw(DimensionMismatch("Minimum values must have same length as RTree dimensions"))
length(maxvalues) == rtree.ndim || throw(DimensionMismatch("Maximum values must have same length as RTree dimensions"))
C.Index_InsertData(rtree.index, Int64(id), pointer(minvalues),
pointer(maxvalues), UInt32(length(minvalues)), Ptr{UInt8}(0), Cint(0)
pointer(maxvalues), UInt32(rtree.ndim), Ptr{UInt8}(0), Cint(0)
)
end
function insert!(rtree::RTree, id::Integer, extent::GI.Extent)
Expand Down Expand Up @@ -213,10 +215,13 @@ module LibSpatialIndex
minvalues::Vector{Float64},
maxvalues::Vector{Float64}
)
length(minvalues) == rtree.ndim || throw(DimensionMismatch("Minimum values must have same length as RTree dimensions"))
length(maxvalues) == rtree.ndim || throw(DimensionMismatch("Maximum values must have same length as RTree dimensions"))

items = Ref{Ptr{Int64}}()
nresults = Ref{UInt64}()
result = C.Index_Intersects_id(rtree.index, pointer(minvalues),
pointer(maxvalues), UInt32(length(minvalues)), items, nresults
pointer(maxvalues), UInt32(rtree.ndim), items, nresults
)
_checkresult(result, "Index_Intersects_id: Failed to evaluate")
unsafe_wrap(Array, items[], nresults[])
Expand Down Expand Up @@ -260,10 +265,13 @@ module LibSpatialIndex
maxvalues::Vector{Float64},
k::Integer
)
length(minvalues) == rtree.ndim || throw(DimensionMismatch("Minimum values must have same length as RTree dimensions"))
length(maxvalues) == rtree.ndim || throw(DimensionMismatch("Maximum values must have same length as RTree dimensions"))

items = Ref{Ptr{Int64}}()
nresults = Ref{UInt64}(k)
result = C.Index_NearestNeighbors_id(rtree.index, pointer(minvalues),
pointer(maxvalues), UInt32(length(minvalues)), items, nresults)
pointer(maxvalues), UInt32(rtree.ndim), items, nresults)
_checkresult(result, "Index_NearestNeighbors_id: Failed to evaluate")
unsafe_wrap(Array, items[], nresults[])
end
Expand Down
146 changes: 86 additions & 60 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,98 @@ import GeoInterface as GI
import LibSpatialIndex as SI
import Aqua

@testset "Simple Tutorial" begin
# based on https://github.com/libspatialindex/libspatialindex/wiki/Simple-Tutorial
println("Testing LibSpatialIndex v$(SI.version())")
props = SI.C.IndexProperty_Create()
SI.C.IndexProperty_SetIndexType(props, SI.C.RT_RTree)
SI.C.IndexProperty_SetIndexStorage(props, SI.C.RT_Memory)
idx = SI.C.Index_Create(props)
SI.C.IndexProperty_Destroy(props)
@test Bool(SI.C.Index_IsValid(idx))
@testset "LibSpatialIndex" begin
@testset "Simple Tutorial" begin
# based on https://github.com/libspatialindex/libspatialindex/wiki/Simple-Tutorial
println("Testing LibSpatialIndex v$(SI.version())")
props = SI.C.IndexProperty_Create()
SI.C.IndexProperty_SetIndexType(props, SI.C.RT_RTree)
SI.C.IndexProperty_SetIndexStorage(props, SI.C.RT_Memory)
idx = SI.C.Index_Create(props)
SI.C.IndexProperty_Destroy(props)
@test Bool(SI.C.Index_IsValid(idx))

# load()
min = [0.5, 0.5]
max = [0.5, 0.5]
SI.C.Index_InsertData(idx, 1, min, max, 2, Ptr{UInt8}(C_NULL), 0)
# load()
min = [0.5, 0.5]
max = [0.5, 0.5]
SI.C.Index_InsertData(idx, 1, min, max, 2, Ptr{UInt8}(C_NULL), 0)

# query()
min = [0.0, 0.0]
max = [1.0, 1.0]
ndims = UInt32(2)
nresults = Ref{UInt64}()
SI.C.Index_Intersects_count(idx, min, max, ndims, nresults)
@test nresults[] == 1
# query()
min = [0.0, 0.0]
max = [1.0, 1.0]
ndims = UInt32(2)
nresults = Ref{UInt64}()
SI.C.Index_Intersects_count(idx, min, max, ndims, nresults)
@test nresults[] == 1

# bounds()
pmins = zeros(2)
pmaxs = zeros(2)
ndims = Ref{UInt32}()
SI.C.Index_GetBounds(idx, pointer_from_objref(pmins), pointer_from_objref(pmaxs), ndims);
@test ndims[] == 2
@test isapprox(pmins, [0.5, 0.5])
@test isapprox(pmaxs, [0.5, 0.5])
end
# bounds()
# reference to null pointer to float64 is okay
# the pointer will be overwritten by Index_GetBounds
pmins_p = Ref{Ptr{Float64}}()
pmaxs_p = Ref{Ptr{Float64}}()
ndims = Ref{UInt32}()

@testset "Simple Operations" begin
rtree = SI.RTree(2)
result = SI.insert!(rtree, 1, [0.,0.], [1.,1.])
@test result == SI.C.RT_None
result = SI.insert!(rtree, 2, [0.,0.], [2.,2.])
@test result == SI.C.RT_None
@test SI.intersects(rtree, [0.,0.],[1.,1.]) == [1,2]
@test SI.intersects(rtree, [0.,0.]) == [1,2]
@test SI.intersects(rtree, [2.,2.]) == [2]
@test SI.intersects(rtree, [1.5,1.5],[2.,2.]) == [2]
@test sort(SI.knn(rtree, [2.,2.],[2.,2.], 1)) == [2]
@test sort(SI.knn(rtree, [2.,2.],[2.,2.], 2)) == [1,2]
@test sort(SI.knn(rtree, [2.,2.],[2.,2.], 3)) == [1,2]
@test sort(SI.knn(rtree, [2.,2.], 1)) == [2]
@test sort(SI.knn(rtree, [2.,2.], 2)) == [1,2]
end
SI.C.Index_GetBounds(idx, pmins_p, pmaxs_p, ndims);

@testset "GeoInterface/Extents Operations" begin
rtree = SI.RTree(2)
result = SI.insert!(rtree, 1, GI.Extent(X=(0.0, 1.0), Y=(0.0, 1.0)))
@test result == SI.C.RT_None
@test ndims[] == 2
pmins = unsafe_wrap(Vector{Float64}, pmins_p[], ndims[], own=true)
pmaxs = unsafe_wrap(Vector{Float64}, pmaxs_p[], ndims[], own=true)

polygon = GI.Polygon([GI.LinearRing([(0.0, 0.0), (0.5, 0.0), (2.0, 0.5), (0.0, 2.0), (0.0, 0.0)])])
result = SI.insert!(rtree, 2, polygon)
@test isapprox(pmins, [0.5, 0.5])
@test isapprox(pmaxs, [0.5, 0.5])
end

@test result == SI.C.RT_None
@test SI.intersects(rtree, GI.LineString([(0.0, 0.0), (1.0, 1.0)])) == [1, 2]
@test SI.intersects(rtree, GI.Point(0.0, 0.0)) == [1, 2]
@test SI.intersects(rtree, (X=2.0, Y=2.0)) == [2]
@test sort(SI.knn(rtree, GI.Extent(X=(2.0, 2.0), Y=(2.0, 2.0)), 1)) == [2]
@test sort(SI.knn(rtree, (2.0, 2.0), 1)) == [2]
end
@testset "Simple Operations" begin
rtree = SI.RTree(2)
result = SI.insert!(rtree, 1, [0.,0.], [1.,1.])
@test result == SI.C.RT_None
result = SI.insert!(rtree, 2, [0.,0.], [2.,2.])
@test result == SI.C.RT_None
@test SI.intersects(rtree, [0.,0.],[1.,1.]) == [1,2]
@test SI.intersects(rtree, [0.,0.]) == [1,2]
@test SI.intersects(rtree, [2.,2.]) == [2]
@test SI.intersects(rtree, [1.5,1.5],[2.,2.]) == [2]
@test sort(SI.knn(rtree, [2.,2.],[2.,2.], 1)) == [2]
@test sort(SI.knn(rtree, [2.,2.],[2.,2.], 2)) == [1,2]
@test sort(SI.knn(rtree, [2.,2.],[2.,2.], 3)) == [1,2]
@test sort(SI.knn(rtree, [2.,2.], 1)) == [2]
@test sort(SI.knn(rtree, [2.,2.], 2)) == [1,2]
end

@testset "GeoInterface/Extents Operations" begin
rtree = SI.RTree(2)
result = SI.insert!(rtree, 1, GI.Extent(X=(0.0, 1.0), Y=(0.0, 1.0)))
@test result == SI.C.RT_None

polygon = GI.Polygon([GI.LinearRing([(0.0, 0.0), (0.5, 0.0), (2.0, 0.5), (0.0, 2.0), (0.0, 0.0)])])
result = SI.insert!(rtree, 2, polygon)

@test result == SI.C.RT_None
@test SI.intersects(rtree, GI.LineString([(0.0, 0.0), (1.0, 1.0)])) == [1, 2]
@test SI.intersects(rtree, GI.Point(0.0, 0.0)) == [1, 2]
@test SI.intersects(rtree, (X=2.0, Y=2.0)) == [2]
@test sort(SI.knn(rtree, GI.Extent(X=(2.0, 2.0), Y=(2.0, 2.0)), 1)) == [2]
@test sort(SI.knn(rtree, (2.0, 2.0), 1)) == [2]
end

@testset "Bounds checks" begin
# confirm that bounds checks on the Julia side are working
tree = SI.RTree(2)
@test_throws DimensionMismatch SI.insert!(tree, 0, [0.0], [0.0, 0.1])
@test_throws DimensionMismatch SI.insert!(tree, 0, [0.0, 1.0], [0.1])
# should throw even if they're the same length if they don't match dimensions
@test_throws DimensionMismatch SI.insert!(tree, 0, [0.0, 0.1, 1.1], [0.0, 0.1, 1.1])

@test_throws DimensionMismatch SI.intersects(tree, [0.0], [0.0, 0.1])
@test_throws DimensionMismatch SI.intersects(tree, [0.0, 1.0], [0.1])
@test_throws DimensionMismatch SI.intersects(tree, [0.0, 0.1, 1.1], [0.0, 0.1, 1.1])

@test_throws DimensionMismatch SI.knn(tree, [0.0], [0.0, 0.1], 1)
@test_throws DimensionMismatch SI.knn(tree, [0.0, 1.0], [0.1], 1)
@test_throws DimensionMismatch SI.knn(tree, [0.0, 0.1, 1.1], [0.0, 0.1, 1.1], 1)
end

@testset "Aqua" begin
Aqua.test_all(LibSpatialIndex)
@testset "Aqua" begin
Aqua.test_all(LibSpatialIndex)
end
end
Loading