def transform(self, sourceCoordinate: CrsCoordinate, targetCoordinateExpected: CrsCoordinate, problemTransformationResults: list[str]): targetCrs: CrsProjection = targetCoordinateExpected.get_crs_projection( ) targetCoordinate: CrsCoordinate = sourceCoordinate.transform(targetCrs) isTargetEpsgWgs84: bool = targetCrs.is_wgs84() # double maxDifference = isTargetEpsgWgs84 ? 0.000002 : 0.2; // fails, Epsg 3022 ==> 4326 , diffLongitude 2.39811809521484E-06 # double maxDifference = isTargetEpsgWgs84 ? 0.000003 : 0.1; // fails, Epsg 4326 ==> 3022 , diffLongitude 0.117090131156147 maxDifference = 0.000003 if isTargetEpsgWgs84 else 0.2 # the other (i.e. non-WGS84) are using meter as unit, so 0.2 is just two decimeters difference diffLongitude = abs((targetCoordinate.get_longitude_x() - targetCoordinateExpected.get_longitude_x())) diffLatitude = abs((targetCoordinate.get_latitude_y() - targetCoordinateExpected.get_latitude_y())) if (diffLongitude > maxDifference or diffLatitude > maxDifference): problem = f""" "Projection {sourceCoordinate.get_crs_projection()} ==> {targetCoordinateExpected.get_crs_projection()} , diffLongitude {diffLongitude} , diffLatitude {diffLatitude}" "sourceCoordinate xLongitude/yLatitude: {sourceCoordinate.get_longitude_x()}/{sourceCoordinate.get_latitude_y()}" "targetCoordinate xLongitude/yLatitude: {targetCoordinate.get_longitude_x()}/{targetCoordinate.get_latitude_y()}" "targetCoordinateExpected xLongitude/yLatitude: {targetCoordinateExpected.get_longitude_x()}/{targetCoordinateExpected.get_latitude_y()}" """ # problem = "TODO python 2.7" # no not really needed ... if there is a problem then e.g. python 3.9 can be used for seeing the formatted message with above formatted string problemTransformationResults.append(problem)
def setUp(self): self.coordinateWgs84: CrsCoordinate = CrsCoordinate.create_coordinate( CrsProjection.WGS84, 60.0, 20.0) self.coordinateSweref99 = CrsCoordinate.create_coordinate( CrsProjection.SWEREF_99_TM, 6484098.0, 333538.0) self.coordinateRT90 = CrsCoordinate.create_coordinate( CrsProjection.RT90_2_5_GON_V, 6797357.0, 1500627.0)
def test_string(self): coordinate: CrsCoordinate = CrsCoordinate.create_coordinate(CrsProjection.SWEREF_99_18_00, 6579457.649, 153369.673) self.assertEqual( "CrsCoordinate [ Y: 6579457.649 , X: 153369.673 , CRS: SWEREF_99_18_00(EPSG:3011) ]", str(coordinate) ) coordinate2: CrsCoordinate = CrsCoordinate.create_coordinate(CrsProjection.WGS84, 59.330231, 18.059196) expectedDefaultToStringResultForCoordinate2 = "CrsCoordinate [ Latitude: 59.330231 , Longitude: 18.059196 , CRS: WGS84(EPSG:4326) ]" self.assertEqual( expectedDefaultToStringResultForCoordinate2 , str(coordinate2) )
def __init__(self, lineFromFile: str): array = lineFromFile.split( TransformingCoordinatesFromFileTest.columnSeparator) self.coordinateList = [ # Note that the order of the parameters in the input file (with its lines being used here) # are in the order x/Longitude first, but the create method below takes the y/Latitude first # (and therefore the parameters are not in the sequential order regarding the array indexes) CrsCoordinate.create_coordinate_by_epsg_number( int(array[0]), float(array[2]), float(array[1])), CrsCoordinate.create_coordinate_by_epsg_number( int(array[3]), float(array[5]), float(array[4])), CrsCoordinate.create_coordinate_by_epsg_number( int(array[6]), float(array[8]), float(array[7])) ]
def transform(self, source_coordinate: CrsCoordinate, final_target_crs_projection: CrsProjection ) -> CrsCoordinate: from sweden_crs_transformations.transformation._transformer import _Transformer source_coordinate_projection: CrsProjection = source_coordinate.get_crs_projection() if (not ( (source_coordinate_projection.is_sweref99() or source_coordinate_projection.is_rt90()) and (final_target_crs_projection.is_sweref99() or final_target_crs_projection.is_rt90()) )): _Transformer._throwExceptionMessage(source_coordinate.get_crs_projection(), final_target_crs_projection) intermediate_crs_projection = CrsProjection.WGS84 intermediate_wgs84_coordinate = _Transformer.transform(source_coordinate, intermediate_crs_projection) return _Transformer.transform(intermediate_wgs84_coordinate, final_target_crs_projection)
def test_create_coordinate_by_epsg_number(self): x = 20.0 y = 60.0 crsCoordinate: CrsCoordinate = CrsCoordinate.create_coordinate_by_epsg_number(CrsProjectionTest.epsgNumberForSweref99tm, y, x) self.assertEqual(CrsProjectionTest.epsgNumberForSweref99tm, crsCoordinate.get_crs_projection().get_epsg_number()) self.assertEqual(x, crsCoordinate.get_longitude_x()) self.assertEqual(y, crsCoordinate.get_latitude_y())
def test_create_coordinate(self): x = 22.5 y = 62.5 crsCoordinate: CrsCoordinate = CrsCoordinate.create_coordinate(CrsProjection.SWEREF_99_TM, y, x) self.assertEqual(CrsProjectionTest.epsgNumberForSweref99tm, crsCoordinate.get_crs_projection().get_epsg_number()) self.assertEqual(CrsProjection.SWEREF_99_TM, crsCoordinate.get_crs_projection()) self.assertEqual(x, crsCoordinate.get_longitude_x()) self.assertEqual(y, crsCoordinate.get_latitude_y())
def transform(self, source_coordinate: CrsCoordinate, target_crs_projection: CrsProjection) -> CrsCoordinate: source_coordinate_projection = source_coordinate.get_crs_projection() if (not ((source_coordinate_projection.is_sweref99() or source_coordinate_projection.is_rt90()) and target_crs_projection.is_wgs84())): from sweden_crs_transformations.transformation._transformer import _Transformer _Transformer._throwExceptionMessage( source_coordinate.get_crs_projection(), target_crs_projection) gaussKreugerParameterObject = _GaussKreugerParameterObject( source_coordinate_projection) gaussKreuger = _GaussKreuger(gaussKreugerParameterObject) lat_lon: _LatLon = gaussKreuger.grid_to_geodetic( source_coordinate.get_latitude_y(), source_coordinate.get_longitude_x()) return CrsCoordinate.create_coordinate(target_crs_projection, lat_lon.latitude_y, lat_lon.longitude_x)
def _transform_with_explicit_strategy( _transform_strategy: _TransformStrategy, source_coordinate: CrsCoordinate, target_crs_projection: CrsProjection) -> CrsCoordinate: if (_transform_strategy is None): _Transformer._throwExceptionMessage( source_coordinate.get_crs_projection(), target_crs_projection) else: return _transform_strategy.transform(source_coordinate, target_crs_projection)
def create_coordinate( self, y_latitude: float, x_longitude: float ) -> CrsCoordinate: # requires 'from __future__ import annotations' at the top of the file """ :param y_latitude: the coordinate position value representing the latitude or Y or Northing :param x_longitude: the coordinate position value representing the longitude or X or Easting :return: a coordinate (CrsCoordinate) """ # the below 'from ... import' statement can not be at the top of the file since it causes error with circular import from sweden_crs_transformations.crs_coordinate import CrsCoordinate return CrsCoordinate.create_coordinate(self, y_latitude, x_longitude)
def assertEqualCoordinate(self, crsCoordinate_1: CrsCoordinate, crsCoordinate_2: CrsCoordinate) : # Python 3.6+ # messageToDisplayIfAssertionFails = f"crsCoordinate_1: {crsCoordinate_1} , crsCoordinate_2 : {crsCoordinate_2}" # The below works with older Python versions e.g. 2.7 messageToDisplayIfAssertionFails = "crsCoordinate_1: " + str(crsCoordinate_1) + " , crsCoordinate_2 : " +str(crsCoordinate_2) self.assertEqual(crsCoordinate_1.get_crs_projection(), crsCoordinate_2.get_crs_projection(), messageToDisplayIfAssertionFails) maxDifference = 0.000007 if crsCoordinate_1.get_crs_projection().is_wgs84() else 0.5 # the other (i.e. non-WGS84) value is using meter as unit, so 0.5 is just five decimeters difference self.assertAlmostEqual(crsCoordinate_1.get_longitude_x(), crsCoordinate_2.get_longitude_x(), msg=messageToDisplayIfAssertionFails, delta=maxDifference) self.assertAlmostEqual(crsCoordinate_1.get_latitude_y(), crsCoordinate_2.get_latitude_y(), msg=messageToDisplayIfAssertionFails, delta=maxDifference)
def transform(source_cordinate: CrsCoordinate, target_crs_projection: CrsProjection) -> CrsCoordinate: if (source_cordinate.get_crs_projection() == target_crs_projection): return source_cordinate _transFormStrategy: _TransformStrategy = None # Transform FROM wgs84: if (source_cordinate.get_crs_projection().is_wgs84() and (target_crs_projection.is_sweref99() or target_crs_projection.is_rt90())): _transFormStrategy = _Transformer.transformStrategy_From_WGS84_to_SWEREF99_or_RT90 # Transform TO wgs84: elif (target_crs_projection.is_wgs84() and (source_cordinate.get_crs_projection().is_sweref99() or source_cordinate.get_crs_projection().is_rt90())): _transFormStrategy = _Transformer.transformStrategy_From_SWEREF99_or_RT90_to_WGS84 # Transform between two non-wgs84: elif ((source_cordinate.get_crs_projection().is_sweref99() or source_cordinate.get_crs_projection().is_rt90()) and (target_crs_projection.is_sweref99() or target_crs_projection.is_rt90())): # the only direct transform supported is to/from WGS84, so therefore first transform to wgs84 _transFormStrategy = _Transformer.transFormStrategy_From_Sweref99OrRT90_to_WGS84_andThenToRealTarget return _Transformer._transform_with_explicit_strategy( _transFormStrategy, source_cordinate, target_crs_projection)
def test_equality(self): coordinateInstance_1: CrsCoordinate = CrsCoordinate.create_coordinate(CrsProjection.WGS84, CrsCoordinateTest.stockholmCentralStation_WGS84_longitude, CrsCoordinateTest.stockholmCentralStation_WGS84_latitude) coordinateInstance_2: CrsCoordinate = CrsCoordinate.create_coordinate(CrsProjection.WGS84, CrsCoordinateTest.stockholmCentralStation_WGS84_longitude, CrsCoordinateTest.stockholmCentralStation_WGS84_latitude) self.assertEqual(coordinateInstance_1, coordinateInstance_2) self.assertEqual(hash(coordinateInstance_1), hash(coordinateInstance_2)) self.assertTrue(coordinateInstance_1 == coordinateInstance_2) self.assertTrue(coordinateInstance_2 == coordinateInstance_1) delta = 0.000000000000001 # see comments further below regarding the value of "delta" coordinateInstance_3: CrsCoordinate = CrsCoordinate.create_coordinate( CrsProjection.WGS84, CrsCoordinateTest.stockholmCentralStation_WGS84_longitude + delta, CrsCoordinateTest.stockholmCentralStation_WGS84_latitude + delta ) self.assertEqual(coordinateInstance_1, coordinateInstance_3) self.assertEqual(hash(coordinateInstance_1), hash(coordinateInstance_3)) self.assertTrue(coordinateInstance_1 == coordinateInstance_3) # method "operator ==" self.assertTrue(coordinateInstance_3 == coordinateInstance_1) ''' // Regarding the chosen value for "delta" (which is added to the lon/lat values, to create a slightly different value) above and below, // it is because of experimentation this "breakpoint" value has been determined, i.e. the above value still resulted in equality // but when it was increased as below with one decimal then the above kind of assertions failed and therefore the other assertions below // are used instead e.g. testing the overloaded operator "!=". // You should generally be cautios when comparing floating point values but the above test indicate that values are considered equal even though // the difference is as 'big' as in the "delta" value above. ''' delta = delta * 10 # moving the decimal one bit to get a somewhat larger values, and then the instances are not considered equal, as you can see in the tests below. coordinateInstance_4: CrsCoordinate = CrsCoordinate.create_coordinate( CrsProjection.WGS84, CrsCoordinateTest.stockholmCentralStation_WGS84_longitude + delta, CrsCoordinateTest.stockholmCentralStation_WGS84_latitude + delta ) # Note that below are the Are*NOT*Equal assertions made instead of AreEqual as further above when a smaller delta value was used self.assertNotEqual(coordinateInstance_1, coordinateInstance_4) self.assertNotEqual(hash(coordinateInstance_1), hash(coordinateInstance_4)) self.assertTrue(coordinateInstance_1 != coordinateInstance_4) self.assertTrue(coordinateInstance_4 != coordinateInstance_1) self.assertIsNot(coordinateInstance_4, coordinateInstance_1)
def example(self): # rename this method with test_ prefix as in the above row, if/when you want to execute it stockholmWGS84: CrsCoordinate = CrsCoordinate.create_coordinate( CrsProjection.WGS84, CrsCoordinateTest.stockholmCentralStation_WGS84_latitude, CrsCoordinateTest.stockholmCentralStation_WGS84_longitude ) stockholmSweref99tm: CrsCoordinate = stockholmWGS84.transform(CrsProjection.SWEREF_99_TM) print(f"stockholmSweref99tm X: {stockholmSweref99tm.get_longitude_x()}") # Python 3.6+ print(f"stockholmSweref99tm Y: {stockholmSweref99tm.get_latitude_y()}") print(f"stockholmSweref99tm as string: {str(stockholmSweref99tm)}") ''' Output from the above: stockholmSweref99tm X: 674032.357 stockholmSweref99tm Y: 6580821.991 stockholmSweref99tm as string: CrsCoordinate [ Y: 6580821.991 , X: 674032.357 , CRS: SWEREF_99_TM(EPSG:3006) ] ''' all_projections = CrsProjection.get_all_crs_projections() for crs_projection in all_projections: print(stockholmWGS84.transform(crs_projection)) '''
def test_transform(self): stockholmWGS84: CrsCoordinate = CrsCoordinate.create_coordinate( CrsProjection.WGS84, CrsCoordinateTest.stockholmCentralStation_WGS84_latitude, CrsCoordinateTest.stockholmCentralStation_WGS84_longitude ) stockholmSWEREF99TM: CrsCoordinate = CrsCoordinate.create_coordinate( CrsProjection.SWEREF_99_TM, CrsCoordinateTest.stockholmCentralStation_SWEREF99TM_northing, CrsCoordinateTest.stockholmCentralStation_SWEREF99TM_easting ) stockholmRT90: CrsCoordinate = CrsCoordinate.create_coordinate( CrsProjection.RT90_2_5_GON_V, CrsCoordinateTest.stockholmCentralStation_RT90_northing, CrsCoordinateTest.stockholmCentralStation_RT90_easting ) self.assertIsNotNone(stockholmWGS84) self.assertIsNotNone(stockholmSWEREF99TM) self.assertIsNotNone(stockholmRT90) # Transformations to WGS84 (from SWEREF99TM and RT90): self.assertEqualCoordinate( stockholmWGS84, # expected WGS84 stockholmSWEREF99TM.transform(CrsProjection.WGS84) # actual/transformed WGS84 ) self.assertEqualCoordinate( stockholmWGS84, # expected WGS84 stockholmRT90.transform(CrsProjection.WGS84) # actual/transformed WGS84 ) # below is a similar test as one of the above tests but using the overloaded Transform method # which takes an integer as parameter instead of an instance of the enum CrsProjection epsgNumberForWgs84: int = CrsProjection.WGS84.get_epsg_number() self.assertEqualCoordinate( stockholmWGS84, stockholmRT90.transform_by_epsg_number(epsgNumberForWgs84) # testing the overloaded Transform method with an integer parameter ) # Transformations to SWEREF99TM (from WGS84 and RT90): self.assertEqualCoordinate( stockholmSWEREF99TM, # expected SWEREF99TM stockholmWGS84.transform(CrsProjection.SWEREF_99_TM) # actual/transformed SWEREF99TM ) self.assertEqualCoordinate( stockholmSWEREF99TM, # expected SWEREF99TM stockholmRT90.transform(CrsProjection.SWEREF_99_TM) # actual/transformed SWEREF99TM ) # Transformations to RT90 (from WGS84 and SWEREF99TM): self.assertEqualCoordinate( stockholmRT90, # expected RT90 stockholmWGS84.transform(CrsProjection.RT90_2_5_GON_V) # actual/transformed RT90 ) self.assertEqualCoordinate( stockholmRT90, # expected RT90 stockholmSWEREF99TM.transform(CrsProjection.RT90_2_5_GON_V) # actual/transformed RT90 )