Skip to content

Commit 09a5773

Browse files
authored
Created function to convert an XY polygon to a LatLon polygon (#505)
* implemented function * tests pass
1 parent 9ce7897 commit 09a5773

File tree

2 files changed

+59
-17
lines changed

2 files changed

+59
-17
lines changed

src/local_pathfinding/local_pathfinding/coord_systems.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,27 @@ def xy_to_latlon(reference: HelperLatLon, xy: XY) -> HelperLatLon:
8383
return HelperLatLon(latitude=dest_lat, longitude=dest_lon)
8484

8585

86+
def xy_polygon_to_latlon_polygon(reference: HelperLatLon, poly: Polygon):
87+
"""
88+
Transforms a polygon in XY coordinates to a rectangular polygon in lat lon coordinates.
89+
"""
90+
if poly.is_empty:
91+
return poly
92+
93+
def _xy_point_to_latlon_point(xy_point: XY) -> Point:
94+
latlon = xy_to_latlon(reference=reference, xy=xy_point)
95+
return Point(latlon.longitude, latlon.latitude)
96+
97+
return Polygon(
98+
list(
99+
map(
100+
_xy_point_to_latlon_point,
101+
[XY(x=point[0], y=point[1]) for point in poly.exterior.coords],
102+
)
103+
)
104+
)
105+
106+
86107
def latlon_polygon_list_to_xy_polygon_list(
87108
polygons: List[Polygon], reference: HelperLatLon
88109
) -> List[Polygon]:

src/local_pathfinding/test/test_coord_systems.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33

44
import pytest
55
from custom_interfaces.msg import HelperLatLon
6-
from shapely.geometry import MultiPolygon, Polygon, box
6+
from shapely.geometry import MultiPolygon, Point, Polygon, box
77

8-
import local_pathfinding.coord_systems as coord_systems
8+
import local_pathfinding.coord_systems as cs
99

1010

1111
@pytest.mark.parametrize(
@@ -18,7 +18,7 @@
1818
],
1919
)
2020
def test_cartesian_to_true_bearing(cartesian: float, true_bearing: float):
21-
assert coord_systems.cartesian_to_true_bearing(cartesian) == pytest.approx(
21+
assert cs.cartesian_to_true_bearing(cartesian) == pytest.approx(
2222
true_bearing
2323
), "incorrect angle conversion"
2424

@@ -28,15 +28,15 @@ def test_cartesian_to_true_bearing(cartesian: float, true_bearing: float):
2828
[(0.0, 0.0), (30, 0.03), (500, 0.5), (-30.5, -0.0305), (-0.0, 0.0)],
2929
)
3030
def test_meters_to_km(meters: float, km: float):
31-
assert coord_systems.meters_to_km(meters) == pytest.approx(km), "incorrect distance conversion"
31+
assert cs.meters_to_km(meters) == pytest.approx(km), "incorrect distance conversion"
3232

3333

3434
@pytest.mark.parametrize(
3535
"km,meters",
3636
[(0.0, 0.0), (0.03, 30), (0.5, 500), (-0.0305, -30.5), (-0.0, 0.0)],
3737
)
3838
def test_km_to_meters(km: float, meters: float):
39-
assert coord_systems.km_to_meters(km) == pytest.approx(meters), "incorrect distance conversion"
39+
assert cs.km_to_meters(km) == pytest.approx(meters), "incorrect distance conversion"
4040

4141

4242
@pytest.mark.parametrize(
@@ -53,19 +53,19 @@ def test_km_to_meters(km: float, meters: float):
5353
def test_latlon_to_xy(ref_lat: float, ref_lon: float, true_bearing_deg: float, dist_km: float):
5454
# create inputs
5555
reference = HelperLatLon(latitude=ref_lat, longitude=ref_lon)
56-
lon, lat, _ = coord_systems.GEODESIC.fwd(
56+
lon, lat, _ = cs.GEODESIC.fwd(
5757
lons=ref_lon, lats=ref_lat, az=true_bearing_deg, dist=dist_km * 1000
5858
)
5959
latlon = HelperLatLon(latitude=lat, longitude=lon)
6060

6161
# create expected output
6262
true_bearing = math.radians(true_bearing_deg)
63-
xy = coord_systems.XY(
63+
xy = cs.XY(
6464
x=dist_km * math.sin(true_bearing),
6565
y=dist_km * math.cos(true_bearing),
6666
)
6767

68-
assert coord_systems.latlon_to_xy(reference, latlon) == pytest.approx(
68+
assert cs.latlon_to_xy(reference, latlon) == pytest.approx(
6969
xy
7070
), "incorrect coordinate conversion"
7171

@@ -85,26 +85,49 @@ def test_latlon_to_xy(ref_lat: float, ref_lon: float, true_bearing_deg: float, d
8585
def test_xy_to_latlon(ref_lat: float, ref_lon: float, true_bearing_deg: float, dist_km: float):
8686
# create inputs
8787
true_bearing = math.radians(true_bearing_deg)
88-
xy = coord_systems.XY(
88+
xy = cs.XY(
8989
x=dist_km * math.sin(true_bearing),
9090
y=dist_km * math.cos(true_bearing),
9191
)
9292

9393
# create expected output
9494
reference = HelperLatLon(latitude=ref_lat, longitude=ref_lon)
95-
lon, lat, _ = coord_systems.GEODESIC.fwd(
95+
lon, lat, _ = cs.GEODESIC.fwd(
9696
lons=ref_lon, lats=ref_lat, az=true_bearing_deg, dist=dist_km * 1000
9797
)
9898
latlon = HelperLatLon(latitude=lat, longitude=lon)
9999

100-
converted_latlon = coord_systems.xy_to_latlon(reference, xy)
100+
converted_latlon = cs.xy_to_latlon(reference, xy)
101101
assert (converted_latlon.latitude, converted_latlon.longitude) == pytest.approx(
102102
(latlon.latitude, latlon.longitude)
103103
), "incorrect coordinate conversion"
104104

105105

106+
@pytest.mark.parametrize(
107+
"reference_latlon, polygon",
108+
[
109+
(
110+
HelperLatLon(latitude=50.0, longitude=100.0),
111+
Polygon([Point([0, 0]), Point([0, 1]), Point([1, 1]), Point([1, 0])]),
112+
)
113+
],
114+
)
115+
def test_xy_polygon_to_latlon_polygon(reference_latlon: HelperLatLon, polygon: Polygon):
116+
117+
latlon_polygon = cs.xy_polygon_to_latlon_polygon(reference=reference_latlon, poly=polygon)
118+
119+
for i, point in enumerate(latlon_polygon.exterior.coords):
120+
assert (
121+
cs.latlon_to_xy(
122+
reference_latlon, cs.HelperLatLon(longitude=point[0], latitude=point[1])
123+
)
124+
) == pytest.approx(
125+
polygon.exterior.coords[i]
126+
), "Incorrect conversion from xy polygon to latlon polygon"
127+
128+
106129
# Test latlon_polygon_list_to_xy_polygon_list
107-
# just asserts that every point in every xy_polygon agrees with latlon_to_xy() from coord_systems
130+
# just asserts that every point in every xy_polygon agrees with latlon_to_xy() from cs
108131
@pytest.mark.parametrize(
109132
"latlon_polygons, reference_point",
110133
[
@@ -205,9 +228,7 @@ def test_latlon_polygons_to_xy_polygons(
205228
latlon_polygons: List[Polygon], reference_point: HelperLatLon
206229
):
207230

208-
xy_polygons = coord_systems.latlon_polygon_list_to_xy_polygon_list(
209-
latlon_polygons, reference_point
210-
)
231+
xy_polygons = cs.latlon_polygon_list_to_xy_polygon_list(latlon_polygons, reference_point)
211232
assert isinstance(xy_polygons, list)
212233
assert len(xy_polygons) == len(latlon_polygons)
213234

@@ -221,7 +242,7 @@ def test_latlon_polygons_to_xy_polygons(
221242
latlon_point = latlon_poly.exterior.coords[j]
222243
assert isinstance(xy_point, tuple)
223244
assert xy_point == pytest.approx(
224-
coord_systems.latlon_to_xy(
245+
cs.latlon_to_xy(
225246
reference_point,
226247
HelperLatLon(longitude=latlon_point[0], latitude=latlon_point[1]),
227248
)
@@ -238,7 +259,7 @@ def test_latlon_polygons_to_xy_polygons_empty_Polygon():
238259
assert isinstance(empty_poly, Polygon)
239260
assert empty_poly.is_empty
240261

241-
result = coord_systems.latlon_polygon_list_to_xy_polygon_list([empty_poly], reference_point)
262+
result = cs.latlon_polygon_list_to_xy_polygon_list([empty_poly], reference_point)
242263
assert isinstance(result, List)
243264
assert len(result) == 1
244265
assert result[0].is_empty

0 commit comments

Comments
 (0)