Skip to content

Commit

Permalink
ENH: Added authority, accuracy, and allow_ballpark kwargs to Transfor…
Browse files Browse the repository at this point in the history
…merGroup (#1076)
  • Loading branch information
snowman2 committed May 12, 2022
1 parent 659852e commit e0b7cd0
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .pylintrc
Expand Up @@ -348,7 +348,7 @@ indent-string=' '
max-line-length=100

# Maximum number of lines in a module.
max-module-lines=1300
max-module-lines=1350

# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
Expand Down
1 change: 1 addition & 0 deletions docs/history.rst
Expand Up @@ -5,6 +5,7 @@ Latest
-------
- DEP: Minimum PROJ version 8.1 (issue #1011)
- BUG: Fix transformer list for 3D transformations in :class:`pyproj.transformer.TransformerGroup` (discussion #1072)
- ENH: Added authority, accuracy, and allow_ballpark kwargs to :class:`pyproj.transformer.TransformerGroup` (pull #1076)

3.3.1
-------
Expand Down
7 changes: 5 additions & 2 deletions pyproj/_transformer.pyi
Expand Up @@ -35,8 +35,11 @@ class _TransformerGroup:
self,
crs_from: str,
crs_to: str,
always_xy: bool = False,
area_of_interest: Optional[AreaOfInterest] = None,
always_xy: bool,
area_of_interest: Optional[AreaOfInterest],
authority: Optional[str],
accuracy: Optional[float],
allow_ballpark: bool,
) -> None: ...

class _Transformer(Base):
Expand Down
26 changes: 22 additions & 4 deletions pyproj/_transformer.pyx
Expand Up @@ -116,8 +116,11 @@ cdef class _TransformerGroup:
self,
_CRS crs_from not None,
_CRS crs_to not None,
bint always_xy=False,
area_of_interest=None,
bint always_xy,
area_of_interest,
bint allow_ballpark,
str authority,
double accuracy,
):
"""
From PROJ docs:
Expand All @@ -133,13 +136,18 @@ cdef class _TransformerGroup:
cdef PJ_OBJ_LIST * pj_operations = NULL
cdef PJ* pj_transform = NULL
cdef PJ_CONTEXT* context = NULL
cdef const char* c_authority = NULL
cdef int num_operations = 0
cdef int is_instantiable = 0
cdef double west_lon_degree, south_lat_degree, east_lon_degree, north_lat_degree

if authority is not None:
c_authority = authority

try:
operation_factory_context = proj_create_operation_factory_context(
self.context,
NULL,
c_authority,
)
if area_of_interest is not None:
if not isinstance(area_of_interest, AreaOfInterest):
Expand All @@ -159,7 +167,17 @@ cdef class _TransformerGroup:
east_lon_degree,
north_lat_degree,
)

if accuracy > 0:
proj_operation_factory_context_set_desired_accuracy(
self.context,
operation_factory_context,
accuracy,
)
proj_operation_factory_context_set_allow_ballpark_transformations(
self.context,
operation_factory_context,
allow_ballpark,
)
proj_operation_factory_context_set_grid_availability_use(
self.context,
operation_factory_context,
Expand Down
12 changes: 11 additions & 1 deletion pyproj/proj.pxi
Expand Up @@ -456,7 +456,16 @@ cdef extern from "proj.h" nogil:
double east_lon_degree,
double north_lat_degree
)

void proj_operation_factory_context_set_allow_ballpark_transformations(
PJ_CONTEXT *ctx,
PJ_OPERATION_FACTORY_CONTEXT *factory_ctx,
int allow
)
void proj_operation_factory_context_set_desired_accuracy(
PJ_CONTEXT *ctx,
PJ_OPERATION_FACTORY_CONTEXT *factory_ctx,
double accuracy
)
ctypedef enum PROJ_SPATIAL_CRITERION:
PROJ_SPATIAL_CRITERION_STRICT_CONTAINMENT
PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION
Expand All @@ -465,6 +474,7 @@ cdef extern from "proj.h" nogil:
PROJ_GRID_AVAILABILITY_USED_FOR_SORTING
PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID
PROJ_GRID_AVAILABILITY_IGNORED
PROJ_GRID_AVAILABILITY_KNOWN_AVAILABLE

ctypedef struct PJ_FACTORS:
double meridional_scale
Expand Down
23 changes: 23 additions & 0 deletions pyproj/transformer.py
Expand Up @@ -150,10 +150,15 @@ def __init__(
skip_equivalent: bool = False,
always_xy: bool = False,
area_of_interest: Optional[AreaOfInterest] = None,
authority: Optional[str] = None,
accuracy: Optional[float] = None,
allow_ballpark: bool = True,
) -> None:
"""Get all possible transformations from a :obj:`pyproj.crs.CRS`
or input used to create one.
.. versionadded:: 3.4.0 authority, accuracy, allow_ballpark
.. deprecated:: 3.1 skip_equivalent
Parameters
Expand All @@ -172,6 +177,21 @@ def __init__(
area_of_interest: :class:`pyproj.transformer.AreaOfInterest`, optional
The area of interest to help order the transformations based on the
best operation for the area.
authority: str, optional
When not specified, coordinate operations from any authority will be
searched, with the restrictions set in the
authority_to_authority_preference database table related to the
authority of the source/target CRS themselves. If authority is set
to “any”, then coordinate operations from any authority will be
searched. If authority is a non-empty string different from "any",
then coordinate operations will be searched only in that authority
namespace (e.g. EPSG).
accuracy: float, optional
The minimum desired accuracy (in metres) of the candidate
coordinate operations.
allow_ballpark: bool, default=True
Set to False to disallow the use of Ballpark transformation
in the candidate coordinate operations. Default is to allow.
"""
if skip_equivalent:
Expand All @@ -186,6 +206,9 @@ def __init__(
CRS.from_user_input(crs_to)._crs,
always_xy=always_xy,
area_of_interest=area_of_interest,
authority=authority,
accuracy=-1 if accuracy is None else accuracy,
allow_ballpark=allow_ballpark,
)
for iii, transformer in enumerate(self._transformers):
# pylint: disable=unsupported-assignment-operation
Expand Down
24 changes: 24 additions & 0 deletions test/test_transformer.py
Expand Up @@ -1536,3 +1536,27 @@ def test_pickle_transformer_from_crs():
area_of_interest=AreaOfInterest(-136.46, 49.0, -60.72, 83.17),
)
assert transformer == pickle.loads(pickle.dumps(transformer))


def test_transformer_group_accuracy_filter():
group = TransformerGroup("EPSG:4326", "EPSG:4258", accuracy=0.05)
assert not group.transformers
assert not group.unavailable_operations


def test_transformer_group_allow_ballpark_filter():
group = TransformerGroup(
"EPSG:4326", "EPSG:4258", authority="PROJ", allow_ballpark=False
)
assert not group.transformers
assert not group.unavailable_operations


def test_transformer_group_authority_filter():
group = TransformerGroup("EPSG:4326", "EPSG:4258", authority="PROJ")
assert len(group.transformers) == 1
assert not group.unavailable_operations
assert (
group.transformers[0].description
== "Ballpark geographic offset from WGS 84 to ETRS89"
)

0 comments on commit e0b7cd0

Please sign in to comment.