|
1 | 1 | import click |
2 | | -import geopandas as gpd |
| 2 | +from os import path |
| 3 | +import osmnx as ox |
3 | 4 |
|
4 | | -from . import populate, constrain, schema |
| 5 | +from . import crossings, intersections, io |
5 | 6 |
|
6 | 7 |
|
7 | | -@click.command() |
| 8 | +# TODO: See if there's a more proper way to find the project root dir |
| 9 | +# TODO: use a temporary dir? |
| 10 | +ox.utils.config(cache_folder=path.join(path.dirname(__file__), '../cache'), |
| 11 | + use_cache=True) |
| 12 | + |
| 13 | +# Groups: |
| 14 | +# - Download all data from OSM bounding box, produce OSM file |
| 15 | +# - Download all data from OSM bounding box, produce GeoJSON file |
| 16 | +# - Provide own sidewalks data, produce OSM file |
| 17 | +# - Provide own sidewalks data, produce GeoJSON file |
| 18 | + |
| 19 | +# So, the arguments are: |
| 20 | +# - Where is the info coming from? A file or a bounding box in OSM? |
| 21 | +# - What is the output format? |
| 22 | + |
| 23 | +# crossify from_bbox [bbox] output.extension |
| 24 | +# crossify from_file sidewalks.geojson output.extension |
| 25 | + |
| 26 | + |
| 27 | +@click.group() |
| 28 | +def crossify(): |
| 29 | + pass |
| 30 | + |
| 31 | + |
| 32 | +@crossify.command() |
8 | 33 | @click.argument('sidewalks_in') |
9 | | -@click.argument('streets_in') |
10 | 34 | @click.argument('outfile') |
11 | | -def crossify(sidewalks_in, streets_in, outfile): |
12 | | - # FIXME: these should be turned into configuration options |
13 | | - intersections_only = True |
14 | | - osm_schema = True |
| 35 | +def from_file(sidewalks_in, outfile): |
| 36 | + # |
| 37 | + # Read, fetch, and standardize data |
| 38 | + # |
| 39 | + |
| 40 | + # Note: all are converted to WGS84 by default |
| 41 | + sidewalks = io.read_sidewalks(sidewalks_in) |
| 42 | + core(sidewalks, outfile) |
| 43 | + |
| 44 | + |
| 45 | +@crossify.command() |
| 46 | +@click.argument('west') |
| 47 | +@click.argument('south') |
| 48 | +@click.argument('east') |
| 49 | +@click.argument('north') |
| 50 | +@click.argument('outfile') |
| 51 | +@click.option('--debug', is_flag=True) |
| 52 | +def from_bbox(west, south, east, north, outfile, debug): |
| 53 | + # |
| 54 | + # Read, fetch, and standardize data |
| 55 | + # |
| 56 | + |
| 57 | + # Note: all are converted to WGS84 by default |
| 58 | + sidewalks = io.fetch_sidewalks(west, south, east, north) |
| 59 | + core(sidewalks, outfile, debug) |
| 60 | + |
| 61 | + |
| 62 | +def core(sidewalks, outfile, debug=False): |
| 63 | + # |
| 64 | + # Read, fetch, and standardize data |
| 65 | + # |
| 66 | + |
| 67 | + # Note: all are converted to WGS84 by default |
| 68 | + click.echo('Fetching street network from OpenStreetMap...') |
| 69 | + G_streets = io.fetch_street_graph(sidewalks) |
| 70 | + |
| 71 | + # Work in UTM |
| 72 | + click.echo('Generating street graph...') |
| 73 | + G_streets_u = ox.projection.project_graph(G_streets) |
| 74 | + sidewalks_u = ox.projection.project_gdf(sidewalks) |
15 | 75 |
|
16 | | - sidewalks = gpd.read_file(sidewalks_in) |
17 | | - streets = gpd.read_file(streets_in) |
| 76 | + # Get the undirected street graph |
| 77 | + G_undirected_u = ox.save_load.get_undirected(G_streets_u) |
18 | 78 |
|
19 | | - # Ensure we're working in the same CRS as the sidewalks dataset |
20 | | - crs = sidewalks.crs |
21 | | - streets = streets.to_crs(crs) |
| 79 | + # Extract streets from streets graph |
| 80 | + click.echo('Extracting geospatial data from street graph...') |
| 81 | + streets = ox.save_load.graph_to_gdfs(G_undirected_u, nodes=False, |
| 82 | + edges=True) |
| 83 | + streets.crs = sidewalks_u.crs |
22 | 84 |
|
23 | | - # FIXME: this is where we'd create the crossings |
24 | | - dense_crossings = populate.populate(sidewalks, streets) |
| 85 | + # |
| 86 | + # Isolate intersections that need crossings (degree > 3), group with |
| 87 | + # their streets (all pointing out from the intersection) |
| 88 | + # |
| 89 | + click.echo('Isolating street intersections...') |
| 90 | + ixns = intersections.group_intersections(G_streets_u) |
25 | 91 |
|
26 | | - if intersections_only: |
27 | | - crossings = constrain.constrain(dense_crossings) |
28 | | - else: |
29 | | - crossings = dense_crossings |
| 92 | + # |
| 93 | + # Draw crossings using the intersection + street + sidewalk info |
| 94 | + # |
| 95 | + click.echo('Drawing crossings...') |
| 96 | + st_crossings = crossings.make_crossings(ixns, sidewalks_u, debug=debug) |
| 97 | + if debug: |
| 98 | + st_crossings, street_segments = st_crossings |
30 | 99 |
|
31 | | - if osm_schema: |
32 | | - crossings = schema.apply_schema(crossings) |
| 100 | + # |
| 101 | + # Write to file |
| 102 | + # |
| 103 | + click.echo('Writing to file...') |
| 104 | + io.write_crossings(st_crossings, outfile) |
| 105 | + if debug: |
| 106 | + base, ext = path.splitext(outfile) |
| 107 | + debug_outfile = '{}_debug{}'.format(base, ext) |
| 108 | + io.write_debug(street_segments, debug_outfile) |
33 | 109 |
|
34 | | - crossings.to_file(outfile) |
35 | 110 |
|
36 | 111 | if __name__ == '__main__': |
37 | 112 | crossify() |
0 commit comments