diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index ff13a2c..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -recursive-include mappymatch/resources * \ No newline at end of file diff --git a/README.md b/README.md index 8775c5c..e4cc696 100644 --- a/README.md +++ b/README.md @@ -60,4 +60,4 @@ df = matches.matches_to_dataframe() ## Example Notebooks -Check out the [LCSS Example](https://nrel.github.io/mappymatch/lcss-example.html) for an example of working with the package. +Check out the [LCSS Example](https://nrel.github.io/mappymatch/lcss-example.html) for a more detailed example of working with the LCSSMatcher. diff --git a/mappymatch/utils/process_trace.py b/mappymatch/utils/process_trace.py index f24fcc0..b1a57e0 100644 --- a/mappymatch/utils/process_trace.py +++ b/mappymatch/utils/process_trace.py @@ -14,6 +14,9 @@ def split_large_trace(trace: Trace, ideal_size: int) -> list[Trace]: Returns: A list of split traces. """ + if ideal_size == 0: + raise ValueError("ideal_size must be greater than 0") + if len(trace) <= ideal_size: return [trace] else: @@ -42,7 +45,6 @@ def remove_bad_start_from_trace(trace: Trace, distance_threshold: float) -> Trac """ def _trim_frame(frame): - """Pivate no docstring required.""" for index in range(len(frame)): rows = frame.iloc[index : index + 2] diff --git a/tests/test_assets/test_trace.geojson b/tests/test_assets/test_trace.geojson index 72efd70..1129751 100644 --- a/tests/test_assets/test_trace.geojson +++ b/tests/test_assets/test_trace.geojson @@ -1,6 +1,6 @@ { "type": "FeatureCollection", -"name": "trace_bad_start", +"name": "test_trace", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, "features": [ { "type": "Feature", "properties": { "id": 1 }, "geometry": { "type": "Point", "coordinates": [ -104.986097142015026, 39.747533038401798 ] } }, diff --git a/tests/test_geo.py b/tests/test_geo.py new file mode 100644 index 0000000..a329e6f --- /dev/null +++ b/tests/test_geo.py @@ -0,0 +1,46 @@ +from unittest import TestCase + +from mappymatch.constructs.coordinate import Coordinate +from mappymatch.utils.geo import coord_to_coord_dist, latlon_to_xy, xy_to_latlon + + +class TestGeoUtils(TestCase): + def setUp(self): + self.lat, self.lon = 40.7128, -74.0060 + self.x, self.y = -8238310.23, 4970071.58 + + # We'll use simple x, y coordinates for testing + self.coordinate_a = Coordinate.from_lat_lon(1, 1) + self.coordinate_b = Coordinate.from_lat_lon(2, 2) + + def test_xy_to_latlon(self): + lat, lon = xy_to_latlon(self.x, self.y) + self.assertIsInstance(lat, float) + self.assertIsInstance(lon, float) + + self.assertAlmostEqual(lat, self.lat, delta=0.01) + self.assertAlmostEqual(lon, self.lon, delta=0.01) + + def test_latlon_to_xy(self): + x, y = latlon_to_xy(self.lat, self.lon) + self.assertIsInstance(x, float) + self.assertIsInstance(y, float) + + self.assertAlmostEqual(x, self.x, delta=0.01) + self.assertAlmostEqual(y, self.y, delta=0.01) + + def test_xy_to_latlon_and_back(self): + # Test round-trip conversion + lat, lon = xy_to_latlon(self.x, self.y) + x_new, y_new = latlon_to_xy(lat, lon) + + # Ensure the round-trip results are consistent + self.assertAlmostEqual(self.x, x_new, delta=0.01) + self.assertAlmostEqual(self.y, y_new, delta=0.01) + + def test_coord_to_coord_dist(self): + dist = coord_to_coord_dist(self.coordinate_a, self.coordinate_b) + self.assertIsInstance(dist, float) + + self.assertGreater(dist, 0) + self.assertAlmostEqual(dist, 1.41, delta=0.01) diff --git a/tests/test_process_trace.py b/tests/test_process_trace.py index 400f504..667ec27 100644 --- a/tests/test_process_trace.py +++ b/tests/test_process_trace.py @@ -1,23 +1,57 @@ from unittest import TestCase from mappymatch.constructs.trace import Trace -from mappymatch.utils.process_trace import remove_bad_start_from_trace +from mappymatch.utils.process_trace import ( + remove_bad_start_from_trace, + split_large_trace, +) from tests import get_test_dir class TestProcessTrace(TestCase): + def setUp(self) -> None: + bad_trace_file = get_test_dir() / "test_assets" / "trace_bad_start.geojson" + + self.trace_bad_start = Trace.from_geojson(bad_trace_file, xy=True) + + trace_file = get_test_dir() / "test_assets" / "test_trace.geojson" + + # This trace has 16 points + self.trace = Trace.from_geojson(trace_file, xy=True) + def test_remove_bad_start_from_trace(self): """ a test to ensure that the gap in the beginning of the trace is removed """ - tfile = get_test_dir() / "test_assets" / "trace_bad_start.geojson" - - trace = Trace.from_geojson(tfile, xy=True) - bad_point = trace.coords[0] + bad_point = self.trace_bad_start.coords[0] - trace = remove_bad_start_from_trace(trace, 30) + new_trace = remove_bad_start_from_trace(self.trace_bad_start, 30) self.assertTrue( - bad_point not in trace.coords, + bad_point not in new_trace.coords, f"trace should have the first point {bad_point} removed", ) + + def test_trace_smaller_than_ideal_size(self): + result = split_large_trace(self.trace, 20) + self.assertEqual(len(result), 1) + self.assertEqual(result[0], self.trace) + + def test_trace_equal_to_ideal_size(self): + result = split_large_trace(self.trace, 16) + self.assertEqual(len(result), 1) + self.assertEqual(result[0], self.trace) + + def test_ideal_size_zero(self): + with self.assertRaises(ValueError): + split_large_trace(self.trace, 0) + + def test_ideal_size(self): + result = split_large_trace(self.trace, 10) + self.assertEqual(len(result), 1) + self.assertEqual(len(result[0]), 16) + + def test_trace_larger_with_merging(self): + result = split_large_trace(self.trace, 12) # Splitting into chunks of 12 + self.assertEqual(len(result), 1) # Expect merging to create a single chunk + self.assertEqual(len(result[0]), 16) # All points are in one merged trace