Repository: JuliaEarth/CoordRefSystems.jl (julia)

Issue:
Allow conversion `LatLon{WGS84Latest}` --> `Mercator{ITRF{2008}}`
MWE:

```julia
julia> convert(Mercator{ITRF{2008}}, LatLon{WGS84Latest}(0,0))
ERROR: MethodError: Cannot `convert` an object of type 
  GeodeticLatLon{WGS84Latest, Unitful.Quantity{Float64, NoDims, Unitful.FreeUnits{(°,), NoDims, nothing}}} to an object of type      
  Mercator{ITRF{2008}}
```

Pull request description:
closes #72

Patch:
diff --git a/src/crs/projected.jl b/src/crs/projected.jl
index 1832d5e6..9d6b33db 100644
--- a/src/crs/projected.jl
+++ b/src/crs/projected.jl
@@ -90,6 +90,12 @@ function Base.convert(::Type{LatLon{Datum}}, coords::C) where {Datum,C<:Projecte
   LatLon{Datum}(rad2deg(ϕ) * u"°", rad2deg(λ) * u"°")
 end
 
+Base.convert(C::Type{<:Projected{Datumₜ}}, coords::LatLon{Datumₛ}) where {Datumₜ,Datumₛ} =
+  convert(C, convert(LatLon{Datumₜ}, coords))
+
+Base.convert(C::Type{LatLon{Datumₜ}}, coords::Projected{Datumₛ}) where {Datumₜ,Datumₛ} =
+  convert(C, convert(LatLon, coords))
+
 Base.convert(::Type{Cartesian}, coords::Projected{Datum}) where {Datum} = convert(Cartesian{Datum,2}, coords)
 
 Base.convert(::Type{Cartesian{Datum,2}}, coords::Projected{Datum}) where {Datum} = Cartesian{Datum}(coords.x, coords.y)
diff --git a/src/crs/projected/shifted.jl b/src/crs/projected/shifted.jl
index 2edf7974..c70ccb24 100644
--- a/src/crs/projected/shifted.jl
+++ b/src/crs/projected/shifted.jl
@@ -95,7 +95,7 @@ function Base.convert(C::Type{<:ShiftedCRS{CRS,lonₒ,xₒ,yₒ}}, coords::LatLo
   C(pcoords.x + x, pcoords.y + y)
 end
 
-function Base.convert(C::Type{<:LatLon}, coords::ShiftedCRS{CRS,lonₒ,xₒ,yₒ}) where {CRS,lonₒ,xₒ,yₒ}
+function Base.convert(C::Type{LatLon{Datum}}, coords::ShiftedCRS{CRS,lonₒ,xₒ,yₒ}) where {CRS,lonₒ,xₒ,yₒ,Datum}
   T = numtype(coords.x)
   x = numconvert(T, xₒ)
   y = numconvert(T, yₒ)
@@ -105,6 +105,12 @@ function Base.convert(C::Type{<:LatLon}, coords::ShiftedCRS{CRS,lonₒ,xₒ,yₒ
   C(latlon.lat, latlon.lon + lon)
 end
 
+# ----------
+# FALLBACKS
+# ----------
+
+Base.convert(::Type{LatLon}, coords::ShiftedCRS) = convert(LatLon{datum(coords)}, coords)
+
 Base.convert(C::Type{<:ShiftedCRS{<:Projected{Datum}}}, coords::Cartesian{Datum,2}) where {Datum} =
   C(coords.x, coords.y)
 


Test patch:
diff --git a/test/crs/conversions.jl b/test/crs/conversions.jl
index 0545e14d..b18474fa 100644
--- a/test/crs/conversions.jl
+++ b/test/crs/conversions.jl
@@ -949,6 +949,52 @@
       @inferred convert(LatLon, c2)
     end
 
+    @testset "LatLon <> Projected (different datums)" begin
+      # WGS84 (G1762) to ITRF2008
+      c1 = LatLon(T(45), T(90))
+      c2 = convert(Mercator{ITRF{2008}}, c1)
+      @test allapprox(c2, Mercator{ITRF{2008}}(T(10018754.171394622), T(5591295.9185533915)))
+
+      c1 = Mercator(T(10018754.171394622), T(5591295.9185533915))
+      c2 = convert(LatLon{ITRF{2008}}, c1)
+      @test allapprox(c2, LatLon{ITRF{2008}}(T(45), T(90)))
+
+      # ITRF2008 to ITRF2020
+      ShiftedMercator = CoordRefSystems.shift(Mercator{ITRFLatest}, lonₒ=15.0u"°", xₒ=200.0u"m", yₒ=200.0u"m")
+      c1 = LatLon{ITRF{2008}}(T(45), T(90))
+      c2 = convert(ShiftedMercator, c1)
+      @test allapprox(c2, ShiftedMercator(T(8349161.8090374395), T(5591495.918071649)))
+
+      ShiftedMercator = CoordRefSystems.shift(Mercator{ITRF{2008}}, lonₒ=15.0u"°", xₒ=200.0u"m", yₒ=200.0u"m")
+      c1 = ShiftedMercator(T(8349161.8090374395), T(5591495.918071649))
+      c2 = convert(LatLon{ITRFLatest}, c1)
+      @test allapprox(c2, LatLon{ITRFLatest}(T(44.99999999574679), T(89.99999999177004)))
+
+      # GGRS87 to WGS84
+      c1 = LatLon{GGRS87}(T(45), T(90))
+      c2 = convert(PlateCarree{WGS84Latest}, c1)
+      @test allapprox(c2, PlateCarree(T(10019036.352134585), T(5009498.78549335)))
+
+      c1 = PlateCarree{GGRS87}(T(10019036.352134585), T(5009498.78549335))
+      c2 = convert(LatLon{WGS84Latest}, c1)
+      @test allapprox(c2, LatLon(T(45.002186400242984), T(90.00506975166428)))
+
+      # NAD83 to WGS84
+      c1 = LatLon{NAD83}(T(45), T(90))
+      c2 = convert(WinkelTripel{WGS84Latest}, c1)
+      @test allapprox(c2, WinkelTripel(T(7044801.698007298), T(5231448.051441181)))
+
+      c1 = WinkelTripel{NAD83}(T(7044801.698007298), T(5231448.051441181))
+      c2 = convert(LatLon{WGS84Latest}, c1)
+      @test allapprox(c2, LatLon(T(45), T(90)))
+
+      # type stability
+      c1 = LatLon(T(45), T(90))
+      c2 = Mercator(T(10018754.171394622), T(5591295.9185533915))
+      @inferred convert(Mercator{ITRF{2008}}, c1)
+      @inferred convert(LatLon{ITRF{2008}}, c2)
+    end
+
     @testset "Cartesian <> Projected" begin
       ShiftedMercator = CoordRefSystems.shift(Mercator{WGS84Latest}, lonₒ=15.0u"°", xₒ=200.0u"m", yₒ=200.0u"m")