Skip to content

Commit

Permalink
clean OpenSkiMap coordinates
Browse files Browse the repository at this point in the history
refs russellporter/openskimap.org#137

and address NaN mean_bearing validation fails
  • Loading branch information
dhimmel committed Oct 15, 2024
1 parent 9e26b44 commit c69a600
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 7 deletions.
8 changes: 7 additions & 1 deletion ski_bearings/bearing.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,15 @@ def get_bearing_summary_stats(

# Calculate the strength/magnitude of the mean bearing
mean_bearing_strength = np.linalg.norm(vector_sum) / np.sum(weights)
if np.isnan(mean_bearing_strength):
# some ski areas have no elevation variation, example 7cc74a14-fdc2-4b15-aaf9-8998433ffd86
mean_bearing_strength = 0.0

# Convert the sum vector back to a bearing
mean_bearing_rad = np.arctan2(vector_sum[1], vector_sum[0])
mean_bearing_deg = np.rad2deg(mean_bearing_rad) % 360

return BearingSummaryStats(mean_bearing_deg, mean_bearing_strength)
return BearingSummaryStats(
mean_bearing_deg=round(mean_bearing_deg, 7),
mean_bearing_strength=round(mean_bearing_strength, 7),
)
29 changes: 23 additions & 6 deletions ski_bearings/osmnx_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ def suppress_user_warning(
yield


def _clean_coordinates(
coordinates: list[tuple[float, float, float]],
) -> list[tuple[float, float, float]]:
"""
Sanitize coordinates to remove floating point errors and ensure downhill runs.
NOTE: longitude comes before latitude in GeoJSON and osmnx, which is different than GPS coordinates.
"""
# Round coordinates to undo floating point errors.
# https://github.com/russellporter/openskimap.org/issues/137
coordinates = [
(round(lon, 7), round(lat, 7), round(ele, 2)) for lon, lat, ele in coordinates
]
if coordinates[0][2] < coordinates[-1][2]:
# Ensure the run is going downhill, such that starting elevation > ending elevation
coordinates.reverse()
return coordinates


def create_networkx(runs: list[Any]) -> nx.MultiDiGraph:
"""
Convert runs to an newtorkx MultiDiGraph compatible with OSMnx.
Expand All @@ -31,14 +49,13 @@ def create_networkx(runs: list[Any]) -> nx.MultiDiGraph:
runs = [run for run in runs if run["geometry"]["type"] == "LineString"]
graph.graph["run_count_filtered"] = len(runs)
for run in runs:
# NOTE: longitude comes before latitude in GeoJSON and osmnx, which is different than GPS coordinates
for lon, lat, elevation in run["geometry"]["coordinates"]:
run["geometry"]["coordinates_clean"] = _clean_coordinates(
run["geometry"]["coordinates"]
)
for lon, lat, elevation in run["geometry"]["coordinates_clean"]:
graph.add_node((lon, lat), x=lon, y=lat, elevation=elevation)
for run in runs:
coordinates = run["geometry"]["coordinates"].copy()
if coordinates[0][2] < coordinates[-1][2]:
# Ensure the run is going downhill, such that starting elevation > ending elevation
coordinates.reverse()
coordinates = run["geometry"]["coordinates_clean"].copy()
lon_0, lat_0, elevation_0 = coordinates.pop(0)
for lon_1, lat_1, elevation_1 in coordinates:
graph.add_edge(
Expand Down

0 comments on commit c69a600

Please sign in to comment.