diff --git a/src/GeometryOps.jl b/src/GeometryOps.jl index 9e19dd553..b5d06507d 100644 --- a/src/GeometryOps.jl +++ b/src/GeometryOps.jl @@ -33,6 +33,7 @@ include("methods/polygonize.jl") include("methods/barycentric.jl") include("methods/equals.jl") +include("transformations/extent.jl") include("transformations/flip.jl") include("transformations/simplify.jl") include("transformations/reproject.jl") diff --git a/src/primitives.jl b/src/primitives.jl index 1ca4e0224..9a9ea8127 100644 --- a/src/primitives.jl +++ b/src/primitives.jl @@ -1,10 +1,19 @@ +const THREADED_KEYWORD = "- `threaded`: `true` or `false`. Whether to use multithreading. Defaults to `false`." +const CRS_KEYWORD = "- `crs`: The CRS to attach to geometries. Defaults to `nothing`." +const CALC_EXTENT_KEYWORD = "- `calc_extent`: `true` or `false`. Whether to calculate the extent. Defaults to `false`." + +const APPLY_KEYWORDS = """ +$THREADED_KEYWORD +$CRS_KEYWORD +$CALC_EXTENT_KEYWORD +""" # # Primitive functions # This file mainly defines the [`apply`](@ref) function. """ - apply(f, target::Type{<:AbstractTrait}, obj; crs) + apply(f, target::Type{<:AbstractTrait}, obj; kw...) Reconstruct a geometry or feature using the function `f` on the `target` trait. @@ -12,7 +21,11 @@ Reconstruct a geometry or feature using the function `f` on the `target` trait. The result is an functionally similar geometry with values depending on `f` -# Flipped point the order in any feature or geometry, or iterables of either: +$APPLY_KEYWORDS + +# Example + +Flipped point the order in any feature or geometry, or iterables of either: ```juia import GeoInterface as GI diff --git a/src/transformations/extent.jl b/src/transformations/extent.jl index 98051bf6e..9055de135 100644 --- a/src/transformations/extent.jl +++ b/src/transformations/extent.jl @@ -1,24 +1,17 @@ """ embed_extent(obj) -Recursively wrap the object with a `GeoInterface.Wrappers` geometry, +Recursively wrap the object with a GeoInterface.jl geometry, calculating and adding an `Extents.Extent` to all objects. -This can improve performance when extents need to be checked multiple times. -""" -embed_extent(x; kw...) = apply(AbstractTrait, x; kw...) +This can improve performance when extents need to be checked multiple times, +such when needing to check if many points are in geometries, and using their extents +as a quick filter for obviously exterior points. + +# Keywords -extent_applicator(x) = extent_applicator(trait(x), x) -extent_applicator(::Nothing, xs::AbstractArray) = embed_extent.(xs) -extent_applicator(::Union{AbstractCurveTrait,MultiPointTrait}, point) = point - -function extent_applicator(trait::AbstractGeometryTrait, geom) - children_with_extents = map(GI.getgeom(geom)) do g - embed_extent(g) - end - wrapper_type = GI.geointerface_geomtype(trait) - extent = GI.extent(wrapper_type(children_with_extents)) - return wrapper_type(children_with_extents, extent) -end -extent_applicator(::PointTrait, point) = point -extent_applicator(::PointTrait, point) = point +$THREADED_KEYWORD +$CRS_KEYWORD +""" +embed_extent(x; threaded=false, crs=nothing) = + apply(identity, GI.PointTrait, x; calc_extent=true, threaded, crs) diff --git a/src/transformations/flip.jl b/src/transformations/flip.jl index e746456bb..eee3bed42 100644 --- a/src/transformations/flip.jl +++ b/src/transformations/flip.jl @@ -9,6 +9,10 @@ Swap all of the x and y coordinates in obj, otherwise keeping the original structure (but not necessarily the original type). + +## Keywords + +$APPLY_KEYWORDS """ function flip(geom; kw...) if _is3d(geom) diff --git a/src/transformations/reproject.jl b/src/transformations/reproject.jl index dd61c15bd..d59cbd92f 100644 --- a/src/transformations/reproject.jl +++ b/src/transformations/reproject.jl @@ -30,9 +30,10 @@ needed if it is not retreivable from the geometry with `GeoInterface.crs(geometr ## Keywords --`always_xy`: force x, y coordinate order, `true` by default. +- `always_xy`: force x, y coordinate order, `true` by default. `false` will expect and return points in the crs coordinate order. --`time`: the time for the coordinates. `Inf` by default. +- `time`: the time for the coordinates. `Inf` by default. +$APPLY_KEYWORDS """ function reproject(geom; source_crs=nothing, target_crs=nothing, transform=nothing, kw... diff --git a/src/transformations/simplify.jl b/src/transformations/simplify.jl index ee095f5b0..1dd2fb55b 100644 --- a/src/transformations/simplify.jl +++ b/src/transformations/simplify.jl @@ -22,6 +22,7 @@ abstract type SimplifyAlg end const SIMPLIFY_ALG_KEYWORDS = """ ## Keywords + - `ratio`: the fraction of points that should remain after `simplify`. Useful as it will generalise for large collections of objects. - `number`: the number of points that should remain after `simplify`. @@ -48,7 +49,7 @@ end """ simplify(obj; kw...) - simplify(::SimplifyAlg, obj) + simplify(::SimplifyAlg, obj; kw...) Simplify a geometry, feature, feature collection, or nested vectors or a table of these. @@ -62,6 +63,14 @@ listed in order of increasing quality but decreaseing performance. The default behaviour is `simplify(DouglasPeucker(; kw...), obj)`. Pass in other [`SimplifyAlg`](@ref) to use other algorithms. +# Keywords + +$APPLY_KEYWORDS + +Keywords for DouglasPeucker are allowed when no algorithm is specified: + +$SIMPLIFY_ALG_KEYWORDS + # Example Simplify a polygon to have six points: @@ -99,8 +108,8 @@ GI.npoint(simple) 6 ``` """ -simplify(data; calc_extent=false, threaded=false, kw...) = - _simplify(DouglasPeucker(; kw...), data; calc_extent, threaded) +simplify(data; calc_extent=false, threaded=false, crs=nothing, kw...) = + _simplify(DouglasPeucker(; kw...), data; calc_extent, threaded, crs) simplify(alg::SimplifyAlg, data; kw...) = _simplify(alg, data; kw...) function _simplify(alg::SimplifyAlg, data; kw...) diff --git a/src/transformations/tuples.jl b/src/transformations/tuples.jl index ff82b781b..fe1bf0026 100644 --- a/src/transformations/tuples.jl +++ b/src/transformations/tuples.jl @@ -3,7 +3,14 @@ """ tuples(obj) -Convert all points on obj to `Tuple`s. +Convert all points in `obj` to `Tuple`s, wherever the are nested. + +Returns a similar object or collection of objects using GeoInterface.jl +geometries wrapping `Tuple` points. + +# Keywords + +$APPLY_KEYWORDS """ function tuples(geom; kw...) if _is3d(geom) diff --git a/test/runtests.jl b/test/runtests.jl index ee2065017..88e71bec3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -23,6 +23,7 @@ const GO = GeometryOps @testset "Signed Area" begin include("methods/signed_area.jl") end @testset "Overlaps" begin include("methods/overlaps.jl") end # Transformations + @testset "Embed Extent" begin include("transformations/extent.jl") end @testset "Reproject" begin include("transformations/reproject.jl") end @testset "Flip" begin include("transformations/flip.jl") end @testset "Simplify" begin include("transformations/simplify.jl") end diff --git a/test/transformations/extent.jl b/test/transformations/extent.jl new file mode 100644 index 000000000..beadeba9f --- /dev/null +++ b/test/transformations/extent.jl @@ -0,0 +1,16 @@ +using Test + +import GeoInterface as GI +import GeometryOps as GO +using GeoInterface: Extents + +@testset "embed_extent" begin + poly = GI.Polygon([GI.LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), + GI.LinearRing([(3, 4), (5, 6), (6, 7), (3, 4)])]) + + ext_poly = GO.embed_extent(poly) + lr1, lr2 = GI.getgeom(ext_poly) + @test ext_poly.extent == Extents.Extent(X=(1, 6), Y=(2, 7)) + @test lr1.extent == Extents.Extent(X=(1, 5), Y=(2, 6)) + @test lr2.extent == Extents.Extent(X=(3, 6), Y=(4, 7)) +end