Skip to content

Commit

Permalink
add convert methods
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaqz committed May 19, 2022
1 parent 596fc46 commit 806a376
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 93 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ table = Shapefile.Table(path)
geoms = Shapefile.shapes(table)

# whole columns can be retrieved by their name
table.Descriptio # => Union{String, Missing}["Square with triangle missing", "Smaller triangle", missing]
table.Description # => Union{String, Missing}["Square with triangle missing", "Smaller triangle", missing]

# example function that iterates over the rows and gathers shapes that meet specific criteria
function selectshapes(table)
Expand Down Expand Up @@ -50,6 +50,7 @@ julia> GeoInterface.coordinates(Shapefile.shape(first(table)))
```

## Alternative packages

If you want another lightweight pure Julia package for reading feature files, consider
also [GeoJSON.jl](https://github.com/JuliaGeo/GeoJSON.jl).

Expand Down
1 change: 1 addition & 0 deletions src/Shapefile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ include("polygons.jl")
include("polylines.jl")
include("multipoints.jl")
include("multipatch.jl")
include("utils.jl")

# Handle/Table

Expand Down
5 changes: 5 additions & 0 deletions src/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ abstract type AbstractShape end
GeoInterface.isgeometry(::Type{<:AbstractShape}) = true
GeoInterface.ncoord(::GI.AbstractGeometryTrait, ::AbstractShape) = 2 # With specific methods when 3

Base.convert(T::Type{<:AbstractShape}, geom) = Base.convert(T, GI.geomtrait(geom), geom)
Base.convert(::Type{T}, geom::T) where {T<:AbstractShape} = geom
Base.convert(::Type{<:AbstractShape}, ::Nothing, geom) =
throw(ArgumentError("object to convert is not a GeoInterface compatible geometry"))

"""
Rect
Expand Down
18 changes: 14 additions & 4 deletions src/extent.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
const Shape3D = Union{PolylineZ,PolygonZ,MultiPointZ,MultiPatch}
const ShapeZ = Union{PolylineZ,PolygonZ,MultiPointZ,MultiPatch}
const ShapeM = Union{ShapeZ,PolylineM,PolygonM,MultiPointM}

# extent
# 3d
GI.is3d(::GI.AbstractGeometryTrait, ::AbstractShape) = false
GI.is3d(::GI.AbstractGeometryTrait, ::Shape3D) = true
GI.is3d(::GI.AbstractPointTrait, ::AbstractPoint) = false
GI.is3d(::GI.AbstractGeometryTrait, ::ShapeZ) = true
GI.is3d(::GI.AbstractPointTrait, ::PointZ) = true

# measured
GI.ismeasured(::GI.AbstractGeometryTrait, ::AbstractShape) = false
GI.ismeasured(::GI.AbstractGeometryTrait, ::ShapeM) = true
GI.ismeasured(::GI.AbstractPointTrait, ::Point) = false
GI.ismeasured(::GI.AbstractPointTrait, ::Union{PointM,PointZ}) = true

# extent
function GI.extent(x::AbstractShape)
rect = x.MBR
return Extents.Extent(X=(rect.left, rect.right), Y=(rect.bottom, rect.top))
end
function GI.extent(x::Union{Shape3D,Handle})
function GI.extent(x::Union{ShapeZ,Handle})
rect = x.MBR
return Extents.Extent(X=(rect.left, rect.right), Y=(rect.bottom, rect.top), Z=(x.zrange.left, x.zrange.right))
end
10 changes: 3 additions & 7 deletions src/multipatch.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,11 @@ function Base.read(io::IO, ::Type{MultiPatch})
box = read(io, Rect)
numparts = read(io, Int32)
numpoints = read(io, Int32)
parts = Vector{Int32}(undef, numparts)
read!(io, parts)
parts = _readparts(io, numparts)
parttypes = Vector{Int32}(undef, numparts)
read!(io, parttypes)
points = Vector{Point}(undef, numpoints)
read!(io, points)
zrange = read(io, Interval)
zvalues = Vector{Float64}(undef, numpoints)
read!(io, zvalues)
points = _readpoints(io, numpoints)
zrange, zvalues = _readfloats(io, numpoints)
# mrange = Vector{Float64}(2)
# read!(io, mrange)
# measures = Vector{Float64}(numpoints)
Expand Down
29 changes: 13 additions & 16 deletions src/multipoints.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

abstract type AbstractMultiPoint{T} <: AbstractShape end

_pointtype(::Type{<:AbstractMultiPoint{T}}) where T = T

Base.convert(::Type{T}, ::GI.MultiPointTrait, geom) where T<:AbstractMultiPoint =
T(_convert(_pointtype(T), geom)...)

GI.geomtrait(::AbstractMultiPoint) = GI.MultiPointTrait()
GI.ngeom(::GI.MultiPointTrait, geom::AbstractMultiPoint) = length(geom.points)
GI.ncoord(::GI.MultiPointTrait, geom::AbstractMultiPoint{T}) where {T} = _ncoord(T)
Expand All @@ -23,13 +28,13 @@ end
function Base.read(io::IO, ::Type{MultiPoint})
box = read(io, Rect)
numpoints = read(io, Int32)
points = Vector{Point}(undef, numpoints)
read!(io, points)
MultiPoint(box, points)
points = _readpoints(io, numpoints)
return MultiPoint(box, points)
end

GI.getgeom(::GI.MultiPointTrait, geom::MultiPoint, i::Integer) = geom.points[i]


"""
MultiPointM <: AbstractMultiPoint
Expand All @@ -54,11 +59,8 @@ end
function Base.read(io::IO, ::Type{MultiPointM})
box = read(io, Rect)
numpoints = read(io, Int32)
points = Vector{Point}(undef, numpoints)
read!(io, points)
mrange = read(io, Interval)
measures = Vector{Float64}(undef, numpoints)
read!(io, measures)
points = _readpoints(io, numpoints)
mrange, measures = _readm(io, numpoints)
MultiPointM(box, points, mrange, measures)
end

Expand Down Expand Up @@ -95,13 +97,8 @@ GI.getgeom(::GI.MultiPointTrait, geom::MultiPointZ, i::Integer) =
function Base.read(io::IO, ::Type{MultiPointZ})
box = read(io, Rect)
numpoints = read(io, Int32)
points = Vector{Point}(undef, numpoints)
read!(io, points)
zrange = read(io, Interval)
zvalues = Vector{Float64}(undef, numpoints)
read!(io, zvalues)
mrange = read(io, Interval)
measures = Vector{Float64}(undef, numpoints)
read!(io, measures)
points = _readpoints(io, numpoints)
zrange, zvalues = _readz(io, numpoints)
mrange, measures = _readm(io, numpoints)
MultiPointZ(box, points, zrange, zvalues, mrange, measures)
end
13 changes: 13 additions & 0 deletions src/points.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ function Base.read(io::IO, ::Type{Point})
Point(x, y)
end

Base.convert(::Type{<:Point}, ::GI.PointTrait, geom) = Point(GI.x(geom), GI.y(geom))

"""
PointM <: AbstractPoint
Expand All @@ -50,6 +52,11 @@ function Base.read(io::IO, ::Type{PointM})
PointM(x, y, m)
end

function Base.convert(::Type{<:PointM}, ::GI.PointTrait, geom)
m = GI.ismeasured(geom) ? GI.m(geom) : 0.0
PointM(GI.x(geom), GI.y(geom), m)
end

GI.m(::GI.PointTrait, point::PointM) = point.m

"""
Expand Down Expand Up @@ -77,6 +84,12 @@ function Base.read(io::IO, ::Type{PointZ})
PointZ(x, y, z, m)
end

function Base.convert(::Type{<:PointZ}, ::GI.PointTrait, geom)
z = GI.is3d(geom) ? GI.z(geom) : 0.0
m = GI.ismeasured(geom) ? GI.m(geom) : 0.0
PointZ(GI.x(geom), GI.y(geom), z, m)
end

GI.m(::GI.PointTrait, point::PointZ) = point.m
GI.z(::GI.PointTrait, point::PointZ) = point.z

Expand Down
38 changes: 16 additions & 22 deletions src/polygons.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ GI.getgeom(::GI.LinearRingTrait, lr::LinearRing, i::Integer) = lr[i]

Base.getindex(lr::LinearRing{Point}, i) = lr.xy[i]
Base.getindex(lr::LinearRing{PointM}, i) = PointM(lr.xy[i], lr.m[i])
Base.getindex(lr::LinearRing{PointZ}, i) = PointZ(lr.xy[i], lr.m[i], lr.z[i])
Base.getindex(lr::LinearRing{PointZ}, i) = PointZ(lr.xy[i], lr.z[i], lr.m[i])
Base.size(lr::LinearRing) = (length(lr),)
Base.length(lr::LinearRing) = length(lr.xy)

Expand All @@ -45,6 +45,11 @@ Base.push!(p::SubPolygon, x) = Base.push!(parent(p), x)

abstract type AbstractPolygon{T} <: AbstractShape end

_pointtype(::Type{<:AbstractPolygon{T}}) where T = T

Base.convert(::Type{T}, ::GI.MultiPolygonTrait, geom) where T<:AbstractPolygon =
T(_convertparts(_pointtype(T), geom)...)

# Shapefile polygons are OGC multipolygons
GI.geomtrait(geom::AbstractPolygon) = GI.MultiPolygonTrait()
GI.nring(::GI.MultiPolygonTrait, geom::AbstractPolygon) = length(geom.parts)
Expand All @@ -59,6 +64,7 @@ function GI.ngeom(::GI.MultiPolygonTrait, geom::AbstractPolygon)
return n
end


function GI.getring(t::GI.MultiPolygonTrait, geom::AbstractPolygon)
return (GI.getring(t, geom, i) for i in eachindex(geom.parts))
end
Expand Down Expand Up @@ -146,10 +152,8 @@ function Base.read(io::IO, ::Type{Polygon})
box = read(io, Rect)
numparts = read(io, Int32)
numpoints = read(io, Int32)
parts = Vector{Int32}(undef, numparts)
read!(io, parts)
points = Vector{Point}(undef, numpoints)
read!(io, points)
parts = _readparts(io, numparts)
points = _readpoints(io, numpoints)
Polygon(box, parts, points)
end

Expand All @@ -176,13 +180,9 @@ function Base.read(io::IO, ::Type{PolygonM})
box = read(io, Rect)
numparts = read(io, Int32)
numpoints = read(io, Int32)
parts = Vector{Int32}(undef, numparts)
read!(io, parts)
points = Vector{Point}(undef, numpoints)
read!(io, points)
mrange = read(io, Interval)
measures = Vector{Float64}(undef, numpoints)
read!(io, measures)
parts = _readparts(io, numparts)
points = _readpoints(io, numpoints)
mrange, measures = _readm(io, numpoints)
PolygonM(box, parts, points, mrange, measures)
end

Expand Down Expand Up @@ -212,15 +212,9 @@ function Base.read(io::IO, ::Type{PolygonZ})
box = read(io, Rect)
numparts = read(io, Int32)
numpoints = read(io, Int32)
parts = Vector{Int32}(undef, numparts)
read!(io, parts)
points = Vector{Point}(undef, numpoints)
read!(io, points)
zrange = read(io, Interval)
zvalues = Vector{Float64}(undef, numpoints)
read!(io, zvalues)
mrange = read(io, Interval)
measures = Vector{Float64}(undef, numpoints)
read!(io, measures)
parts = _readparts(io, numparts)
points = _readpoints(io, numpoints)
zrange, zvalues = _readz(io, numpoints)
mrange, measures = _readm(io, numpoints)
PolygonZ(box, parts, points, zrange, zvalues, mrange, measures)
end
37 changes: 15 additions & 22 deletions src/polylines.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ Base.size(p::LineString) = (length(p),)
Base.length(lr::LineString) = length(parent(lr))
Base.getindex(lr::LineString{Point}, i) = lr.xy[i]
Base.getindex(lr::LineString{PointM}, i) = PointM(lr.xy[i], lr.m[i])
Base.getindex(lr::LineString{PointZ}, i) = PointZ(lr.xy[i], lr.m[i], lr.z[i])
Base.getindex(lr::LineString{PointZ}, i) = PointZ(lr.xy[i], lr.z[i], lr.m[i])


abstract type AbstractPolyline{T} <: AbstractShape end

_pointtype(::Type{<:AbstractPolyline{T}}) where T = T

Base.convert(::Type{T}, ::GI.MultiLineStringTrait, geom) where T<:AbstractPolyline =
T(_convertparts(_pointtype(T), geom)...)

GI.geomtrait(::AbstractPolyline) = GI.MultiLineStringTrait()
GI.ngeom(::GI.MultiLineStringTrait, geom::AbstractPolyline) = length(geom.parts)
GI.ncoord(::GI.MultiLineStringTrait, ::AbstractPolyline{T}) where {T} = _ncoord(T)
Expand Down Expand Up @@ -59,10 +64,8 @@ function Base.read(io::IO, ::Type{Polyline})
box = read(io, Rect)
numparts = read(io, Int32)
numpoints = read(io, Int32)
parts = Vector{Int32}(undef, numparts)
read!(io, parts)
points = Vector{Point}(undef, numpoints)
read!(io, points)
parts = _readparts(io, numparts)
points = _readpoints(io, numpoints)
Polyline(box, parts, points)
end

Expand Down Expand Up @@ -94,13 +97,9 @@ function Base.read(io::IO, ::Type{PolylineM})
box = read(io, Rect)
numparts = read(io, Int32)
numpoints = read(io, Int32)
parts = Vector{Int32}(undef, numparts)
read!(io, parts)
points = Vector{Point}(undef, numpoints)
read!(io, points)
mrange = read(io, Interval)
measures = Vector{Float64}(undef, numpoints)
read!(io, measures)
parts = _readparts(io, numparts)
points = _readpoints(io, numpoints)
mrange, measures = _readm(io, numpoints)
PolylineM(box, parts, points, mrange, measures)
end

Expand Down Expand Up @@ -133,15 +132,9 @@ function Base.read(io::IO, ::Type{PolylineZ})
box = read(io, Rect)
numparts = read(io, Int32)
numpoints = read(io, Int32)
parts = Vector{Int32}(undef, numparts)
read!(io, parts)
points = Vector{Point}(undef, numpoints)
read!(io, points)
zrange = read(io, Interval)
zvalues = Vector{Float64}(undef, numpoints)
read!(io, zvalues)
mrange = read(io, Interval)
measures = Vector{Float64}(undef, numpoints)
read!(io, measures)
parts = _readparts(io, numparts)
points = _readpoints(io, numpoints)
zrange, zvalues = _readz(io, numpoints)
mrange, measures = _readm(io, numpoints)
PolylineZ(box, parts, points, zrange, zvalues, mrange, measures)
end
Loading

0 comments on commit 806a376

Please sign in to comment.