Skip to content

Commit 1ba01f5

Browse files
committed
Added iterators. Added feature interface. Updated documentation based on review.
1 parent 7af21e4 commit 1ba01f5

File tree

9 files changed

+165
-46
lines changed

9 files changed

+165
-46
lines changed

docs/src/background/sf.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Simple Features
2-
Simple Features (SF) are OGC standards describing two dimensional geographic features, such as Points and Polygons and the relations between them.
3-
The standards describe a hierarchy of types (Part 1), an interface with SQL (Part II) and an SQL/MM extension with support for circular geometry.
2+
Simple Features ([SF](https://en.wikipedia.org/wiki/Simple_Features)) are OGC standards describing two dimensional geographic features, such as Points and Polygons and the relations between them.
3+
The standards describe a hierarchy of types (Part 1), a functional interface with SQL (Part II) and an SQL/MM extension with support for circular geometry types, such as `Circularstring`.
44

55
## Type hierarchy
66
All types used here come from the SF. We added `Trait` to all geometry types here to distinguish them from actual geometry structs.
@@ -12,7 +12,7 @@ All types used here come from the SF. We added `Trait` to all geometry types her
1212
While we try to adhere to SF, there are changes and extensions to make it more Julian.
1313

1414
### Function names
15-
All function names are without the `ST_` prefix and are lowercased. In some cases the names have changed as well, to be inline with common Julia functions. `NumX` becomes `nx` and `Xn` becomes `getX`:
15+
All function names are without the `ST_` prefix and are lowercased. In some cases the names have changed as well, to be inline with common Julia functions. `NumX` becomes `nx` and `geomN` becomes `getgeom`:
1616
```julia
1717
GeometryType -> geomtype
1818
NumGeometries -> ngeom
@@ -24,15 +24,18 @@ NumPatches -> npatch
2424
We generalized [`ngeom`](@ref) and [`getgeom`](@ref) to apply to
2525
all geometries, not just a [`AbstractGeometryCollectionTrait`](@ref)s.
2626

27-
We also simplified the dimension functions. From the three original (`dimension`, `coordinateDimension`, `spatialDimension`) there's now only the coordinate dimension, so not to overlap with the Julia `ndims`.
27+
We also simplified the dimension functions. From the three original (`dimension`, `coordinateDimension`, `spatialDimension`) there's now only the coordinate dimension, by using `ncoords`, which represent coordinate dimensions like `X`, `Y`, `Z` and `M`. Topological dimensions (a point is 0-dimensional), and the functions related to it, are not used in this interface to prevent confusion. Similarly, we do not overload the Julia `ndims`, to prevent confusion and possible conflict with custom vector based geometries.
28+
2829
```julia
2930
coordinateDimension -> ncoords # x, y, z, m
31+
dimension -> unused
32+
spatialDimension -> unused
3033
```
3134

32-
We've generalized the some functions:
35+
We've generalized the naming of some functions:
3336
```julia
3437
SRID -> crs
35-
envelope -> extent
38+
envelope -> extent # also aliased to bbox
3639
```
3740

3841
And added a helper method to clarify the naming of coordinates.
@@ -44,10 +47,9 @@ coordnames = (:X, :Y, :Z, :M)
4447
Not all SF functions are implemented, either as a possibly slower fallback or empty descriptor or not at all. The following SF functions are not (yet) available.
4548

4649
```julia
47-
dimension
50+
dimension # topological dimensions
4851
spatialDimension
49-
asText
50-
asBinary
52+
5153

5254
locateAlong
5355
locateBetween

docs/src/guides/defaults.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@ Of note here are the `ngeom` and `getgeom` for each geometry type, which transla
55
| | ngeom | getgeom |
66
|----------------------------|-------------|---------------|
77
| [`AbstractPointTrait`](@ref) | - | - |
8-
| [`AbstractCurveTrait`](@ref), [`MultiPointTrait`](@ref) | [`npoint`](@ref) | [`getpoint`](@ref) |
9-
| [`AbstractPolygonTrait`](@ref) | [`nring`](@ref) | [`getring`](@ref) |
10-
| [`AbstractMultiLineStringTrait`](@ref) | [`nlinestring`](@ref) | [`getlinestring`](@ref) |
11-
| [`AbstractMultiPolygonTrait`](@ref) | [`npolygon`](@ref) | [`getpolygon`](@ref) |
12-
| [`AbstractPolyhedralSurfaceTrait`](@ref) | [`npatch`](@ref) | [`getpatch`](@ref) |
13-
| [`AbstractGeometryCollectionTrait`](@ref) | [`ngeom`](@ref) | [`getgeom`](@ref) |
8+
| [`AbstractCurveTrait`](@ref), [`MultiPointTrait`](@ref) | [`npoint(geom)`](@ref) | [`getpoint(geom)`](@ref) |
9+
| [`AbstractPolygonTrait`](@ref) | [`nring(geom)`](@ref) | [`getring(geom)`](@ref) |
10+
| [`AbstractMultiLineStringTrait`](@ref) | [`nlinestring(geom)`](@ref) | [`getlinestring(geom)`](@ref) |
11+
| [`AbstractMultiPolygonTrait`](@ref) | [`npolygon(geom)`](@ref) | [`getpolygon(geom)`](@ref) |
12+
| [`AbstractPolyhedralSurfaceTrait`](@ref) | [`npatch(geom)`](@ref) | [`getpatch(geom)`](@ref) |
13+
| [`AbstractGeometryCollectionTrait`](@ref) | [`ngeom(geom)`](@ref) | [`getgeom(geom)`](@ref) |
1414

1515
## Polygons
1616
Of note are `PolygonTrait`s, which can have holes, for which we automatically add the following
17-
functions based on the `ngeom` implemented by package authors.
17+
functions based on the `ngeom` implemented by package authors. In some cases, the assumptions here
18+
are not correct (most notably Shapefile), where the second ring is not necessarily a hole, but could
19+
be another exterior.
1820

1921
```julia
2022
getexterior(p::AbstractPolygonTrait, geom) = getring(p, geom, 1)

docs/src/guides/developer.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ GeoInterface.getcoord(geomtype(geom), geom::customgeom, i)::Real # only for Poi
1515
GeoInterface.ngeom(geomtype(geom), geom::customgeom)::Integer
1616
GeoInterface.getgeom(geomtype(geom), geom::customgeom, i) # geomtype -> GeoInterface.Y
1717
```
18-
Where the `getgeom` could be an iterator (without the i) as well. It will return a new geom with the correct `geomtype`. The `ngeom` and `getgeom` are aliases for their geom specific counterparts, such as `npoints` and `getpoint` for LineStrings.
18+
Where the `getgeom` and `getcoord` could be an iterator (without the `i`) as well. It will return a new geom with the correct `geomtype`. The `ngeom` and `getgeom` are aliases for their geom specific counterparts, such as `npoints` and `getpoint` for LineStrings.
1919

2020
You read more about the `geomtype` in the [Type hierarchy](@ref).
2121

@@ -29,6 +29,13 @@ GeoInterface.extent(geomtype(geom), geom::customgeom)::Extents.Extent
2929

3030
And lastly, there are many other optional functions for each specific geometry. GeoInterface provides fallback implementations based on the generic functions above, but these are not optimized. These are detailed in [Fallbacks](@ref).
3131

32+
## Required for Feature
33+
```julia
34+
GeoInterface.isfeature(feat::customfeat)::Bool = true
35+
GeoInterface.properties(feat::customfeat)
36+
GeoInterface.geometry(feat::customfeat)
37+
```
38+
3239
## GeoSpatial Operations
3340
```julia
3441
distance(geomtype(a), geomtype(b), a, b)

docs/src/tutorials/usage.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
# Traits interface
2-
GeoInterface provides a traits interface, not unlike Tables.jl, by a set of functions and types.
2+
GeoInterface provides a traits interface, not unlike Tables.jl, by a set of functions and types for geospatial data.
33

44
## Functions
55
(a) a set of functions:
66
```julia
77
isgeometry(geom)
88
geomtype(geom)
99
ncoord(geom)
10+
getcoord(geom, i)
1011
ngeom(geom)
11-
getgeom(geom::geomtype, i)
12+
getgeom(geom, i)
1213
...
1314
```
1415

@@ -32,7 +33,7 @@ to work with their custom geometries, you can just call the above generic functi
3233
julia> using ArchGDAL
3334
julia> geom = createpolygon(...)::ArchGDAL.IGeometry # no idea about the interface
3435
35-
# With GeoInterface
36+
# Inspect with GeoInterface methods
3637
julia> isgeometry(geom)
3738
True
3839
julia> geomtype(geom)

src/defaults.jl

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,42 @@ isempty(T, geom) = false
2020

2121
## Points
2222
ngeom(::AbstractPointTrait, geom)::Integer = 0
23+
getgeom(::AbstractPointTrait, geom) = nothing
2324
getgeom(::AbstractPointTrait, geom, i) = nothing
2425

2526
## LineStrings
2627
npoint(c::AbstractCurveTrait, geom) = ngeom(c, geom)
28+
getpoint(c::AbstractCurveTrait, geom) = getgeom(c, geom)
2729
getpoint(c::AbstractCurveTrait, geom, i) = getgeom(c, geom, i)
2830
startpoint(c::AbstractCurveTrait, geom) = getpoint(c, geom, 1)
2931
endpoint(c::AbstractCurveTrait, geom) = getpoint(c, geom, length(geom))
3032

3133
## Polygons
3234
nring(p::AbstractPolygonTrait, geom) = ngeom(p, geom)
35+
getring(p::AbstractPolygonTrait, geom) = getgeom(p, geom)
3336
getring(p::AbstractPolygonTrait, geom, i) = getgeom(p, geom, i)
3437
getexterior(p::AbstractPolygonTrait, geom) = getring(p, geom, 1)
3538
nhole(p::AbstractPolygonTrait, geom) = nring(p, geom) - 1
3639
gethole(p::AbstractPolygonTrait, geom, i) = getring(p, geom, i + 1)
3740

3841
## MultiLineString
3942
nlinestring(p::AbstractMultiLineStringTrait, geom) = ngeom(p, geom)
43+
getlinestring(p::AbstractMultiLineStringTrait, geom) = getgeom(p, geom)
4044
getlinestring(p::AbstractMultiLineStringTrait, geom, i) = getgeom(p, geom, i)
4145

4246
## MultiPolygon
4347
npolygon(p::AbstractMultiPolygonTrait, geom) = ngeom(p, geom)
48+
getpolygon(p::AbstractMultiPolygonTrait, geom) = getgeom(p, geom)
4449
getpolygon(p::AbstractMultiPolygonTrait, geom, i) = getgeom(p, geom, i)
4550

4651
## Surface
4752
npatch(p::AbstractPolyHedralSurfaceTrait, geom)::Integer = ngeom(p, geom)
53+
getpatch(p::AbstractPolyHedralSurfaceTrait, geom) = getgeom(p, geom)
4854
getpatch(p::AbstractPolyHedralSurfaceTrait, geom, i::Integer) = getgeom(p, geom, i)
4955

56+
## Default iterator
57+
getgeom(p::AbstractGeometryTrait, geom) = (getgeom(p, geom, i) for i in 1:ngeom(p, geom))
58+
getcoord(p::AbstractPointTrait, geom) = (getcoord(p, geom, i) for i in 1:ncoord(p, geom))
5059

5160
## Npoints
5261
npoint(::LineTrait, _) = 2
@@ -71,8 +80,17 @@ extent(::AbstractGeometryTrait, geom) = nothing
7180

7281
# Backwards compatibility
7382
function coordinates(::AbstractPointTrait, geom)
74-
collect(getcoord(geom, i) for i in 1:ncoord(geom))
83+
collect(getcoord(geom))
7584
end
7685
function coordinates(::AbstractGeometryTrait, geom)
77-
collect(coordinates(getgeom(geom, i)) for i in 1:ngeom(geom))
86+
collect(coordinates(getgeom(geom)))
7887
end
88+
89+
# Subtraits
90+
subtrait(::PointTrait) = nothing
91+
subtrait(::LineStringTrait) = PointTrait
92+
subtrait(::PolygonTrait) = LineStringTrait
93+
subtrait(::MultiPointTrait) = PointTrait
94+
subtrait(::MultiLineStringTrait) = LineStringTrait
95+
subtrait(::MultiPolygonTrait) = PolygonTrait
96+
subtrait(::GeometryCollectionTrait) = nothing

src/interface.jl

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,35 @@ method.
1010
isgeometry(x::T) where {T} = isgeometry(T)
1111
isgeometry(::Type{T}) where {T} = false
1212

13+
"""
14+
GeoInterface.isfeature(x) => Bool
15+
16+
Check if an object `x` is a feature and thus implicitely supports some GeoInterface methods.
17+
A feature is a combination of a geometry and properties, not unlike a row in a table.
18+
It is recommended that for users implementing `MyType`, they define only
19+
`isfeature(::Type{MyType})`. `isfeature(::MyType)` will then automatically delegate to this
20+
method.
21+
Ensures backwards compatibility with the older GeoInterface.
22+
"""
23+
isfeature(x::T) where {T} = isfeature(T)
24+
isfeature(::Type{T}) where {T} = false
25+
26+
"""
27+
GeoInterface.geometry(feat) => geom
28+
29+
Retrieve the geometry of `feat`. It is expected that `isgeometry(geom) === true`.
30+
Ensures backwards compatibility with the older GeoInterface.
31+
"""
32+
geometry(feat) = nothing
33+
34+
"""
35+
GeoInterface.properties(feat) => properties
36+
37+
Retrieve the properties of `feat`. This can be any Iterable that behaves like an AbstractRow.
38+
Ensures backwards compatibility with the older GeoInterface.
39+
"""
40+
properties(feat) = nothing
41+
1342
"""
1443
GeoInterface.geomtype(geom) => T <: AbstractGeometry
1544
@@ -54,6 +83,10 @@ Return the `i`th coordinate for a given `geom`.
5483
Note that this is only valid for individual [`AbstractPoint`]s.
5584
"""
5685
getcoord(geom, i::Integer) = getcoord(geomtype(geom), geom, i)
86+
"""
87+
getcoord(geom) -> Iterator
88+
"""
89+
getcoord(geom) = getcoord(geomtype(geom), geom)
5790

5891
# Curve, LineString, MultiPoint
5992
"""
@@ -71,6 +104,10 @@ Return the `i`th Point in given `geom`.
71104
Note that this is only valid for [`AbstractCurve`](@ref)s and [`AbstractMultiPoint`](@ref)s.
72105
"""
73106
getpoint(geom, i::Integer) = getpoint(geomtype(geom), geom, i)
107+
"""
108+
getpoint(geom) -> Iterator
109+
"""
110+
getpoint(geom) = getpoint(geomtype(geom), geom)
74111

75112
# Curve
76113
"""
@@ -164,6 +201,10 @@ nring(geom) = nring(geomtype(geom), geom)
164201
Return the `i`th ring for a given `geom`.
165202
Note that this is only valid for [`AbstractPolygon`](@ref)s.
166203
"""
204+
getring(geom, i::Integer) = getring(geomtype(geom), geom, i)
205+
"""
206+
getring(geom) -> Iterator
207+
"""
167208
getring(geom) = getring(geomtype(geom), geom)
168209

169210
"""
@@ -189,6 +230,10 @@ Returns the `i`th interior ring for this given `geom`.
189230
Note that this is only valid for [`AbstractPolygon`](@ref)s.
190231
"""
191232
gethole(geom, i::Integer) = gethole(geomtype(geom), geom, i)
233+
"""
234+
gethole(geom) -> Iterator
235+
"""
236+
gethole(geom) = gethole(geomtype(geom), geom)
192237

193238
# PolyHedralSurface
194239
"""
@@ -206,6 +251,10 @@ Returns the `i`th patch for the given `geom`.
206251
Note that this is only valid for [`AbstractPolyHedralSurface`](@ref)s.
207252
"""
208253
getpatch(geom, i::Integer) = getpatch(geomtype(geom), geom, i)
254+
"""
255+
getpatch(geom) -> Iterator
256+
"""
257+
getpatch(geom) = getpatch(geomtype(geom), geom)
209258

210259
"""
211260
boundingpolygons(geom, i) -> AbstractMultiPolygon
@@ -228,6 +277,10 @@ ngeom(geom) = ngeom(geomtype(geom), geom)
228277
Returns the `i`th geometry for the given `geom`.
229278
"""
230279
getgeom(geom, i::Integer) = getgeom(geomtype(geom), geom, i)
280+
"""
281+
getgeom(geom) -> Iterator
282+
"""
283+
getgeom(geom) = getgeom(geomtype(geom), geom)
231284

232285
# MultiLineString
233286
"""
@@ -245,6 +298,10 @@ Returns the `i`th linestring for the given `geom`.
245298
Note that this is only valid for [`AbstractMultiLineString`](@ref)s.
246299
"""
247300
getlinestring(geom, i::Integer) = getlinestring(geomtype(geom), geom, i)
301+
"""
302+
getlinestring(geom) -> Iterator
303+
"""
304+
getlinestring(geom) = getlinestring(geomtype(geom), geom)
248305

249306
# MultiPolygon
250307
"""
@@ -254,13 +311,18 @@ Returns the number of polygons for the given `geom`.
254311
Note that this is only valid for [`AbstractMultiPolygon`](@ref)s.
255312
"""
256313
npolygon(geom) = npolygon(geomtype(geom), geom)
314+
257315
"""
258316
getpolygon(geom, i::Integer) -> AbstractCurve
259317
260318
Returns the `i`th polygon for the given `geom`.
261319
Note that this is only valid for [`AbstractMultiPolygon`](@ref)s.
262320
"""
263321
getpolygon(geom, i::Integer) = getpolygon(geomtype(geom), geom, i)
322+
"""
323+
getpolygon(geom) -> Iterator
324+
"""
325+
getpolygon(geom) = getpolygon(geomtype(geom), geom)
264326

265327
# Other methods
266328
"""
@@ -284,6 +346,7 @@ extent(geom) = extent(geomtype(geom), geom)
284346
285347
Alias for [`extent`](@ref), for compatibility with
286348
GeoJSON and the Python geointerface.
349+
Ensures backwards compatibility with the older GeoInterface.
287350
"""
288351
bbox(geom) = extent(geom)
289352

@@ -458,7 +521,7 @@ ismeasured(geom) = ismeasured(geomtype(geom), geom)
458521
coordinates(geom) -> Vector
459522
460523
Return (an iterator of) point coordinates.
461-
Ensure backwards compatibility with the older GeoInterface
524+
Ensures backwards compatibility with the older GeoInterface.
462525
"""
463526
coordinates(geom) = coordinates(geomtype(geom), geom)
464527

0 commit comments

Comments
 (0)