From 657bfa1f3abebbbb24fe49d14df8891c8bde5e72 Mon Sep 17 00:00:00 2001 From: Martijn Visser Date: Mon, 19 Nov 2018 23:19:48 +0100 Subject: [PATCH] add Documenter docs (#19) * moved the basic example to the docs * added docstrings and fixed examples * updated to Documenter 2.0 for building the docs We will need to explicitly update our doc build dependencies through docs/Manifest.toml --- .travis.yml | 10 ++ README.md | 78 +------------ docs/.gitignore | 2 + docs/Manifest.toml | 100 +++++++++++++++++ docs/Project.toml | 7 ++ docs/make.jl | 12 ++ docs/src/index.md | 126 +++++++++++++++++++++ src/GeoJSON.jl | 267 ++++++++++++++++++++++++++++----------------- 8 files changed, 426 insertions(+), 176 deletions(-) create mode 100644 docs/.gitignore create mode 100644 docs/Manifest.toml create mode 100644 docs/Project.toml create mode 100644 docs/make.jl create mode 100644 docs/src/index.md diff --git a/.travis.yml b/.travis.yml index 4ed79e3..e9feb57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,3 +15,13 @@ notifications: after_success: # push coverage results to Coveralls - julia -e 'using Pkg; cd(Pkg.dir("GeoJSON")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())' +jobs: + include: + - stage: "Documentation" + julia: 1.0 + os: linux + script: + - julia --project=docs/ -e 'using Pkg; Pkg.instantiate(); + Pkg.develop(PackageSpec(path=pwd()))' + - julia --project=docs/ docs/make.jl + after_success: skip diff --git a/README.md b/README.md index 7fea396..775a4a2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![Build Status](https://travis-ci.org/JuliaGeo/GeoJSON.jl.svg)](https://travis-ci.org/JuliaGeo/GeoJSON.jl) [![Build Status](https://ci.appveyor.com/api/projects/status/github/JuliaGeo/GeoJSON.jl?svg=true&branch=master)](https://ci.appveyor.com/project/JuliaGeo/GeoJSON-jl/branch/master) [![Coverage Status](https://coveralls.io/repos/JuliaGeo/GeoJSON.jl/badge.svg)](https://coveralls.io/r/JuliaGeo/GeoJSON.jl) +[![Stable Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliageo.github.io/GeoJSON.jl/stable) +[![Latest Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://juliageo.github.io/GeoJSON.jl/latest) This library is developed independently of, but is heavily influenced in design by the [python-geojson](https://github.com/frewsxcv/python-geojson) package. It contains: @@ -10,78 +12,6 @@ This library is developed independently of, but is heavily influenced in design - a type hierarchy (according to the [GeoJSON specification](http://geojson.org/geojson-spec.html)) - An implementation of the [\__geo_interface\__](https://gist.github.com/sgillies/2217756), a GeoJSON-like protocol for geo-spatial (GIS) vector data. -## Installation -```julia -Pkg.add("GeoJSON") -# Running Pkg.update() will always give you the freshest version of GeoJSON -# Double-check that it works: -Pkg.test("GeoJSON") -``` +## Documentation -## Basic Usage -Although we use GeoInterface types for representing GeoJSON objects, it works in tandem with the [JSON.jl](https://github.com/JuliaIO/JSON.jl) package, for parsing ~~and printing~~ objects. Here are some examples of its functionality: - -- Parses a GeoJSON String or IO stream into a GeoInterface object -```julia -julia> using GeoJSON -julia> osm_buildings = """{ - "type": "FeatureCollection", - "features": [{ - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [13.42634, 52.49533], - [13.42660, 52.49524], - [13.42619, 52.49483], - [13.42583, 52.49495], - [13.42590, 52.49501], - [13.42611, 52.49494], - [13.42640, 52.49525], - [13.42630, 52.49529], - [13.42634, 52.49533] - ] - ] - }, - "properties": { - "color": "rgb(255,200,150)", - "height": 150 - } - }] - }""" -julia> buildings = GeoJSON.parse(osm_buildings) # GeoJSON.parse -- parse a GeoJSON string or stream -GeoInterface.FeatureCollection{GeoInterface.Feature}(GeoInterface.Feature[GeoInterface.Feature(GeoInterface.Polygon(Array{Array{Float64,1},1}[Array{Float64,1}[[13.4263,52.4953],[13.4266,52.4952],[13.4262,52.4948],[13.4258,52.495],[13.4259,52.495],[13.4261,52.4949],[13.4264,52.4952],[13.4263,52.4953],[13.4263,52.4953]]]),Dict{String,Any}(Pair{String,Any}("height",150),Pair{String,Any}("color","rgb(255,200,150)")))],nothing,nothing) -``` -Use `GeoJSON.parsefile("tech_square.geojson")` to read GeoJSON files from disk. - -- Transforms a GeoInterface object into a nested Array or Dict - -```julia -julia> dict = geo2dict(buildings) # geo2dict -- GeoInterface object to Dict/Array-representation -Dict{String,Any} with 2 entries: - "features" => Dict{String,Any}[Dict{String,Any}(Pair{String,Any}("geometry",Dict{String,Any}(Pair{String,Any}("coordi… - "type" => "FeatureCollection" - -julia> JSON.parse(osm_buildings) # should be comparable (if not the same) -Dict{String,Any} with 2 entries: - "features" => Any[Dict{String,Any}(Pair{String,Any}("geometry",Dict{String,Any}(Pair{String,Any}("coordinates",Any[An… - "type" => "FeatureCollection" -``` - -- Transforms from a nested Array/Dict to a GeoInterface object - -```julia -julia> dict2geo(dict) -GeoInterface.FeatureCollection{GeoInterface.Feature}(GeoInterface.Feature[GeoInterface.Feature(GeoInterface.Polygon(Array{Array{Float64,1},1}[Array{Float64,1}[[13.4263,52.4953],[13.4266,52.4952],[13.4262,52.4948],[13.4258,52.495],[13.4259,52.495],[13.4261,52.4949],[13.4264,52.4952],[13.4263,52.4953],[13.4263,52.4953]]]),Dict{String,Any}(Pair{String,Any}("height",150),Pair{String,Any}("color","rgb(255,200,150)")))],nothing,nothing) - -julia> GeoJSON.parse(osm_buildings) # the original object (for comparison) -GeoInterface.FeatureCollection{GeoInterface.Feature}(GeoInterface.Feature[GeoInterface.Feature(GeoInterface.Polygon(Array{Array{Float64,1},1}[Array{Float64,1}[[13.4263,52.4953],[13.4266,52.4952],[13.4262,52.4948],[13.4258,52.495],[13.4259,52.495],[13.4261,52.4949],[13.4264,52.4952],[13.4263,52.4953],[13.4263,52.4953]]]),Dict{String,Any}(Pair{String,Any}("height",150),Pair{String,Any}("color","rgb(255,200,150)")))],nothing,nothing) -``` - -- Writing back GeoJSON strings is not yet implemented - -## GeoInterface -This library implements the [GeoInterface](https://github.com/JuliaGeo/GeoInterface.jl). -For more information on the types that are returned by this package, and the methods that can be -used on them, refer to the documentation of the GeoInterface package. +Documentation for GeoJSON.jl can be found at https://juliageo.github.io/GeoJSON.jl/. diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..a303fff --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +build/ +site/ diff --git a/docs/Manifest.toml b/docs/Manifest.toml new file mode 100644 index 0000000..4e53165 --- /dev/null +++ b/docs/Manifest.toml @@ -0,0 +1,100 @@ +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[Distributed]] +deps = ["LinearAlgebra", "Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[DocStringExtensions]] +deps = ["LibGit2", "Markdown", "Pkg", "Test"] +git-tree-sha1 = "a016e0bfe98a748c4488e2248c2ef4c67d6fdd35" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.5.0" + +[[Documenter]] +deps = ["Base64", "DocStringExtensions", "InteractiveUtils", "LibGit2", "Logging", "Markdown", "Pkg", "REPL", "Random", "Test", "Unicode"] +git-tree-sha1 = "9f2135e0e7ecb63f9c3ef73ea15a31d8cdb79bb7" +uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +version = "0.20.0" + +[[GeoInterface]] +deps = ["RecipesBase"] +git-tree-sha1 = "59d34b371abfeda6a876e7d5ad5a12ac45faf252" +uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" +version = "0.4.0" + +[[InteractiveUtils]] +deps = ["LinearAlgebra", "Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[JSON]] +deps = ["Dates", "Distributed", "Mmap", "Sockets", "Test", "Unicode"] +git-tree-sha1 = "fec8e4d433072731466d37ed0061b3ba7f70eeb9" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.19.0" + +[[LibGit2]] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[LinearAlgebra]] +deps = ["Libdl"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[Pkg]] +deps = ["Dates", "LibGit2", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[RecipesBase]] +deps = ["Random", "Test"] +git-tree-sha1 = "0b3cb370ee4dc00f47f1193101600949f3dcf884" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "0.6.0" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[Test]] +deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[UUIDs]] +deps = ["Random"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..2935b1c --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,7 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" +JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" + +[compat] +Documenter = "~0.20" diff --git a/docs/make.jl b/docs/make.jl new file mode 100644 index 0000000..7a31d97 --- /dev/null +++ b/docs/make.jl @@ -0,0 +1,12 @@ +using Documenter +using GeoJSON + +makedocs( + sitename = "GeoJSON", + format = :html, + modules = [GeoJSON], +) + +deploydocs( + repo = "github.com/JuliaGeo/GeoJSON.jl.git" +) diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..98be69c --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,126 @@ +# GeoJSON.jl + +## Introduction +[![Build Status](https://travis-ci.org/JuliaGeo/GeoJSON.jl.svg)](https://travis-ci.org/JuliaGeo/GeoJSON.jl) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/JuliaGeo/GeoJSON.jl?svg=true&branch=master)](https://ci.appveyor.com/project/JuliaGeo/GeoJSON-jl/branch/master) +[![Coverage Status](https://coveralls.io/repos/JuliaGeo/GeoJSON.jl/badge.svg)](https://coveralls.io/r/JuliaGeo/GeoJSON.jl) +[![Stable Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliageo.github.io/GeoJSON.jl/stable) +[![Latest Documentation](https://img.shields.io/badge/docs-dev-blue.svg)](https://juliageo.github.io/GeoJSON.jl/dev) + +This library is developed independently of, but is heavily influenced in design by the [python-geojson](https://github.com/frewsxcv/python-geojson) package. It contains: + +- Functions for encoding and decoding GeoJSON formatted data +- a type hierarchy (according to the [GeoJSON specification](http://geojson.org/geojson-spec.html)) +- An implementation of the [\__geo_interface\__](https://gist.github.com/sgillies/2217756), a GeoJSON-like protocol for geo-spatial (GIS) vector data. + +## Contents +```@contents +``` + +## Installation +The package is registered and can be added using the package manager: +```julia +pkg> add GeoJSON +``` + +To test if it is installed correctly run: +```julia +pkg> test GeoJSON +``` + +## Basic Usage +Although we use GeoInterface types for representing GeoJSON objects, it works in tandem +with the [JSON.jl](https://github.com/JuliaIO/JSON.jl) package, for parsing and some +printing of objects. Here are some examples of its functionality: + +### Parses a GeoJSON String or IO stream into a GeoInterface object + +```@example basic +using GeoJSON +osm_buildings = """ +{ + "type": "FeatureCollection", + "features": [{ + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [13.42634, 52.49533], + [13.42630, 52.49529], + [13.42640, 52.49525], + [13.42611, 52.49494], + [13.42590, 52.49501], + [13.42583, 52.49495], + [13.42619, 52.49483], + [13.42660, 52.49524], + [13.42634, 52.49533] + ] + ] + }, + "properties": { + "color": "rgb(255,200,150)", + "height": 150 + } + }] +}""" +buildings = GeoJSON.parse(osm_buildings) +buildings +``` + +Use `GeoJSON.parsefile("tech_square.geojson")` to read GeoJSON files from disk. + +### Transforms a GeoInterface object into a nested Array or Dict + +```@example basic +dict = geo2dict(buildings) # geo2dict -- GeoInterface object to Dict/Array-representation +dict +``` + +```@example basic +using JSON +JSON.parse(osm_buildings) # should be comparable (if not the same) +``` + +### Transforms from a nested Array/Dict to a GeoInterface object + +```@example basic +dict2geo(dict) +``` + +```@example basic +GeoJSON.parse(osm_buildings) # the original object (for comparison) +``` + +*Writing back GeoJSON strings is not yet implemented.* + +## GeoInterface +This library implements the [GeoInterface](https://github.com/JuliaGeo/GeoInterface.jl). +For more information on the types that are returned by this package, and the methods that can be +used on them, refer to the documentation of the GeoInterface package. + +## Functions +### Input +To read in GeoJSON data, use [`GeoJSON.parse`](@ref), or to read a file from disk use +[`GeoJSON.parsefile`](@ref). +```@docs +GeoJSON.parse +GeoJSON.parsefile +``` + +### Output +```@docs +geojson +``` + +### Conversion +For more fine grained control, to construct or deconstruct parts of a GeoJSON, use +[`geo2dict`](@ref) or [`dict2geo`](@ref). +```@docs +geo2dict +dict2geo +``` + +## Index +```@index +``` diff --git a/src/GeoJSON.jl b/src/GeoJSON.jl index d2fe704..d6653a6 100644 --- a/src/GeoJSON.jl +++ b/src/GeoJSON.jl @@ -1,118 +1,181 @@ module GeoJSON - import GeoInterface - import JSON - - export dict2geo, - geo2dict, - geojson - - # String/File -> GeoJSON - parse(input; kwargs...) = dict2geo(JSON.parse(input; kwargs...)) - parsefile(filename; kwargs...) = dict2geo(JSON.parsefile(filename; kwargs...)) - - # GeoJSON -> String/IO - for geom in (:AbstractFeatureCollection, :AbstractGeometryCollection, :AbstractFeature, - :AbstractMultiPolygon, :AbstractPolygon, :AbstractMultiLineString, - :AbstractLineString, :AbstractMultiPoint, :AbstractPoint) - @eval geojson(obj::GeoInterface.$geom) = JSON.json(geo2dict(obj)) - end +import GeoInterface +import JSON - dict2geo(obj::Nothing) = nothing - - function dict2geo(obj::Dict{String,Any}) - t = Symbol(obj["type"]) - if t == :FeatureCollection - return parseFeatureCollection(obj) - elseif t == :Feature - return parseFeature(obj) - elseif t == :GeometryCollection - return parseGeometryCollection(obj) - elseif t == :MultiPolygon - return GeoInterface.MultiPolygon(obj["coordinates"]) - elseif t == :Polygon - return GeoInterface.Polygon(obj["coordinates"]) - elseif t == :MultiLineString - return GeoInterface.MultiLineString(obj["coordinates"]) - elseif t == :LineString - return GeoInterface.LineString(obj["coordinates"]) - elseif t == :MultiPoint - return GeoInterface.MultiPoint(obj["coordinates"]) - elseif t == :Point - return GeoInterface.Point(obj["coordinates"]) - end - end +export dict2geo, + geo2dict, + geojson - parseGeometryCollection(obj::Dict{String,Any}) = - GeoInterface.GeometryCollection(map(dict2geo,obj["geometries"])) - - function parseFeature(obj::Dict{String,Any}) - feature = GeoInterface.Feature(dict2geo(obj["geometry"]), obj["properties"]) - if haskey(obj, "id") - feature.properties["featureid"] = obj["id"] - end - if haskey(obj, "bbox") - feature.properties["bbox"] = GeoInterface.BBox(obj["bbox"]) - end - if haskey(obj, "crs") - feature.properties["crs"] = obj["crs"] - end - feature - end +""" + parse(input::Union{String, IO}, inttype::Type{<:Real}=Int64) - function parseFeatureCollection(obj::Dict{String,Any}) - features = GeoInterface.Feature[map(parseFeature,obj["features"])...] - featurecollection = GeoInterface.FeatureCollection(features) - if haskey(obj, "bbox") - featurecollection.bbox = GeoInterface.BBox(obj["bbox"]) - end - if haskey(obj, "crs") - featurecollection.crs = obj["crs"] - end - featurecollection - end +Parse a GeoJSON string or IO stream into a GeoInterface object. + +See also: [`parsefile`](@ref) + +# Examples +```julia +julia> GeoJSON.parse("{\"type\": \"Point\", \"coordinates\": [30, 10]}") +GeoInterface.Point([30.0, 10.0]) +``` +""" +parse(input; kwargs...) = dict2geo(JSON.parse(input; kwargs...)) + +""" + parsefile(filename::AbstractString, inttype::Type{<:Real}=Int64) + +Parse a GeoJSON file into a GeoInterface object. + +See also: [`parse`](@ref) +""" +parsefile(filename; kwargs...) = dict2geo(JSON.parsefile(filename; kwargs...)) + +""" + geojson(obj) - geo2dict(obj::Nothing) = nothing +Create a GeoJSON string from an object that implements the GeoInterface, either +`AbstractGeometry`, `AbstractFeature` or `AbstractFeatureCollection`. - function geo2dict(obj::GeoInterface.AbstractGeometry) - Dict("type" => string(GeoInterface.geotype(obj)), - "coordinates" => GeoInterface.coordinates(obj)) +# Examples +```julia +julia> geojson(Point([30.0, 10.0])) +\"{\"coordinates\":[30.0,10.0],\"type\":\"Point\"}\" +``` +""" +function geojson end + +for geom in (:AbstractFeatureCollection, :AbstractGeometryCollection, :AbstractFeature, + :AbstractMultiPolygon, :AbstractPolygon, :AbstractMultiLineString, + :AbstractLineString, :AbstractMultiPoint, :AbstractPoint) + @eval geojson(obj::GeoInterface.$geom) = JSON.json(geo2dict(obj)) +end + +""" + dict2geo(obj::Dict{String, Any}) + +Transform a parsed JSON dictionary to a GeoInterface object. + +See also: [`geo2dict`](@ref) + +# Examples +```julia +julia> dict2geo(Dict("type" => "Point", "coordinates" => [30.0, 10.0])) +Point([30.0, 10.0]) +``` +""" +function dict2geo(obj::Dict{String,Any}) + t = Symbol(obj["type"]) + if t == :FeatureCollection + return parseFeatureCollection(obj) + elseif t == :Feature + return parseFeature(obj) + elseif t == :GeometryCollection + return parseGeometryCollection(obj) + elseif t == :MultiPolygon + return GeoInterface.MultiPolygon(obj["coordinates"]) + elseif t == :Polygon + return GeoInterface.Polygon(obj["coordinates"]) + elseif t == :MultiLineString + return GeoInterface.MultiLineString(obj["coordinates"]) + elseif t == :LineString + return GeoInterface.LineString(obj["coordinates"]) + elseif t == :MultiPoint + return GeoInterface.MultiPoint(obj["coordinates"]) + elseif t == :Point + return GeoInterface.Point(obj["coordinates"]) end +end + +dict2geo(obj::Nothing) = nothing - function geo2dict(obj::GeoInterface.AbstractGeometryCollection) - Dict("type" => string(GeoInterface.geotype(obj)), - "geometries" => map(geo2dict, GeoInterface.geometries(obj))) +parseGeometryCollection(obj::Dict{String,Any}) = + GeoInterface.GeometryCollection(map(dict2geo,obj["geometries"])) + +function parseFeature(obj::Dict{String,Any}) + feature = GeoInterface.Feature(dict2geo(obj["geometry"]), obj["properties"]) + if haskey(obj, "id") + feature.properties["featureid"] = obj["id"] + end + if haskey(obj, "bbox") + feature.properties["bbox"] = GeoInterface.BBox(obj["bbox"]) end + if haskey(obj, "crs") + feature.properties["crs"] = obj["crs"] + end + feature +end - function geo2dict(obj::GeoInterface.AbstractFeature) - result = Dict("type" => string(GeoInterface.geotype(obj)), - "geometry" => geo2dict(GeoInterface.geometry(obj)), - "properties" => copy(GeoInterface.properties(obj))) - if haskey(result["properties"], "bbox") - result["bbox"] = result["properties"]["bbox"] - delete!(result["properties"], "bbox") - end - if haskey(result["properties"], "crs") - result["crs"] = result["properties"]["crs"] - delete!(result["properties"], "crs") - end - if haskey(result["properties"], "featureid") - result["id"] = result["properties"]["featureid"] - delete!(result["properties"], "featureid") - end - result +function parseFeatureCollection(obj::Dict{String,Any}) + features = GeoInterface.Feature[map(parseFeature,obj["features"])...] + featurecollection = GeoInterface.FeatureCollection(features) + if haskey(obj, "bbox") + featurecollection.bbox = GeoInterface.BBox(obj["bbox"]) + end + if haskey(obj, "crs") + featurecollection.crs = obj["crs"] end + featurecollection +end + +""" + geo2dict(obj) + +Transform a GeoInterface object to a JSON dictionary. + +See also: [`dict2geo`](@ref) + +# Examples +```julia +julia> geo2dict(Point([30.0, 10.0])) +Dict{String,Any} with 2 entries: + "coordinates" => [30.0, 10.0] + "type" => "Point" +``` +""" +function geo2dict end + +function geo2dict(obj::GeoInterface.AbstractGeometry) + Dict("type" => string(GeoInterface.geotype(obj)), + "coordinates" => GeoInterface.coordinates(obj)) +end - function geo2dict(obj::GeoInterface.AbstractFeatureCollection) - result = Dict("type" => string(GeoInterface.geotype(obj)), - "features" => map(geo2dict, GeoInterface.features(obj))) - if GeoInterface.bbox(obj) != nothing - result["bbox"] = GeoInterface.bbox(obj) - end - if GeoInterface.crs(obj) != nothing - result["crs"] = GeoInterface.crs(obj) - end - result +function geo2dict(obj::GeoInterface.AbstractGeometryCollection) + Dict("type" => string(GeoInterface.geotype(obj)), + "geometries" => map(geo2dict, GeoInterface.geometries(obj))) +end + +function geo2dict(obj::GeoInterface.AbstractFeature) + result = Dict("type" => string(GeoInterface.geotype(obj)), + "geometry" => geo2dict(GeoInterface.geometry(obj)), + "properties" => copy(GeoInterface.properties(obj))) + if haskey(result["properties"], "bbox") + result["bbox"] = result["properties"]["bbox"] + delete!(result["properties"], "bbox") + end + if haskey(result["properties"], "crs") + result["crs"] = result["properties"]["crs"] + delete!(result["properties"], "crs") end + if haskey(result["properties"], "featureid") + result["id"] = result["properties"]["featureid"] + delete!(result["properties"], "featureid") + end + result +end +function geo2dict(obj::GeoInterface.AbstractFeatureCollection) + result = Dict("type" => string(GeoInterface.geotype(obj)), + "features" => map(geo2dict, GeoInterface.features(obj))) + if GeoInterface.bbox(obj) != nothing + result["bbox"] = GeoInterface.bbox(obj) + end + if GeoInterface.crs(obj) != nothing + result["crs"] = GeoInterface.crs(obj) + end + result end + +geo2dict(obj::Nothing) = nothing + +end # module