-
Notifications
You must be signed in to change notification settings - Fork 9
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
Code Reorganization and Geodesic Routines #4
Closed
Closed
Changes from 19 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
f77c2fd
Provide ESRI and EPSG codes
yeesian 2ac8d6f
fix mispelling
yeesian 359b6cc
backwards compatibility for v0.3
yeesian d596b15
runtests: print projection strings that couldn't be parsed
yeesian a30cb0e
merge upstream changes
yeesian 9be44d6
some reorganization
yeesian b1a83b0
low-level wrapper
yeesian 9795c8e
wrap more low-level proj_api functions
yeesian 40f8dab
implement functions for geodesic operations
yeesian e92bc95
added new methods and tests
yeesian 4761bfc
bugfixes for v0.3
yeesian 3f9ccfa
provide consistency of behavior
yeesian a9e5fcf
drop support for v0.3
yeesian ed926de
rename `is_identical` -> `compare_datums`
yeesian f38c9f8
convert deg2rad and vice versa for only first 2 dimensions
yeesian 9061a78
check errno for forward and inverse projection calls
yeesian ee4228b
remove transform2 and transform3
yeesian 650827e
improved assertion style
yeesian 517dcdf
conditionally load geodesic routines
yeesian d21c115
fix dangling pointer for geod_geodesic
yeesian cf5e8ea
update REQUIRE
yeesian 36f3864
rename geodesic methods
yeesian File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
julia 0.3 | ||
julia 0.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,171 +1,31 @@ | ||
module Proj4 | ||
|
||
using Compat | ||
|
||
export transform, transform!, Projection, is_latlong, is_geocent | ||
|
||
## Types | ||
|
||
# Projection context. TODO: Will this be exposed? | ||
#type Context | ||
# rep::Ptr{Void} # Pointer to internal projCtx struct | ||
#end | ||
|
||
""" | ||
Cartographic projection type | ||
""" | ||
type Projection | ||
#ctx::Context # Projection context object | ||
rep::Ptr{Void} # Pointer to internal projPJ struct | ||
end | ||
|
||
## Low-level interface pieces | ||
const libproj = "libproj" | ||
|
||
# The following functions are generally named after the associated C API | ||
# functions, but without the pj prefix. | ||
|
||
"Free C datastructure associated with a projection. For internal use only!" | ||
function _free(proj::Projection) | ||
@assert proj.rep != C_NULL | ||
ccall((:pj_free, libproj), Void, (Ptr{Void},), proj.rep) | ||
proj.rep = C_NULL | ||
end | ||
|
||
"Get human readable error string from proj.4 error code" | ||
function _strerrno(code::Cint) | ||
bytestring(ccall((:pj_strerrno, libproj), Cstring, (Cint,), code)) | ||
end | ||
|
||
"Get global errno string in human readable form" | ||
function _strerrno() | ||
_strerrno(unsafe_load(ccall((:pj_get_errno_ref, libproj), Ptr{Cint}, ()))) | ||
end | ||
|
||
"Get projection definition string in the proj.4 plus format" | ||
function _get_def(proj::Projection) | ||
@assert proj.rep != C_NULL | ||
opts = 0 # Apparently obsolete argument, not used in current proj source | ||
bytestring(ccall((:pj_get_def, libproj), Cstring, (Ptr{Void}, Cint), proj.rep, opts)) | ||
end | ||
|
||
"""Low level interface to libproj transform, allowing user to specify strides""" | ||
function _transform!(src::Projection, dest::Projection, point_count, point_stride, x, y, z) | ||
@assert src.rep != C_NULL && dest.rep != C_NULL | ||
ccall((:pj_transform, libproj), Cint, | ||
(Ptr{Void}, Ptr{Void}, Clong, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), | ||
src.rep, dest.rep, point_count, point_stride, x, y, z) | ||
end | ||
|
||
## High level interface | ||
|
||
""" | ||
Construct a projection from a string in proj.4 "plus format" | ||
|
||
The projection string `proj_string` is defined in the proj.4 format, | ||
with each part of the projection specification prefixed with '+' character. | ||
For example: | ||
export Projection, # proj_types.jl | ||
transform, transform!, # proj_functions.jl | ||
is_latlong, is_geocent, compare_datums, spheroid_params, | ||
xy2lonlat, xy2lonlat!, lonlat2xy, lonlat2xy! | ||
|
||
`wgs84 = Projection("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")` | ||
""" | ||
function Projection(proj_string::ASCIIString) | ||
proj = Projection(ccall((:pj_init_plus, libproj), Ptr{Void}, (Cstring,), proj_string)) | ||
if proj.rep == C_NULL | ||
# TODO: use context? | ||
error("Could not parse projection string: \"$proj_string\": $(_strerrno())") | ||
end | ||
finalizer(proj, _free) | ||
proj | ||
end | ||
|
||
# Pretty printing | ||
Base.print(io::IO, proj::Projection) = print(io, strip(_get_def(proj))) | ||
Base.show(io::IO, proj::Projection) = print(io, "Projection(\"$proj\")") | ||
|
||
""" | ||
Return true if the projection is a geographic coordinate system (lon,lat) | ||
""" | ||
function is_latlong(proj::Projection) | ||
@assert proj.rep != C_NULL | ||
ccall((:pj_is_latlong, libproj), Cint, (Ptr{Void},), proj.rep) != 0 | ||
end | ||
|
||
""" | ||
Return true if the projection is a geocentric coordinate system | ||
""" | ||
function is_geocent(proj::Projection) | ||
@assert proj.rep != C_NULL | ||
ccall((:pj_is_geocent, libproj), Cint, (Ptr{Void},), proj.rep) != 0 | ||
end | ||
|
||
|
||
""" | ||
Transform between geographic or projected coordinate systems in place. | ||
include("projection_codes.jl") # ESRI and EPSG projection strings | ||
include("proj_capi.jl") # low-level C-facing functions (corresponding to src/proj_api.h) | ||
|
||
See transform() for details | ||
|
||
""" | ||
function transform!(src::Projection, dest::Projection, position::Array{Float64,2}; radians::Bool=false) | ||
npoints = size(position,1) | ||
ncomps = size(position,2) | ||
if ncomps != 2 && ncomps != 3 | ||
error("position must be Nx2 or Nx3") | ||
end | ||
if !radians && is_latlong(src) | ||
position[:,1:2] = deg2rad(position[:,1:2]) | ||
end | ||
P = pointer(position) | ||
x = P | ||
y = P + sizeof(Cdouble)*npoints | ||
z = (ncomps < 3) ? C_NULL : P + 2*sizeof(Cdouble)*npoints | ||
err = _transform!(src, dest, npoints, 1, x, y, z) | ||
if err != 0 | ||
error("transform error: $(_strerrno(err))") | ||
end | ||
if !radians && is_latlong(dest) | ||
position[:,1:2] = rad2deg(position[:,1:2]) | ||
end | ||
position | ||
__m = match(r"(\d+).(\d+).(\d+),.+", _get_release()) | ||
version_release = parse(Int, __m[1]) | ||
version_major = parse(Int, __m[2]) | ||
version_minor = parse(Int, __m[3]) | ||
if version_release >= 4 && version_major >= 9 && version_minor >= 1 | ||
export geod_direct, geod_inverse, destination, ellps_distance | ||
include("proj_geodesic.jl") # low-level C-facing functions (corresponding to src/geodesic.h) | ||
end | ||
|
||
transform!(src::Projection, dest::Projection, position::Vector{Float64}; radians::Bool=false) = | ||
transform!(src, dest, reshape(position,(1,length(position))), radians=radians) | ||
|
||
include("proj_types.jl") # type definitions for proj objects | ||
include("proj_functions.jl") # user-facing proj functions | ||
|
||
""" | ||
Transform between geographic or projected coordinate systems | ||
|
||
Args: | ||
|
||
src - Source coordinate system definition | ||
dest - Destination coordinate system definition | ||
position - An Nx2 or Nx3 array of coordinates to be transformed in place. | ||
For geographic coordinate systems, the first two columns are | ||
the *longitude* and *latitude*, in that order. | ||
radians - If true, treat geographic lon,lat coordinates as radians on | ||
input and output. | ||
|
||
Returns: | ||
|
||
position - Transformed position | ||
""" | ||
transform(src::Projection, dest::Projection, position::Array{Float64,2}; radians::Bool=false) = | ||
transform!(src, dest, copy(position), radians=radians) | ||
|
||
transform(src::Projection, dest::Projection, position::Vector{Float64}; radians::Bool=false) = | ||
transform!(src, dest, copy(reshape(position,(1,length(position)))), radians=radians) | ||
|
||
transform{T <: Real}(src::Projection, dest::Projection, position::Array{T,2}; radians::Bool=false) = | ||
transform!(src, dest, @compat(map(Float64,position)), radians=radians) | ||
|
||
transform{T <: Real}(src::Projection, dest::Projection, position::Vector{T}; radians::Bool=false) = | ||
transform!(src, dest, reshape(@compat(map(Float64,position)),(1,length(position))), radians=radians) | ||
|
||
"Get a string describing the underlying version of libproj in use" | ||
function libproj_version() | ||
bytestring(ccall((:pj_get_release, libproj), Cstring, ())) | ||
end | ||
@doc "Get a global error string in human readable form" -> | ||
error_message() = _strerrno() | ||
|
||
include("projection_codes.jl") | ||
@doc "Get a string describing the underlying version of libproj in use" -> | ||
version() = _get_release() | ||
|
||
end # module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
# The following functions are generally named after the associated C API | ||
# functions, but without the pj prefix. | ||
|
||
immutable ProjUV | ||
u::Cdouble | ||
v::Cdouble | ||
end | ||
|
||
@doc "forward projection from Lat/Lon to X/Y (only supports 2 dimensions)" -> | ||
function _fwd!(lonlat::Vector{Cdouble}, proj_ptr::Ptr{Void}) | ||
xy = ccall((:pj_fwd, libproj), ProjUV, (ProjUV, Ptr{Void}), ProjUV(lonlat[1], lonlat[2]), proj_ptr) | ||
_errno() == 0 || error("forward projection error: $(_strerrno())") | ||
lonlat[1] = xy.u; lonlat[2] = xy.v | ||
lonlat | ||
end | ||
|
||
@doc "Row-wise projection from Lat/Lon to X/Y (only supports 2 dimensions)" -> | ||
function _fwd!(lonlat::Array{Cdouble,2}, proj_ptr::Ptr{Void}) | ||
for i=1:size(lonlat,1) | ||
xy = ccall((:pj_fwd, libproj), ProjUV, (ProjUV, Ptr{Void}), | ||
ProjUV(lonlat[i,1], lonlat[i,2]), proj_ptr) | ||
lonlat[i,1] = xy.u; lonlat[i,2] = xy.v | ||
end | ||
_errno() == 0 || error("forward projection error: $(_strerrno())") | ||
lonlat | ||
end | ||
|
||
@doc "inverse projection from X/Y to Lat/Lon (only supports 2 dimensions)" -> | ||
function _inv!(xy::Vector{Cdouble}, proj_ptr::Ptr{Void}) | ||
lonlat = ccall((:pj_inv, libproj), ProjUV, (ProjUV, Ptr{Void}), | ||
ProjUV(xy[1], xy[2]), proj_ptr) | ||
_errno() == 0 || error("inverse projection error: $(_strerrno())") | ||
xy[1] = lonlat.u; xy[2] = lonlat.v | ||
xy | ||
end | ||
|
||
@doc "Row-wise projection from X/Y to Lat/Lon (only supports 2 dimensions)" -> | ||
function _inv!(xy::Array{Cdouble,2}, proj_ptr::Ptr{Void}) | ||
for i=1:size(xy,1) | ||
lonlat = ccall((:pj_inv, libproj), ProjUV, (ProjUV, Ptr{Void}), | ||
ProjUV(xy[i,1], xy[i,2]), proj_ptr) | ||
xy[i,1] = lonlat.u; xy[i,2] = lonlat.v | ||
end | ||
_errno() == 0 || error("inverse projection error: $(_strerrno())") | ||
xy | ||
end | ||
|
||
function _init_plus(proj_string::ASCIIString) | ||
proj_ptr = ccall((:pj_init_plus, libproj), Ptr{Void}, (Cstring,), proj_string) | ||
if proj_ptr == C_NULL | ||
# TODO: use context? | ||
error("Could not parse projection: \"$proj_string\": $(_strerrno())") | ||
end | ||
proj_ptr | ||
end | ||
|
||
@doc "Free C datastructure associated with a projection. For internal use!" -> | ||
function _free(proj_ptr::Ptr{Void}) | ||
@assert proj_ptr != C_NULL | ||
ccall((:pj_free, libproj), Void, (Ptr{Void},), proj_ptr) | ||
end | ||
|
||
@doc "Get human readable error string from proj.4 error code" -> | ||
function _strerrno(code::Cint) | ||
bytestring(ccall((:pj_strerrno, libproj), Cstring, (Cint,), code)) | ||
end | ||
|
||
@doc "Get global errno string in human readable form" -> | ||
function _strerrno() | ||
_strerrno(_errno()) | ||
end | ||
|
||
@doc "Get error number" | ||
function _errno() | ||
unsafe_load(ccall((:pj_get_errno_ref, libproj), Ptr{Cint}, ())) | ||
end | ||
|
||
@doc "Get projection definition string in the proj.4 plus format" -> | ||
function _get_def(proj_ptr::Ptr{Void}) | ||
@assert proj_ptr != C_NULL | ||
opts = 0 # Apparently obsolete argument, not used in current proj source | ||
bytestring(ccall((:pj_get_def, libproj), Cstring, (Ptr{Void}, Cint), proj_ptr, opts)) | ||
end | ||
|
||
@doc "Low level interface to libproj transform, C_NULL can be passed in for z, if it's 2-dimensional" -> | ||
function _transform!(src_ptr::Ptr{Void}, dest_ptr::Ptr{Void}, point_count::Int, point_stride::Int, | ||
x::Ptr{Cdouble}, y::Ptr{Cdouble}, z::Ptr{Cdouble}) | ||
@assert src_ptr != C_NULL && dest_ptr != C_NULL | ||
err = ccall((:pj_transform, libproj), Cint, (Ptr{Void}, Ptr{Void}, Clong, Cint, Ptr{Cdouble}, Ptr{Cdouble}, | ||
Ptr{Cdouble}), src_ptr, dest_ptr, Clong(point_count), Cint(point_stride), x, y, z) | ||
err != 0 && error("transform error: $(_strerrno(err))") | ||
end | ||
|
||
function _transform!(src_ptr::Ptr{Void}, dest_ptr::Ptr{Void}, position::Vector{Cdouble}) | ||
@assert src_ptr != C_NULL && dest_ptr != C_NULL | ||
ndim = length(position) | ||
@assert ndim >= 2 | ||
|
||
x = pointer(position) | ||
y = x + sizeof(Cdouble) | ||
z = (ndim == 2) ? Ptr{Cdouble}(C_NULL) : 2*sizeof(Cdouble) | ||
|
||
_transform!(src_ptr, dest_ptr, 1, 1, x, y, z) | ||
position | ||
end | ||
function _transform!(src_ptr::Ptr{Void}, dest_ptr::Ptr{Void}, position::Array{Cdouble,2}) | ||
@assert src_ptr != C_NULL && dest_ptr != C_NULL | ||
npoints, ndim = size(position) | ||
@assert ndim >= 2 | ||
|
||
x = pointer(position) | ||
y = x + sizeof(Cdouble)*npoints | ||
z = (ndim == 2) ? Ptr{Cdouble}(C_NULL) : 2*sizeof(Cdouble)*npoints | ||
#z = Ptr{Cdouble}((ndim == 2) * (x + 2*sizeof(Cdouble)*npoints)) | ||
|
||
_transform!(src_ptr, dest_ptr, npoints, 1, x, y, z) | ||
position | ||
end | ||
|
||
function _is_latlong(proj_ptr::Ptr{Void}) | ||
@assert proj_ptr != C_NULL | ||
ccall((:pj_is_latlong, libproj), Cint, (Ptr{Void},), proj_ptr) != 0 | ||
end | ||
|
||
function _is_geocent(proj_ptr::Ptr{Void}) | ||
@assert proj_ptr != C_NULL | ||
ccall((:pj_is_geocent, libproj), Cint, (Ptr{Void},), proj_ptr) != 0 | ||
end | ||
|
||
@doc "Get a string describing the underlying version of libproj in use" -> | ||
function _get_release() | ||
bytestring(ccall((:pj_get_release, libproj), Cstring, ())) | ||
end | ||
|
||
@doc """ | ||
Fetch the internal definition of the spheroid as a tuple (a, es), where | ||
|
||
a = major_axis | ||
es = eccentricity squared | ||
|
||
""" -> | ||
function _get_spheroid_defn(proj_ptr::Ptr{Void}) | ||
major_axis = Ref{Cdouble}() | ||
eccentricity_squared = Ref{Cdouble}() | ||
ccall((:pj_get_spheroid_defn, libproj), Void, (Ptr{Void}, Ptr{Cdouble}, Ptr{Cdouble}), | ||
proj_ptr, major_axis, eccentricity_squared) | ||
major_axis[], eccentricity_squared[] | ||
end | ||
|
||
@doc "Returns true if the two datums are identical, otherwise false." -> | ||
function _compare_datums(p1_ptr::Ptr{Void}, p2_ptr::Ptr{Void}) | ||
Bool(ccall((:pj_compare_datums, libproj), Cint, (Ptr{Void}, Ptr{Void}), p1_ptr, p2_ptr)) | ||
end | ||
|
||
# Unused/untested | ||
|
||
# @doc """ | ||
# Return the lat/long coordinate system on which a projection is based. | ||
# If the coordinate system passed in is latlong, a clone of the same will be returned. | ||
# """ -> | ||
# function _latlong_from_proj(proj_ptr::Ptr{Void}) | ||
# ccall((:pj_latlong_from_proj, libproj), Ptr{Void}, (Ptr{Void},), proj_ptr) | ||
# end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
pj_fwd and pj_inv both set errno - we should check it.
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.
👌
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.
thanks