CoordRefSystems.jl provides conversions between Coordinate Reference Systems (CRS) in native Julia. It was designed to work with units from Unitful.jl, respects projection bounds catalogued in https://epsg.io, and is very fast thanks to advanced parametrizations at compile-time.
This package addresses various design issues encountered in previous attempts such as Geodesy.jl and MapMaths.jl. Our benchmarks show that CoordRefSystems.jl is often faster than PROJ, which is the most widely used software library for cartography in the world (written in C/C++).
Examples of usage are available in the README:
With this package, we are one step closer from a complete GIS experience with GeoStats.jl in native Julia. We are planning to refactor the stack in the following months to accommodate this CRS work.
The package is awaiting registration in the General registry.
Acknowledgements
We would like to thank @cormullion for the awesome logo made with Luxor.jl, and the C/C++ PROJ software from where we got inspiration for this new Julia design.
It has always been a pain to use GeoMakie.jl - not due to GeoMakieās fault, but because in essense all arguments for the projection where passed as āold C command line argumentsā to PROJ, and that made it difficult for me at least to reason with the code and get the results I expected.
It is a very welcomed sight to see a pure Julia alternatve to PROJ!
Not only that, we will now be able to dispatch algorithms in Meshes.jl (and therefore GeoStats.jl) based on CRS, meaning that we will never compute an area with angular coordinates for example.
We carefully designed CoordRefSystems.jl to be able to send GeoTables for visualization without manual selection of axis, like it is done in GeoMakie.jl and the PROJ strings.
Awesome package, thank you very much for sharing all the expertise and hard work that went into this! CoordRefSystems fixes most of the usability beefs I had with Geodesy.jl and implements a much larger set of coordinate conversions than MapMaths.jl, so I can see myself giving up on MapMaths.jl soon and adopting this package instead. However, CoordRefSystems currently lacks a few features which would make this move somewhat painful, so Iām curious to hear whether you would be willing to add them.
Would it be possible to add fallback conversions between Cartesian and Projected coordinate types to cover conversions such as this one?
julia> convert(Cartesian, WebMercator(0,0))
ERROR: MethodError: Cannot `convert` an object of type
WebMercator{WGS84Latest, Quantity{Float64, š, Unitful.FreeUnits{(m,), š, nothing}}} to an object of type
Cartesian
We frequently switch to cartesian coordinates when doing coordinate arithmetic, so it would be great if we could rely on convert(Cartesian, x) to work regardless of what x we throw at it.
Another missing conversion:
julia> convert(LatLon, LatLonAlt(0,0,0))
ERROR: MethodError: Cannot `convert` an object of type
GeodeticLatLonAlt{WGS84Latest, Quantity{Float64, NoDims, Unitful.FreeUnits{(Ā°,), NoDims, nothing}}, Quantity{Float64, š, Unitful.FreeUnits{(m,), š, nothing}}} to an object of type
GeodeticLatLon
Admittedly, this isnāt just a conversion since we drop altitude information, but I donāt think this should stop us since CoordRefSystems supports converting Cartesian to LatLon and this conversion faces the same problem.
Do you have any plans for adding local coordinates systems (e.g. ENU)? Local coordinates can be very convenient e.g. for computing the LatLon of a point 500m to the east of a given point. Further bonus points will be awarded if you support both cartesian local coordinates and āwrappingā local coordinates (i.e. a non-cartesian local coordinate system such that alt = 0 is always on the surface of the sea).
AFAICT, if you want to convert say latlon::LatLon to a pair of WebMercator coordinates without the WebMercator wrapper type, you currently have to do this:
This operation is required frequently if you have to interact with non-CoordRefSystems-aware software (e.g. maths or plotting libraries), so thereās significant benefit in making it as ergonomic as possible. Would it be possible to add some convenience function for this operation (e.g. cstrip())?
If you are agreeable to adding something like cstrip(), would it be possible to also add a function cwrap() such that x -> cwrap(args..., cstrip(args..., x) becomes the identity and cstrip() returns an SVector? Such a pair of functions would make it very easy to express a lot of highly useful coordinate arithmetic. For example:
function rhumb_line(x::CRS, y::CRS)
C = Mercator
return t -> cwrap(C, t * cstrip(C, x) + (1-t) * cstrip(C, y))
end
function mean(coords::AbstractVector{<:CRS})
C = Cartesian{WGS84latest}
m = cwrap(C, mean(cstrip(C, x) for x in coords))
# Throw an error if mean is too far underground
# (i.e. the `coords` are not local enough)
@assert abs(convert(LatLonAlt, m).alt) < 10
return m
end
translated_latlon(x::CRS, d::SVector{3}) = cstrip(LatLon, cwrap(ENU(x), d))
Minor nitpick: The docstring for LatLon currently only shows up if you query for GeodeticLatLon.
help?> LatLon
No documentation found.
help?> GeodeticLatLon
LatLon(lat, lon)
LatLon{Datum}(lat, lon)
GeodeticLatLon(lat, lon)
GeodeticLatLon{Datum}(lat, lon)
Geodetic latitude lat ā [-90Ā°,90Ā°] and longitude lon ā [-180Ā°,180Ā°] in angular units (default to degree) with a given Datum (default to WGS84).
Would be nice to understand if thereās something that can be reused or done consistently. Especially given that earth and sky coordinates are used together sometimes.
Stupid question from me, regarding astro coordinate systems.
What coordinate system to the astronauts in the International Space Station use?
I would guess htey use UTC time also.
Thank you @ettersi for your feedback! We would be happy to fix all issues raised. Can you please copy/paste the bullet points into new GitHub issues in CoordRefSystems.jl?
Thank you @aplavin! Letās join forces in CoordRefSystems.jl and absorb any missing CRS from SkyCoords.jl. We need a central place to evolve these systems to be able to seamlessly track objects on Earth and on the Sky.
If the question is to me, then I have no idea (: By astro coordinates, I mean coordinates of astronomical objects on the celestial sphere.
Hm, first it would be nice to understand what are the relevant differences in the design/API. I just noticed a lot of surface-level similarities, and commented on that.
Iām familiar with SkyCoords.jl, and it has generally been good enough for me (aside from the stalled projected coords PR).
Then the best approaches from both could be unified.
I can tell you already that SkyCoords.jl is minimal in functionality compared to CoordRefSystems.jl. It doesnāt have the notion of datum, nor explicit units. CoordRefSystems.jl has a much more ambitious scope.
I always struggle with the convention LatLon, I prefer LonLat. For understanding purposes, whatās the reason behind this convention?
Note also, in the docs, when doing (looks inconsistent)
julia> convert(Mercator, latlon)
Mercator{WGS84Latest} coordinates
āā x: 6.679169447596414e6 m # this is to Lon, right?
āā y: 3.482189085408618e6 m # and this to lat?
No major reason as far as I know. The latitude is the most difficult coordinate to compute in the pair, and perhaps people decided to place it first historically in EPSG codes, and textbooks.
This is not inconsistent, it is actually nice that the package explicitly names things to avoid confusion. Projected coordinates are x and y in meters, and they are usually associated with longitude and latitude (reversed) order in degrees.
PROJ handled this issue with the swap_xy option everywhere, but CoordRefSystems.jl avoided that altogether by enforcing structs with well-defined fields and types in a specific order. We could introduce another struct LonLat for convenience later, but there is no use case that really justifies it yet.
Heh, I also noticed that āprojectedā coordinates here donāt mean what I expected (:
In CRS.jl, you mean projection of the whole sphere onto some surface, like Mercator and similar ā right?
What about projection to the tangent plane? Basically, a system that has a reference (lon, lat) position on the sphere, and coordinates are represented in terms of (projected) offsets from that point. In astronomy, this is very common: you may have an image centered at some lon, lat, and coordinates within the image are ārelative latā + ārelative projected lonā.
Or both senses of āprojectedā are the same general beast?..
Any historians on here are free to correct me if Iām wrong, but I believe itās because latitude is the easier of the two to measure, and was used in navigation for centuries before longitude could be reliably calculated. I imagine shipsā masters were used to logging latitude, then started adding longitude second when accurate lunar almanacs and chronometers became available in around the turn of the 19th century. So the answer is āmaritime tradition,ā though it is also now an official ISO Standard to quote latitude before longitude.