Skip to content

Commit 7ca8080

Browse files
jjimenezshawsnowman2
authored andcommitted
Add query_geodetic_crs_from_datum
1 parent d1e00aa commit 7ca8080

File tree

6 files changed

+154
-1
lines changed

6 files changed

+154
-1
lines changed

docs/api/database.rst

+6
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@ pyproj.database.get_database_metadata
4949
---------------------------------------
5050

5151
.. autofunction:: pyproj.database.get_database_metadata
52+
53+
54+
pyproj.database.query_geodetic_crs_from_datum
55+
---------------------------------------
56+
57+
.. autofunction:: pyproj.database.query_geodetic_crs_from_datum

docs/history.rst

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Latest
55
------
66
- DEP: Minimum PROJ version 9.4 (pull #1481)
77
- DEP: Minimum supported Python version 3.11 (pull #1483)
8+
- ENH: Add :meth:`database.query_geodetic_crs_from_datum` (pull #1390)
89

910
3.7.1
1011
------

pyproj/database.pyi

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

33
from pyproj.aoi import AreaOfInterest, AreaOfUse
4+
from pyproj.crs import CRS
45
from pyproj.enums import PJType
56

67
class Unit(NamedTuple):
@@ -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

+97-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ from collections import namedtuple
66
from libc.stdlib cimport free, malloc
77

88
from pyproj._compat cimport cstrdecode, cstrencode
9-
from pyproj._context cimport pyproj_context_create
9+
from pyproj._context cimport _clear_proj_error, pyproj_context_create
1010

1111
from pyproj.aoi import AreaOfUse
12+
from pyproj.crs import CRS
1213
from pyproj.enums import PJType
1314

1415

@@ -465,3 +466,98 @@ def get_database_metadata(str key not None):
465466
if metadata == NULL:
466467
return None
467468
return metadata
469+
470+
471+
def query_geodetic_crs_from_datum(
472+
str crs_auth_name,
473+
str datum_auth_name not None,
474+
str datum_code not None,
475+
pj_type=None
476+
):
477+
"""
478+
.. versionadded:: 3.8.0
479+
480+
Return GeodeticCRS that use the specified datum
481+
482+
See: :c:func:`proj_query_geodetic_crs_from_datum`
483+
484+
Parameters
485+
----------
486+
crs_auth_name: str | None
487+
The authority name to filter by (e.g. EPSG, ESRI). None is all.
488+
datum_auth_name: str
489+
The authority of the datum
490+
datum_code: str
491+
Datum code
492+
pj_type: pyproj.enums.PJType | None, optional
493+
The type of object to get the CRSs. Can be PJType.GEOCENTRIC_CRS,
494+
PJType.GEOGRAPHIC_3D_CRS, PJType.GEOGRAPHIC_2D_CRS or None for all.
495+
496+
Returns
497+
-------
498+
list[CRS]
499+
"""
500+
501+
cdef const char* c_crs_type = NULL
502+
if pj_type is None:
503+
pass
504+
elif pj_type is PJType.GEOCENTRIC_CRS:
505+
c_crs_type = b"geocentric"
506+
elif pj_type is PJType.GEOGRAPHIC_2D_CRS:
507+
c_crs_type = b"geographic 2D"
508+
elif pj_type is PJType.GEOGRAPHIC_3D_CRS:
509+
c_crs_type = b"geographic 3D"
510+
else:
511+
raise ValueError("type must be GEOCENTRIC_CRS, GEOGRAPHIC_2D_CRS, GEOGRAPHIC_3D_CRS or None")
512+
513+
cdef const char* c_crs_auth_name = NULL
514+
cdef const char* c_datum_auth_name = NULL
515+
cdef const char* c_datum_code = NULL
516+
cdef bytes b_crs_auth_name
517+
cdef bytes b_datum_auth_name
518+
cdef bytes b_datum_code
519+
520+
if crs_auth_name is not None:
521+
b_crs_auth_name = cstrencode(crs_auth_name)
522+
c_crs_auth_name = b_crs_auth_name
523+
524+
if datum_auth_name is not None:
525+
b_datum_auth_name = cstrencode(datum_auth_name)
526+
c_datum_auth_name = b_datum_auth_name
527+
528+
if datum_code is not None:
529+
b_datum_code = cstrencode(datum_code)
530+
c_datum_code = b_datum_code
531+
532+
ret_list = []
533+
534+
cdef PJ_OBJ_LIST *proj_list = NULL
535+
cdef int num_proj_objects = 0
536+
537+
cdef PJ_CONTEXT* context = pyproj_context_create()
538+
proj_list = proj_query_geodetic_crs_from_datum(
539+
context,
540+
c_crs_auth_name,
541+
c_datum_auth_name,
542+
c_datum_code,
543+
c_crs_type
544+
)
545+
546+
if proj_list != NULL:
547+
num_proj_objects = proj_list_get_count(proj_list)
548+
549+
cdef PJ* proj = NULL
550+
try:
551+
for iii in range(num_proj_objects):
552+
proj = proj_list_get(context, proj_list, iii)
553+
ret_list.append(CRS(proj_as_wkt(context, proj, PJ_WKT2_2019, NULL)))
554+
proj_destroy(proj)
555+
proj = NULL
556+
finally:
557+
# If there was an error we have to call proj_destroy
558+
# If there was none, calling it on NULL does nothing
559+
proj_destroy(proj)
560+
proj_list_destroy(proj_list)
561+
_clear_proj_error()
562+
563+
return ret_list

pyproj/proj.pxi

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

565565
int proj_is_deprecated(const PJ *obj)
566566
PJ_OBJ_LIST *proj_get_non_deprecated(PJ_CONTEXT *ctx, const PJ *obj)
567+
568+
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
@@ -268,3 +269,43 @@ def test_get_database_metadata():
268269

269270
def test_get_database_metadata__invalid():
270271
assert get_database_metadata("doesnotexist") is None
272+
273+
274+
def test_query_geodetic_crs_from_datum():
275+
crss = query_geodetic_crs_from_datum("EPSG", "EPSG", "1116", PJType.GEOCENTRIC_CRS)
276+
assert len(crss) == 1
277+
assert crss[0].to_authority()[1] == "6317"
278+
279+
crss = query_geodetic_crs_from_datum(None, "EPSG", "1116")
280+
assert len(crss) == 3
281+
codes = [x.to_authority()[1] for x in crss]
282+
assert "6317" in codes
283+
assert "6318" in codes
284+
assert "6319" in codes
285+
286+
crss = query_geodetic_crs_from_datum("EPSG", "EPSG", "6269", None)
287+
assert len(crss) == 1
288+
assert crss[0].to_authority()[1] == "4269"
289+
290+
crss = query_geodetic_crs_from_datum(None, "EPSG", "6269")
291+
assert len(crss) == 3 # EPSG, ESRI, OGC
292+
293+
294+
def test_query_geodetic_crs_from_datum_invalid():
295+
crss = query_geodetic_crs_from_datum(None, "EPSG", "11")
296+
assert len(crss) == 0
297+
298+
crss = query_geodetic_crs_from_datum(None, "EPSG", "32632")
299+
assert len(crss) == 0
300+
301+
crss = query_geodetic_crs_from_datum("foo-bar", "EPSG", "6269", None)
302+
assert len(crss) == 0
303+
304+
with pytest.raises(ValueError):
305+
query_geodetic_crs_from_datum("EPSG", "EPSG", "1116", PJType.PROJECTED_CRS)
306+
307+
with pytest.raises(TypeError):
308+
query_geodetic_crs_from_datum("EPSG", "EPSG", None)
309+
310+
with pytest.raises(TypeError):
311+
query_geodetic_crs_from_datum("EPSG", None, "1116")

0 commit comments

Comments
 (0)