Skip to content

Commit

Permalink
ENH: Added only_best kwarg to Transformer.from_crs
Browse files Browse the repository at this point in the history
  • Loading branch information
snowman2 committed Jan 20, 2023
1 parent f1fb8cd commit 6b0ab1f
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 6 deletions.
1 change: 1 addition & 0 deletions docs/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Latest
`fwd` and `fwd_intermediate`, `inv` and `inv_intermediate`,
Note: BREAKING CHANGE for the default value `return_back_azimuth=True` in the functions `fwd_intermediate` and `inv_intermediate`
to mach the default value in `fwd` and `inv`
- ENH: Added only_best kwarg to :meth:`.Transformer.from_crs` (issue #1228)
- PERF: Optimize point transformations (pull #1204)
- REF: Raise error when :meth:`.CRS.to_wkt`, :meth:`.CRS.to_json`, or :meth:`.CRS.to_proj4` returns None (issue #1036)
- CLN: Remove `AzumuthalEquidistantConversion` & :class:`LambertAzumuthalEqualAreaConversion`. :class:`AzimuthalEquidistantConversion` & :class:`LambertAzimuthalEqualAreaConversion` should be used instead (pull #1219)
Expand Down
24 changes: 18 additions & 6 deletions pyproj/_transformer.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ cdef PJ* proj_create_crs_to_crs(
str accuracy,
allow_ballpark,
bint force_over,
only_best,
) except NULL:
"""
This is the same as proj_create_crs_to_crs in proj.h
Expand All @@ -290,16 +291,15 @@ cdef PJ* proj_create_crs_to_crs(
return NULL

cdef:
const char* options[5]
const char* options[6]
bytes b_authority
bytes b_accuracy
int options_index = 0
int options_init_iii = 0

for options_init_iii in range(6):
options[options_init_iii] = NULL

options[0] = NULL
options[1] = NULL
options[2] = NULL
options[3] = NULL
options[4] = NULL
if authority is not None:
b_authority = cstrencode(f"AUTHORITY={authority}")
options[options_index] = b_authority
Expand All @@ -317,6 +317,16 @@ cdef PJ* proj_create_crs_to_crs(
options[options_index] = b"FORCE_OVER=YES"
ELSE:
raise NotImplementedError("force_over requires PROJ 9+.")
options_index += 1
if only_best is not None:
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 2):
if only_best:
options[options_index] = b"ONLY_BEST=YES"
else:
options[options_index] = b"ONLY_BEST=NO"
ELSE:
raise NotImplementedError("only_best requires PROJ 9.2+.")


cdef PJ* transform = proj_create_crs_to_crs_from_pj(
ctx,
Expand Down Expand Up @@ -519,6 +529,7 @@ cdef class _Transformer(Base):
str accuracy=None,
allow_ballpark=None,
bint force_over=False,
only_best=None,
):
"""
Create a transformer from CRS objects
Expand Down Expand Up @@ -560,6 +571,7 @@ cdef class _Transformer(Base):
accuracy=accuracy,
allow_ballpark=allow_ballpark,
force_over=force_over,
only_best=only_best,
)
finally:
if pj_area_of_interest != NULL:
Expand Down
17 changes: 17 additions & 0 deletions pyproj/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class TransformerFromCRS( # pylint: disable=too-many-instance-attributes
accuracy: Optional[str]
allow_ballpark: Optional[bool]
force_over: bool = False
only_best: Optional[bool] = None

def __call__(self) -> _Transformer:
"""
Expand All @@ -109,6 +110,7 @@ def __call__(self) -> _Transformer:
accuracy=self.accuracy,
allow_ballpark=self.allow_ballpark,
force_over=self.force_over,
only_best=self.only_best,
)


Expand Down Expand Up @@ -549,6 +551,7 @@ def from_crs(
accuracy: Optional[float] = None,
allow_ballpark: Optional[bool] = None,
force_over: bool = False,
only_best: Optional[bool] = None,
) -> "Transformer":
"""Make a Transformer from a :obj:`pyproj.crs.CRS` or input used to create one.
Expand All @@ -561,6 +564,7 @@ def from_crs(
.. versionadded:: 2.3.0 area_of_interest
.. versionadded:: 3.1.0 authority, accuracy, allow_ballpark
.. versionadded:: 3.4.0 force_over
.. versionadded:: 3.5.0 only_best
Parameters
----------
Expand Down Expand Up @@ -592,6 +596,18 @@ def from_crs(
force_over: bool, default=False
If True, it will to force the +over flag on the transformation.
Requires PROJ 9+.
only_best: bool, optional
Can be set to True to cause PROJ to error out if the best
transformation known to PROJ and usable by PROJ if all grids known and
usable by PROJ were accessible, cannot be used. Best transformation should
be understood as the transformation returned by
:c:func:`proj_get_suggested_operation` if all known grids were
accessible (either locally or through network).
Note that the default value for this option can be also set with the
:envvar:`PROJ_ONLY_BEST_DEFAULT` environment variable, or with the
``only_best_default`` setting of :ref:`proj-ini`.
The only_best kwarg overrides the default value if set.
Requires PROJ 9.2+.
Returns
-------
Expand All @@ -608,6 +624,7 @@ def from_crs(
accuracy=accuracy if accuracy is None else str(accuracy),
allow_ballpark=allow_ballpark,
force_over=force_over,
only_best=only_best,
)
)

Expand Down
15 changes: 15 additions & 0 deletions test/test_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import pickle
from array import array
from contextlib import nullcontext
from functools import partial
from glob import glob
from itertools import permutations
Expand Down Expand Up @@ -666,6 +667,20 @@ def test_transformer__operations__scope_remarks():
]


@pytest.mark.grid
def test_transformer__only_best():
with nullcontext() if PROJ_GTE_92 else pytest.raises(
NotImplementedError, match="only_best requires PROJ 9.2"
):
transformer = Transformer.from_crs(4326, 2964, only_best=True)
if not grids_available("ca_nrc_ntv2_0.tif"):
with pytest.raises(
ProjError,
match="Grid ca_nrc_ntv2_0.tif is not available.",
):
transformer.transform(60, -100, errcheck=True)


def test_transformer_group():
trans_group = TransformerGroup(7789, 8401)
assert len(trans_group.transformers) == 2
Expand Down

0 comments on commit 6b0ab1f

Please sign in to comment.