-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
improve cellsize and switch from Archgdal to Proj #768
Changes from 23 commits
691c39d
076819c
8b8fde8
62885bc
0e65df2
3a6972b
4d30a81
51ce721
fe5eed4
82d8a38
d1300dc
deac9d7
2d3c1c5
dc83ae9
7fbfd5a
2deb169
c0c7b9c
98a60f5
497a452
98724c2
4906076
b110844
8c76b51
ae793e6
7f444f3
ff979f4
4e86b0a
0709a39
89bd796
de73bb8
6c9201a
df5b7d4
90dfa27
89001d2
99c2fd6
520723b
11deb98
c1632a1
276144b
21e77e9
ded1ec8
c890a83
8520a13
6c43aef
599ce4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,105 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
## Get the area of a LinearRing with coordinates in radians | ||||||||||||||||||||||||||||||||||||||||||||||
struct SphericalPoint{T <: Real} | ||||||||||||||||||||||||||||||||||||||||||||||
data::NTuple{3, T} | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
SphericalPoint(x, y, z) = SphericalPoint((x, y, z)) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
# define the 4 basic mathematical operators elementwise on the data tuple | ||||||||||||||||||||||||||||||||||||||||||||||
Base.:+(p::SphericalPoint, q::SphericalPoint) = SphericalPoint(p.data .+ q.data) | ||||||||||||||||||||||||||||||||||||||||||||||
Base.:-(p::SphericalPoint, q::SphericalPoint) = SphericalPoint(p.data .- q.data) | ||||||||||||||||||||||||||||||||||||||||||||||
Base.:*(p::SphericalPoint, q::SphericalPoint) = SphericalPoint(p.data .* q.data) | ||||||||||||||||||||||||||||||||||||||||||||||
Base.:/(p::SphericalPoint, q::SphericalPoint) = SphericalPoint(p.data ./ q.data) | ||||||||||||||||||||||||||||||||||||||||||||||
# Define sum on a SphericalPoint to sum across its data | ||||||||||||||||||||||||||||||||||||||||||||||
Base.sum(p::SphericalPoint) = sum(p.data) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
# define dot and cross products | ||||||||||||||||||||||||||||||||||||||||||||||
dot(p::SphericalPoint, q::SphericalPoint) = sum(p * q) | ||||||||||||||||||||||||||||||||||||||||||||||
function cross(a::SphericalPoint, b::SphericalPoint) | ||||||||||||||||||||||||||||||||||||||||||||||
a1, a2, a3 = a.data | ||||||||||||||||||||||||||||||||||||||||||||||
b1, b2, b3 = b.data | ||||||||||||||||||||||||||||||||||||||||||||||
SphericalPoint((a2*b3-a3*b2, a3*b1-a1*b3, a1*b2-a2*b1)) | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
function _spherical_quadrilateral_area(ring) | ||||||||||||||||||||||||||||||||||||||||||||||
ps = GI.getpoint(ring) | ||||||||||||||||||||||||||||||||||||||||||||||
(p1, p2, p3, p4) = _lonlat_to_sphericalpoint.((ps[1], ps[2], ps[3], ps[4])) | ||||||||||||||||||||||||||||||||||||||||||||||
area = 0.0 | ||||||||||||||||||||||||||||||||||||||||||||||
area += _spherical_triangle_area(p1, p2, p3) | ||||||||||||||||||||||||||||||||||||||||||||||
area += _spherical_triangle_area(p3, p4, p1) | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
# Using Eriksson's formula for the area of spherical triangles: https://www.jstor.org/stable/2691141 | ||||||||||||||||||||||||||||||||||||||||||||||
function _spherical_triangle_area(a, b, c) | ||||||||||||||||||||||||||||||||||||||||||||||
#t = abs(dot(a, cross(b, c))) | ||||||||||||||||||||||||||||||||||||||||||||||
#t /= 1 + dot(b,c) + dot(c, a) + dot(a, b) | ||||||||||||||||||||||||||||||||||||||||||||||
t = abs(dot(a, (cross(b - a, c - a))) / dot(b + a, c + a)) | ||||||||||||||||||||||||||||||||||||||||||||||
2*atan(t) | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
_lonlat_to_sphericalpoint(args) = _lonlat_to_sphericalpoint(args...) | ||||||||||||||||||||||||||||||||||||||||||||||
function _lonlat_to_sphericalpoint(lon, lat) | ||||||||||||||||||||||||||||||||||||||||||||||
x = cosd(lat) * cosd(lon) | ||||||||||||||||||||||||||||||||||||||||||||||
y = cosd(lat) * sind(lon) | ||||||||||||||||||||||||||||||||||||||||||||||
z = sind(lat) | ||||||||||||||||||||||||||||||||||||||||||||||
return SphericalPoint(x,y,z) | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
_area_from_coords(transform, geom) = _area_from_coords(transform, GI.trait(geom), geom) | ||||||||||||||||||||||||||||||||||||||||||||||
function _area_from_coords(transform::AG.CoordTransform, ::GI.LinearRingTrait, ring) | ||||||||||||||||||||||||||||||||||||||||||||||
points = map(GI.getpoint(ring)) do p | ||||||||||||||||||||||||||||||||||||||||||||||
t = AG.transform!(AG.createpoint(p...), transform) | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||||||||||||||
(GI.x(t), GI.y(t)) | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
return _spherical_quadrilateral_area(GI.LinearRing(points)) | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Something like this should be better as GI skips around ArchGDAL point creation and just works on the internal vectors of points in the LinearRing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guessing this will be 3x faster It also means a lot less calls to (We could also just add a Proj dep and skip around GDAL completely, Proj is super fast just on points...) |
||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
# For lat-lon projections. Get the area of each latitudinal band, then multiply by the width | ||||||||||||||||||||||||||||||||||||||||||||||
function _area_from_lonlat(lon::XDim, lat::YDim; radius) | ||||||||||||||||||||||||||||||||||||||||||||||
two_pi_R2 = 2 * pi * radius * radius | ||||||||||||||||||||||||||||||||||||||||||||||
band_area = broadcast(DD.intervalbounds(lat)) do yb | ||||||||||||||||||||||||||||||||||||||||||||||
two_pi_R2 * (sind(yb[2]) - sind(yb[1])) | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
broadcast(DD.intervalbounds(lon), band_area') do xb, ba | ||||||||||||||||||||||||||||||||||||||||||||||
abs((xb[2] - xb[1]) / 360 * ba) | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
function _spherical_cellarea(dims::Tuple{<:XDim, <:YDim}; radius = 6371008.8) | ||||||||||||||||||||||||||||||||||||||||||||||
# check the dimensions | ||||||||||||||||||||||||||||||||||||||||||||||
isnothing(crs(dims)) && _no_crs_error() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
areas = if _isdegrees(crs(dims)) # check if need to reproject | ||||||||||||||||||||||||||||||||||||||||||||||
_area_from_lonlat(dims...; radius) | ||||||||||||||||||||||||||||||||||||||||||||||
elseif !isnothing(mappedcrs(dims)) && _isdegrees(mappedcrs(dims)) | ||||||||||||||||||||||||||||||||||||||||||||||
tiemvanderdeure marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||
_area_from_lonlat(reproject(dims; crs = mappedcrs(dims))...; radius) | ||||||||||||||||||||||||||||||||||||||||||||||
tiemvanderdeure marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||
xbnds, ybnds = DD.intervalbounds(dims) | ||||||||||||||||||||||||||||||||||||||||||||||
R2 = radius * radius | ||||||||||||||||||||||||||||||||||||||||||||||
AG.crs2transform(crs(dims), EPSG(4326); order = :trad) do transform | ||||||||||||||||||||||||||||||||||||||||||||||
[_area_from_coords( | ||||||||||||||||||||||||||||||||||||||||||||||
transform, | ||||||||||||||||||||||||||||||||||||||||||||||
GI.LinearRing([ | ||||||||||||||||||||||||||||||||||||||||||||||
(xb[1], yb[1]), | ||||||||||||||||||||||||||||||||||||||||||||||
(xb[2], yb[1]), | ||||||||||||||||||||||||||||||||||||||||||||||
(xb[2], yb[2]), | ||||||||||||||||||||||||||||||||||||||||||||||
(xb[1], yb[2]), | ||||||||||||||||||||||||||||||||||||||||||||||
(xb[1], yb[1]) | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might give some more micro optimisation, 4 things is usually better than 5 things with computers...
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
typo |
||||||||||||||||||||||||||||||||||||||||||||||
]) | ||||||||||||||||||||||||||||||||||||||||||||||
) * R2 | ||||||||||||||||||||||||||||||||||||||||||||||
for xb in xbnds, yb in ybnds] | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
# TODO: put these in ArchGDAL | ||||||||||||||||||||||||||||||||||||||||||||||
_isgeographic(crs) = _isgeographic(AG.importCRS(crs)) | ||||||||||||||||||||||||||||||||||||||||||||||
_isgeographic(crs::AG.ISpatialRef) = AG.GDAL.osrisgeographic(crs) |> Bool | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
_isdegrees(crs) = _isdegrees(AG.importCRS(crs)) | ||||||||||||||||||||||||||||||||||||||||||||||
function _isdegrees(crs::AG.ISpatialRef) | ||||||||||||||||||||||||||||||||||||||||||||||
_isgeographic(crs) || return false | ||||||||||||||||||||||||||||||||||||||||||||||
pointer = Ref{Cstring}() | ||||||||||||||||||||||||||||||||||||||||||||||
result = AG.GDAL.osrgetangularunits(crs, pointer) | ||||||||||||||||||||||||||||||||||||||||||||||
return unsafe_string(pointer[]) == "degree" | ||||||||||||||||||||||||||||||||||||||||||||||
end |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
const AG = ArchGDAL | ||
|
||
const GDAL_LOCUS = Start() | ||
|
||
const GDAL_DIM_ORDER = (X(), Y(), Band()) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last point isn't actually used here so my
LineString
approach below does make sense