diff --git a/create_polygon.py b/create_polygon.py index e2c14e4..b88fcf5 100755 --- a/create_polygon.py +++ b/create_polygon.py @@ -1,27 +1,26 @@ #!/bin/python3 +import argparse import osmapi import shapely import pickle -from os.path import exists - - -OSM_KOGGENLAND_ID = 161930 -PICKLE_FILE = 'polygon.pickle' def chunks(lst, n): - """Yield successive n-sized chunks from lst.""" + """Yield successive n-sized chunks from lst. + https://stackoverflow.com/a/312464 + CC BY-SA 4.0 + """ for i in range(0, len(lst), n): yield lst[i:i + n] -def dump_polygon(): - osm_api = osmapi.OsmApi() - koggenland = osm_api.RelationGet(OSM_KOGGENLAND_ID) - ways = filter(lambda x: x['type'] == 'way', koggenland['member']) - shell_ids = [] - +def get_shell_ids(osm_api, ways): + """ + Get a list of OSM node IDs + that forms the shell of the area's polygon. + """ + shell_ids = list() for way in ways: way = osm_api.WayGet(way['ref']) node_ids = way['nd'] @@ -30,35 +29,52 @@ def dump_polygon(): for node_id in node_ids[1:]: shell_ids.append(node_id) + return shell_ids + + +def get_node_data(osm_api, shell_ids): + """Get the data of OSM nodes as a dict of (id -> data).""" node_data = dict() for chunk in chunks(shell_ids, 100): node_data |= osm_api.NodesGet(chunk) + return node_data + + +def get_shell(shell_ids, node_data): + """Get the shell of the area's polygon as a list of (lat, lon) tuples.""" shell = list() for shell_id in shell_ids: node = node_data[shell_id] shell.append((node['lat'], node['lon'])) - koggenland_polygon = shapely.Polygon(shell) - with open(PICKLE_FILE, 'wb') as f: - pickle.dump(koggenland_polygon, f) + return shell -def main(): - if not exists(PICKLE_FILE): - print('Using OSM API to create polygon...') - dump_polygon() - print('Dumped polygon to file.') - with open(PICKLE_FILE, 'rb') as f: - area = pickle.load(f) - print('Loaded polygon from file.') +def main(args): + osm_api = osmapi.OsmApi() + rel = osm_api.RelationGet(args.osm_relation_id) + # Filter out city centre etc. + ways = filter(lambda x: x['type'] == 'way', rel['member']) + shell_ids = get_shell_ids(osm_api, ways) + node_data = get_node_data(osm_api, shell_ids) + shell = get_shell(shell_ids, node_data) + polygon = shapely.Polygon(shell) - point_out = shapely.Point(52.68811, 4.91267) - point_in = shapely.Point(52.69168, 4.91324) - - print('out', area.contains(point_out)) - print('in', area.contains(point_in)) + with open(args.output_file, 'wb') as f: + pickle.dump(polygon, f) if __name__ == '__main__': - main() + parser = argparse.ArgumentParser(description=""" + Creates a polygon from an OpenStreetMap relation and saves this + to a file as a Python pickle. + """) + parser.add_argument("osm-relation-id", + help="OpenStreetMap relation ID", type=int) + parser.add_argument( + "-v", "--output-file", help="Output file for the resulting polygon", + default="polygon.pickle") + args = parser.parse_args() + + main(args) diff --git a/gc_area.py b/gc_area.py new file mode 100755 index 0000000..a980ee5 --- /dev/null +++ b/gc_area.py @@ -0,0 +1,36 @@ +#!/bin/python3 + +import argparse +import gpxpy +import gpxpy.gpx +import shapely +import pickle + + +def main(args): + with open(args.polygon_file, 'rb') as f: + area = pickle.load(f) + + with open(args.input_file, 'rb') as f: + gpx = gpxpy.parse(f) + + gpx.waypoints = list(filter(lambda wp: area.contains( + shapely.Point(wp.latitude, wp.longitude)), gpx.waypoints)) + + with open(args.output_file, 'w') as f: + f.write(gpx.to_xml()) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=""" + Takes an input GPX file containing + geocaches and filters out any waypoints outside a given area. + """) + parser.add_argument("input-file", help="Input GPX file") + parser.add_argument("output-file", help="Output GPX file") + parser.add_argument( + "-p", "--polygon-file", help="File containing area's polygon", + default="polygon.pickle") + args = parser.parse_args() + + main(args) diff --git a/parse_gpx.py b/parse_gpx.py deleted file mode 100755 index e4e6b93..0000000 --- a/parse_gpx.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/python3 - -import gpxpy -import gpxpy.gpx -import shapely -import pickle - -GPX_IN_FILE = 'caches.gpx' -GPX_OUT_FILE = 'koggenland.gpx' -PICKLE_FILE = 'polygon.pickle' - - -def main(): - with open(PICKLE_FILE, 'rb') as f: - area = pickle.load(f) - - with open(GPX_IN_FILE, 'rb') as f: - gpx = gpxpy.parse(f) - - gpx.waypoints = list(filter(lambda wp: area.contains( - shapely.Point(wp.latitude, wp.longitude)), gpx.waypoints)) - - with open(GPX_OUT_FILE, 'w') as f: - f.write(gpx.to_xml()) - - -if __name__ == '__main__': - main()