Skip to content

Commit

Permalink
add mode traits for convert
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaqz committed Dec 27, 2019
1 parent 881ef41 commit 58347d6
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 21 deletions.
76 changes: 59 additions & 17 deletions src/GeoFormatTypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@ end GeoFormatTypes

export GeoFormat

export CoordinateReferenceSystemFormat, EPSG, ProjString
export CoordinateReferenceSystemFormat, EPSG, ProjString, CoordSys

export GeometryFormat, GeoJSON, KML

export MixedFormat, GML
export MixedFormat, GML

export AbstractWellKnownText, WellKnownText, WellKnownText2, ESRIWellKnownText, WellKnownBinary

const PROJ_PREFIX = "+proj="
const EPSG_PREFIX = "EPSG:"
# TODO more verification that types are wrapping the right format.


# Traits for mixed crs/geometry formats.
abstract type FormatMode end
struct Geom <: FormatMode end
struct CRS <: FormatMode end
struct Mixed <: FormatMode end

"""
val(f::GeoFormat)
Expand All @@ -35,6 +39,25 @@ Abstract supertype for geospatial data formats
"""
abstract type GeoFormat end

# Convert from the same type does nothing.
Base.convert(::T, source::S) where {T<:GeoFormat,S<:T} = source
# Convert uses the `mode` trait to distinguish crs form geometry conversion
Base.convert(target::Type{<:GeoFormat}, input::GeoFormat) = begin
inputmode = mode(input)
targetmode = mode(target)
if inputmode isa Mixed
if targetmode isa Mixed
throw(ArgumentError("convert mode cannot be determined: please specify CRS() or Geom for mode in convert(::T, mode, source)"))
else
convert(target, targetmode, input)
end
elseif targetmode isa typeof(inputmode)
convert(target, inputmode, input)
else
throw(ArgumentError("cannot convert $(typeof(input)) to $target"))
end
end

"""
Formats representing coordinate reference systems
"""
Expand All @@ -49,10 +72,16 @@ abstract type GeometryFormat <: GeoFormat end
"""
Formats that may hold either or both coordinate reference systems and geometries.
"""
abstract type MixedFormat <: GeoFormat end
abstract type MixedFormat{X} <: GeoFormat end

val(x::GeoFormat) = x.val

mode(format::GeoFormat) = mode(typeof(format))
mode(::Type{<:GeometryFormat}) = Geom()
mode(::Type{<:CoordinateReferenceSystemFormat}) = CRS()
mode(::Type{<:MixedFormat}) = Mixed()
mode(::Type{<:MixedFormat{M}}) where M = M()

# Most GeoFormat types wrap String or have a constructor for string inputs
Base.convert(::Type{String}, input::GeoFormat) = val(input)
Base.convert(::Type{T}, input::AbstractString) where T <: GeoFormat = T(input)
Expand All @@ -70,44 +99,56 @@ struct ProjString <: CoordinateReferenceSystemFormat
end

"""
Well known text has a number of versions and standards, and can
Mapinfo CoordSys string
"""
struct CoordSys <: CoordinateReferenceSystemFormat
val::String
end

"""
Well known text has a number of versions and standards, and can
represent coordinate reference systems or geometric data.
"""
abstract type AbstractWellKnownText <: MixedFormat end
abstract type AbstractWellKnownText{X} <: MixedFormat{X} end

"""
Well known text v1 following the OGC standard
"""
struct WellKnownText <: AbstractWellKnownText
val::String
struct WellKnownText{X,T<:String} <: AbstractWellKnownText{X}
mode::X
val::T
end

"""
Well known text v2 following the new OGC standard
"""
struct WellKnownText2 <: AbstractWellKnownText
val::String
struct WellKnownText2{X,T<:String} <: AbstractWellKnownText{X}
mode::X
val::T
end

"""
Well known text following the ESRI standard
"""
struct ESRIWellKnownText <: AbstractWellKnownText
val::String
struct ESRIWellKnownText{X,T<:String} <: AbstractWellKnownText{X}
mode::X
val::T
end

"""
Well known binary
"""
struct WellKnownBinary{T} <: AbstractWellKnownText
struct WellKnownBinary{X,T} <: MixedFormat{X}
mode::X
val::T
end

Base.convert(::Type{String}, input::WellKnownBinary) = error("`convert` is not defined for `WellKnownBinary`")
Base.convert(::Type{String}, input::WellKnownBinary) =
error("`convert` to `String` is not defined for `WellKnownBinary`")


"""
EPSG code representing a coordinate reference system from the
EPSG code representing a coordinate reference system from the
EPSG spatial reference system registry.
"""
struct EPSG <: CoordinateReferenceSystemFormat
Expand Down Expand Up @@ -137,8 +178,9 @@ end
"""
Geography Markup Language
"""
struct GML <: MixedFormat
val::String
struct GML{X,T<:String} <: MixedFormat{X}
mode::X
val::T
end

"""
Expand Down
11 changes: 7 additions & 4 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GeoFormatTypes, Test
using GeoFormatTypes: Geom, CRS, Mixed

@test_throws ArgumentError ProjString("+lat_ts=56.5 +ellps=GRS80")
convert(String, ProjString("+proj=merc +lat_ts=56.5 +ellps=GRS80")) == "+proj=merc +lat_ts=56.5 +ellps=GRS80"
Expand All @@ -8,9 +9,11 @@ convert(String, ProjString("+proj=merc +lat_ts=56.5 +ellps=GRS80")) == "+proj=me
@test convert(String, EPSG(4326)) == "EPSG:4326"
@test convert(Int, EPSG("EPSG:4326")) == 4326

@test convert(String, WellKnownText("test")) == "test"
@test convert(String, WellKnownText2("test")) == "test"
@test convert(String, ESRIWellKnownText("test")) == "test"
@test convert(String, GML("test")) == "test"
@test convert(String, WellKnownText(Geom(), "test")) == "test"
@test convert(String, WellKnownText2(CRS(), "test")) == "test"
@test convert(String, ESRIWellKnownText(Geom(), "test")) == "test"
@test convert(String, GML(Mixed(), "test")) == "test"
@test convert(String, KML("test")) == "test"
@test convert(String, GeoJSON("test")) == "test"

@test_throws ArgumentError convert(KML, ProjString("+proj=test"))

0 comments on commit 58347d6

Please sign in to comment.