Skip to content

Commit b3811be

Browse files
authored
Add backward methods for Horizontal Grid Shift and Point Motion (#16)
* Add backward methods for Horizontal Grid Shift and Point Motion * Add utils.jl * Add tests * Update comments * Fix code * Update tests * Fix code * Add comments * Rename variables * Update comments * More adjustments
1 parent 7490c80 commit b3811be

File tree

6 files changed

+211
-1
lines changed

6 files changed

+211
-1
lines changed

src/CoordGridTransforms.jl

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ function __init__()
2222
ENV["DATADEPS_ALWAYS_ACCEPT"] = true
2323
end
2424

25+
include("utils.jl")
2526
include("grids.jl")
2627
include("transforms.jl")
2728

src/transforms/hgridshift.jl

+37
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ macro hgridshift(Datumₛ, Datumₜ)
1919
latlon′ = hgridshiftfwd(Dₛ, Dₜ, latlon)
2020
LatLon{Dₜ}(latlon′...)
2121
end
22+
23+
function Base.convert(::Type{LatLon{Dₛ}}, coords::LatLon{Dₜ}) where {Dₛ<:$Datumₛ,Dₜ<:$Datumₜ}
24+
latlon = (coords.lat, coords.lon)
25+
latlon′ = hgridshiftbwd(Dₛ, Dₜ, latlon)
26+
LatLon{Dₛ}(latlon′...)
27+
end
2228
end
2329
esc(expr)
2430
end
@@ -28,6 +34,37 @@ function hgridshiftfwd(Datumₛ, Datumₜ, (lat, lon))
2834
lat + latshift, lon + lonshift
2935
end
3036

37+
# Adapted from PROJ coordinate transformation software
38+
# Initial PROJ 4.3 public domain code was put as Frank Warmerdam as copyright
39+
# holder, but he didn't mean to imply he did the work. Essentially all work was
40+
# done by Gerald Evenden.
41+
42+
# reference code: https://github.com/OSGeo/PROJ/blob/master/src/grids.cpp
43+
44+
function hgridshiftbwd(Datumₛ, Datumₜ, (lat, lon))
45+
tol = atol(numtype(lon))
46+
# initial guess
47+
latshift, lonshift = hgridshiftparams(Datumₛ, Datumₜ, lat, lon)
48+
latᵢ = lat - latshift
49+
lonᵢ = lon - lonshift
50+
for _ in 1:MAXITER
51+
# to check if the guess is equivalent to the original Datumₛ coordinates,
52+
# forward the guess coordinates to compare them with the Datumₜ input coordinates
53+
latᵢ′, lonᵢ′ = hgridshiftfwd(Datumₛ, Datumₜ, (latᵢ, lonᵢ))
54+
# difference between forward coordinates and input coordinates for comparison
55+
latΔ = latᵢ′ - lat
56+
lonΔ = lonᵢ′ - lon
57+
# if the difference is small, stop the iteration
58+
if hypot(latΔ, lonΔ) tol
59+
break
60+
end
61+
# otherwise, subtract the difference and continue
62+
latᵢ -= latΔ
63+
lonᵢ -= lonΔ
64+
end
65+
latᵢ, lonᵢ
66+
end
67+
3168
function hgridshiftparams(Datumₛ, Datumₜ, lat, lon)
3269
T = numtype(lon)
3370
itp = interpolatelatlon(Datumₛ, Datumₜ, lat, lon)

src/transforms/pointmotion.jl

+55
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ macro pointmotion(Datumₛ, Datumₜ)
1818
latlonalt′ = pointmotionfwd(Dₛ, Dₜ, latlonalt)
1919
LatLonAlt{Dₜ}(latlonalt′...)
2020
end
21+
22+
function Base.convert(::Type{LatLonAlt{Dₛ}}, coords::LatLonAlt{Dₜ}) where {Dₛ<:$Datumₛ,Dₜ<:$Datumₜ}
23+
latlonalt = (coords.lat, coords.lon, coords.alt)
24+
latlonalt′ = pointmotionbwd(Dₛ, Dₜ, latlonalt)
25+
LatLonAlt{Dₛ}(latlonalt′...)
26+
end
2127
end
2228
esc(expr)
2329
end
@@ -40,6 +46,55 @@ function pointmotionfwd(Datumₛ, Datumₜ, (lat, lon, alt))
4046
lat′, lon′, alt′
4147
end
4248

49+
# Adapted from PROJ coordinate transformation software
50+
# Initial PROJ 4.3 public domain code was put as Frank Warmerdam as copyright
51+
# holder, but he didn't mean to imply he did the work. Essentially all work was
52+
# done by Gerald Evenden.
53+
54+
# reference code: https://github.com/OSGeo/PROJ/blob/master/src/grids.cpp
55+
56+
function pointmotionbwd(Datumₛ, Datumₜ, (lat, lon, alt))
57+
λ = ustrip(deg2rad(lon))
58+
ϕ = ustrip(deg2rad(lat))
59+
h = ustrip(m, alt)
60+
tol = atol(λ)
61+
62+
# initial guess
63+
λₛ, ϕₛ, hₛ = pointmotionparams(Datumₛ, Datumₜ, lat, lon, ϕ, h)
64+
λᵢ = λ - λₛ
65+
ϕᵢ = ϕ - ϕₛ
66+
hᵢ = h - hₛ
67+
for _ in 1:MAXITER
68+
# to check if the guess is equivalent to the original Datumₛ coordinates,
69+
# forward the guess coordinates to compare them with the Datumₜ input coordinates
70+
latᵢ = rad2deg(ϕᵢ) * °
71+
lonᵢ = rad2deg(λᵢ) * °
72+
λᵢₛ, ϕᵢₛ, hᵢₛ = pointmotionparams(Datumₛ, Datumₜ, latᵢ, lonᵢ, ϕᵢ, hᵢ)
73+
λᵢ′ = λᵢ + λᵢₛ
74+
ϕᵢ′ = ϕᵢ + ϕᵢₛ
75+
hᵢ′ = hᵢ + hᵢₛ
76+
# difference between forward coordinates and input coordinates for comparison
77+
λΔ = λᵢ′ - λ
78+
ϕΔ = ϕᵢ′ - ϕ
79+
= hᵢ′ - h
80+
# if the difference is small, stop the iteration
81+
if hypot(λΔ, ϕΔ, hΔ) tol
82+
break
83+
end
84+
# otherwise, subtract the difference and continue
85+
λᵢ -= λΔ
86+
ϕᵢ -= ϕΔ
87+
hᵢ -=
88+
end
89+
90+
# https://github.com/PainterQubits/Unitful.jl/issues/753
91+
lonᵢ = rad2deg(λᵢ) * °
92+
latᵢ = rad2deg(ϕᵢ) * °
93+
altᵢ = uconvert(unit(alt), hᵢ * m)
94+
95+
latᵢ, lonᵢ, altᵢ
96+
end
97+
4398
function pointmotionparams(Datumₛ, Datumₜ, lat, lon, ϕ, h)
4499
🌎 = ellipsoid(Datumₛ)
45100
T = numtype(lon)

src/utils.jl

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# ------------------------------------------------------------------
2+
# Licensed under the MIT License. See LICENSE in the project root.
3+
# ------------------------------------------------------------------
4+
5+
# maximum number of iterations in iterative algorithms
6+
const MAXITER = 10
7+
8+
"""
9+
atol(T)
10+
atol(x::T)
11+
12+
Absolute tolerance used in source code for approximate
13+
comparison with numbers of type `T`.
14+
"""
15+
atol(x) = atol(typeof(x))
16+
atol(::Type{Float64}) = 1e-10
17+
atol(::Type{Float32}) = 1.0f-5

0 commit comments

Comments
 (0)