Skip to content

Commit d414b1d

Browse files
committed
Implement GEOS, Proj, TG as algorithms
1 parent 262b33b commit d414b1d

File tree

1 file changed

+116
-18
lines changed

1 file changed

+116
-18
lines changed

src/types.jl

+116-18
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
#=
22
# Types
33
4-
This file defines some fundamental types used in GeometryOps.
4+
This file defines some types used in GeometryOps.
55
66
!!! warning
7-
Unlike in other Julia packages, only some types are defined in this file, not all.
8-
This is because we define types in the files where they are used, to make it easier to understand the code.
7+
Many type definitions are in `GeometryOpsCore`, not here. Look there for the definitions of the basic types like `Manifold`, `Algorithm`, etc.
8+
9+
10+
## Naming
11+
12+
We force all our external algorithm types to be uppercase, to make them different
13+
from the package names. This is really relevant for the `PROJ` algorithm, since
14+
the Julia package is called `Proj.jl`. If we called our type `Proj`, it would
15+
conflict with the package's name - as we saw with GeoFormatTypes' `GeoJSON` and `GeoJSON.jl`.
916
1017
=#
11-
export GEOS
18+
export GEOS, TG, PROJ
1219
#=
1320
1421
## `GEOS`
@@ -23,6 +30,62 @@ useful for two reasons:
2330
2431
=#
2532

33+
# ## C-library planar algorithms
34+
"""
35+
abstract type CLibraryPlanarAlgorithm <: GeometryOpsCore.SingleManifoldAlgorithm{Planar} end
36+
37+
This is a type which extends `GeometryOpsCore.SingleManifoldAlgorithm{Planar}`,
38+
and is used as an abstract supertype for some C library based algorithms.
39+
40+
The type requires that algorithm structs be arranged as:
41+
```
42+
struct MyAlgorithm <: CLibraryPlanarAlgorithm
43+
manifold::Planar
44+
params::NamedTuple
45+
end
46+
```
47+
48+
Then you get a nice constructor for free, as well as the
49+
`get(alg, key, value)` and `get(alg, key) do ...` syntax.
50+
Plus the [`enforce`](@ref) method, which will check that given keyword arguments
51+
are present.
52+
"""
53+
abstract type CLibraryPlanarAlgorithm <: GeometryOpsCore.SingleManifoldAlgorithm{Planar} end
54+
55+
56+
function (::Type{T})(; params...) where {T <: CLibraryPlanarAlgorithm}
57+
nt = NamedTuple(params)
58+
return T(Planar(), nt)
59+
end
60+
(T::Type{<: CLibraryPlanarAlgorithm})(params::NamedTuple) = T(Planar(), params)
61+
62+
63+
# These are definitions for convenience, so we don't have to type out
64+
# `alg.params` every time.
65+
66+
Base.get(alg::CLibraryPlanarAlgorithm, key, value) = Base.get(alg.params, key, value)
67+
Base.get(f::Function, alg::CLibraryPlanarAlgorithm, key) = Base.get(f, alg.params, key)
68+
69+
"""
70+
enforce(alg::CLibraryPlanarAlgorithm, kw::Symbol, f)
71+
72+
Enforce the presence of a keyword argument in a `GEOS` algorithm, and return `alg.params[kw]`.
73+
74+
Throws an error if the key is not present, and mentions `f` in the error message (since there isn't
75+
a good way to get the name of the function that called this method).
76+
77+
This applies to all `CLibraryPlanarAlgorithm` types, like [`GEOS`](@ref) and [`TG`](@ref).
78+
"""
79+
function enforce(alg::CLibraryPlanarAlgorithm, kw::Symbol, f)
80+
if haskey(alg.params, kw)
81+
return alg.params[kw]
82+
else
83+
error("$(f) requires a `$(kw)` keyword argument to the `GEOS` algorithm, which was not provided.")
84+
end
85+
end
86+
87+
# ## GEOS - call into LibGEOS.jl
88+
2689
"""
2790
GEOS(; params...)
2891
@@ -33,31 +96,66 @@ Dispatch is generally carried out using the names of the keyword arguments.
3396
For example, `segmentize` will only accept a `GEOS` struct with only a
3497
`max_distance` keyword, and no other.
3598
36-
It's generally a lot slower than the native Julia implementations, since
99+
It's generally somewhat slower than the native Julia implementations, since
37100
it must convert to the LibGEOS implementation and back - so be warned!
101+
102+
## Extended help
103+
104+
This uses the [LibGEOS.jl](https://github.com/JuliaGeometry/LibGEOS.jl) package,
105+
which is a Julia wrapper around the C library GEOS (https://trac.osgeo.org/geos).
38106
"""
39-
struct GEOS
107+
struct GEOS <: CLibraryPlanarAlgorithm # SingleManifoldAlgorithm{Planar}
108+
manifold::Planar
40109
params::NamedTuple
41110
end
42111

43-
function GEOS(; params...)
44-
nt = NamedTuple(params)
45-
return GEOS(nt)
112+
# ## TG - call into TGGeometry.jl
113+
114+
"""
115+
TG(; params...)
116+
117+
A struct which instructs the method it's passed to as an algorithm
118+
to use the appropriate TG function via `TGGeometry.jl` for the operation.
119+
120+
It's generally a lot faster than the native Julia implementations, but only
121+
supports planar manifolds / operations. Also, it only supports geometric predicates,
122+
specifically the ones which the underlying `tg` library supports. These are:
123+
124+
[`equals`](@ref), [`intersects`](@ref), [`disjoint`](@ref), [`contains`](@ref),
125+
[`within`](@ref), [`covers`](@ref), [`coveredby`](@ref), and [`touches`](@ref).
126+
127+
## Extended help
128+
129+
This uses the [TGGeometry.jl](https://github.com/JuliaGeo/TGGeometry.jl) package,
130+
which is a Julia wrapper around the `tg` C library (https://github.com/tidwall/tg).
131+
"""
132+
struct TG <: CLibraryPlanarAlgorithm
133+
manifold::Planar
134+
params::NamedTuple
46135
end
47-
# These are definitions for convenience, so we don't have to type out
48-
# `alg.params` every time.
49-
Base.get(alg::GEOS, key, value) = Base.get(alg.params, key, value)
50-
Base.get(f::Function, alg::GEOS, key) = Base.get(f, alg.params, key)
136+
137+
# ## PROJ - call into Proj.jl
51138

52139
"""
53-
enforce(alg::GO.GEOS, kw::Symbol, f)
140+
PROJ(; params...)
54141
55-
Enforce the presence of a keyword argument in a `GEOS` algorithm, and return `alg.params[kw]`.
142+
A struct which instructs the method it's passed to as an algorithm
143+
to use the appropriate PROJ function via `Proj.jl` for the operation.
56144
57-
Throws an error if the key is not present, and mentions `f` in the error message (since there isn't
58-
a good way to get the name of the function that called this method).
145+
## Extended help
146+
147+
This is the default algorithm for [`reproject`](@ref), and is also the default algorithm for
59148
"""
60-
function enforce(alg::GEOS, kw::Symbol, f)
149+
struct PROJ{M <: Manifold} <: Algorithm{M}
150+
manifold::M
151+
params::NamedTuple
152+
end
153+
154+
# We repeat these functions here because PROJ does not subtype `CLibraryPlanarAlgorithm`.
155+
156+
Base.get(alg::PROJ, key, value) = Base.get(alg.params, key, value)
157+
Base.get(f::Function, alg::PROJ, key) = Base.get(f, alg.params, key)
158+
function enforce(alg::PROJ, kw::Symbol, f)
61159
if haskey(alg.params, kw)
62160
return alg.params[kw]
63161
else

0 commit comments

Comments
 (0)