Skip to content
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

Would be good to add a to_epsg implimentation #88

Closed
alex-s-gardner opened this issue Jul 20, 2023 · 13 comments
Closed

Would be good to add a to_epsg implimentation #88

alex-s-gardner opened this issue Jul 20, 2023 · 13 comments

Comments

@alex-s-gardner
Copy link
Contributor

robustly retrieving the epsg from a crs requires an implementation of pyproj's to_epsg

@visr
Copy link
Member

visr commented Jul 21, 2023

Isn't this already present?

Proj.jl/src/crs.jl

Lines 129 to 133 in d88918c

function GFT.EPSG(crs::CRS)
str = proj_get_id_code(crs)
code = parse(Int, str)
return GFT.EPSG(code)
end

Although it looks like this doesn't use proj_get_id_auth_name to check if it is EPSG, so that's a bug.

@alex-s-gardner
Copy link
Contributor Author

alex-s-gardner commented Jul 21, 2023

I believe this is a very limited version of to_epsg as it can only find an EPSG code if the Authority and code is contained in the CRS. For example it can't infer the EPSG code from a ProjString or wkt that does not include the authority. This is the same limitation as my ArchGDAL PR. to_epsg has a bunch of logic to try and infer the EPSG and also returns a confidence level that it found the right code.

@alex-s-gardner
Copy link
Contributor Author

I think we'll need to use Proj.proj_identify

@alex-s-gardner
Copy link
Contributor Author

Can someone provide an example of how to use Proj.proj_identify, I can't seem to figure out how to assign and retrieve the C objects.

@visr
Copy link
Member

visr commented Aug 4, 2023

This seems to work:

using Proj
import GeoFormatTypes as GFT

# create a CRS from the proj string that represents EPSG:4326
crs = Proj.CRS("+proj=longlat +datum=WGS84 +no_defs +type=crs")
# attempt to identify the corresponding EPSG code using proj_identify
out_confidence = Ref(Ptr{Cint}(C_NULL))
pj_list = Proj.proj_identify(crs, "EPSG", out_confidence)
# TODO use these to check for error and list length
pj_list == C_NULL
Proj.proj_list_get_count(pj_list)
# get the first resulting CRS
pj_1 = Proj.proj_list_get(pj_list, 0)
crs_1 = Proj.CRS(pj_1)
confidence_1 = unsafe_load(out_confidence[])
# use i in unsafe_load(p::Ptr{T}, i::Integer=1) for other indices

# doesn't work: https://github.com/JuliaGeo/Proj.jl/issues/88#issuecomment-1645894753
GFT.EPSG(crs)
# does work:
GFT.EPSG(crs_1) == GFT.EPSG(4326)

@alex-s-gardner
Copy link
Contributor Author

Should we introduce this into proj as to_epsg() then use that for GFT.EPSG(crs::CRS)?

@visr
Copy link
Member

visr commented Aug 4, 2023

Yeah perhaps we can create a Proj.identify that is a nicely wrapped version of the C API Proj.proj_identify.

Then for GFT.EPSG(crs::CRS) we can use that function with auth_name set to EPSG and only accepting a confidence of 70 or higher like pyproj.

I just noticed my use of out_confidence was incorrect, that is an array that is filled by proj with the confidence level per entry.

@alex-s-gardner
Copy link
Contributor Author

In the example above how should out_confidence be initialized then? I don't have a great mental model yet when
calling out to C

@visr
Copy link
Member

visr commented Aug 4, 2023

Hmm yeah I'm also not great with this stuff, but managed to figure it out, see the updated example.

So you need a reference to a pointer of the right type. We can initialize this with a null pointer, PROJ will point it to an array that it allocates itself. After calling the function we can see that out_confidence[] now points somewhere, and use unsafe_load to get the value(s). In this example I got 70. Note the C API docs that explain that we have to free the PROJ allocated array ourselves with Proj.proj_int_list_destroy(out_confidence[]).

@alex-s-gardner
Copy link
Contributor Author

I'll work on a PR

@alex-s-gardner
Copy link
Contributor Author

alex-s-gardner commented Aug 4, 2023

@visr for the higher level identify I think we should just return the top result. I can really see a use case for returning all matches. If that functionality is needed the user can drop a level to proj_identify

@alex-s-gardner
Copy link
Contributor Author

@visr I think this is good to merge. If you agree I will work on to_EPSG next

@visr
Copy link
Member

visr commented Aug 25, 2023

Left some comments on #92. For to_EPSG you mean GFT.EPSG(crs::CRS) right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants