From d4a4b3cbe20d7a0fbca0d009c935b1b799b124f5 Mon Sep 17 00:00:00 2001 From: Wouter Date: Tue, 5 Mar 2024 14:28:59 +0100 Subject: [PATCH] 2d epoch (#145) * Bump the python-packages group with 6 updates Bumps the python-packages group with 6 updates: | Package | From | To | | --- | --- | --- | | [fastapi[all]](https://github.com/tiangolo/fastapi) | `0.109.2` | `0.110.0` | | [pydantic-settings](https://github.com/pydantic/pydantic-settings) | `2.1.0` | `2.2.1` | | [email-validator](https://github.com/JoshData/python-email-validator) | `2.1.0.post1` | `2.1.1` | | [coverage](https://github.com/nedbat/coveragepy) | `7.4.1` | `7.4.3` | | [pytest](https://github.com/pytest-dev/pytest) | `8.0.0` | `8.1.0` | | [ruff](https://github.com/astral-sh/ruff) | `0.2.1` | `0.3.0` | Updates `fastapi[all]` from 0.109.2 to 0.110.0 - [Release notes](https://github.com/tiangolo/fastapi/releases) - [Commits](https://github.com/tiangolo/fastapi/compare/0.109.2...0.110.0) Updates `pydantic-settings` from 2.1.0 to 2.2.1 - [Release notes](https://github.com/pydantic/pydantic-settings/releases) - [Commits](https://github.com/pydantic/pydantic-settings/compare/v2.1.0...v2.2.1) Updates `email-validator` from 2.1.0.post1 to 2.1.1 - [Release notes](https://github.com/JoshData/python-email-validator/releases) - [Changelog](https://github.com/JoshData/python-email-validator/blob/main/CHANGELOG.md) - [Commits](https://github.com/JoshData/python-email-validator/commits/v2.1.1) Updates `coverage` from 7.4.1 to 7.4.3 - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/7.4.1...7.4.3) Updates `pytest` from 8.0.0 to 8.1.0 - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.0.0...8.1.0) Updates `ruff` from 0.2.1 to 0.3.0 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/v0.2.1...v0.3.0) --- updated-dependencies: - dependency-name: fastapi[all] dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-packages - dependency-name: pydantic-settings dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-packages - dependency-name: email-validator dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-packages - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-packages - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-packages - dependency-name: ruff dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-packages ... Signed-off-by: dependabot[bot] * added 2d with epoch test * mv logic -> own def, added & update tests * fix launch.json --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../crs_transform.py | 37 +++++++++---- tests/data/test_2d_with_epoch.json | 8 +++ tests/test_geojson_transformation.py | 54 +++++++++++++++++++ tests/test_transformer_selection.py | 19 ++++++- 4 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 tests/data/test_2d_with_epoch.json diff --git a/src/coordinate_transformation_api/crs_transform.py b/src/coordinate_transformation_api/crs_transform.py index f78af26..7c036ba 100644 --- a/src/coordinate_transformation_api/crs_transform.py +++ b/src/coordinate_transformation_api/crs_transform.py @@ -341,6 +341,32 @@ def get_individual_epsg_code(compound_crs: CRS) -> tuple[str, str]: return (f"{horizontal[0]}:{horizontal[1]}", f"{vertical[0]}:{vertical[1]}") +def build_input_coord(coord: CoordinatesType, epoch: float | None) -> CoordinatesType: + + # When 2D input is given with an epoch we need to add a height. So pyproj knows to + # that the epoch is an epoch and not the height, without this intervention the epoch + # would be place in the firth position of the tuple. + if len(coord) == TWO_DIMENSIONAL and epoch is not None: + return tuple([*coord, 0.0, epoch]) + + # Default behaviour + # The input_coord == coord that are given. When an epoch is provided with a 3D coord + # this is added or the value None is given for any other. Note: with 2D the additional None + # is the height. But this doesn't influence the result, because it's None. + input_coord = tuple( + [ + *coord, + ( + float(epoch) + if len(coord) == THREE_DIMENSIONAL and epoch is not None + else None + ), + ] + ) + + return input_coord + + def get_transform_crs_fun( # source_crs: str, target_crs: str, @@ -414,16 +440,7 @@ def transform_crs(val: CoordinatesType) -> tuple[float, ...]: # when one of the src or tgt crs has a dynamic time component # or the transformation used has a datetime component # for now simple check on coords length (which is not correct) - input = tuple( - [ - *val, - ( - float(epoch) - if len(val) == THREE_DIMENSIONAL and epoch is not None - else None - ), - ] - ) + input = build_input_coord(val, epoch) # GeoJSON and CityJSON by definition has coordinates always in lon-lat-height (or x-y-z) order. Transformer has been created with `always_xy=True`, # to ensure input and output coordinates are in in lon-lat-height (or x-y-z) order. diff --git a/tests/data/test_2d_with_epoch.json b/tests/data/test_2d_with_epoch.json new file mode 100644 index 0000000..4b75d45 --- /dev/null +++ b/tests/data/test_2d_with_epoch.json @@ -0,0 +1,8 @@ +{ + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [663000.0, 5781000.0] + } +} diff --git a/tests/test_geojson_transformation.py b/tests/test_geojson_transformation.py index a279a04..ec474fe 100644 --- a/tests/test_geojson_transformation.py +++ b/tests/test_geojson_transformation.py @@ -162,6 +162,60 @@ def test_validate_crs_transformed_geojson(feature): validate_crs_transformed_geojson(feature_no_exc) +def test_2d_with_epoch(): + with open("tests/data/test_2d_with_epoch.json") as f: + data = json.load(f) + feature_2d_2000 = Feature(**data) + feature_2d_2020 = Feature(**data) + feature_2d_org = Feature(**data) + + crs_transform(feature_2d_2000, "EPSG:3043", "EPSG:32631", 2000) + crs_transform(feature_2d_2020, "EPSG:3043", "EPSG:32631", 2020) + + assert feature_2d_2000 != feature_2d_org + assert feature_2d_2020 != feature_2d_org + + coords_2000 = feature_2d_2000.geometry.coordinates + coords_2020 = feature_2d_2020.geometry.coordinates + coords_org = feature_2d_org.geometry.coordinates + + dif_2000_org = 0.29 + dif_2020_org = 0.76 + + assert ( + round( + math.sqrt( + ( + (coords_2000[0] - coords_org[0]) + * (coords_2000[0] - coords_org[0]) + ) + + ( + (coords_2000[1] - coords_org[1]) + * (coords_2000[1] - coords_org[1]) + ) + ), + 2, + ) + == dif_2000_org + ) + assert ( + round( + math.sqrt( + ( + (coords_2020[0] - coords_org[0]) + * (coords_2020[0] - coords_org[0]) + ) + + ( + (coords_2020[1] - coords_org[1]) + * (coords_2020[1] - coords_org[1]) + ) + ), + 2, + ) + == dif_2020_org + ) + + def test_wgs_epoch(): with open("tests/data/test_wgs_epoch.json") as f: data = json.load(f) diff --git a/tests/test_transformer_selection.py b/tests/test_transformer_selection.py index a1b807a..b7795e5 100644 --- a/tests/test_transformer_selection.py +++ b/tests/test_transformer_selection.py @@ -1,5 +1,9 @@ import pytest -from coordinate_transformation_api.crs_transform import get_transformer, needs_epoch +from coordinate_transformation_api.crs_transform import ( + build_input_coord, + get_transformer, + needs_epoch, +) # This test needs the modified proj.time.dependent.transformations.db from @@ -17,3 +21,16 @@ ) def test_time_dependant_operation_method(source, target, epoch, expectation): assert needs_epoch(get_transformer(source, target, epoch)) == expectation + + +@pytest.mark.parametrize( + ("coord", "epoch", "expectation"), + [ + (tuple([1000.0, 1000.0]), 2000.0, tuple([1000.0, 1000.0, 0.0, 2000.0])), + (tuple([1000.0, 1000.0]), None, tuple([1000.0, 1000.0, None])), + (tuple([1000.0, 1000.0, 10.0]), 2000.0, tuple([1000.0, 1000.0, 10.0, 2000.0])), + (tuple([1000.0, 1000.0, 10.0]), None, tuple([1000.0, 1000.0, 10.0, None])), + ], +) +def test_build_input_coord(coord, epoch, expectation): + assert build_input_coord(coord, epoch) == expectation