diff --git a/src/fallbacks.jl b/src/fallbacks.jl index c90de2ed..220fa084 100644 --- a/src/fallbacks.jl +++ b/src/fallbacks.jl @@ -109,6 +109,15 @@ function coordinates(t::AbstractFeatureTrait, feature) end coordinates(t::AbstractFeatureCollectionTrait, fc) = [coordinates(f) for f in getfeature(fc)] +# Package level `GeoInterface.convert` method +# Packages must implement their own `traittype` method +# that accepts a GeoInterface.jl trait and returns the +# corresponding geometry type +function convert(package::Module, geom) + t = trait(geom) + convert(package.geointerface_geomtype(t), t, geom) +end + # Subtraits """ diff --git a/src/interface.jl b/src/interface.jl index 99242350..599335ec 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -605,8 +605,12 @@ coordinates(obj) = coordinates(trait(obj), obj) """ convert(type::CustomGeom, geom) + convert(module::Module, geom) Create a `CustomGeom` from any `geom` that implements the GeoInterface. + +Can also convert to a `Module`, which finds the corresponding +geom type for the trait using the modules `geointerface_traittype` method. """ convert(T, geom) = convert(T, geomtrait(geom), geom) convert(::Type{T}, x::T) where {T} = x # no-op diff --git a/test/test_primitives.jl b/test/test_primitives.jl index 99958da3..d61a3f25 100644 --- a/test/test_primitives.jl +++ b/test/test_primitives.jl @@ -1,87 +1,88 @@ using GeoInterface using Test -@testset "Developer" begin - # Implement interface - struct MyPoint end - struct MyEmptyPoint end - struct MyCurve end - struct MyPolygon end - struct MyTriangle end - struct MyMultiPoint end - struct MyMultiCurve end - struct MyMultiPolygon end - struct MyTIN end - struct MyCollection end - struct MyFeature{G,P} - geometry::G - properties::P - end - struct MyFeatureCollection{G} - geoms::G - end +# Implement interface +struct MyPoint end +struct MyEmptyPoint end +struct MyCurve end +struct MyPolygon end +struct MyTriangle end +struct MyMultiPoint end +struct MyMultiCurve end +struct MyMultiPolygon end +struct MyTIN end +struct MyCollection end +struct MyFeature{G,P} + geometry::G + properties::P +end +struct MyFeatureCollection{G} + geoms::G +end + +GeoInterface.isgeometry(::MyPoint) = true +GeoInterface.geomtrait(::MyPoint) = PointTrait() +GeoInterface.ncoord(::PointTrait, geom::MyPoint) = 2 +GeoInterface.getcoord(::PointTrait, geom::MyPoint, i) = [1, 2][i] + +GeoInterface.isgeometry(::MyEmptyPoint) = true +GeoInterface.geomtrait(::MyEmptyPoint) = PointTrait() +GeoInterface.ncoord(::PointTrait, geom::MyEmptyPoint) = 0 +GeoInterface.isempty(::PointTrait, geom::MyEmptyPoint) = true + +GeoInterface.isgeometry(::MyCurve) = true +GeoInterface.geomtrait(::MyCurve) = LineStringTrait() +GeoInterface.ngeom(::LineStringTrait, geom::MyCurve) = 2 +GeoInterface.getgeom(::LineStringTrait, geom::MyCurve, i) = MyPoint() + +GeoInterface.isgeometry(::MyPolygon) = true +GeoInterface.geomtrait(::MyPolygon) = PolygonTrait() +GeoInterface.ngeom(::PolygonTrait, geom::MyPolygon) = 2 +GeoInterface.getgeom(::PolygonTrait, geom::MyPolygon, i) = MyCurve() + +GeoInterface.isgeometry(::MyTriangle) = true +GeoInterface.geomtrait(::MyTriangle) = TriangleTrait() +GeoInterface.ngeom(::TriangleTrait, geom::MyTriangle) = 3 +GeoInterface.getgeom(::TriangleTrait, geom::MyTriangle, i) = MyCurve() + +GeoInterface.isgeometry(::MyMultiPoint) = true +GeoInterface.geomtrait(::MyMultiPoint) = MultiPointTrait() +GeoInterface.ngeom(::MultiPointTrait, geom::MyMultiPoint) = 2 +GeoInterface.getgeom(::MultiPointTrait, geom::MyMultiPoint, i) = MyPoint() + +GeoInterface.isgeometry(::MyMultiCurve) = true +GeoInterface.geomtrait(::MyMultiCurve) = MultiCurveTrait() +GeoInterface.ngeom(::MultiCurveTrait, geom::MyMultiCurve) = 2 +GeoInterface.getgeom(::MultiCurveTrait, geom::MyMultiCurve, i) = MyCurve() + +GeoInterface.isgeometry(::MyMultiPolygon) = true +GeoInterface.geomtrait(::MyMultiPolygon) = MultiPolygonTrait() +GeoInterface.ngeom(::MultiPolygonTrait, geom::MyMultiPolygon) = 2 +GeoInterface.getgeom(::MultiPolygonTrait, geom::MyMultiPolygon, i) = MyPolygon() + +GeoInterface.isgeometry(::MyTIN) = true +GeoInterface.geomtrait(::MyTIN) = PolyhedralSurfaceTrait() +GeoInterface.ngeom(::PolyhedralSurfaceTrait, geom::MyTIN) = 2 +GeoInterface.getgeom(::PolyhedralSurfaceTrait, geom::MyTIN, i) = MyTriangle() + +GeoInterface.isgeometry(::MyCollection) = true +GeoInterface.geomtrait(::MyCollection) = GeometryCollectionTrait() +GeoInterface.ngeom(::GeometryCollectionTrait, geom::MyCollection) = 2 +GeoInterface.getgeom(::GeometryCollectionTrait, geom::MyCollection, i) = MyCurve() + +GeoInterface.isfeature(::Type{<:MyFeature}) = true +GeoInterface.trait(feature::MyFeature) = FeatureTrait() +GeoInterface.geometry(f::MyFeature) = f.geometry +GeoInterface.properties(f::MyFeature) = f.properties +GeoInterface.extent(f::MyFeature) = nothing + +GeoInterface.isfeaturecollection(fc::Type{<:MyFeatureCollection}) = true +GeoInterface.trait(fc::MyFeatureCollection) = FeatureCollectionTrait() +GeoInterface.nfeature(::FeatureCollectionTrait, fc::MyFeatureCollection) = length(fc.geoms) +GeoInterface.getfeature(::FeatureCollectionTrait, fc::MyFeatureCollection) = fc.geoms +GeoInterface.getfeature(::FeatureCollectionTrait, fc::MyFeatureCollection, i::Integer) = fc.geoms[i] - GeoInterface.isgeometry(::MyPoint) = true - GeoInterface.geomtrait(::MyPoint) = PointTrait() - GeoInterface.ncoord(::PointTrait, geom::MyPoint) = 2 - GeoInterface.getcoord(::PointTrait, geom::MyPoint, i) = [1, 2][i] - - GeoInterface.isgeometry(::MyEmptyPoint) = true - GeoInterface.geomtrait(::MyEmptyPoint) = PointTrait() - GeoInterface.ncoord(::PointTrait, geom::MyEmptyPoint) = 0 - GeoInterface.isempty(::PointTrait, geom::MyEmptyPoint) = true - - GeoInterface.isgeometry(::MyCurve) = true - GeoInterface.geomtrait(::MyCurve) = LineStringTrait() - GeoInterface.ngeom(::LineStringTrait, geom::MyCurve) = 2 - GeoInterface.getgeom(::LineStringTrait, geom::MyCurve, i) = MyPoint() - - GeoInterface.isgeometry(::MyPolygon) = true - GeoInterface.geomtrait(::MyPolygon) = PolygonTrait() - GeoInterface.ngeom(::PolygonTrait, geom::MyPolygon) = 2 - GeoInterface.getgeom(::PolygonTrait, geom::MyPolygon, i) = MyCurve() - - GeoInterface.isgeometry(::MyTriangle) = true - GeoInterface.geomtrait(::MyTriangle) = TriangleTrait() - GeoInterface.ngeom(::TriangleTrait, geom::MyTriangle) = 3 - GeoInterface.getgeom(::TriangleTrait, geom::MyTriangle, i) = MyCurve() - - GeoInterface.isgeometry(::MyMultiPoint) = true - GeoInterface.geomtrait(::MyMultiPoint) = MultiPointTrait() - GeoInterface.ngeom(::MultiPointTrait, geom::MyMultiPoint) = 2 - GeoInterface.getgeom(::MultiPointTrait, geom::MyMultiPoint, i) = MyPoint() - - GeoInterface.isgeometry(::MyMultiCurve) = true - GeoInterface.geomtrait(::MyMultiCurve) = MultiCurveTrait() - GeoInterface.ngeom(::MultiCurveTrait, geom::MyMultiCurve) = 2 - GeoInterface.getgeom(::MultiCurveTrait, geom::MyMultiCurve, i) = MyCurve() - - GeoInterface.isgeometry(::MyMultiPolygon) = true - GeoInterface.geomtrait(::MyMultiPolygon) = MultiPolygonTrait() - GeoInterface.ngeom(::MultiPolygonTrait, geom::MyMultiPolygon) = 2 - GeoInterface.getgeom(::MultiPolygonTrait, geom::MyMultiPolygon, i) = MyPolygon() - - GeoInterface.isgeometry(::MyTIN) = true - GeoInterface.geomtrait(::MyTIN) = PolyhedralSurfaceTrait() - GeoInterface.ngeom(::PolyhedralSurfaceTrait, geom::MyTIN) = 2 - GeoInterface.getgeom(::PolyhedralSurfaceTrait, geom::MyTIN, i) = MyTriangle() - - GeoInterface.isgeometry(::MyCollection) = true - GeoInterface.geomtrait(::MyCollection) = GeometryCollectionTrait() - GeoInterface.ngeom(::GeometryCollectionTrait, geom::MyCollection) = 2 - GeoInterface.getgeom(::GeometryCollectionTrait, geom::MyCollection, i) = MyCurve() - - GeoInterface.isfeature(::Type{<:MyFeature}) = true - GeoInterface.trait(feature::MyFeature) = FeatureTrait() - GeoInterface.geometry(f::MyFeature) = f.geometry - GeoInterface.properties(f::MyFeature) = f.properties - GeoInterface.extent(f::MyFeature) = nothing - - GeoInterface.isfeaturecollection(fc::Type{<:MyFeatureCollection}) = true - GeoInterface.trait(fc::MyFeatureCollection) = FeatureCollectionTrait() - GeoInterface.nfeature(::FeatureCollectionTrait, fc::MyFeatureCollection) = length(fc.geoms) - GeoInterface.getfeature(::FeatureCollectionTrait, fc::MyFeatureCollection) = fc.geoms - GeoInterface.getfeature(::FeatureCollectionTrait, fc::MyFeatureCollection, i::Integer) = fc.geoms[i] +@testset "Developer" begin @testset "Point" begin geom = MyPoint() @@ -366,4 +367,20 @@ end @test GeoInterface.testfeature(feature) @test GeoInterface.testfeaturecollection([feature, feature]) end + + +end + +module ConvertTestModule + using GeoInterface + struct TestPolygon end + geointerface_geomtype(::GeoInterface.PolygonTrait) = TestPolygon + + GeoInterface.isgeometry(::TestPolygon) = true + GeoInterface.geomtrait(::TestPolygon) = PolygonTrait() + GeoInterface.ngeom(::PolygonTrait, geom::TestPolygon) = 2 + GeoInterface.getgeom(::PolygonTrait, geom::TestPolygon, i) = TestCurve() + GeoInterface.convert(::Type{<:TestPolygon}, ::PolygonTrait, geom) = TestPolygon() end + +@test GeoInterface.convert(ConvertTestModule, MyPolygon()) == ConvertTestModule.TestPolygon()