Skip to content

Commit f5b4857

Browse files
committed
Initial commit
1 parent ec2da53 commit f5b4857

15 files changed

+319
-50
lines changed

.JuliaFormatter.toml

+10-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
# See https://domluna.github.io/JuliaFormatter.jl/stable/ for a list of options
1+
indent = 2
2+
margin = 120
3+
always_for_in = true
4+
always_use_return = false
5+
whitespace_typedefs = false
6+
whitespace_in_kwargs = false
7+
whitespace_ops_in_indices = true
8+
remove_extra_newlines = true
9+
trailing_comma = false
10+
normalize_line_endings = "unix"

.github/workflows/CI.yml

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ jobs:
2323
fail-fast: false
2424
matrix:
2525
version:
26-
- '1.10'
27-
- '1.11'
28-
- 'pre'
26+
- 'lts'
27+
- '1'
2928
os:
3029
- ubuntu-latest
30+
- macOS-latest
31+
- windows-latest
3132
arch:
3233
- x64
3334
steps:

.github/workflows/FormatPR.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: FormatPR
2+
on:
3+
push:
4+
branches:
5+
- main
6+
jobs:
7+
build:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
- name: Install JuliaFormatter and format
12+
run: |
13+
julia -e 'import Pkg; Pkg.add("JuliaFormatter")'
14+
julia -e 'using JuliaFormatter; format(".")'
15+
- name: Create Pull Request
16+
id: cpr
17+
uses: peter-evans/create-pull-request@v7
18+
with:
19+
token: ${{ secrets.GITHUB_TOKEN }}
20+
commit-message: ":robot: Format .jl files"
21+
title: '[AUTO] JuliaFormatter.jl run'
22+
branch: auto-juliaformatter-pr
23+
delete-branch: true
24+
labels: formatting, automated pr, no changelog
25+
- name: Check outputs
26+
run: |
27+
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
28+
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
*.jl.*.cov
22
*.jl.cov
33
*.jl.mem
4-
/Manifest.toml
4+
.DS_Store
5+
Manifest.toml
6+
.vscode

Project.toml

+16
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,21 @@ uuid = "1cf1ec0c-22f7-4062-925b-8db09db48fc3"
33
authors = ["Elias Carvalho <eliascarvdev@gmail.com> and contributors"]
44
version = "0.1.0"
55

6+
[deps]
7+
CoordRefSystems = "b46f11dc-f210-4604-bfba-323c1ec968cb"
8+
DataDeps = "124859b0-ceae-595e-8997-d05f6a7a8dfe"
9+
GeoTIFF = "c470187e-1474-4b46-a068-a417f109db17"
10+
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
11+
MappedArrays = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
12+
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
13+
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
14+
615
[compat]
16+
CoordRefSystems = "0.16"
17+
DataDeps = "0.7"
18+
GeoTIFF = "0.3"
19+
Interpolations = "0.15"
20+
MappedArrays = "0.4"
21+
StaticArrays = "1.9"
22+
Unitful = "1.21"
723
julia = "1.10"

README.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
# CoordGridTransforms
1+
# CoordGridTransforms.jl
22

33
[![Build Status](https://github.com/JuliaEarth/CoordGridTransforms.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/JuliaEarth/CoordGridTransforms.jl/actions/workflows/CI.yml?query=branch%3Amain)
44
[![Coverage](https://codecov.io/gh/JuliaEarth/CoordGridTransforms.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/JuliaEarth/CoordGridTransforms.jl)
5+
6+
CoordGridTransforms.jl is a extension for the [CoordRefSystems.jl](https://github.com/JuliaEarth/CoordRefSystems.jl) package
7+
that adds support for transforms that requires GeoTIFF grid files.
8+
For now, only grids from the [PROJ CDN](https://cdn.proj.org/) are supported.
9+
10+
## Installation
11+
12+
Get the latest stable release with Julia's package manager:
13+
14+
```
15+
] add CoordGridTransforms
16+
```

src/CoordGridTransforms.jl

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
1+
# ------------------------------------------------------------------
2+
# Licensed under the MIT License. See LICENSE in the project root.
3+
# ------------------------------------------------------------------
4+
15
module CoordGridTransforms
26

3-
# Write your package code here.
7+
using CoordRefSystems
8+
9+
using Unitful: °
10+
using Unitful: numtype, ustrip
11+
using StaticArrays: SVector, SA
12+
using MappedArrays: mappedarray
13+
using Interpolations: interpolate, Gridded, Linear
14+
using DataDeps: @datadep_str, register, DataDep
15+
16+
import GeoTIFF
17+
18+
include("grids.jl")
19+
include("transforms.jl")
420

521
end

src/grids.jl

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# ------------------------------------------------------------------
2+
# Licensed under the MIT License. See LICENSE in the project root.
3+
# ------------------------------------------------------------------
4+
5+
"""
6+
geotiff(Datumₛ, Datumₜ)
7+
8+
GeoTIFF file used in transforms that convert source `Datumₛ` to target `Datumₜ`.
9+
"""
10+
function geotiff end
11+
12+
# cache interpolator objects to avoid interpolating the same grid twice
13+
const INTERPOLATOR = IdDict()
14+
15+
"""
16+
interpolator(Datumₛ, Datumₜ)
17+
18+
Linear interpolation of GeoTIFF grid that converts `Datumₛ` to `Datumₜ`.
19+
All of the GeoTIFF channels are combined into the interpolated grid as a vector.
20+
"""
21+
function interpolator(Datumₛ, Datumₜ)
22+
if haskey(INTERPOLATOR, (Datumₛ, Datumₜ))
23+
return INTERPOLATOR[(Datumₛ, Datumₜ)]
24+
end
25+
26+
# download geotiff from PROJ CDN
27+
file = downloadgeotiff(Datumₛ, Datumₜ)
28+
geotiff = GeoTIFF.load(file)
29+
30+
# construct the interpolation grid
31+
img = GeoTIFF.image(geotiff)
32+
grid = mappedarray(img) do color
33+
N = GeoTIFF.nchannels(color)
34+
tup = ntuple(i -> GeoTIFF.channel(color, i), N)
35+
SVector(tup)
36+
end
37+
38+
# lon lat range
39+
m, n = size(grid)
40+
A, b = GeoTIFF.affineparams2D(GeoTIFF.metadata(geotiff))
41+
lon₀, lat₀ = muladd(A, SA[0, 0], b)
42+
lonₘ, latₙ = muladd(A, SA[m, n], b)
43+
44+
# Interpolations.jl requires ordered ranges
45+
reverselon = lon₀ > lonₘ
46+
reverselat = lat₀ > latₙ
47+
lonₛ, lonₑ = reverselon ? (lonₘ, lon₀) : (lon₀, lonₘ)
48+
latₛ, latₑ = reverselat ? (latₙ, lat₀) : (lat₀, latₙ)
49+
lonrange = range(start=lonₛ, stop=lonₑ, length=m)
50+
latrange = range(start=latₛ, stop=latₑ, length=n)
51+
52+
# reverse dimensions if range is reversed
53+
if reverselon
54+
grid = @view grid[m:-1:1, :]
55+
end
56+
57+
if reverselat
58+
grid = @view grid[:, n:-1:1]
59+
end
60+
61+
# create the interpolation
62+
interp = interpolate((lonrange, latrange), grid, Gridded(Linear()))
63+
64+
INTERPOLATOR[(Datumₛ, Datumₜ)] = interp
65+
66+
interp
67+
end
68+
69+
"""
70+
downloadgeotiff(Datumₛ, Datumₜ)
71+
72+
Download the GeoTIFF file that converts `Datumₛ` to `Datumₜ` from PROJ CDN.
73+
"""
74+
function downloadgeotiff(Datumₛ, Datumₜ)
75+
fname = geotiff(Datumₛ, Datumₜ)
76+
url = "https://cdn.proj.org/$fname"
77+
ID = splitext(fname) |> first
78+
79+
dir = try
80+
# if data is already on disk
81+
# we just return the path
82+
@datadep_str ID
83+
catch
84+
# otherwise we register the data
85+
# and download using DataDeps.jl
86+
try
87+
register(DataDep(ID, "Grid file provided by PROJ CDN", url, Any))
88+
@datadep_str ID
89+
catch
90+
throw(ErrorException("download failed due to internet and/or server issues"))
91+
end
92+
end
93+
94+
# file path
95+
joinpath(dir, fname)
96+
end
97+
98+
# ----------------
99+
# IMPLEMENTATIONS
100+
# ----------------
101+
102+
geotiff(::Type{SAD69}, ::Type{SIRGAS2000}) = "br_ibge_SAD69_003.tif"
103+
104+
geotiff(::Type{SAD96}, ::Type{SIRGAS2000}) = "br_ibge_SAD96_003.tif"

src/transforms.jl

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# ------------------------------------------------------------------
2+
# Licensed under the MIT License. See LICENSE in the project root.
3+
# ------------------------------------------------------------------
4+
5+
include("transforms/hgridshift.jl")
6+
7+
# ----------------
8+
# IMPLEMENTATIONS
9+
# ----------------
10+
11+
# Adapted from PROJ coordinate transformation software
12+
# Initial PROJ 4.3 public domain code was put as Frank Warmerdam as copyright
13+
# holder, but he didn't mean to imply he did the work. Essentially all work was
14+
# done by Gerald Evenden.
15+
16+
# source of parameters:
17+
# EPSG Database: https://epsg.org/search/by-name
18+
# PROJ source code: https://github.com/OSGeo/PROJ/blob/master/src/datums.cpp
19+
20+
# https://epsg.org/transformation_5529/SAD69-96-to-SIRGAS-2000-1.html
21+
@hgridshift SAD96 SIRGAS2000

src/transforms/hgridshift.jl

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# ------------------------------------------------------------------
2+
# Licensed under the MIT License. See LICENSE in the project root.
3+
# ------------------------------------------------------------------
4+
5+
"""
6+
@hgridshift Datumₛ Datumₜ
7+
8+
Horizontal Grid Shift transform that uses grid interpolation
9+
to calculate coordinate offsets.
10+
11+
## References
12+
13+
* Section 4.4.6 of EPSG Guidance Note 7-2: <https://epsg.org/guidance-notes.html>
14+
"""
15+
macro hgridshift(Datumₛ, Datumₜ)
16+
expr = quote
17+
function Base.convert(::Type{LatLon{Dₜ}}, coords::LatLon{Dₛ}) where {Dₛ<:$Datumₛ,Dₜ<:$Datumₜ}
18+
latlon = (coords.lat, coords.lon)
19+
latlon′ = hgridshiftfwd(Dₛ, Dₜ, latlon)
20+
LatLon{Dₜ}(latlon′...)
21+
end
22+
end
23+
esc(expr)
24+
end
25+
26+
function hgridshiftfwd(Datumₛ, Datumₜ, (lat, lon))
27+
latshift, lonshift = hgridshiftparams(Datumₛ, Datumₜ, (lat, lon))
28+
lat + latshift, lon + lonshift
29+
end
30+
31+
function hgridshiftparams(Datumₛ, Datumₜ, (lat, lon))
32+
T = numtype(lon)
33+
interp = interpolator(Datumₛ, Datumₜ)
34+
itp = interp(ustrip(lon), ustrip(lat))
35+
# type assertion is necessary for type stability
36+
latshift::T = T(itp[1])
37+
lonshift::T = T(itp[2])
38+
# convert arc seconds to degrees
39+
latshift′ = latshift / 3600 * °
40+
lonshift′ = lonshift / 3600 * °
41+
latshift′, lonshift′
42+
end

test/Manifest.toml

-41
This file was deleted.

test/Project.toml

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
[deps]
2+
CoordRefSystems = "b46f11dc-f210-4604-bfba-323c1ec968cb"
23
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
4+
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

test/converions.jl

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@testset "conversions" begin
2+
# SAD96 to SIRGAS2000
3+
# note: the results differ from PROJ because we use the standard implementation described
4+
# in the EPSG Guidance Note 7-2, Section 4.4.6, Geographic Offset by Interpolation of Gridded Velocity Data
5+
c1 = LatLon{SAD96}(T(-15), T(-45))
6+
c2 = convert(LatLon{SIRGAS2000}, c1)
7+
@test allapprox(c2, LatLon{SIRGAS2000}(T(-15.000451566492272), T(-45.00042666174454)))
8+
9+
c1 = LatLon{SAD96}(T(-10), T(-40))
10+
c2 = convert(LatLon{SIRGAS2000}, c1)
11+
@test allapprox(c2, LatLon{SIRGAS2000}(T(-10.000428915126209), T(-40.00037063898611)))
12+
end

test/runtests.jl

+27-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
11
using CoordGridTransforms
2+
using CoordRefSystems
23
using Test
34

4-
@testset "CoordGridTransforms.jl" begin
5-
# Write your tests here.
5+
include("testutils.jl")
6+
7+
testfiles = ["converions.jl"]
8+
9+
# --------------------------------
10+
# RUN TESTS WITH SINGLE PRECISION
11+
# --------------------------------
12+
13+
T = Float32
14+
@testset "CoordGridTransforms.jl ($T)" begin
15+
for testfile in testfiles
16+
println("Testing $testfile...")
17+
include(testfile)
18+
end
619
end
20+
21+
# --------------------------------
22+
# RUN TESTS WITH DOUBLE PRECISION
23+
# --------------------------------
24+
25+
T = Float64
26+
@testset "CoordGridTransforms.jl ($T)" begin
27+
for testfile in testfiles
28+
println("Testing $testfile...")
29+
include(testfile)
30+
end
31+
end

0 commit comments

Comments
 (0)