1212from uxarray .grid .coordinates import _populate_node_latlon , _lonlat_rad_to_xyz , _normalize_xyz , _xyz_to_lonlat_rad
1313from uxarray .grid .arcs import extreme_gca_latitude
1414from uxarray .grid .utils import _get_cartesian_face_edge_nodes , _get_lonlat_rad_face_edge_nodes
15- from uxarray .grid .geometry import _populate_face_latlon_bound , _populate_bounds
15+ from uxarray .grid .geometry import _populate_face_latlon_bound , _populate_bounds , stereographic_projection , \
16+ inverse_stereographic_projection
1617
1718from spatialpandas .geometry import MultiPolygon
1819
2728grid_files = [gridfile_CSne8 , gridfile_geoflow ]
2829data_files = [datafile_CSne30 , datafile_geoflow ]
2930
30- grid_quad_hex = current_path / "meshfiles" / "ugrid" / "quad-hexagon" / "grid.nc"
31- grid_geoflow = current_path / "meshfiles" / "ugrid" / "geoflow-small" / "grid.nc"
32- grid_mpas = current_path / "meshfiles" / "mpas" / "QU" / "oQU480.231010.nc"
33-
31+ grid_quad_hex = current_path / "meshfiles" / "ugrid" / "quad-hexagon" / "grid.nc"
32+ grid_geoflow = current_path / "meshfiles" / "ugrid" / "geoflow-small" / "grid.nc"
33+ grid_mpas = current_path / "meshfiles" / "mpas" / "QU" / "oQU480.231010.nc"
3434
3535# List of grid files to test
3636grid_files_latlonBound = [grid_quad_hex , grid_geoflow , gridfile_CSne8 , grid_mpas ]
3737
38+
3839class TestAntimeridian (TestCase ):
3940
4041 def test_crossing (self ):
@@ -63,8 +64,6 @@ def test_linecollection_execution(self):
6364 lines = uxgrid .to_linecollection ()
6465
6566
66-
67-
6867class TestPredicate (TestCase ):
6968
7069 def test_pole_point_inside_polygon_from_vertice_north (self ):
@@ -377,7 +376,7 @@ def test_extreme_gca_latitude_max(self):
377376
378377 def test_extreme_gca_latitude_max_short (self ):
379378 # Define a great circle arc in 3D space that has a small span
380- gca_cart = np .array ( [[ 0.65465367 , - 0.37796447 , - 0.65465367 ], [ 0.6652466 , - 0.33896007 , - 0.6652466 ]])
379+ gca_cart = np .array ([[ 0.65465367 , - 0.37796447 , - 0.65465367 ], [0.6652466 , - 0.33896007 , - 0.6652466 ]])
381380
382381 # Calculate the maximum latitude
383382 max_latitude = ux .grid .arcs .extreme_gca_latitude (gca_cart , 'max' )
@@ -463,7 +462,7 @@ def test_insert_pt_in_empty_state(self):
463462class TestLatlonBoundsGCA (TestCase ):
464463
465464 def _get_cartesian_face_edge_nodes_testcase_helper (
466- self ,face_nodes_ind , face_edges_ind , edge_nodes_grid , node_x , node_y , node_z
465+ self , face_nodes_ind , face_edges_ind , edge_nodes_grid , node_x , node_y , node_z
467466 ):
468467 """This function is only used to help generating the testcase and
469468 should not be used in the actual implementation. Construct an array to
@@ -522,7 +521,7 @@ def _get_cartesian_face_edge_nodes_testcase_helper(
522521 return cartesian_coordinates
523522
524523 def _get_lonlat_rad_face_edge_nodes_testcase_helper (
525- self ,face_nodes_ind , face_edges_ind , edge_nodes_grid , node_lon , node_lat
524+ self , face_nodes_ind , face_edges_ind , edge_nodes_grid , node_lon , node_lat
526525 ):
527526 """This function is only used to help generating the testcase and
528527 should not be used in the actual implementation. Construct an array to
@@ -691,7 +690,7 @@ def test_populate_bounds_near_pole(self):
691690 [[_xyz_to_lonlat_rad (* edge [0 ]), _xyz_to_lonlat_rad (* edge [1 ])] for edge in face_edges_cart ])
692691
693692 bounds = _populate_face_latlon_bound (face_edges_cart , face_edges_lonlat )
694- expected_bounds = np .array ([[- 1.20427718 , - 1.14935491 ], [0 ,0.13568803 ]])
693+ expected_bounds = np .array ([[- 1.20427718 , - 1.14935491 ], [0 , 0.13568803 ]])
695694 nt .assert_allclose (bounds , expected_bounds , atol = ERROR_TOLERANCE )
696695
697696 def test_populate_bounds_near_pole2 (self ):
@@ -703,13 +702,12 @@ def test_populate_bounds_near_pole2(self):
703702 [[4.06271283e-01 , - 4.78221112e-02 , - 9.12500241e-01 ], [3.57939780e-01 , - 4.88684203e-02 , - 9.32465008e-01 ]]
704703 ])
705704
706-
707705 # Apply the inverse transformation to get the lat lon coordinates
708706 face_edges_lonlat = np .array (
709707 [[_xyz_to_lonlat_rad (* edge [0 ]), _xyz_to_lonlat_rad (* edge [1 ])] for edge in face_edges_cart ])
710708
711709 bounds = _populate_face_latlon_bound (face_edges_cart , face_edges_lonlat )
712- expected_bounds = np .array ([[- 1.20427718 , - 1.14935491 ], [6.147497 ,4.960524e-16 ]])
710+ expected_bounds = np .array ([[- 1.20427718 , - 1.14935491 ], [6.147497 , 4.960524e-16 ]])
713711 nt .assert_allclose (bounds , expected_bounds , atol = ERROR_TOLERANCE )
714712
715713 def test_populate_bounds_long_face (self ):
@@ -735,10 +733,7 @@ def test_populate_bounds_long_face(self):
735733 bounds = _populate_face_latlon_bound (face_edges_cart , face_edges_lonlat )
736734
737735 # The expected bounds should not contains the south pole [0,-0.5*np.pi]
738- self .assertTrue (bounds [1 ][0 ] != 0.0 )
739-
740-
741-
736+ self .assertTrue (bounds [1 ][0 ] != 0.0 )
742737
743738 def test_populate_bounds_node_on_pole (self ):
744739 # Generate a normal face that is crossing the antimeridian
@@ -828,7 +823,7 @@ def test_populate_bounds_pole_inside(self):
828823class TestLatlonBoundsLatLonFace (TestCase ):
829824
830825 def _get_cartesian_face_edge_nodes_testcase_helper (
831- self ,face_nodes_ind , face_edges_ind , edge_nodes_grid , node_x , node_y , node_z
826+ self , face_nodes_ind , face_edges_ind , edge_nodes_grid , node_x , node_y , node_z
832827 ):
833828 """This function is only used to help generating the testcase and
834829 should not be used in the actual implementation. Construct an array to
@@ -887,7 +882,7 @@ def _get_cartesian_face_edge_nodes_testcase_helper(
887882 return cartesian_coordinates
888883
889884 def _get_lonlat_rad_face_edge_nodes_testcase_helper (
890- self ,face_nodes_ind , face_edges_ind , edge_nodes_grid , node_lon , node_lat
885+ self , face_nodes_ind , face_edges_ind , edge_nodes_grid , node_lon , node_lat
891886 ):
892887 """This function is only used to help generating the testcase and
893888 should not be used in the actual implementation. Construct an array to
@@ -1088,7 +1083,7 @@ def test_populate_bounds_pole_inside(self):
10881083
10891084class TestLatlonBoundsGCAList (TestCase ):
10901085 def _get_cartesian_face_edge_nodes_testcase_helper (
1091- self ,face_nodes_ind , face_edges_ind , edge_nodes_grid , node_x , node_y , node_z
1086+ self , face_nodes_ind , face_edges_ind , edge_nodes_grid , node_x , node_y , node_z
10921087 ):
10931088 """This function is only used to help generating the testcase and
10941089 should not be used in the actual implementation. Construct an array to
@@ -1147,7 +1142,7 @@ def _get_cartesian_face_edge_nodes_testcase_helper(
11471142 return cartesian_coordinates
11481143
11491144 def _get_lonlat_rad_face_edge_nodes_testcase_helper (
1150- self ,face_nodes_ind , face_edges_ind , edge_nodes_grid , node_lon , node_lat
1145+ self , face_nodes_ind , face_edges_ind , edge_nodes_grid , node_lon , node_lat
11511146 ):
11521147 """This function is only used to help generating the testcase and
11531148 should not be used in the actual implementation. Construct an array to
@@ -1235,8 +1230,6 @@ def test_populate_bounds_normal(self):
12351230 is_GCA_list = [True , False , True , False ])
12361231 nt .assert_allclose (bounds , expected_bounds , atol = ERROR_TOLERANCE )
12371232
1238-
1239-
12401233 def test_populate_bounds_antimeridian (self ):
12411234 # Generate a normal face that is crossing the antimeridian
12421235 vertices_lonlat = [[350 , 60.0 ], [350 , 10.0 ], [50.0 , 10.0 ], [50.0 , 60.0 ]]
@@ -1436,7 +1429,6 @@ def test_face_bounds(self):
14361429
14371430class TestGeoDataFrame (TestCase ):
14381431
1439-
14401432 def test_engine (self ):
14411433 uxgrid = ux .open_grid (gridfile_geoflow )
14421434 for engine in ['geopandas' , 'spatialpandas' ]:
@@ -1483,3 +1475,20 @@ def test_cache_and_override(self):
14831475 gdf_f = uxgrid .to_geodataframe (exclude_antimeridian = True )
14841476
14851477 assert gdf_f is not gdf_e
1478+
1479+
1480+ class TestStereographicProjection (TestCase ):
1481+ def test_stereographic_projection (self ):
1482+ lon = np .array (0 )
1483+ lat = np .array (0 )
1484+
1485+ central_lon = np .array (0 )
1486+ central_lat = np .array (0 )
1487+
1488+ x , y = stereographic_projection (lon , lat , central_lon , central_lat )
1489+
1490+ new_lon , new_lat = inverse_stereographic_projection (x , y , central_lon , central_lat )
1491+
1492+ self .assertTrue (lon == new_lon )
1493+ self .assertTrue (lat == new_lat )
1494+ self .assertTrue (x == y == 0 )
0 commit comments