diff --git a/crossify/__main__.py b/crossify/__main__.py index a972bcf..309d9bf 100644 --- a/crossify/__main__.py +++ b/crossify/__main__.py @@ -49,19 +49,21 @@ def from_file(sidewalks_in, outfile): @click.argument('east') @click.argument('north') @click.argument('outfile') +@click.argument('dist_param') +@click.argument('angle_param') @click.option('--debug', is_flag=True) @click.option('--opensidewalks', is_flag=True) -def from_bbox(west, south, east, north, outfile, debug, opensidewalks): +def from_bbox(west, south, east, north, outfile, dist_param, angle_param, debug, opensidewalks): # # Read, fetch, and standardize data # # Note: all are converted to WGS84 by default sidewalks = io.fetch_sidewalks(west, south, east, north) - core(sidewalks, outfile, debug=debug, opensidewalks=opensidewalks) + core(sidewalks, outfile, dist_param=dist_param, angle_param=angle_param, debug=debug, opensidewalks=opensidewalks) -def core(sidewalks, outfile, debug=False, opensidewalks=False): +def core(sidewalks, outfile, dist_param, angle_param, debug=False, opensidewalks=False): # # Read, fetch, and standardize data # @@ -108,7 +110,7 @@ def core(sidewalks, outfile, debug=False, opensidewalks=False): # click.echo('Drawing crossings...', nl=False) - st_crossings = crossings.make_crossings(ixns, sidewalks_u, debug=debug) + st_crossings = crossings.make_crossings(ixns, sidewalks_u, dist_param, angle_param, debug=debug) if debug: st_crossings, street_segments = st_crossings diff --git a/crossify/crossings.py b/crossify/crossings.py index 6582d83..3473eb6 100644 --- a/crossify/crossings.py +++ b/crossify/crossings.py @@ -3,7 +3,7 @@ from shapely.geometry import LineString, Point, Polygon -def make_crossings(intersections_dict, sidewalks, debug=False): +def make_crossings(intersections_dict, sidewalks, dist_param, angle_param, debug=False): crs = sidewalks.crs st_crossings = [] street_segments = [] @@ -14,7 +14,7 @@ def make_crossings(intersections_dict, sidewalks, debug=False): 'ixn': i }) for street in data['streets']: - new_crossing = make_crossing(street, sidewalks, data['streets'], + new_crossing = make_crossing(street, sidewalks, data['streets'], dist_param, angle_param, debug) if debug: new_crossing, street_segment = new_crossing @@ -47,7 +47,7 @@ def comp(geom): return st_crossings -def make_crossing(street, sidewalks, streets_list, debug=False): +def make_crossing(street, sidewalks, streets_list, dist_param, angle_param, debug=False): '''Attempts to create a street crossing line given a street segment and a GeoDataFrame sidewalks dataset. The street and sidewalks should have these properties: @@ -85,7 +85,7 @@ def make_crossing(street, sidewalks, streets_list, debug=False): # FIXME: use 'z layer' data if available (e.g. OSM) START_DIST = 4 - INCREMENT = 2 + INCREMENT = 1 MAX_DIST_ALONG = 25 MAX_CROSSING_DIST = 30 OFFSET = MAX_CROSSING_DIST / 2 @@ -131,7 +131,8 @@ def make_crossing(street, sidewalks, streets_list, debug=False): # The sides have passed the filter! Add their data to the list if crosses_self and not crosses_others: - candidates.append({'geometry': crossing, 'distance': dist}) + angle = find_angle(crossing, street) + candidates.append({'geometry': crossing, 'distance': dist, 'angle': angle}) if not candidates: if debug: @@ -148,8 +149,8 @@ def make_crossing(street, sidewalks, streets_list, debug=False): # distance_metric = 1 / np.array([line['distance'] for line in lines]) # lengths * distance_metric - def metric(candidate): - return candidate['geometry'].length + 1e-1 * candidate['distance'] + def metric(candidate, dist_param = dist_param, angle_param = angle_param): + return candidate['geometry'].length + float(dist_param)*candidate['distance'] + float(angle_param)*candidate['angle'] best = sorted(candidates, key=metric)[0] @@ -229,3 +230,29 @@ def cut(line, distance): return [ LineString(coords[:i] + [(cp.x, cp.y)]), LineString([(cp.x, cp.y)] + coords[i:])] + + +def azimuth(point1, point2): + '''azimuth between 2 shapely points (interval 0 - 360)''' + angle = np.arctan2(point2.x - point1.x, point2.y - point1.y) + return np.degrees(angle)if angle>0 else np.degrees(angle) + 360 + +def find_angle(candidate, street): + + try: + intersect = list(street.intersection(candidate).coords)[0] + shortest_dist = 99999999 + for coord in list(street.coords): + dist = abs(coord[0] - intersect[0]) + abs(coord[1] - intersect[1]) + if dist < shortest_dist: + closest = coord + shortest_dist = dist + + candid_point = candidate.bounds[0], candidate.bounds[1] + + angle = azimuth(Point(closest), Point(candid_point)) + + return min(abs(90 - angle%90), angle%90) + + except NotImplementedError: + return 15