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

ENH: Added authority, accuracy, and allow_ballpark kwargs to TransformerGroup #1076

Merged
merged 1 commit into from May 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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"
)