From 0588c4a4238a6279662a31566024ade11a08f912 Mon Sep 17 00:00:00 2001 From: Wouter Date: Tue, 5 Mar 2024 14:13:25 +0100 Subject: [PATCH] mv logic -> own def, added & update tests --- .vscode/launch.json | 20 ++++---- .../crs_transform.py | 37 ++++++++++---- tests/test_geojson_transformation.py | 49 +++++++++++++++++-- tests/test_transformer_selection.py | 19 ++++++- 4 files changed, 101 insertions(+), 24 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index fb3c504..918d5a1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,16 +27,16 @@ }, "jinja": true, "justMyCode": false - }, - { - "name": "Python: Debug Tests", - "type": "debugpy", - "request": "launch", - "module": "pytest", - "args": ["${file}"], - "purpose": ["debug-test"], - "console": "integratedTerminal", - "justMyCode": false } + // { + // "name": "Python: Debug Tests", + // "type": "debugpy", + // "request": "launch", + // "module": "pytest", + // "args": ["${file}"], + // "purpose": ["debug-test"], + // "console": "integratedTerminal", + // "justMyCode": false + // } ] } 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/test_geojson_transformation.py b/tests/test_geojson_transformation.py index 50d0525..ec474fe 100644 --- a/tests/test_geojson_transformation.py +++ b/tests/test_geojson_transformation.py @@ -165,12 +165,55 @@ def test_validate_crs_transformed_geojson(feature): def test_2d_with_epoch(): with open("tests/data/test_2d_with_epoch.json") as f: data = json.load(f) - feature_2d = Feature(**data) + feature_2d_2000 = Feature(**data) + feature_2d_2020 = Feature(**data) feature_2d_org = Feature(**data) - crs_transform(feature_2d, "EPSG:3043", "EPSG:32631", 2024) + crs_transform(feature_2d_2000, "EPSG:3043", "EPSG:32631", 2000) + crs_transform(feature_2d_2020, "EPSG:3043", "EPSG:32631", 2020) - assert feature_2d == feature_2d_org + 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(): 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