Skip to content

Commit dc10ebd

Browse files
committed
Add query_geodetic_crs_from_datum
1 parent 28cc117 commit dc10ebd

File tree

4 files changed

+158
-1
lines changed

4 files changed

+158
-1
lines changed

pyproj/database.pyi

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import NamedTuple
22

3+
from pyproj._crs import _CRS
34
from pyproj.aoi import AreaOfInterest, AreaOfUse
45
from pyproj.enums import PJType
56

@@ -44,3 +45,9 @@ def query_utm_crs_info(
4445
contains: bool = False,
4546
) -> list[CRSInfo]: ...
4647
def get_database_metadata(key: str) -> str | None: ...
48+
def query_geodetic_crs_from_datum(
49+
crs_auth_name: str | None,
50+
datum_auth_name: str,
51+
datum_code: str,
52+
pj_type: PJType | None = None,
53+
) -> list[_CRS]: ...

pyproj/database.pyx

+108-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ from collections import namedtuple
66
from libc.stdlib cimport free, malloc
77

88
from pyproj._compat cimport cstrdecode, cstrencode
9-
from pyproj._datadir cimport pyproj_context_create, pyproj_context_destroy
9+
from pyproj._datadir cimport (
10+
_clear_proj_error,
11+
pyproj_context_create,
12+
pyproj_context_destroy,
13+
)
1014

15+
from pyproj._crs import _CRS
1116
from pyproj.aoi import AreaOfUse
1217
from pyproj.enums import PJType
1318

@@ -483,3 +488,105 @@ def get_database_metadata(str key not None):
483488
return metadata
484489
finally:
485490
pyproj_context_destroy(context)
491+
492+
493+
def query_geodetic_crs_from_datum(
494+
str crs_auth_name,
495+
str datum_auth_name not None,
496+
str datum_code not None,
497+
pj_type=None
498+
):
499+
"""
500+
.. versionadded:: 3.7.0
501+
502+
Return GeodeticCRS that use the specified datum
503+
504+
See: :c:func:`proj_query_geodetic_crs_from_datum`
505+
506+
Parameters
507+
----------
508+
crs_auth_name: str | None
509+
The authority name to filter by (e.g. EPSG, ESRI). None is all.
510+
datum_auth_name: str
511+
The authority of the datum
512+
datum_code: str
513+
Datum code
514+
pj_type: pyproj.enums.PJType | None, optional
515+
The type of object to get the CRSs. Can be PJType.GEOCENTRIC_CRS,
516+
PJType.GEOGRAPHIC_3D_CRS, PJType.GEOGRAPHIC_2D_CRS or None for all.
517+
518+
Returns
519+
-------
520+
list[_CRS]
521+
"""
522+
523+
cdef const char* c_crs_type = NULL
524+
cdef bytes b_crs_type
525+
cdef str crs_type = ""
526+
if pj_type is None:
527+
pass
528+
elif pj_type == PJType.GEOCENTRIC_CRS:
529+
crs_type = "geocentric"
530+
elif pj_type == PJType.GEOGRAPHIC_2D_CRS:
531+
crs_type = "geographic 2D"
532+
elif pj_type == PJType.GEOGRAPHIC_3D_CRS:
533+
crs_type = "geographic 3D"
534+
else:
535+
raise ValueError("type must be GEOCENTRIC_CRS, GEOGRAPHIC_2D_CRS, GEOGRAPHIC_3D_CRS or None")
536+
537+
if pj_type is not None:
538+
b_crs_type = cstrencode(crs_type)
539+
c_crs_type = b_crs_type
540+
541+
cdef const char* c_crs_auth_name = NULL
542+
cdef const char* c_datum_auth_name = NULL
543+
cdef const char* c_datum_code = NULL
544+
cdef bytes b_crs_auth_name
545+
cdef bytes b_datum_auth_name
546+
cdef bytes b_datum_code
547+
548+
if crs_auth_name is not None:
549+
b_crs_auth_name = cstrencode(crs_auth_name)
550+
c_crs_auth_name = b_crs_auth_name
551+
552+
if datum_auth_name is not None:
553+
b_datum_auth_name = cstrencode(datum_auth_name)
554+
c_datum_auth_name = b_datum_auth_name
555+
556+
if datum_code is not None:
557+
b_datum_code = cstrencode(datum_code)
558+
c_datum_code = b_datum_code
559+
560+
ret_list = []
561+
562+
cdef PJ_OBJ_LIST *proj_list = NULL
563+
cdef int num_proj_objects = 0
564+
565+
cdef PJ_CONTEXT* context = pyproj_context_create()
566+
proj_list = proj_query_geodetic_crs_from_datum(
567+
context,
568+
c_crs_auth_name,
569+
c_datum_auth_name,
570+
c_datum_code,
571+
c_crs_type
572+
)
573+
574+
if proj_list != NULL:
575+
num_proj_objects = proj_list_get_count(proj_list)
576+
577+
cdef PJ* proj = NULL
578+
try:
579+
for iii in range(num_proj_objects):
580+
proj = proj_list_get(context, proj_list, iii)
581+
ret_list.append(_CRS(proj_as_wkt(context, proj, PJ_WKT2_2019, NULL)))
582+
proj_destroy(proj)
583+
proj = NULL
584+
finally:
585+
# If there was an error we have to call proj_destroy
586+
# If there was none, calling it on NULL does nothing
587+
proj_destroy(proj)
588+
proj_list_destroy(proj_list)
589+
pyproj_context_destroy(context)
590+
_clear_proj_error()
591+
592+
return ret_list

pyproj/proj.pxi

+2
Original file line numberDiff line numberDiff line change
@@ -549,3 +549,5 @@ cdef extern from "proj.h" nogil:
549549

550550
int proj_is_deprecated(const PJ *obj)
551551
PJ_OBJ_LIST *proj_get_non_deprecated(PJ_CONTEXT *ctx, const PJ *obj)
552+
553+
PJ_OBJ_LIST *proj_query_geodetic_crs_from_datum(PJ_CONTEXT *ctx, const char *crs_auth_name, const char *datum_auth_name, const char *datum_code, const char *crs_type)

test/test_database.py

+41
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
get_database_metadata,
99
get_units_map,
1010
query_crs_info,
11+
query_geodetic_crs_from_datum,
1112
query_utm_crs_info,
1213
)
1314
from pyproj.enums import PJType
@@ -281,3 +282,43 @@ def test_get_database_metadata():
281282

282283
def test_get_database_metadata__invalid():
283284
assert get_database_metadata("doesnotexist") is None
285+
286+
287+
def test_query_geodetic_crs_from_datum():
288+
crss = query_geodetic_crs_from_datum("EPSG", "EPSG", "1116", PJType.GEOCENTRIC_CRS)
289+
assert len(crss) == 1
290+
assert crss[0].to_authority()[1] == "6317"
291+
292+
crss = query_geodetic_crs_from_datum(None, "EPSG", "1116")
293+
assert len(crss) == 3
294+
codes = [x.to_authority()[1] for x in crss]
295+
assert "6317" in codes
296+
assert "6318" in codes
297+
assert "6319" in codes
298+
299+
crss = query_geodetic_crs_from_datum("EPSG", "EPSG", "6269", None)
300+
assert len(crss) == 1
301+
assert crss[0].to_authority()[1] == "4269"
302+
303+
crss = query_geodetic_crs_from_datum(None, "EPSG", "6269")
304+
assert len(crss) == 3 # EPSG, ESRI, OGC
305+
306+
307+
def test_query_geodetic_crs_from_datum_invalid():
308+
crss = query_geodetic_crs_from_datum(None, "EPSG", "11")
309+
assert len(crss) == 0
310+
311+
crss = query_geodetic_crs_from_datum(None, "EPSG", "32632")
312+
assert len(crss) == 0
313+
314+
crss = query_geodetic_crs_from_datum("foo-bar", "EPSG", "6269", None)
315+
assert len(crss) == 0
316+
317+
with pytest.raises(ValueError):
318+
query_geodetic_crs_from_datum("EPSG", "EPSG", "1116", PJType.PROJECTED_CRS)
319+
320+
with pytest.raises(TypeError):
321+
query_geodetic_crs_from_datum("EPSG", "EPSG", None)
322+
323+
with pytest.raises(TypeError):
324+
query_geodetic_crs_from_datum("EPSG", None, "1116")

0 commit comments

Comments
 (0)