Skip to content

Commit

Permalink
Coordinate sanity check (#716)
Browse files Browse the repository at this point in the history
Added a check if coordinates are within a certain distance to the parent

---------

Co-authored-by: Frank Elsinga <[email protected]>
  • Loading branch information
quarz12 and CommanderStorm authored Jul 11, 2023
1 parent a90d186 commit 0949696
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 14 deletions.
27 changes: 27 additions & 0 deletions data/processors/coords.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import logging

import utm
from utils import distance_via_great_circle

MAX_DISTANCE_METERS_FROM_PARENT = 200


def assert_buildings_have_coords(data):
Expand Down Expand Up @@ -119,8 +122,32 @@ def check_coords(input_data):
)


def validate_coords(input_data):
"""Check that coordinates are not too far away from their parent"""
for iid, data in input_data.items():
if data["type"] != "room":
continue
coords = data["coords"]
parent_id = data["parents"][-1]
parent_coords = input_data[parent_id]["coords"]

distance_to_parent = distance_via_great_circle(
coords["lat"],
coords["lon"],
parent_coords["lat"],
parent_coords["lon"],
)

if distance_to_parent > MAX_DISTANCE_METERS_FROM_PARENT:
logging.warning(
f"{iid} {coords} is {distance_to_parent}m away from its parent {parent_id} {parent_coords}. "
"Please recheck if the coordinate makes sense",
)


def add_and_check_coords(data):
"""Add coordinates to all entries and check for issues"""
assert_buildings_have_coords(data)
assign_coordinates(data)
check_coords(data)
validate_coords(data)
16 changes: 2 additions & 14 deletions data/processors/public_transport.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
import json
from dataclasses import asdict
from math import acos, cos, radians, sin

from external.models.public_transport import Station
from utils import distance_via_great_circle

MAXDISTANCE = 1000
METERS_PER_LATITUDE_DEGREE = 111210
MAXDEGDIFF_PER_LATITUDE_DEGREE = MAXDISTANCE / METERS_PER_LATITUDE_DEGREE
EARTH_RADIUS_METERS = 6_371_000


def _distance_via_great_circle(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
"""
Calculate the approximate distance in meters betweeen two points using the great circle approach
Basic idea from https://blog.petehouston.com/calculate-distance-of-two-locations-on-earth/
"""
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
# angular distance using the https://wikipedia.org/wiki/Haversine_formula
angular_distance = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon1 - lon2))
return EARTH_RADIUS_METERS * angular_distance


def _filter_by_latitude(lat: float, stations: list[Station]) -> list[Station]:
Expand All @@ -35,7 +23,7 @@ def nearby_stations(lat: float, lon: float, stations: list[Station]) -> list[dic
"""returns a list of tuples in form: [distance in meter, station]"""
results = []
for station in _filter_by_latitude(lat, stations):
if (distance := _distance_via_great_circle(station.lat, station.lon, lat, lon)) <= MAXDISTANCE:
if (distance := distance_via_great_circle(station.lat, station.lon, lat, lon)) <= MAXDISTANCE:
station_dict = {"distance": distance} | asdict(station)
results.append(station_dict)
return sorted(results, key=lambda x: x["distance"])
Expand Down
1 change: 1 addition & 0 deletions data/sources/01_areas-extended.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ zentralgelaende:
"05": { use_as: "04" }
"0510": # Verwaltungsbau (Z10)
osm: ["relation/6758375"] # smaller part: "way/31095179"
coords: { lat: 48.14884, lon: 11.56790 }
"0511": # Elektro/Werkstatt/Lösungsmittel (Z11)
osm: ["way/42918170"]
#"0512": # Garagen (Z12)
Expand Down
17 changes: 17 additions & 0 deletions data/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import os
from math import acos, cos, radians, sin
from pathlib import Path

from PIL import Image
Expand Down Expand Up @@ -102,3 +103,19 @@ def setup_logging(level):
logging.addLevelName(logging.WARNING, f"\033[1;33m{logging.getLevelName(logging.WARNING)}\033[1;0m")
logging.addLevelName(logging.ERROR, f"\033[1;41m{logging.getLevelName(logging.ERROR)}\033[1;0m")
logging.addLevelName(logging.CRITICAL, f"\033[1;41m{logging.getLevelName(logging.CRITICAL)}\033[1;0m")


EARTH_RADIUS_METERS = 6_371_000


def distance_via_great_circle(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
"""
Calculate the approximate distance in meters betweeen two points using the great circle approach
Basic idea from https://blog.petehouston.com/calculate-distance-of-two-locations-on-earth/
"""
if lat1 == lat2 and lon1 == lon2:
return 0.0
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
# angular distance using the https://wikipedia.org/wiki/Haversine_formula
angular_distance = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon1 - lon2))
return EARTH_RADIUS_METERS * angular_distance

0 comments on commit 0949696

Please sign in to comment.